home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archimedes / arafio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  30KB  |  1,001 lines

  1. /* -> c.ckafio
  2.  */
  3.  
  4. char *ckzv = "Arthur file support, 25 June 87";
  5.  
  6. /* C K A F I O  --  Kermit file system support for Arthur */
  7.  
  8. /*
  9.  Author: Frank da Cruz (SY.FDC@CU20B),
  10.  Columbia University Center for Computing Activities, January 1985.
  11.  Copyright (C) 1985, Trustees of Columbia University in the City of New York.
  12.  Permission is granted to any individual or institution to use, copy, or
  13.  redistribute this software so long as it is not sold for profit,
  14.  provided this copyright notice is retained. 
  15.  Arthur version: Graham Toal/Acorn VLSI Tools Group (c) Acorn Computers Plc.
  16. */
  17.  
  18. /* Includes */
  19.  
  20. #include "ckcker.h"         /* Kermit definitions */
  21. #include "ckcdeb.h"         /* Typedefs, debug formats, etc */
  22. #include <stdio.h>          /* Standard i/o */
  23. #ifdef PANOS
  24. #include <ascii.h>
  25. #endif
  26. #ifdef ANSI
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include "h.ckuusr"
  31. #include "h.ckafio"
  32. #include "h.ckamis"
  33. #endif
  34. #ifdef ARTHUR
  35. #include "h.plib"
  36. #include "h.dir"
  37. #endif
  38. #define NL LF
  39.  
  40. char *ckzsys = " Acorn Arthur";
  41.  
  42. /* Definitions of some Arthur system commands - needs changing */
  43.  
  44. char *DIRCMD = "cat ";                      /* For directory listing */
  45. char *DELCMD = "delete ";                   /* For file deletion */
  46. char *TYPCMD = "type ";                     /* For typing a file */
  47. char *PWDCMD = "pwd ";                      /* For saying where I am */
  48. char *CWDCMD = "dir ";                      /* For selecting new dir */
  49.  
  50. char *SPACMD = "run du ";       /* Space/quota of current directory */
  51. char *SPACM2 = "run du ";       /* For space in specified directory */
  52. char *WHOCMD = "users ";      /* For seeing who's logged in */
  53.  
  54. /*
  55.   Functions (n is one of the predefined file numbers from ckermi.h):
  56.  
  57.    zopeni(n,name)   -- Opens an existing file for input.
  58.    zopeno(n,name)   -- Opens a new file for output.
  59.    zclose(n)        -- Closes a file.
  60.    zchin(n,&c)      -- Gets the next character from an input file.
  61.    zsout(n,s)       -- Write a null-terminated string to output file,
  62.                         buffered.
  63.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  64.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  65.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  66.    zchki(name)      -- Check if named file exists and is readable,
  67.                        return size.
  68.    zchko(name)      -- Check if named file can be created.
  69.    znewn(name,s)    -- Make a new unique file name based on the given name.
  70.    zdelet(name)     -- Delete the named file.
  71.    zxpand(string)   -- Expands the given wildcard string into a list of files.
  72.    znext(string)    -- Returns the next file from the list in "string".
  73.    zxcmd(cmd)       -- Execute the command in a lower fork.
  74.    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
  75.    zrtol(n1,n2)     -- Convert remote filename into local form.
  76.    zltor(n1,n2)     -- Convert local filename into remote form.
  77.    zchdir(dirnam)   -- Change working directory.
  78.    zhome()          -- Return pointer to home directory name string.
  79.    zkself()         -- Kill self, log out own job.
  80.  */
  81.  
  82. /* Declarations */
  83. #define NOFILE -99
  84.  
  85. int fp[ZNFILS]   = { NOFILE, NOFILE, NOFILE, NOFILE, NOFILE, NOFILE, NOFILE,
  86. NOFILE, NOFILE };
  87. int isout[ZNFILS]= { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  88.  
  89. #ifdef PANOS
  90. extern int GetFileInformation () asm;
  91. extern int EndOfFile() asm;
  92. extern int SWriteByte() asm; 
  93. extern int XSWriteByte() asm;
  94. extern int SBlockWrite() asm;
  95. extern int XSBlockWrite() asm;
  96. extern int SReadByte() asm;
  97. extern int XSReadByte() asm;
  98. extern int BytesOutstanding() asm;
  99. extern int XBytesOutstanding() asm;
  100. extern int XFindInput() asm;
  101. extern int XFindOutput() asm;
  102. extern int XCloseStream() asm;
  103. extern int XSFlushOutput() asm;
  104. #endif
  105.  
  106. #define ZOBUFSIZ 4096
  107.  
  108. static char zobuf[ZOBUFSIZ];
  109. int zohandle = NOFILE, zosize = 0;
  110.  
  111. #ifdef ANSI
  112. void
  113. #endif
  114. Buffer(stream) int stream; /* select this stream to be buffered */
  115. {
  116. #ifdef ANSI
  117. extern void BFlush( int );
  118. #endif
  119.  
  120.   if (zohandle != NOFILE) BFlush(zohandle);
  121.   zohandle = stream; zosize = 0;
  122. }
  123.  
  124. #ifdef ANSI
  125. void
  126. #endif
  127. BFlush(stream) int stream; {
  128.   if (stream == zohandle) {
  129.     if (zosize) { XSBlockWrite(stream, zosize, zobuf); zosize = 0; }
  130.   }
  131.   XSFlushOutput(stream);
  132. }
  133.  
  134. #ifdef ANSI
  135. void
  136. #endif
  137. BWrite(stream, num, data) int stream, num; char *data; 
  138. {
  139.   if (stream == zohandle) {
  140.     while (num--) {
  141.       zobuf[zosize++] = *data++;
  142.       if (zosize >= ZOBUFSIZ) BFlush(stream);
  143.     }
  144.   }
  145.   else XSBlockWrite(stream, num, data);
  146. }
  147.  
  148. /***************************************************************/
  149. /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
  150. /***************************************************************/
  151.  
  152. #ifdef ANSI
  153. int
  154. #endif
  155. zkself() { return(0); }
  156.  
  157. /******************************************************/
  158. /*  Z O P E N I  --  Open an existing file for input. */
  159. /******************************************************/
  160.  
  161. #ifdef ANSI
  162. int
  163. #endif
  164. zopeni(n,name) int n; char *name; {
  165.   debug(F111," zopeni",name,n);
  166.   debug(F101,"  fp","", fp[n]);
  167.   if (chkfn(n) != 0) return(0);
  168.   isout[n] = 0;
  169.   if (n == ZSYSFN) {            /* Input from a system function? */
  170.     debug(F110," invoking zxcmd",name,0);
  171.     return(zxcmd(name));        /* Try to fork the command */
  172.   }
  173.   if (n == ZSTDIO) {            /* Standard input? */
  174.     /* no easy way to check in Arthur ?
  175.     if (isatty(0)) { ermsg("Terminal input not allowed"); return(0); }
  176.     */
  177.     fp[ZIFILE] = XFindInput("INPUT:", 6); return(1);
  178.   }
  179.   fp[n] = XFindInput(name, strlen(name)); isout[n] = 0;
  180.   debug(F111," zopeni", name, fp[n]);
  181.   if (fp[n] < 0) { perror("zopeni"); fp[n] = NOFILE; }
  182.   return(1);
  183. }
  184.  
  185. /**************************************************/
  186. /*  Z O P E N O  --  Open a new file for output.  */
  187. /**************************************************/
  188.  
  189. #ifdef ANSI
  190. int
  191. #endif
  192. zopeno(n,name) int n; char *name; {
  193.   if (chkfn(n)) return(0);
  194.   isout[n] = 1;
  195.   if (n == ZCTERM) { fp[ZOFILE] = XFindOutput("VDU:", 4); return(1); }
  196.   if (n == ZSTDIO) { fp[ZOFILE] = XFindOutput("OUTPUT:", 7); return(1); }
  197.   fp[n] = XFindOutput(name, strlen(name));
  198.   if (n == ZOFILE) Buffer(fp[n]);
  199.   if (fp[n] < 0) { perror("zopeno can't open"); fp[n] = NOFILE; }
  200.   return((fp[n] >= 0) ? 1 : 0);
  201. }
  202.  
  203. /********************************************/
  204. /*  Z C L O S E  --  Close the given file.  */
  205. /********************************************/
  206.  
  207. #ifdef ANSI
  208. int
  209. #endif
  210. zclose(n) int n; {
  211.   if (chkfn(n) < 1) return(0);  /* Check range of n */
  212.   if ((n == ZIFILE) && (fp[ZSYSFN] >= 0) ) { zclosf(); return(1); }
  213.   if (fp[n] >= 0) { 
  214.     if (isout[n]) { BFlush(fp[n]); }
  215.     XCloseStream(fp[n]); 
  216.   }
  217.   fp[n] = NOFILE; isout[n] = 0; return(1);
  218. }
  219.  
  220. /************************************************************************/
  221. /*  Z C H I N  --  Get a character from the input file.                 */
  222. /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
  223. /************************************************************************/
  224.  
  225. #ifdef ANSI
  226. int
  227. #endif
  228. zchin(n,c) int n; char *c;
  229. { int a;
  230.   if (chkfn(n) < 1) return(-1);
  231.   if (EndOfFile(fp[n]) == 1) return(-1);
  232.   a = SReadByte(fp[n]);
  233.   if (a < 0) return(-1);
  234.   *c = a & 0377;
  235.   return(0);
  236. }
  237.  
  238. /****************************************************************/
  239. /*  Z S O U T  --  Write a string to the given file, buffered.  */
  240. /****************************************************************/
  241.  
  242. #ifdef ANSI
  243. int
  244. #endif
  245. zsout(n,s) int n; char *s; {
  246.   if (chkfn(n) < 1) return(-1);
  247.   BWrite(fp[n], strlen(s), s); return(0);
  248. }
  249.  
  250. /***************************************************************************/
  251. /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
  252. /***************************************************************************/
  253.  
  254. #ifdef ANSI
  255. int
  256. #endif
  257. zsoutl(n,s) int n; char *s; {
  258.   if (chkfn(n) < 1) return(-1);
  259.   zsout(n,s); zchout(n,NL); return(0);
  260. }
  261.  
  262. /**************************************************************/
  263. /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
  264. /**************************************************************/
  265.  
  266. #ifdef ANSI
  267. int
  268. #endif
  269. zsoutx(n,s,x) int n, x; char *s; {
  270.   BWrite(fp[n], x, s); BFlush(fp[n]); return(0);
  271. }
  272.  
  273. /***************************************************************************/
  274. /*  Z C H O U T  --  Add a character to the given file.                    */
  275. /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
  276. /***************************************************************************/
  277.  
  278. #ifdef ANSI
  279. int
  280. #endif
  281. zchout(
  282. #ifdef ANSI
  283. int n, char c)
  284. #else
  285. n,c) int n; char c;
  286. #endif
  287. {
  288.   BWrite(fp[n], 1, &c); return(0);
  289. }
  290.  
  291. /******************************************************************/
  292. /*  C H K F N  --  Internal function to verify file number is ok  */
  293. /*                                                                */
  294. /* Returns:                                                       */
  295. /*  -1: File number n is out of range                             */
  296. /*   0: n is in range, but file is not open                       */
  297. /*   1: n in range and file is open                               */
  298. /******************************************************************/
  299.  
  300. #ifdef ANSI
  301. int
  302. #endif
  303. chkfn(n) int n; {
  304.     switch (n) {
  305.     case ZCTERM:
  306.     case ZSTDIO:
  307.     case ZIFILE:
  308.     case ZOFILE:
  309.     case ZDFILE:
  310.     case ZTFILE:
  311.     case ZPFILE:
  312.     case ZSFILE:
  313.     case ZSYSFN: break;
  314.     default:
  315.         debug(F101,"chkfn: file number out of range","",n);
  316.         return(-1);
  317.     }
  318.     return( (fp[n] == NOFILE) ? 0 : 1 );
  319. }
  320.  
  321. /************************************************************************/
  322. /*  Z C H K I  --  Check if input file exists and is readable           */
  323. /*                                                                      */
  324. /*  Returns:                                                            */
  325. /*   >= 0 if the file can be read (returns the size).                   */
  326. /*     -1 if file doesn't exist or can't be accessed,                   */
  327. /*     -2 if file exists but is not readable (e.g. a directory file).   */
  328. /*     -3 if file exists but protected against read access.             */
  329. /*                                                                      */
  330. /*                                                                      */
  331. /* For Berkeley Unix, a file must be of type "regular" to be readable.  */
  332. /* Directory files, special files, and symbolic links are not readable. */
  333. /************************************************************************/
  334.  
  335. #ifndef ANSI
  336. struct FileData {int loadaddr, execaddr, length, attrib;};
  337.  
  338. struct BTim {int low, high;};
  339. #endif
  340.  
  341. long zchki(name) char *name; {
  342.   struct FileData fileinfo;
  343.   struct BTim timeinfo;
  344.   int rc;
  345.   fileinfo.length = -1;
  346.   rc = GetFileInformation(&fileinfo, &timeinfo, name, strlen(name));
  347.   if (rc == 2) return(-2);
  348.   if (rc < 0)  return(-1);
  349.   return(fileinfo.length);
  350. }
  351.  
  352. /****************************************************************************/
  353. /*  Z C H K O  --  Check if output file can be created                      */
  354. /*                                                                          */
  355. /* Returns -1 if write permission for the file would be denied, 0 otherwise.*/
  356. /****************************************************************************/
  357.  
  358. #ifdef ANSI
  359. int
  360. #endif
  361. zchko(name) char *name; { return(0); }
  362.  
  363. /*********************************************/
  364. /*  Z D E L E T  --  Delete the named file.  */
  365. /*********************************************/
  366.  
  367. #ifdef ANSI
  368. int
  369. #endif
  370. zdelet(name) char *name; {
  371.   char cmdstr [512];
  372.   char *prefix, *suffix;
  373.   char *cp;
  374.   prefix = DELCMD; suffix = name;
  375.   if (prefix == NULL || *prefix == '\0') return(0);
  376.   for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
  377. #ifdef ANSI
  378.   while ( (*cp++ = *suffix++) != '\0' ) ;
  379. #else
  380.   while (*cp++ = *suffix++) ;
  381. #endif
  382.   system(cmdstr);
  383.   return(1);
  384. }
  385.  
  386. #ifdef PANOS
  387. /*******************************************************************/
  388. /*  Z R T O L  --  Convert remote filename into local form         */
  389. /*  For Arthur, this means changing dots into dashes.              */
  390. /*******************************************************************/
  391.  
  392. #ifdef ANSI
  393. static void
  394. #endif
  395. editfname(s,oldc,newc,newlast) char *s; char oldc,newc,newlast;
  396. /*  changes occurrences of oldc in string s to newc, except for  */
  397. /*  last occurrence which gets changed to newlast                */
  398. { char *p,*pos;
  399.   pos = 0;
  400.   for (p = s; *p; ++p) if (*p == oldc) { *p = newc; pos = p; }
  401.   if (pos) *pos = newlast;
  402. }
  403.        
  404. #ifdef ANSI
  405. void
  406. #endif
  407. zrtol(remote,local) char *remote,*local; 
  408. { char *ans = local;
  409. #ifdef ANSI
  410.   while ( (*local++ = *remote++) != '\0' );
  411. #else
  412.   while (*local++ = *remote++);
  413. #endif
  414.   editfname(ans, '-', '=', '=');
  415.   editfname(ans, '.', '_', '-');
  416.   editfname(ans, '/', '.', '.');
  417. }
  418.  
  419. /*****************************************************************/
  420. /*  Z L T O R  --  Local TO Remote                               */
  421. /*  Convert filename from local format to common (remote) form.  */
  422. /*****************************************************************/
  423.  
  424. #ifdef ANSI
  425. void
  426. #endif
  427. zltor(local,remote) char *local, *remote;
  428. { char *ans = remote;
  429. #ifdef ANSI
  430.   while ( (*remote++ = *local++) != '\0' );
  431. #else
  432.   while (*remote++ = *local++);
  433. #endif
  434.   editfname(ans, '/', '=', '=');
  435.   editfname(ans, '.', '/', '/');
  436.   editfname(ans, '-', '-', '.');
  437. }    
  438. #endif
  439.  
  440.  
  441. #ifdef ARTHUR
  442. /*******************************************************************/
  443. /*  Z R T O L  --  Convert remote filename into local form         */
  444. /*  For Arthur, this means changing dots into dashes.              */
  445. /*******************************************************************/
  446.  
  447. #ifdef ANSI
  448. static void
  449. #endif
  450. editfname(s,oldc,newc,newlast) char *s; char oldc,newc,newlast;
  451. /*  changes occurrences of oldc in string s to newc, except for  */
  452. /*  last occurrence which gets changed to newlast                */
  453. { char *p,*pos;
  454.   pos = 0;
  455.   for (p = s; *p; ++p) if (*p == oldc) { *p = newc; pos = p; }
  456.   if (pos) *pos = newlast;
  457. }
  458.        
  459. #ifdef ANSI
  460. void
  461. #endif
  462. zrtol(remote,local) char *remote,*local; 
  463. { char *ans = local;
  464. #ifdef ANSI
  465.   while ( (*local++ = *remote++) != '\0' );
  466. #else
  467.   while (*local++ = *remote++);
  468. #endif
  469.   editfname(ans, '-', '=', '=');
  470.   editfname(ans, '.', '_', '-');
  471.   editfname(ans, '/', '.', '.');
  472. }
  473.  
  474. /*****************************************************************/
  475. /*  Z L T O R  --  Local TO Remote                               */
  476. /*  Convert filename from local format to common (remote) form.  */
  477. /*****************************************************************/
  478.  
  479. #ifdef ANSI
  480. void
  481. #endif
  482. zltor(local,remote) char *local, *remote;
  483. { char *ans = remote;
  484. #ifdef ANSI
  485.   while ( (*remote++ = *local++) != '\0' );
  486. #else
  487.   while (*remote++ = *local++);
  488. #endif
  489.   editfname(ans, '/', '=', '=');
  490.   editfname(ans, '.', '/', '/');
  491.   editfname(ans, '-', '-', '.');
  492. }    
  493. #endif
  494.  
  495. /***************************************/
  496. /*  Z C H D I R  --  Change directory  */
  497. /***************************************/
  498.  
  499. #ifdef ANSI
  500. int
  501. #endif
  502. zchdir(dirnam) char *dirnam; {
  503. char cmdstr [512];
  504. char *prefix, *suffix;
  505.   char *cp;
  506.   prefix = CWDCMD; suffix = dirnam;
  507.   if (prefix == NULL || *prefix == '\0') return(0);
  508.   for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
  509. #ifdef ANSI
  510.   while ( (*cp++ = *suffix++) != '\0' ) ;
  511. #else
  512.   while (*cp++ = *suffix++) ;
  513. #endif
  514.   system(cmdstr);
  515.   return(1);
  516. }
  517.  
  518. /************************************************************/
  519. /*  Z H O M E  --  Return pointer to user's home directory  */
  520. /************************************************************/
  521. static char *myhome = "&";
  522. char *zhome() { return(myhome); }
  523.  
  524. /****************************************************************************/
  525. /*  Z X C M D -- Run a system command so its output can be read like a file */
  526. /****************************************************************************/
  527.  
  528. #ifdef ANSI
  529. int
  530. #endif
  531. zxcmd(comand) char *comand; {
  532. char *redirect = "{ > kerm-tmp }";
  533. char cmdstr [512];
  534. char *prefix, *suffix;
  535.   char *cp;
  536.   prefix = comand; suffix = redirect;
  537.   if (prefix == NULL || *prefix == '\0') return(0);
  538.  
  539.   for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
  540.  
  541. #ifdef ANSI
  542.   while ( (*cp++ = *suffix++) != '\0' ) ;
  543. #else
  544.   while (*cp++ = *suffix++) ;
  545. #endif
  546.  
  547.   fp[ZSYSFN] = XFindOutput("kerm-tmp", 8);
  548.   XCloseStream(fp[ZSYSFN]); fp[ZSYSFN] = NOFILE;
  549.   /* ensure it is empty in case not written to! */
  550.  
  551.   if( (strncmp(comand,SPACMD,strlen(SPACMD))==0) ||
  552.       (strncmp(comand,SPACM2,strlen(SPACM2))==0) )
  553.     du("kerm-tmp");
  554.   else
  555.     system(cmdstr);
  556.  
  557.  
  558.   fp[ZIFILE] = fp[ZSYSFN] = XFindInput("kerm-tmp", 8);
  559.   return(1);
  560. }
  561.  
  562. /****************************************************************************/
  563. /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
  564. /****************************************************************************/
  565.  
  566. #ifdef ANSI
  567. int
  568. #endif
  569. zclosf() {
  570.   if (fp[ZSYSFN] >= 0) XCloseStream(fp[ZSYSFN]);
  571.   fp[ZIFILE] = fp[ZSYSFN] = NOFILE;
  572.   return(1);
  573. }
  574.  
  575. /****************************************************************************/
  576. /*  Z X P A N D  --  Expand a wildcard string into an array of strings      */
  577. /*                                                                          */
  578. /*  Returns the number of files that match fn1, with data structures set up */
  579. /*  so that first file (if any) will be returned by the next znext() call.  */
  580. /****************************************************************************/
  581.  
  582. #ifdef PANOS
  583. static int countwild, bfptr;
  584. static char namebuff[4096];
  585.  
  586. addfn(fn, len, arg) char *fn; int len, arg; {
  587.   int rslt;
  588.   while (namebuff[bfptr++] = *fn++) ;
  589.   rslt = 0;
  590.   /********************************************************************/
  591.   /*  we want to pass this to be called from Modula-2, which doesn't  */
  592.   /*  expect to have to unwind the stack: this is horrible.           */
  593.   /********************************************************************/
  594.   asm { MOVD rslt, 0; EXIT #0; RXP #12; } 
  595. }
  596.  
  597. static int
  598. addfn(fn, len, arg) char *fn; int len, arg; {
  599. #ifdef ANSI
  600.   while ( (namebuff[bfptr++] = *fn++) != '\0' ) ;
  601. #else
  602.   while (namebuff[bfptr++] = *fn++) ;
  603. #endif
  604.   return 0;
  605. }
  606.  
  607. extern int Expand() asm;
  608.  
  609. int
  610. zxpand(fn) char *fn; {
  611.   bfptr = 0;
  612.   countwild = Expand(fn, strlen(fn),
  613.                      &addfn, /* state arg = */ 42,
  614.                      /* target is dir = false */ 0);
  615.   namebuff[bfptr] = '\0';
  616.   bfptr = 0;
  617.   return(countwild);
  618. }
  619.  
  620. /**************************************************************************/
  621. /*  Z N E X T  --  Get name of next file from list created by zxpand().   */
  622. /*                                                                        */
  623. /* Returns >0 if there's another file, with its name copied into the      */
  624. /* arg string, or 0 if no more files in list.                             */
  625. /**************************************************************************/
  626.  
  627. #ifdef ANSI
  628. int
  629. #endif
  630. znext(fn) char *fn; {
  631. #ifndef ANSI
  632.   int i = 0;
  633. #endif
  634.   char *thisone;
  635.   if (countwild-- > 0) {
  636.     if (namebuff[bfptr] == '\0') {
  637.       printf("Internal error: eos in znext\n"); return(0);
  638.     }
  639.     thisone = &namebuff[bfptr];
  640.     while (namebuff[bfptr++]) ;
  641.     strcpy(fn, thisone);
  642.     return(1);
  643.   } 
  644.   else return(0);
  645. }
  646. #endif
  647.  
  648.  
  649. #ifdef ARTHUR
  650.  
  651.  
  652. #define MAXWLD 50                      /* Maximum wildcard filenames */
  653. static int fcount;                     /* Number of files in wild group */
  654. static char *mtchs[MAXWLD],            /* Matches found for filename */
  655.      **mtchptr;                                /* Pointer to current match */
  656.  
  657. int
  658. zxpand(fn) char *fn; {
  659. extern int fgen( char *, char *[], int );
  660.  
  661.     fcount = fgen(fn,mtchs,MAXWLD);    /* Look up the file. */
  662.     if (fcount > 0) {
  663.        mtchptr = mtchs;                /* Save pointer for next. */
  664.     }
  665.     debug(F111,"zxpand",mtchs[0],fcount);
  666.     return(fcount);
  667. }
  668.  
  669. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  670. /*
  671.  Returns >0 if there's another file, with its name copied into the arg string,
  672.  or 0 if no more files in list.
  673. */
  674. int
  675. znext(fn) char *fn; {
  676.     if (fcount-- > 0) strcpy(fn,*mtchptr++);
  677.     else *fn = '\0';
  678.     debug(F111,"znext",fn,fcount+1);
  679.     return(fcount+1);
  680. }
  681.  
  682. #endif
  683.  
  684.  
  685. /*******************************************************/
  686. /*  Z N E W N  --  Make a new name for the given file  */
  687. /*******************************************************/
  688.  
  689. #ifdef ANSI
  690. void
  691. #endif
  692. znewn(fn,s) char *fn, **s; {
  693.   static char buf[256];
  694.   int i = 0;
  695. #ifdef ANSI
  696.   while ( (buf[i] = fn[i]) != '\0' ) i++;
  697. #else
  698.   while (buf[i] = fn[i]) i++;
  699. #endif
  700.   *s = buf;
  701. }
  702.  
  703. /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
  704.  
  705. /*
  706.  * The path structure is used to represent the name to match.
  707.  * Each slash-separated segment of the name is kept in one
  708.  * such structure, and they are linked together, to make
  709.  * traversing the name easier.
  710.  */
  711.  
  712. struct path {
  713.               char npart[MAXNAMLEN];   /* name part of path segment */
  714.               struct path *fwd;                /* forward ptr */
  715.             };
  716.  
  717. #define SSPACE 2000                   /* size of string-generating buffer */
  718. static char sspace[SSPACE];           /* buffer to generate names in */
  719. static char *freeptr,**resptr;        /* copies of caller's arguments */
  720. static int remlen;                    /* remaining length in caller's array*/
  721. static int numfnd;                    /* number of matches found */
  722. static char nambuf[MAXNAMLEN+1];       /* Buffer for a filename */
  723.  
  724. extern void traverse( struct path *, char *, char *);
  725. extern void addresult( char * );
  726. int iswild( char * );
  727. extern int match( char *, char * );
  728.  
  729. /*
  730.  * splitpath:
  731.  *  takes a string and splits the slash-separated portions into
  732.  *  a list of path structures.  Returns the head of the list.  The
  733.  *  structures are allocated by malloc, so they must be freed.
  734.  *  Splitpath is used internally by the filename generator.
  735.  *
  736.  * Input: A string.
  737.  * Returns: A linked list of the slash-separated segments of the input.
  738.  */
  739.  
  740. struct path *
  741. splitpath(p)
  742. char *p;
  743. {
  744.  struct path *head,*cur,*prv;
  745.  int i;
  746.  head = prv = NULL;
  747. /* if (*p == '$') p++;*/            /* skip leading slash */
  748. /* if (*p == ':') p+=2;*/           /* skip drive spec */
  749.  while (*p != '\0')
  750.  {
  751.    cur = (struct path *) malloc(sizeof (struct path));
  752.    debug(F101,"splitpath malloc","",(int)cur);
  753.    if (cur == NULL) fatal("malloc fails in splitpath()");
  754.    cur -> fwd = NULL;
  755.    if (head == NULL) head = cur;
  756.    else prv -> fwd = cur;       /* link into chain */
  757.    prv = cur;
  758.    for (i=0; i < MAXNAMLEN && *p != '.' && *p != '\0'; i++)
  759.      cur -> npart[i] = *p++;
  760.    cur -> npart[i] = '\0';      /* end this segment */
  761.    if (i >= MAXNAMLEN) while (*p != '.' && *p != '\0') p++;
  762.    if (*p == '.') p++;
  763.  }
  764.  return(head);
  765. }
  766.  
  767. /*
  768.  * fgen:
  769.  *  This is the actual name generator.  It is passed a string,
  770.  *  possibly containing wildcards, and an array of character pointers.
  771.  *  It finds all the matching filenames and stores them into the array.
  772.  *  The returned strings are allocated from a static buffer local to
  773.  *  this module (so the caller doesn't have to worry about deallocating
  774.  *  them); this means that successive calls to fgen will wipe out
  775.  *  the results of previous calls.  This isn't a problem here
  776.  *  because we process one wildcard string at a time.
  777.  *
  778.  * Input: a wildcard string, an array to write names to, the
  779.  *        length of the array.
  780.  * Returns: the number of matches.  The array is filled with filenames
  781.  *          that matched the pattern.  If there wasn't enough room in the
  782.  *         array, -1 is returned.
  783.  * By: Jeff Damens, CUCCA, 1984.
  784.  */
  785.  
  786. int
  787. fgen(pat,resarry,len)
  788. char *pat,*resarry[];
  789. int len;
  790. {
  791.  struct path *head;
  792.  char scratch[100],*sptr;
  793.  
  794.  head = splitpath(pat);
  795.  
  796.  if ( *pat == '.' )
  797.  {
  798.   scratch[0] = '.';
  799.   sptr = scratch+1;
  800.  }
  801.  else
  802.  {
  803. /*  strcpy(scratch,"");*/
  804.   scratch[0] = '\0';
  805.   sptr = scratch/*+2*/;
  806.  }                                     /* init buffer correctly */
  807.  numfnd = 0;                            /* none found yet */
  808.  freeptr = sspace;                     /* this is where matches are copied */
  809.  resptr = resarry;                     /* static copies of these so*/
  810.  remlen = len;                         /* recursive calls can alter them */
  811.  traverse(head,scratch,sptr);          /* go walk the directory tree */
  812.  for (; head != NULL; head = head -> fwd)
  813.    free(head);                         /* return the path segments */
  814.  return(numfnd);                       /* and return the number of matches */
  815. }
  816.  
  817. /* traverse:
  818.  *  Walks the directory tree looking for matches to its arguments.
  819.  *  The algorithm is, briefly:
  820.  *   If the current pattern segment contains no wildcards, that
  821.  *   segment is added to what we already have.  If the name so far
  822.  *   exists, we call ourselves recursively with the next segment
  823.  *   in the pattern string; otherwise, we just return.
  824.  *
  825.  *   If the current pattern segment contains wildcards, we open the name
  826.  *   we've accumulated so far (assuming it is really a directory), then read 
  827.  *   each filename in it, and, if it matches the wildcard pattern segment, add
  828.  *   that filename to what we have so far and call ourselves recursively on the
  829.  *   next segment.
  830.  *
  831.  *   Finally, when no more pattern segments remain, we add what's accumulated
  832.  *   so far to the result array and increment the number of matches.
  833.  *
  834.  * Input: a pattern path list (as generated by splitpath), a string
  835.  *       pointer that points to what we've traversed so far (this
  836.  *       can be initialized to "/" to start the search at the root
  837.  *       directory, or to "./" to start the search at the current
  838.  *       directory), and a string pointer to the end of the string
  839.  *       in the previous argument.
  840.  * Returns: nothing.
  841.  */
  842.  
  843. void
  844. traverse(pl,sofar,endcur)
  845. struct path *pl;
  846. char *sofar,*endcur;
  847. {
  848.  DIR *fd;
  849.  struct dirent dir_entry;
  850.  struct dirent *dirbuf = &dir_entry;
  851.  
  852.  struct FileData fileinfo;
  853.  struct BTim timeinfo;
  854.  int rc;
  855.  int stamped;
  856.  
  857.  if (pl == NULL)
  858.  {
  859.   *--endcur = '\0';                    /* end string, overwrite trailing / */
  860.   addresult(sofar);
  861.   return;
  862.  }
  863.  
  864.  if (!iswild(pl -> npart))
  865.  {
  866.   strcpy(endcur,pl -> npart);
  867.   endcur += strlen(pl -> npart);
  868.   *endcur = '\0';                      /* end current string */
  869. /*  if (stat(sofar,&statbuf) == 0) */      /* if current piece exists */
  870.   rc = GetFileInformation(&fileinfo, &timeinfo, sofar, strlen(sofar));
  871.   if( rc >= 0 )  /* if current piece exists */
  872.   {
  873.       *endcur++ = '.';                  /* add slash to end */
  874.       *endcur = '\0';                  /* and end the string */
  875.       traverse(pl -> fwd,sofar,endcur);
  876.   }
  877.   return;
  878.  }
  879.  
  880. /* segment contains wildcards, have to search directory */
  881.  
  882.  *endcur = '\0'; /* end current string */
  883.  if( *(endcur-1) == '.' )
  884.  {
  885.    /* Stamp on trailing . */
  886.    *--endcur = '\0';
  887.    stamped = 1;
  888.  }
  889.  else
  890.    stamped = 0;
  891. /* if (stat(sofar,&statbuf) == -1) return;*/   /* doesn't exist, forget it */
  892. /* if ((statbuf.st_mode & S_IFDIR) == 0) return;*/  /* not a directory, skip */
  893.  
  894.  if( sofar[0] != '\0' )
  895.  {
  896.   /* cwd is represented as a NULL string!! */
  897.   rc = GetFileInformation(&fileinfo, &timeinfo, sofar, strlen(sofar));
  898.   if( rc == -1 ) return;   /* doesn't exist, forget it */
  899.   if( rc != 2 ) return;    /* not a directory, skip */
  900.  }
  901.  
  902.  if ((fd = opendir(sofar)) == NULL) return;    /* can't open, forget it */
  903.  
  904.  if( stamped != 0 )
  905.  {
  906.    *endcur++ = '.';
  907.    *endcur = '\0';
  908.  }
  909.  
  910.  while ( (dirbuf = readdir(fd)) != NULL )
  911.  {
  912.   strncpy(nambuf,dirbuf->d_name,MAXNAMLEN); /* Get a null terminated copy!!! */
  913.   nambuf[MAXNAMLEN] = '\0';
  914. /*  if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) {*/
  915.   if ( match(pl -> npart,nambuf)) {
  916.     char *eos;
  917.     strcpy(endcur,nambuf);
  918.     eos = endcur + strlen(nambuf);
  919.     *eos = '.';                    /* end this segment */
  920.     traverse(pl -> fwd,sofar,eos+1);
  921.  }
  922. }
  923.  
  924.  closedir(fd);
  925.  
  926. /*
  927.  * addresult:
  928.  *  Adds a result string to the result array.  Increments the number
  929.  *  of matches found, copies the found string into our string
  930.  *  buffer, and puts a pointer to the buffer into the caller's result
  931.  *  array.  Our free buffer pointer is updated.  If there is no
  932.  *  more room in the caller's array, the number of matches is set to -1.
  933.  * Input: a result string.
  934.  * Returns: nothing.
  935.  */
  936.  
  937. void
  938. addresult(str)
  939. char *str;
  940. {
  941.  int l;
  942.  if (strncmp(str,"./",2) == 0) str += 2;
  943.  if (--remlen < 0) {
  944.   numfnd = -1;
  945.   return;
  946.  }
  947.  l = strlen(str) + 1;                  /* size this will take up */
  948.  if ((freeptr + l) > &sspace[SSPACE]) {
  949.     numfnd = -1;                       /* do not record if not enough space */
  950.     return;
  951.   }
  952.  strcpy(freeptr,str);
  953.  *resptr++ = freeptr;
  954.  freeptr += l;
  955.  numfnd++;
  956. }
  957.  
  958. int
  959. iswild(str)
  960. char *str;
  961. {
  962.  char c;
  963.  while ((c = *str++) != '\0')
  964.    if (c == '*' || c == '@') return(1);
  965.  return(0);
  966. }
  967.  
  968. /*
  969.  * match:
  970.  *  pattern matcher.  Takes a string and a pattern possibly containing
  971.  *  the wildcard characters '*' and '@'.  Returns true if the pattern
  972.  *  matches the string, false otherwise.
  973.  * by: Jeff Damens, CUCCA
  974.  *
  975.  * Input: a string and a wildcard pattern.
  976.  * Returns: 1 if match, 0 if no match.
  977.  */
  978.  
  979.  
  980. int
  981. match(pattern,string) char *pattern,*string; {
  982.     char *psave,*ssave; /* back up pointers for failure */
  983.     psave = ssave = NULL;
  984.     while (1) {
  985.        for (; *pattern == *string; pattern++,string++)  /* skip first */
  986.            if (*string == '\0') return(1);     /* end of strings, succeed */
  987.        if (*string != '\0' && *pattern == '@') {
  988.            pattern++;                  /* '@', let it match */
  989.            string++;
  990.        } else if (*pattern == '*') {   /* '*' ... */
  991.            psave = ++pattern;          /* remember where we saw it */
  992.            ssave = string;             /* let it match 0 chars */
  993.        } else if (ssave != NULL && *ssave != '\0') {   /* if not at end  */
  994.                                        /* ...have seen a star */
  995.            string = ++ssave;           /* skip 1 char from string */
  996.            pattern = psave;            /* and back up pattern */
  997.        } else return(0);               /* otherwise just fail */
  998.     }
  999. }
  1000.