home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ck9192.tar.Z / ck9192.tar / ck9fio.c < prev    next >
Text File  |  1996-12-14  |  61KB  |  1,977 lines

  1. char *ckzv = "OS-9 file support, 5A(015) 4 Jul 96";
  2. char *ckzsys = " OS-9/68000";
  3.  
  4. /* c k 9 F I O  --  Kermit file system support for OS-9/68k systems */
  5.  
  6. /*
  7.  Author: Peter Scholz,
  8.  Ruhr University Bochum, Department for Analytical Chemistry,
  9.  Federal Republic of Germany,   February 1987
  10.  
  11.  04/30/87 Robert Larson         Cleanup, merge with standard C-kermit
  12.  04/07/89 Robert Larson         Update for ckermit 4f(77)
  13.  07/16/89 Robert Larson         4f(85)
  14.  Edition: 5A(01)
  15.  06/21/91 Chris  Hemsing        general adaption to 5A(171)
  16.                                 miscellaneous bug fixes, utilization of
  17.                                 initial file size.
  18.  07/25/91 Chris  Hemsing        minor bug fixes, changes for gnu (ansi) C
  19.  01/14/92 Chris  Hemsing        uct/localtime  bug fix
  20.  05/26/92 Chris  Hemsing        zltor and zrtol bug fix
  21.  Edition: 5A(05)
  22.  06/30/92 Chris  Hemsing        pipeopen stderr bug fix,dir shows filesize
  23.  Edition: 5A(06)
  24.  07/09/92 Chris  Hemsing        removed all chaining which would save a
  25.                                 process but f$chain does not look in PATH
  26.  Edition: 5A(07)
  27.  07/10/92 Chris  Hemsing        remove whole process tree of a lower fork
  28.  Edition: 5A(08)
  29.  12/01/92 Chris  Hemsing        zgtdir bugs repaired: upmost dir not closed
  30.                                 closedir of non-open dir could be called
  31.  Edition: 5A(09)
  32.  04/10/94 ?                     adapted password tag of struct zattr
  33.  Edition: 5A(10)
  34.  01/05/95 Ulli Schlueter        changed rename(), added isdir(), zmkdir() and
  35.                                 zfseek()
  36.  Edition: 5A(11)
  37.  01/13/95 Ulli Schlueter        changed zrtol() to enable directories in as-
  38.                                 names, corrected MAXNAMLEN, adapted znewn() to
  39.                                 the fact that it is called with full path
  40.                                 names, fixed bug in tilde_expand() (buffer to
  41.                                 small)
  42.  Edition: 5A(12)
  43.  03/13/95 Ulli Schlueter        some little bug fixies and cleanups
  44.  Edition: 5A(13)
  45.  03/20/95 Ulli Schlueter        kill_tree() now takes care of parent pid
  46.  Edition: 5A(14)
  47.  04/19/95 Ulli Schlueter        Rewrote zgtdir(), made some large buffers
  48.                                 dynamic.
  49.  
  50.   Adapted from UNIX C-Kermit.
  51.   Author: Frank da Cruz <fdc@columbia.edu>.
  52.  
  53.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  54.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  55.   sold for profit as a software product itself, nor may it be included in or
  56.   distributed with commercial products or otherwise distributed by commercial
  57.   concerns to their clients or customers without written permission of the
  58.   Office of Kermit Development and Distribution, Columbia University.  This
  59.   copyright notice must not be removed, altered, or obscured.
  60. */
  61. /* Includes */
  62.  
  63. #include "ckcsym.h"
  64. #include "ckcdeb.h"             /* Typedefs, debug formats, etc */
  65. #include "ckcker.h"             /* Kermit definitions */
  66. #include "ckcasc.h"
  67. #include <errno.h>
  68. #include <dir.h>                /* Directory structure */
  69. #include <direct.h>
  70. #include <modes.h>
  71. #include <procid.h>
  72. #include <signal.h>
  73. #include <strings.h>
  74. #include <time.h>
  75.  
  76. #define DIRSEP       '/'
  77. #define ISDIRSEP(c)  ((c)=='/')
  78.  
  79. /* Definitions of some system commands */
  80.  
  81. char *DIRCMD = "dir -e ";          /* For directory listing with filename*/
  82. char *DIRCM2 = "dir -e ";           /* For directory listing without filename*/
  83. char *DELCMD = "del ";          /* For file deletion */
  84. char *TYPCMD = "list ";         /* For typing a file */
  85. char *PWDCMD = "pd ";           /* For saying where I am */
  86.  
  87. char *SPACMD = "free ";
  88. char *SPACM2 = "free ";         /* For space in specified directory */
  89.  
  90. char *WHOCMD = "procs -e ";        /* we have no who yet*/
  91.  
  92. /*
  93.   Functions (n is one of the predefined file numbers from ckermi.h):
  94.  
  95.    zopeni(n,name)   -- Opens an existing file for input.
  96.    zopeno(n,name,attr,fcb) -- Opens a new file for output.
  97.    zclose(n)        -- Closes a file.
  98.    zchin(n,&c)      -- Gets the next character from an input file.
  99.    zsinl(n,&s,x)    -- Read a line from file n, max len x, into address s.
  100.    zsout(n,s)       -- Write a null-terminated string to output file,buffered.
  101.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  102.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  103.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  104.    zchki(name)      -- Check if named file exists and is readable,return size.
  105.    zchko(name)      -- Check if named file can be created.
  106.    zchkspa(name,n)  -- Check if n bytes available to create new file, name.
  107.    znewn(name,s)    -- Make a new unique file name based on the given name.
  108.    zdelet(name)     -- Delete the named file.
  109.    zxpand(string)   -- Expands the given wildcard string into a list of files.
  110.    znext(string)    -- Returns the next file from the list in "string".
  111.    zxcmd(cmd)       -- Execute the command in a lower fork.
  112.    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
  113.    zrtol(n1,n2)     -- Convert remote filename into local form.
  114.    zltor(n1,n2)     -- Convert local filename into remote form.
  115.    zchdir(dirnam)   -- Change working directory.
  116.    zhome()          -- Return pointer to home directory name string.
  117.    zkself()         -- Kill self, log out own job.
  118.    zsattr(struc zattr *) -- Return attributes for file which is being sent.
  119.    zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
  120.    zrename(old, new) -- Rename a file.
  121.    zmkdir(path)       -- Create the directory path if possible  
  122.  */
  123.  
  124.  
  125. /* Some systems define these in include files, others don't... */
  126.  
  127. #define MAXWLD 500
  128.  
  129. /* MAXNAMLEN in <dir.h> is incorrect */
  130. #ifdef MAXNAMLEN
  131. #undef MAXNAMLEN
  132. #endif /* MAXNAMLEN */
  133. #define MAXNAMLEN 28
  134.  
  135. /* Declarations */
  136. #define MAXPATH 256                     /* not really an OS-9 restriction */
  137.  
  138.  
  139. FILE *fp[ZNFILS] = {    /* File pointers */
  140.     NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  141.  
  142. /* (PWP) external def. of things used in buffered file input and output */
  143. #ifdef DYNAMIC
  144. extern CHAR *zinbuffer, *zoutbuffer;
  145. #else
  146. extern CHAR zinbuffer[], zoutbuffer[];
  147. #endif /* DYNAMIC */
  148. extern CHAR *zinptr, *zoutptr;
  149. extern int zincnt, zoutcnt;
  150.  
  151. struct fildes cur_in_fd;              /* current input filedesc */
  152. static int cur_in_size = -1;          /* current input file length */
  153.  
  154. static int pipe_pid;                            /* pid of child fork */
  155. static int fcount;                      /* Number of files in wild group */
  156. char *getenv(), *strcpy();              /* System functions */
  157. /* VOID *malloc(); */
  158. extern int errno;                       /* System error code */
  159.  
  160. char **mtchs,                           /* Matches found for filename */
  161.      **mtchptr;                         /* Pointer to current match */
  162.  
  163. /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
  164.  
  165. zkself() {                              /* For "bye" */
  166. procid pbuf;
  167.   _get_process_desc(getpid(),sizeof(pbuf),&pbuf);
  168.   if (kill((int)pbuf._pid,SIGKILL)==0)
  169.     doexit(GOOD_EXIT,-1);/*kill parent process*/
  170.   else
  171.     doexit(errno,-1);
  172. }
  173.  
  174. /*  Z G T D I R  --  Get current working directory. */
  175.  
  176. static char *
  177. getcwd (pwdbuf, size)
  178.      char *pwdbuf;
  179.      unsigned size;
  180. {
  181.     DIR *dirp;
  182.     long cur, tmp, here;
  183. #ifdef CWDNU
  184.     void *mem = NULL;
  185. #endif /* CWDNU */
  186.     char *cp;
  187.     char *cd;
  188.     struct direct *ent;
  189.     char buffer[128];
  190. #define MAXDEPTH 64
  191.     char dots[MAXDEPTH+1];
  192.  
  193. #ifdef CWDNU
  194.     if (size < MAXNAMLEN + 2) { /* '/' and '\0' */
  195.         errno = E_ILLARG;
  196.         return NULL;
  197.     }
  198.     if (pwdbuf == NULL) {
  199.         if ((pwdbuf = malloc(size)) == NULL)
  200.           return NULL;
  201.         mem = pwdbuf;
  202.     }
  203. #endif /* CWDNU */
  204.     cp = pwdbuf + size;
  205.     *--cp = '\0';
  206.     cd = dots + sizeof dots;
  207.     *--cd = '\0';
  208.     here = 0;
  209.     do {
  210.         if (cd <= dots) {       /* out of space */
  211.             errno = E_FULL;
  212. #ifdef CWDNU
  213.             if (mem) free(mem);
  214. #endif /* CWDNU */
  215.             return NULL;
  216.         }
  217.         *--cd = '.';
  218.         if ((dirp = opendir(cd)) == NULL) {
  219. #ifdef CWDNU
  220.             if (mem) free(mem);
  221. #endif /* CWDNU */
  222.             return NULL;
  223.         }
  224.         /* read '..' and '.' entries */
  225.         if ((ent = readdir(dirp)) == NULL
  226.             || (tmp = ent->d_addr, (ent = readdir(dirp)) == NULL)) {
  227.             closedir(dirp);
  228. #ifdef CWDNU
  229.             if (mem) free(mem);
  230. #endif /* CWDNU */
  231.             return NULL;
  232.         }
  233.         cur = ent->d_addr;
  234.         if (cur == tmp) cur = 0;
  235.         if (here == 0) {
  236.             here = cur;
  237.             continue;           /* Break if in the root */
  238.         }
  239.         while ((ent = readdir(dirp)) != NULL)
  240.         {
  241.             if (ent->d_addr == here)
  242.             {
  243.                 strcpy(buffer, ent->d_name);
  244.                 cp -= (tmp = strlen(buffer));
  245.                 if (cp <= pwdbuf) { /* out of space */
  246.                     errno = E_FULL;
  247.                     break;
  248.                 }
  249.                 memcpy(cp, buffer, tmp);
  250.                 *--cp = '/';
  251.                 here = cur;
  252.                 break;
  253.             }
  254.         }
  255.         if (here != cur) {      /* read error, entry not found or no space */
  256.             closedir(dirp);
  257. #ifdef CWDNU
  258.             if (mem) free(mem);
  259. #endif /* CWDNU */
  260.             return NULL;
  261.         }
  262.     } while (cur != 0 && (closedir(dirp), 1));
  263.     if (_gs_devn(dirp->dd_fd, buffer) < 0) { /* get device name */
  264.         closedir(dirp);
  265. #ifdef CWDNU
  266.         if (mem) free(mem);
  267. #endif /* CWDNU */
  268.         return NULL;
  269.     }
  270.     closedir(dirp);
  271.     cp -= (tmp = strlen(buffer));
  272.     if (cp <= pwdbuf) {
  273.         errno = E_FULL;
  274. #ifdef CWDNU
  275.         if (mem) free(mem);
  276. #endif /* CWDNU */
  277.         return NULL;
  278.     }
  279.     memcpy(cp, buffer, tmp);
  280.     *--cp = '/';
  281.     memcpy(pwdbuf, cp, pwdbuf + size - cp);
  282.     return pwdbuf;
  283. }
  284.  
  285. char *zgtdir() {
  286.     static char *cwd;
  287. #define CWDBL (MAXPATH + 1)
  288.  
  289.     if (cwd == NULL && (cwd = malloc(CWDBL)) == NULL) return "";
  290.     cwd[0] = '\0';
  291.     getcwd(cwd, CWDBL);
  292.     return cwd;
  293. }
  294.  
  295.  
  296. /*  Z O P E N I  --  Open an existing file for input. */
  297.  
  298. zopeni(n,name) int n; char *name; {
  299.     debug(F111," zopeni",name,n);
  300.     debug(F101,"  fp","",(int) fp[n]);
  301.     if (chkfn(n) != 0) return(0);
  302.     zincnt = 0;                         /* Reset input buffer */
  303.     if (n == ZSYSFN) {                  /* Input from a system function? */
  304. /*** Note, this function should not be called with ZSYSFN ***/
  305. /*** Always call zxcmd() directly, and give it the real file number ***/
  306. /*** you want to use.  ***/
  307.         debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
  308.                 return(0);                      /* fail. */
  309.     }
  310.     if (n == ZSTDIO) {   /* Standard input? */
  311.         if (isatty(0)) {
  312.             ermsg("Terminal input not allowed");
  313.             debug(F110,"zopeni: attempts input from unredirected stdin","",0);
  314.             return(0);
  315.         }
  316.         fp[ZIFILE] = stdin;
  317.         return(1);
  318.     }
  319.     fp[n] = fopen(name,"r");            /* Real file. */
  320.     debug(F111," zopeni", name, (int) fp[n]);
  321.     if (fp[n] == NULL) perror("zopeni");
  322.     return((fp[n] != NULL) ? 1 : 0);
  323. }
  324.  
  325. /*  Z O P E N O  --  Open a new file for output.  */
  326.  
  327. zopeno(n,name,zz,fcb)
  328. /* zopeno */  int n; char *name; struct zattr *zz; struct filinfo *fcb; {
  329.  
  330. /* As of Version 5A, the attribute structure and the file information */
  331. /* structure are included in the arglist. */
  332.  
  333.     char *p;
  334.     int pn;
  335.     debug(F111,"zopeno",name,n);
  336.     if (chkfn(n) != 0) return(0);
  337.     zoutcnt = 0;
  338.     zoutptr = zoutbuffer;
  339.     if (fcb)
  340.     {
  341.           debug(F101,"zopeno fcb disp","",fcb->dsp);
  342.           debug(F101,"zopeno fcb type","",fcb->typ);
  343.           debug(F101,"zopeno fcb char","",fcb->cs);
  344.     }
  345.     else debug(F100,"zopeno fcb is NULL","",0);
  346.     if ((n == ZCTERM) || (n == ZSTDIO))
  347.     {   /* Terminal or standard output */
  348.           fp[ZOFILE] = stdout;
  349.           debug(F101," fp[]=stdout", "", (int) fp[n]);
  350.           return(1);
  351.     }
  352.  
  353. /* A real file.  Open it in desired mode (create or append). */
  354.     p = "w";                            /* Assume write/create mode */
  355.     if (fcb) {                          /* If called with an FCB... */
  356.         if (fcb->dsp == XYFZ_A)         /* Does it say Append? */
  357.           p = "a";                      /* Yes. */
  358.     }
  359.     if (access(name,0) == 0) /* does file exist ? */
  360.     {
  361.       if ((fp[n] = fopen(name,p)) == NULL)      /* Simply open the file */
  362.       {
  363.         perror("zopeno can't open");
  364.         return(0);
  365.       }
  366.       debug(F111, " exist:fp[n]",p, (int) fp[n]);
  367.     }
  368.     else /* file does not exist, we can open with initial size */
  369.          /* this is very important for long files not to be too fragmented */
  370.          /* so that after a long transmission OS-9 may finish saying that */
  371.          /* the segment allocation table is full */
  372.     {
  373.       if ((zz) && ((zz->length > 0) || (zz->lengthk > 0)))
  374.                                     /* length estimate available ? */
  375.       {
  376.         if ((pn = create(name,S_IREAD+S_IWRITE+S_ISIZE,
  377.              S_IREAD+S_IWRITE,
  378.              (zz->length > 0) ? zz->length : (zz->lengthk*1024L))) != -1)
  379.         {
  380.           debug(F111, " create with init. size:",p,
  381.                 (zz->length > 0) ? zz->length : (zz->lengthk*1024L));
  382.           if ((fp[n] = fdopen(pn,"w")) == NULL) /* get filepntr for pn */
  383.           {
  384.             perror("zopeno can't open");
  385.             return(0);
  386.           }
  387.           debug(F111, " create with init. size:fp[n]",p, (int) fp[n]);
  388.         }
  389.         else
  390.         {
  391.           perror("zopeno can't open");
  392.           return(0);
  393.         }
  394.       }
  395.       else /* no length available */
  396.       {
  397.         if ((fp[n] = fopen(name,p)) == NULL)    /* Simply open the file */
  398.         {
  399.           perror("zopeno can't open");
  400.           return(0);
  401.         }
  402.         debug(F111, " create without init size fp[n]",p, (int) fp[n]);
  403.       }
  404.     }
  405.     if((zz) && (zz->systemid.val[0] == 'U') && ( zz->systemid.val[1] == 'D'))
  406.     {
  407.       debug(F101, "zopeno:file originated from OS-9","",zz->lprotect.val[0]);
  408.       if (zz->lprotect.len != 0)
  409.       {
  410.         if (_ss_attr(fp[n]->_fd,(zz->lprotect.val[0]&0x7f)|S_IWRITE) == -1)
  411.         {
  412.           debug(F101, "zopeno:can't set file attr","",errno);
  413.           return(0);
  414.         }
  415.       }
  416.     }
  417.     if (n == ZDFILE) setbuf(fp[n],(char *)NULL); /* Debug file unbuffered */
  418.     return(1);
  419. }
  420.  
  421. /*  Z C L O S E  --  Close the given file.  */
  422. /*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */
  423.  
  424. zclose(n) int n; {
  425.     int x, x2;
  426.     if (chkfn(n) < 1) return(0);        /* Check range of n */
  427.  
  428.     if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
  429.       x2 = zoutdump();
  430.     else
  431.       x2 = 0;
  432.  
  433.     x = 0;                              /* Initialize return code */
  434.     if (fp[ZSYSFN]) {                   /* If file is really pipe */
  435.         x = zclosf(n);                  /* do it specially */
  436.     } else {
  437.         if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
  438.             fp[n] = NULL;
  439.     }
  440.     if (x == EOF)                       /* if we got a close error */
  441.                 return (-1);
  442.     else if (x2 < 0)            /* or an error flushing the last buffer */
  443.                 return (-1);            /* then return an error */
  444.     else
  445.                 return (1);
  446. }
  447.  
  448. /*  Z C H I N  --  Get a character from the input file.  */
  449.  
  450. /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
  451.  
  452. zchin(n,c) int n; int *c; {
  453.     int a;
  454.  
  455.     /* (PWP) Just in case this gets called when it shoudn't */
  456.     if (n == ZIFILE)
  457.         return (zminchar());
  458.  
  459.     /* if (chkfn(n) < 1) return(-1); */
  460.     a = getc(fp[n]);
  461.     if (a == EOF) return(-1);
  462.     *c = a & 0377;
  463.     return(0);
  464. }
  465.  
  466. /*  Z I N F I L L  --  Get a character from the input file.
  467.  * (PWP) (re)fill the buffered input buffer with data.  All file input
  468.  * should go through this routine, usually by calling the zminchar()
  469.  * macro (in ckcker.h).
  470.  */
  471.  
  472. zinfill() {
  473.     zincnt = fread((char *)zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
  474.     if (zincnt == 0) return (-1);       /* end of file */
  475.     zinptr = zinbuffer;    /* set pointer to beginning, (== &zinbuffer[0]) */
  476.     zincnt--;                           /* one less char in buffer */
  477.     return((int)(*zinptr++) & 0377);    /* because we return the first */
  478. }
  479.  
  480. /*  Z S O U T  --  Write a string to the given file, buffered.  */
  481.  
  482. zsout(n,s) int n; char *s; {
  483.     if (chkfn(n) < 1) return(-1);
  484.     fputs(s,fp[n]);
  485.     return(0);
  486. }
  487.  
  488. /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
  489.  
  490. zsoutl(n,s) int n; char *s; {
  491.     /* if (chkfn(n) < 1) return(-1); */
  492.     fputs(s,fp[n]);
  493.     fputs("\n",fp[n]);
  494.     return(0);
  495. }
  496.  
  497. /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
  498.  
  499. zsoutx(n,s,x) int n, x; char *s; {
  500.     /* if (chkfn(n) < 1) return(-1); */
  501.     return(write(fileno(fp[n]),s,(unsigned int)x));
  502. }
  503.  
  504.  
  505. /*  Z C H O U T  --  Add a character to the given file.  */
  506.  
  507. /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
  508.  
  509. int
  510. #ifdef CK_ANSIC
  511. zchout(register int n, char c)
  512. #else
  513. zchout(n,c) register int n; char c;
  514. #endif /* CK_ANSIC */
  515. /* zchout */ {
  516.     /* if (chkfn(n) < 1) return(-1); */
  517.     if (n == ZSFILE)
  518.         return(write(fileno(fp[n]),&c,1));/*Use unbuffered for session log*/
  519.     else {    /* Buffered for everything else */
  520.         if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
  521.         {
  522.             return(ferror(fp[n])); /* Check to make sure */
  523.         }
  524.         else return(0);   /* There was no error. */
  525.     }
  526. }
  527.  
  528. /* (PWP) buffered character output routine to speed up file IO */
  529. zoutdump()
  530. {
  531.     if (zoutcnt == 0) return (0); /* nothing to output */
  532.     if (zoutcnt < 0) return (-1); /* unexpected */
  533.  
  534.     zoutptr = zoutbuffer;      /* Reset buffer pointer in all cases */
  535.     if (fwrite ((char *)zoutbuffer, 1, zoutcnt, fp[ZOFILE]))
  536.     {
  537.         fflush(fp[ZOFILE]);
  538.         zoutcnt = 0;            /* reset output buffer */
  539.         zoutptr = zoutbuffer;
  540.         return(0);              /* things worked OK */
  541.     }
  542.     zoutcnt = 0;            /* reset output buffer */
  543.     return(ferror(fp[ZOFILE])?-1:0); /* Check to make sure */
  544. }
  545.  
  546. /*  C H K F N  --  Internal function to verify file number is ok  */
  547.  
  548. /*
  549.  Returns:
  550.   -1: File number n is out of range
  551.    0: n is in range, but file is not open
  552.    1: n in range and file is open
  553. */
  554. chkfn(n) int n; {
  555.     switch (n) {
  556.         case ZCTERM:
  557.         case ZSTDIO:
  558.         case ZIFILE:
  559.         case ZOFILE:
  560.         case ZDFILE:
  561.         case ZTFILE:
  562.         case ZPFILE:
  563.         case ZSFILE:
  564.         case ZSYSFN:
  565.         case ZRFILE:
  566.         case ZWFILE: break;
  567.  
  568.         default:
  569.             debug(F101,"chkfn: file number out of range","",n);
  570.             fprintf(stderr,"?File number out of range - %d\n",n);
  571.             return(-1);
  572.     }
  573.     return( (fp[n] == NULL) ? 0 : 1 );
  574. }
  575.  
  576. /*  Z C H K I  --  Check if input file exists and is readable  */
  577.  
  578. /*
  579.   Returns:
  580.    >= 0 if the file can be read (returns the size).
  581.      -1 if file doesn't exist or can't be accessed,
  582.      -2 if file exists but is not readable (e.g. a directory file).
  583.      -3 if file exists but protected against read access.
  584. */
  585. long
  586. zchki(name) char *name; {
  587.     int x;
  588.  
  589.     if (strcmp(name, "/nil") == 0) {
  590.         memset(&cur_in_fd, 0, sizeof cur_in_fd);
  591.         cur_in_fd.fd_att = S_IREAD|S_IWRITE;
  592.         getime((struct sgtbuf *)cur_in_fd.fd_date);
  593.         cur_in_size = -1;
  594.         return 0;
  595.     }
  596.     if (access(name,0) < 0) {
  597.         if(access(name,S_IFDIR)>=0) {
  598.             debug(F111,"zchki skipping:",name,errno);
  599.             return(-2);
  600.         }
  601.         debug(F111,"zchki can't access",name,errno);
  602.         return(-1);
  603.     }
  604.  
  605.     if ((x = open(name,S_IREAD)) < 0) {  /* Is the file accessible? */
  606.         debug(F111," access failed:",name,x); /* No */
  607.         return(-3);
  608.     }
  609.     debug(F110," access ok:",name,0);
  610.     cur_in_size = _gs_size(x);                  /* remember size */
  611.     _gs_gfd(x,&cur_in_fd,sizeof(cur_in_fd));    /* remember filedespr. */
  612.     close(x);
  613.     debug(F111," access ok:",name,cur_in_size);
  614.     return( (cur_in_size > -1) ? cur_in_size : 0 );
  615. }
  616.  
  617. /*  Z C H K O  --  Check if output file can be created  */
  618.  
  619. /*
  620.  Returns -1 if write permission for the file would be denied, 0 otherwise.
  621. */
  622. zchko(name) char *name; {
  623.     int i, x;
  624.     char *s;
  625.  
  626.     x = strlen(name);
  627.     debug(F101," length","",x);
  628.     if (x == 0) return(-1);             /* If no filename, fail. */
  629.     if (strcmp(name, "/nil") == 0) return 0;
  630.     if(isdir(name)) return -1;          /* it's a directory */
  631.     for (s = name, i = x; i > 0; i--) { /* Strip filename from right. */
  632.         if (ISDIRSEP(s[i-1])) break;
  633.     }
  634.     debug(F101," i","",i);
  635.     if (_prsnam(s + i) != strlen(s + i)) {
  636.         debug(F111," _prsnam failed:",s,errno);
  637.         return -1;
  638.     }
  639. /* We don't want to write in our arg, so make a copy */
  640.     if ((s = malloc(x + 1 + 1)) == NULL) return -1;
  641.     strcpy(s, name);
  642. /* Now we use "path/." if path given, or "." if no path given. */
  643.     s[i++] = '.';                       /* Append "." to path. */
  644.     s[i] = '\0';
  645.     x = access(s,S_IFDIR|S_IWRITE);     /* Check access of path. */
  646.     if (x < 0) {
  647.         debug(F111,"zchko access failed:",s,errno);
  648.     } else {
  649.         debug(F111,"zchko access ok:",s,x);
  650.     }
  651.     free(s);
  652.     return x < 0 ? -1 : 0;
  653. }
  654.  
  655. /*  Z C H K S P A  --  Check if there is enough space to store the file  */
  656.  
  657. /*
  658.  Call with file specification f, size n in bytes.
  659.  Returns -1 on error, 0 if not enough space, 1 if enough space.
  660. */
  661. zchkspa(f,n) char *f; long n; {         /* Just dummy for now. */
  662.     return(1);                          /* Always say OK. */
  663. }
  664.  
  665.  
  666. /*  Z D E L E T  --  Delete the named file.  */
  667.  
  668. zdelet(name) char *name; {
  669.     return(unlink(name));
  670. }
  671.  
  672.  
  673. /*  Z R T O L  --  Convert remote filename into local form  */
  674.  
  675. /*  For OS9, this means changing uppercase letters to lowercase
  676.     and making shure only a-z,A-Z,0-9,$,_,. are used
  677.     keep the / for dir name (as-names)
  678. */
  679. VOID
  680. zrtol(name,name2) char *name, *name2; {
  681.     char *p; int flag = 0, n = 0;
  682.     int maxnam = MAXNAMLEN;
  683.     if (!name || !name2) return;
  684.     debug(F101,"zrtol original name","",name);
  685.     for (p = name2; *name != '\0' && n < maxnam; name++) {
  686.         if (*name > ' ') flag = 1;      /* Strip leading blanks and controls */
  687.         if (flag == 0 && *name < '!') continue;
  688.         *p = isupper(*name) ? tolower(*name) : *name;
  689.         n++;
  690.         if (ISDIRSEP(*p++)) n = 0;
  691.     }
  692.     *p-- = '\0';                        /* Terminate */
  693.     while (*p < '!' && p > name2)       /* Strip trailing blanks & controls */
  694.       *p-- = '\0';
  695.     if (*name2 == '\0') strcpy(name2,"noname");
  696.     for (p = name2; *p != '\0'; p++) {
  697.         if (!isalnum(*p) && *p != '$' && *p != '.' && *p != '_'
  698.           && !ISDIRSEP(*p))
  699.           *p = '_';
  700.     }
  701.     debug(F110,"zrtol new name",name2,0);
  702. }
  703.  
  704.  
  705. /*  Z S T R I P  --  Strip device & directory name from file specification */
  706.  
  707. /*  Strip pathname from filename "name", return pointer to result in name2 */
  708.  
  709. static char work[MAXPATH+1]; /* buffer for use by zstrip and zltor */
  710.  
  711. VOID
  712. zstrip(name,name2) char *name, **name2; {
  713.     char *cp, *pp;
  714.     debug(F110,"zstrip before",name,0);
  715.     pp = work;
  716. #ifdef DTILDE
  717.     if (*name == '~') name++;
  718. #endif
  719.     for (cp = name; *cp != '\0'; cp++) {
  720.         if (*cp == '/')
  721.           pp = work;
  722.         else
  723.           *pp++ = *cp;
  724.     }
  725.     *pp = '\0';                         /* Terminate the string */
  726.     *name2 = work;
  727.     debug(F110,"zstrip after",*name2,0);
  728. }
  729.  
  730.  
  731. /*  Z L T O R  --  Local TO Remote */
  732.  
  733. /*  Convert filename from local format to common (remote) form.  */
  734. VOID
  735. zltor(name,name2) char *name, *name2; {
  736.     char *cp, *pp;
  737.     int dc = 0;
  738.  
  739.     debug(F110,"zltor",name,0);
  740.     pp = work;
  741.     for (cp = name; *cp != '\0'; cp++) { /* strip path name */
  742.         if (*cp == '/') {
  743.             dc = 0;
  744.             pp = work;
  745.         }
  746.         else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
  747.         else if (*cp == '$') *pp++ = 'X';    /* Change '$' to 'X' */
  748.         else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
  749.         else *pp++ = *cp;
  750.     }
  751.     *pp = '\0';    /* Tie it off. */
  752.     cp = name2;    /* If nothing before dot, */
  753.     if (*work == '.') *cp++ = 'X'; /* insert 'X' */
  754.     strcpy(cp,work);
  755.     debug(F110," name2",name2,0);
  756. }
  757.  
  758.  
  759. /*  Z C H D I R  --  Change directory  */
  760.  
  761. zchdir(dirnam) char *dirnam; {
  762.     char *hd;
  763.     if (dirnam == NULL || *dirnam == '\0') hd = zhome();
  764.     else hd = dirnam;
  765. #ifdef DTILDE
  766.     hd = tilde_expand(dirnam);          /* Attempt to expand tilde */
  767.     if (*hd == '\0') hd = dirnam;       /* in directory name. */
  768. #endif /* DTILDE */
  769.     return((chdir(hd) == 0) ? 1 : 0);
  770. }
  771.  
  772.  
  773. /*  Z H O M E  --  Return pointer to user's home directory  */
  774.  
  775. char *
  776. zhome() {
  777.     char *home = getenv("HOME");
  778.     return home ? home : ".";
  779. }
  780.  
  781. /*  Z X C M D -- Run a system command so its output can be read like a file */
  782.  
  783. zxcmd(filnum,comand) int filnum;char *comand; {
  784. FILE *pipeopen(),*filedesc;
  785.  
  786.     if (chkfn(filnum) < 0) return(-1); /* Need a valid kermit file number */
  787.     if (filnum == ZSTDIO || filnum == ZCTERM) return(0);
  788.  
  789.     if (filnum == ZIFILE || filnum == ZRFILE) /* kermit wants to read */
  790.     {
  791.       debug(F111," zxcmd read:",comand,filnum);
  792.       if ((filedesc = pipeopen(comand,"r")) != (FILE *)NULL)
  793.       {
  794.         fp[filnum] = filedesc;
  795.         fp[ZSYSFN] = fp[filnum];    /* Remember. */
  796.         zincnt = 0;
  797.         zinptr = zinbuffer;
  798.       }
  799.       else
  800.         return(0);
  801.     }
  802.     else
  803.     {
  804.       debug(F111," zxcmd write:",comand,filnum);
  805.       if ((filedesc = pipeopen(comand,"w")) != (FILE *)NULL)
  806.       {
  807.         fp[filnum] = filedesc;
  808.         fp[ZSYSFN] = fp[filnum];    /* Remember. */
  809.         zoutcnt = 0;
  810.         zoutptr = zoutbuffer;
  811.       }
  812.       else
  813.         return(0);
  814.     }
  815.     return(1); /* return success if we ever get here */
  816. }
  817.  
  818. /* KILL_TREE recursively kill all processes of a forked tree */
  819. static void
  820. #ifdef CK_ANSIC
  821. kill_tree(int root, int ppid)
  822. #else
  823. kill_tree(root, ppid) int root; int ppid;
  824. #endif /* CK_ANSIC */
  825. {
  826.   struct {
  827.     unsigned short
  828.       _id,      /* process id */
  829.       _pid,     /* parent's id */
  830.       _sid,     /* sibling's id */
  831.       _cid;     /* child's id */
  832.   } prdesc;     /* NOT whole process descriptor! too much stack needed */
  833.   int child;
  834.  
  835.   if(_get_process_desc(root, sizeof(prdesc), &prdesc) == -1) return;
  836.   if (prdesc._pid != ppid) return;
  837.   /* kill child's tree */
  838.   if ((child = prdesc._cid) != 0) kill_tree(child, root);
  839.   /* kill siblings tree */
  840.   if ((child = prdesc._sid) != 0) kill_tree(child, ppid);
  841.   kill(root,SIGKILL);
  842. }
  843.  
  844. /* Z C L O S F - kill the child(action may have aborted and close the pipe.*/
  845.  
  846. zclosf(filnum) int filnum;{
  847.     int wstat;
  848.     debug(F101," zclosf filnum:","",filnum);
  849.     fclose(fp[filnum]);
  850.     fp[filnum] = fp[ZSYSFN] = NULL;
  851.     if (pipe_pid == 0) return(-1);
  852.     /* kill all lower processes in case things have been aborted */
  853.     kill_tree(pipe_pid, getpid());
  854.     debug(F101," zclosf killed:","",pipe_pid);
  855.     while ((wstat = wait((unsigned int *)0)) != pipe_pid && wstat != -1) ;
  856.     pipe_pid = 0;
  857.     return(1);
  858. }
  859.  
  860. /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
  861. /*
  862.   Returns the number of files that match fn1, with data structures set up
  863.   so that first file (if any) will be returned by the next znext() call.
  864. */
  865. zxpand(fn) char *fn; {
  866. #ifdef DTILDE                           /* Built with tilde-expansion? */
  867.     char *tnam;
  868. #endif /* DTILDE */
  869.     debug(F111,"zxpand entry",fn,0);
  870. #ifdef DTILDE                           /* Built with tilde-expansion? */
  871.     if (*fn == '~') {                   /* Starts with tilde? */
  872.         tnam = tilde_expand(fn);        /* Try to expand it. */
  873.         if (*tnam) fn = tnam;
  874.     }
  875.     debug(F110,"zxpand after tilde_x",fn,0);
  876. #endif /* DTILDE */
  877.     fcount = (mtchs == NULL
  878.               && (mtchs = (char **)malloc(MAXWLD * sizeof(*mtchs))) == NULL)
  879.              ? 0
  880.              : fgen(fn,mtchs,MAXWLD); /* Look up the file. */
  881.     if (fcount > 0) {
  882.         mtchptr = mtchs;  /* Save pointer for next. */
  883.     }
  884.     debug(F111,"zxpand",(fcount > 0 ? mtchs[0] : fn),fcount);
  885.     return(fcount);
  886. }
  887.  
  888.  
  889. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  890. /*
  891.  Returns >0 if there's another file,with its name copied into the arg string
  892.  or 0 if no more files in list.
  893. */
  894. znext(fn) char *fn; {
  895.     if (fcount-- > 0) strcpy(fn,*mtchptr++);
  896.     else *fn = '\0';
  897.     debug(F111,"znext",fn,fcount+1);
  898.     return(fcount+1);
  899. }
  900.  
  901.  
  902. /*  Z N E W N  --  Make a new name for the given file  */
  903. VOID
  904. znewn(fn,s) char *fn, **s; {
  905. #define ZNEWNBL MAXPATH                 /* Name buffer length */
  906. #define ZNEWNMD 4                       /* Max digits for version number */
  907. /* OS-9 names are short, so take a short version number extension */
  908. #define ZNEWNVC 1                       /* Number of additional vers chars */
  909.     static char buf[ZNEWNBL+1];
  910.     char *bp, *xp;
  911.     int len = 0, n = 0, d = 0, t, i, power = 1;
  912.  
  913.     int max;
  914.  
  915.     bp = buf;
  916.     xp = bp;
  917.     while (*fn) {                       /* Copy old name into buf */
  918.         *bp++ = *fn++;
  919.         if (ISDIRSEP(bp[-1])) xp = bp;  /* Remember latest filename */
  920.         if (len++ > ZNEWNBL) break;     /* ...up to buffer length */
  921.     }
  922.     max = (xp - buf) + MAXNAMLEN;
  923.     if (max > ZNEWNBL) max = ZNEWNBL;
  924.  
  925.     *s = NULL;
  926.     for (i = 1; i < ZNEWNMD; i++) {     /* Version numbers up to 10**i - 1 */
  927.         int j, k;
  928.         power *= 10;                    /* Next power of 10 */
  929.         j = max - len;                  /* Space left for version number */
  930.         k = ZNEWNVC + i;                /* Space needed for it */
  931.         if (j < k) {                    /* Make room if necessary */
  932.             len -= k - j;               /* Adjust length of filename */
  933.             bp = buf + len;             /* Point to new end */
  934.         }
  935.         *bp++ = '*';                    /* Put a star on the end */
  936.         *bp-- = '\0';
  937.  
  938.         debug(F110, "znewn: about to expand", buf, 0);
  939.         n = zxpand(buf);                /* Expand the resulting wild name */
  940.                                         /* n is the number of matches */
  941.         while (n-- > 0) {               /* Find any existing name_n files */
  942.             xp = *mtchptr++;            /* Point at matching name */
  943.             xp += len;                  /* Lock for _<n> at the end of it */
  944.             if (*xp == '_') {           /* Has it a version number */
  945.                 t = atoi(xp+1);         /* Get it */
  946.                 if (t > d) d = t;       /* Get maximum d */
  947.             }
  948.         }
  949.         if (d < power-1) {              /* Less than maximum possible? */
  950.             sprintf(bp,"_%d",d+1);      /* Yes, make "name_<d+1>" */
  951.             *s = buf;
  952.             break;
  953.         }
  954.     }
  955.     if (*s == NULL) {
  956.         debug(F110, "znewn: too many names", buf, 0);
  957.         sprintf(bp, "_xxxx");           /* Too many, use xxxx. */
  958.         *s = buf;
  959.     }
  960. }
  961.  
  962. /*  Z S A T T R */
  963. /*
  964.  Fills in a Kermit file attribute structure for the file which is to be sent.
  965.  Returns 0 on success with the structure filled in, or -1 on failure.
  966.  If any string member is null, then it should be ignored.
  967.  If any numeric member is -1, then it should be ignored.
  968. */
  969. zsattr(xx) struct zattr *xx; {
  970.     int k;
  971.     static char protection[2];
  972.     static char * get_gmtime();
  973.  
  974.     k = cur_in_size % 1024L;                  /* File length in K */
  975.     if (k != 0L) k = 1L;
  976.     xx->lengthk = (cur_in_size / 1024L) + k;
  977. /*  if ((cur_in_fd.fd_att & S_IEXEC) || (cur_in_fd.fd_att & S_IOEXEC))
  978.     {
  979.       xx->type.len = 1;
  980.       xx->type.val = "B";
  981.     }
  982.     else
  983.     {
  984.       xx->type.len = 0;
  985.       xx->type.val = "";
  986.     }
  987. */  xx->type.len = 0;               /* better let the user decide */
  988.     xx->type.val = "";
  989.     xx->date.val = get_gmtime(&cur_in_fd); /* get UCT time, if possible */
  990.     xx->date.len = strlen(xx->date.val);
  991.     debug(F111,"zsattr date",xx->date.val,xx->date.len);
  992.     xx->creator.len = 0;                /* File creator */
  993.     xx->creator.val = "";
  994.     xx->account.len = 0;                /* File account */
  995.     xx->account.val = "";
  996.     xx->area.len = 0;                   /* File area */
  997.     xx->area.val = "";
  998.     xx->password.len = 0;                 /* Area password */
  999.     xx->password.val = "";
  1000.     xx->blksize = -1L;                  /* File blocksize */
  1001.     xx->xaccess.len = 0;        /* File access */
  1002.     xx->xaccess.val = "";
  1003.     xx->encoding.len = 0;               /* Transfer syntax */
  1004.     xx->encoding.val = 0;
  1005.     xx->disp.len = 0;                   /* Disposition upon arrival */
  1006.     xx->disp.val = "";
  1007.  
  1008.     protection[0] = cur_in_fd.fd_att & 0x7f;
  1009.     protection[1] = 0;
  1010.     xx->lprotect.val = protection;
  1011.     xx->lprotect.len = 1;
  1012.     debug(F101,"zsattr lprotect","",xx->lprotect.val[0]);
  1013.  
  1014.     xx->gprotect.len = 0;               /* Generic protection */
  1015.     xx->gprotect.val = "";
  1016.     xx->systemid.len = 2;               /* System ID */
  1017.     xx->systemid.val = "UD";
  1018.     xx->recfm.len = 0;                  /* Record format */
  1019.     xx->recfm.val = "";
  1020.     xx->sysparam.len = 0;               /* System-dependent parameters */
  1021.     xx->sysparam.val = "";
  1022.     debug(F101,"zsattr size","",cur_in_size);
  1023.     xx->length = cur_in_size;                 /* Length */
  1024.     return(0);
  1025. }
  1026.  
  1027. zmail(p,f) char *p; char *f; {
  1028.     /* Send file f as mail to address p; no mail on OS-9 */
  1029.     return(-1);
  1030. }
  1031.  
  1032. zprint(p,f) char *p; char *f; {
  1033.     /* Print file f with options p; no unique print device on OS-9 */
  1034.     return(-1);
  1035. }
  1036.  
  1037. /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
  1038. /*
  1039.  * The path structure is used to represent the name to match.
  1040.  * Each slash-separated segment of the name is kept in one
  1041.  * such structure, and they are linked together, to make
  1042.  * traversing the name easier.
  1043.  */
  1044.  
  1045. struct path {
  1046.               char npart[MAXNAMLEN+4]; /* name part of path segment */
  1047.               struct path *fwd;  /* forward ptr */
  1048.             };
  1049.  
  1050. #define SSPACE 2000   /* size of string-generating buffer */
  1051. static char *sspace;                 /* buffer to generate names in */
  1052. static char *freeptr,**resptr;       /* copies of caller's arguments */
  1053. static int remlen;                   /* remaining length in caller's array*/
  1054. static int numfnd;                   /* number of matches found */
  1055.  
  1056. /*
  1057.  * splitpath:
  1058.  *  takes a string and splits the slash-separated portions into
  1059.  *  a list of path structures.  Returns the head of the list.  The
  1060.  *  structures are allocated by malloc, so they must be freed.
  1061.  *  Splitpath is used internally by the filename generator.
  1062.  *
  1063.  * Input: A string.
  1064.  * Returns: A linked list of the slash-separated segments of the input.
  1065.  */
  1066.  
  1067. struct path *
  1068. splitpath(p)
  1069. char *p;
  1070. {
  1071.     struct path *head,*cur,*prv;
  1072.     int i;
  1073.     head = prv = NULL;
  1074.     if (*p == '/') p++;            /* skip leading slash */
  1075.     while (*p != '\0') {
  1076.         cur = (struct path *) malloc(sizeof (struct path));
  1077.         debug(F101,"splitpath malloc","",(int)cur);
  1078.         if (cur == NULL) fatal("malloc fails in splitpath()");
  1079.         cur -> fwd = NULL;
  1080.         if (head == NULL) head = cur;
  1081.         else prv -> fwd = cur;       /* link into chain */
  1082.         prv = cur;
  1083.         for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++)
  1084.             cur -> npart[i] = *p++;
  1085.         cur -> npart[i] = '\0';      /* end this segment */
  1086.         if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++;
  1087.         if (*p == '/') p++;
  1088.     }
  1089.     return(head);
  1090. }
  1091.  
  1092. /*
  1093.  * fgen:
  1094.  *  This is the actual name generator.  It is passed a string,
  1095.  *  possibly containing wildcards, and an array of character pointers.
  1096.  *  It finds all the matching filenames and stores them into the array.
  1097.  *  The returned strings are allocated from a static buffer local to
  1098.  *  this module (so the caller doesn't have to worry about deallocating
  1099.  *  them); this means that successive calls to fgen will wipe out
  1100.  *  the results of previous calls.  This isn't a problem here
  1101.  *  because we process one wildcard string at a time.
  1102.  *
  1103.  * Input: a wildcard string, an array to write names to, the
  1104.  *        length of the array.
  1105.  * Returns: the number of matches.  The array is filled with filenames
  1106.  *          that matched the pattern.  If there wasn't enough room in the
  1107.  *     array, -1 is returned.
  1108.  * By: Jeff Damens, CUCCA, 1984.
  1109.  */
  1110.  
  1111. fgen(pat,resarry,len)
  1112. char *pat,*resarry[];
  1113. int len;
  1114. {
  1115.         VOID traverse();
  1116.     struct path *head;
  1117.     char scratch[100+MAXNAMLEN],*sptr;
  1118.     head = splitpath(pat);
  1119.     if (*pat == '/') {
  1120.         scratch[0] = '/';
  1121.         sptr = scratch+1;
  1122.         *sptr = '\0';
  1123.     } else {
  1124.         strcpy(scratch,"./");
  1125.         sptr = scratch+2;
  1126.     }     /* init buffer correctly */
  1127.     numfnd = 0;                            /* none found yet */
  1128.     if (sspace == NULL && (sspace = malloc(SSPACE)) == NULL) {
  1129.         fprintf(stderr,"fgen can't malloc string space\n");
  1130.         return(-1);
  1131.     }
  1132.     freeptr = sspace;   /* this is where matches are copied */
  1133.     resptr = resarry;   /* static copies of these so*/
  1134.     remlen = len;    /* recursive calls can alter them */
  1135.     traverse(head,scratch,sptr);  /* go walk the directory tree */
  1136.     while (head != NULL) {
  1137.         struct path *next = head -> fwd;
  1138.         free((char *)head);
  1139.         head = next;
  1140.     }
  1141.     return(numfnd);   /* and return the number of matches */
  1142. }
  1143.  
  1144. /* traverse:
  1145.  *  Walks the directory tree looking for matches to its arguments.
  1146.  *  The algorithm is, briefly:
  1147.  *   If the current pattern segment contains no wildcards, that
  1148.  *   segment is added to what we already have.  If the name so far
  1149.  *   exists, we call ourselves recursively with the next segment
  1150.  *   in the pattern string; otherwise, we just return.
  1151.  *
  1152.  *   If the current pattern segment contains wildcards, we open the name
  1153.  *   we've accumulated so far (assuming it is really a directory), then read
  1154.  *   each filename in it, and, if it matches the wildcard pattern segment,add
  1155.  *   that filename to what we have so far and call ourselves recursively on
  1156.  *   the next segment.
  1157.  *
  1158.  *   Finally, when no more pattern segments remain, we add what's accumulated
  1159.  *   so far to the result array and increment the number of matches.
  1160.  *
  1161.  * Input: a pattern path list (as generated by splitpath), a string
  1162.  *   pointer that points to what we've traversed so far (this
  1163.  *   can be initialized to "/" to start the search at the root
  1164.  *   directory, or to "./" to start the search at the current
  1165.  *   directory), and a string pointer to the end of the string
  1166.  *   in the previous argument.
  1167.  * Returns: nothing.
  1168.  */
  1169. VOID
  1170. traverse(pl,sofar,endcur)
  1171. struct path *pl;
  1172. register char *sofar,*endcur;
  1173. {
  1174.     DIR *fd, *opendir();
  1175.         VOID addresult();
  1176.     struct direct *dirbuf;
  1177.     debug(F110,"traverse ",sofar,0);
  1178.     if (pl == NULL) {
  1179.         *--endcur = '\0';               /* end string, overwrite trailing / */
  1180.         addresult(sofar);
  1181.         return;
  1182.     }
  1183.     if (!iswild(pl -> npart)) {
  1184.         strcpy(endcur,pl -> npart);
  1185.         endcur += strlen(endcur);
  1186.         if (access(sofar,S_IFDIR) == 0) { /* if current piece exists & dir */
  1187.             *endcur++ = '/';            /* add slash to end */
  1188.             *endcur = '\0';             /* and end the string */
  1189.             traverse(pl -> fwd,sofar,endcur);
  1190.         } else if(access(sofar,0) == 0 && pl->fwd==NULL) {
  1191.             addresult(sofar);
  1192.         }
  1193.         return;
  1194.     }
  1195.  
  1196. /* segment contains wildcards, have to search directory */
  1197.     *--endcur = '\0';                   /* end current string */
  1198.     if (access(sofar,S_IFDIR) < 0) {
  1199.         debug(F111,"traverse can't access directory",sofar,errno);
  1200.         return; /* doesn't exist, forget it */
  1201.     }
  1202.     if ((fd = opendir(sofar)) == NULL) {
  1203.         debug(F111,"traverse can't open directory",sofar,errno);
  1204.         return; /* can't open, forget it */
  1205.     }
  1206.     *endcur++ = '/';
  1207.     while (dirbuf = readdir(fd)) {
  1208.         if (dirbuf->d_addr != 0) {
  1209.             /* Get a null terminated copy!!! */
  1210.             strncpy(endcur,dirbuf->d_name,MAXNAMLEN);
  1211.             endcur[MAXNAMLEN] = '\0';
  1212.             if(match(pl -> npart,endcur)) {
  1213.                 char *eos;
  1214.                 eos = endcur + strlen(endcur);
  1215.                 *eos++ = '/';                   /* end this segment */
  1216.                 *eos = '\0';
  1217.                 traverse(pl -> fwd,sofar,eos);
  1218.             }
  1219.         }
  1220.     }
  1221.     closedir(fd);
  1222. }
  1223.  
  1224. /*
  1225.  * addresult:
  1226.  *  Adds a result string to the result array.  Increments the number
  1227.  *  of matches found, copies the found string into our string
  1228.  *  buffer, and puts a pointer to the buffer into the caller's result
  1229.  *  array.  Our free buffer pointer is updated.  If there is no
  1230.  *  more room in the caller's array, the number of matches is set to -1.
  1231.  * Input: a result string.
  1232.  * Returns: nothing.
  1233.  */
  1234.  
  1235. VOID
  1236. addresult(str)
  1237. register char *str;
  1238. {
  1239.     register int l;
  1240.     if (strncmp(str,"./",2) == 0) str += 2;
  1241.     if (--remlen < 0) {
  1242.         numfnd = -1;
  1243.         return;
  1244.     }
  1245.     l = strlen(str) + 1;   /* size this will take up */
  1246.     if ((freeptr + l) > &sspace[SSPACE]) {
  1247.         numfnd = -1;   /* do not record if not enough space */
  1248.         return;
  1249.     }
  1250.     strcpy(freeptr,str);
  1251.     *resptr++ = freeptr;
  1252.     freeptr += l;
  1253.     numfnd++;
  1254. }
  1255.  
  1256. iswild(str)
  1257. register char *str;
  1258. {
  1259.     register char c;
  1260.     while ((c = *str++) != '\0')
  1261.         if (c == '*' || c == '?') return(1);
  1262.     return(0);
  1263. }
  1264.  
  1265. /*
  1266.  * match:
  1267.  *  pattern matcher.  Takes a string and a pattern possibly containing
  1268.  *  the wildcard characters '*' and '?'.  Returns true if the pattern
  1269.  *  matches the string, false otherwise.
  1270.  * Input: a string and a wildcard pattern.
  1271.  * Returns: 1 if match, 0 if no match.
  1272.  */
  1273.  
  1274. match(pattern,string) char *pattern,*string; {
  1275.     int i;
  1276.     i = _cmpnam(string,pattern,strlen(pattern))==0;
  1277.     debug(F111,"Match ",string,i);
  1278.     return i;
  1279. }
  1280.  
  1281. #ifndef _UCC
  1282. /* emulate unix perror function */
  1283.  
  1284. perror(string)
  1285. char *string;
  1286. {
  1287.     extern int errno;
  1288.     fprintf(stderr,"%s ERRNO: %d\n",string,errno);
  1289. }
  1290. #endif /* _UCC */
  1291.  
  1292. #ifdef DTILDE
  1293. char *
  1294. tilde_expand(dirname)
  1295. register char *dirname;
  1296. {
  1297.     static char *home = NULL;
  1298.     static char *temp;
  1299.  
  1300.     debug(F111,"tilde_expand dirname", dirname, dirname[0]);
  1301.     if (temp == NULL && (temp = malloc(MAXPATH)) == NULL)
  1302.       return dirname;
  1303.     if(*dirname++ != '~' || (*dirname != '\0' && *dirname != '/'))
  1304.                 return --dirname;
  1305.     if(home == NULL && (home = zhome()) == NULL) return --dirname;
  1306.     if(*dirname == '\0') return home;
  1307.     strcpy(temp, home);
  1308.     strcat(temp, dirname);
  1309.     return temp;
  1310. }
  1311. #endif /* DTILDE */
  1312.  
  1313. #ifdef ZFCDAT
  1314. /* Z F C D A T  --  Get file creation date */
  1315. /*
  1316.   Call with pointer to filename.
  1317.   On success, returns pointer to modification date in yyyymmdd hh:mm:ss format.
  1318.   On failure, returns pointer to null string.
  1319. */
  1320. /* static */
  1321. char *
  1322. zfcdat(name) char *name; {
  1323.     static char datbuf[20];
  1324.     struct my_fildes {                  /* free stack of charge */
  1325.         unsigned char fd_att, fd_own[2], fd_date[5], fd_link, fd_fsize[4],
  1326.         fd_dcr[3];
  1327.     } fdbuf;
  1328.     int fd;
  1329.     int yy;
  1330.  
  1331.     datbuf[0] = '\0';
  1332.     if ((fd = open(name, 0)) != -1) {
  1333.         if (_gs_gfd(fd, &fdbuf, sizeof fdbuf) != -1) {
  1334.             yy = fdbuf.fd_date[0] + 1900;
  1335.             if (fdbuf.fd_date[0] < (unsigned char)70) yy += 100;
  1336.             sprintf(datbuf, "%04d%02d%02d %02d:%02d:00",
  1337.               yy, fdbuf.fd_date[1], fdbuf.fd_date[2], fdbuf.fd_date[3],
  1338.               fdbuf.fd_date[4]);
  1339.             yy = strlen(datbuf);
  1340.             debug(F111, "zfcdat", datbuf, yy);
  1341.             datbuf[17] = '\0';
  1342.         }
  1343.         close(fd);
  1344.     }
  1345.     return(datbuf);
  1346. }
  1347. #endif /* ZFCDAT */
  1348.  
  1349. /* Z S T I M E  --  Set creation date for incoming file */
  1350. /*
  1351.  Call with:
  1352.  f  = pointer to name of existing file.
  1353.  yy = pointer to a Kermit file attribute structure in which yy->date.val
  1354.       is a date of the form [yy]yymmdd[ hh:mm[:ss]] e.g. 19900208 13:00:00.
  1355.  x  = is a function code: 0 means to set the file's creation date as given.
  1356.       1 means compare the given date with the file creation date.
  1357.  Returns:
  1358.  -1 on any kind of error.
  1359.   0 if x is 0 and the file date was set successfully.
  1360.   0 if x is 1 and date from attribute structure > file  creation date.
  1361.   1 if x is 1 and date from attribute structure <= file creation date.
  1362. */
  1363.  
  1364. zstime(f,yy,x) char *f; register struct zattr *yy; int x;
  1365. {
  1366.   extern int errno;
  1367.   int r = -1;                             /* return code */
  1368.   int path;
  1369.   register char *point;
  1370.   register char save;
  1371.   unsigned char year,month,day,hour,minute,second;
  1372.   struct fildes buffer;
  1373.   unsigned char long_year=0,hour_min=0;
  1374.   time_t mktime(),file_date;
  1375.   static VOID convert_to_local_time();
  1376.   struct tm tp;
  1377.  
  1378.     debug(F110,"zstime",f,0);
  1379.  
  1380.     switch (yy->date.len)
  1381.     {
  1382.     case 6:   /* yymmdd */
  1383.         break;
  1384.     case 8:   /* yyyymmdd */
  1385.         long_year = 1;
  1386.         break;
  1387.     case 12:  /* yymmdd hh:mm */
  1388.         hour_min = 1;
  1389.         break;
  1390.     case 14:  /* yyyymmdd hh:mm */
  1391.         long_year = 1;
  1392.         hour_min = 1;
  1393.         break;
  1394.     case 15:  /* yymmdd hh:mm:ss */
  1395.         hour_min = 1;
  1396.         break;
  1397.     case 17:  /* yyyymmdd hh:mm:ss */
  1398.         long_year = 1;
  1399.         hour_min = 1;
  1400.         break;
  1401.     default:
  1402.         debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
  1403.         return(-1);
  1404.     }
  1405.  
  1406.     point = yy->date.val;
  1407.     if (long_year)
  1408.     {
  1409.       save = *(point+4);
  1410.       *(point+4) = '\0';
  1411.       year = atoi(point) % 100; /* OS-9 only has 2 digit year */
  1412.       *(point+4) = save;
  1413.       point += 4;
  1414.     }
  1415.     else
  1416.     {
  1417.       save = *(point+2);
  1418.       *(point+2) = '\0';
  1419.       year = atoi(point);
  1420.       point += 2; /* don't add 1900: OS-9 only has 2 digit year anyway */
  1421.     }
  1422.  
  1423.     save = *(point+2);
  1424.     *(point+2) = '\0';
  1425.     month = atoi(point);
  1426.     *(point+2) = save;
  1427.  
  1428.     point += 2;
  1429.     save = *(point+2);
  1430.     *(point+2) = '\0';
  1431.     day = atoi(point);
  1432.     *(point+2) = save;
  1433.  
  1434.     if (hour_min)
  1435.     {
  1436.         point += 3; /* skip the blank */
  1437.         save = *(point+2);
  1438.         *(point+2) = '\0';
  1439.         hour = atoi(point);
  1440.         *(point+2) = save;
  1441.  
  1442.         point += 3; /* skip the : */
  1443.         save = *(point+2);
  1444.         *(point+2) = '\0';
  1445.         minute = atoi(point);
  1446.         *(point+2) = save;
  1447.  
  1448.         second = 0; /* no OS-9 seconds */
  1449.     }
  1450.     else /* no hours and minutes given */
  1451.     {
  1452.         hour = minute = second = 0;
  1453.     }
  1454.     if (   (year   > 99)
  1455.         || (month  > 12) || (month  < 1)
  1456.         || (day    > 31) || (day    < 1)
  1457.         || (hour   > 23)
  1458.         || (minute > 59))
  1459.     {
  1460.         debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
  1461.         return(-1);
  1462.     }
  1463.  
  1464.     /* Convert GMT broken down time to local broken down time */
  1465.     convert_to_local_time(&year,&month,&day,&hour,&minute,&second);
  1466.  
  1467.     if ((path = open(f,0)) == -1) /* mode 0 is sufficient for _gs_gfd */
  1468.     {
  1469.         debug(F110,"Can't open file to get fdesc:",f,0);
  1470.         return(r);
  1471.     }
  1472.     if (_gs_gfd(path,&buffer,sizeof(buffer)) == -1)
  1473.     {
  1474.         debug(F111,"Can't get descriptor for file:",f,errno);
  1475.         close(path);
  1476.         return(r);
  1477.     }
  1478.     close(path);
  1479.     switch (x)       /* Execute desired function */
  1480.     {
  1481.         case 0:      /* Set the creation and modification date of the file */
  1482.             buffer.fd_date[0] = year;
  1483.             buffer.fd_date[1] = month;
  1484.             buffer.fd_date[2] = day;
  1485.             buffer.fd_date[3] = hour;
  1486.             buffer.fd_date[4] = minute;
  1487. #ifdef COMMENT
  1488. /* The creation date can't be set */
  1489.             buffer.fd_dcr[0] = year;
  1490.             buffer.fd_dcr[1] = month;
  1491.             buffer.fd_dcr[2] = day;
  1492. #endif /* COMMENT */
  1493.             if ((path = open(f,S_IWRITE)) == -1) /* _ss_pfd needs writing */
  1494.             {
  1495.                 debug(F110,"Can't open file for write:",f,0);
  1496.                 return(r);
  1497.             }
  1498.             if (_ss_pfd(path,&buffer) == -1)
  1499.             {
  1500.               debug(F111,"Can't update descriptor for file:",f,errno);
  1501.             }
  1502.             else
  1503.             {
  1504.               debug(F110,"Mod. time is set for file: ",f,0);
  1505.               r = 0;
  1506.             }
  1507.             close(path);
  1508.             break;
  1509.     case 1:             /* Compare the dates */
  1510.             tp.tm_sec  = 0;
  1511.             tp.tm_min  = buffer.fd_date[4];
  1512.             tp.tm_hour = buffer.fd_date[3];
  1513.             tp.tm_mday = buffer.fd_date[2];
  1514.             tp.tm_mon  = buffer.fd_date[1]-1;
  1515.             tp.tm_year = buffer.fd_date[0];
  1516.             if (buffer.fd_date[0] < (unsigned char)70) tp.tm_year += 100;
  1517.  
  1518.             file_date = mktime(&tp);
  1519.  
  1520.             tp.tm_min  = minute;
  1521.             tp.tm_hour = hour;
  1522.             tp.tm_mday = day;
  1523.             tp.tm_mon  = month-1;
  1524.             tp.tm_year = year;
  1525.             if (year < (unsigned char)70) tp.tm_year += 100;
  1526.  
  1527. /* 1 if x is 1 and date from attribute structure <= file creation date. */
  1528.             r = mktime(&tp) <= file_date;
  1529.             break;
  1530.     default:                            /* Error */
  1531.             break;
  1532.     }
  1533.     return(r);
  1534. }
  1535.  
  1536. #ifdef RENAME
  1537. /*  Z R E N A M E  --  Rename a file  */
  1538. /*
  1539.    Call with old and new names.
  1540.    If new name is the name of a directory, the 'old' file is moved to
  1541.    that directory.
  1542.    Returns 0 on success, -1 on failure.
  1543. */
  1544. int
  1545. zrename(old,new) char *old, *new; {
  1546.     char *p = NULL, *s = new;
  1547.     int x;
  1548.  
  1549.     debug(F110,"zrename old",old,0);
  1550.     debug(F110,"zrename new",s,0);
  1551.     if (isdir(new)) {
  1552.         char *q = NULL;
  1553.         x = strlen(new);
  1554.         if (!(p = malloc(strlen(new) + strlen(old) + 2)))
  1555.           return(-1);
  1556.         strcpy(p,new);                  /* Directory part */
  1557.         if (!ISDIRSEP(*(new+x-1)))      /* Separator, if needed */
  1558.           strcat(p,"/");
  1559.         zstrip(old,&q);                 /* Strip path part from old name */
  1560.         strcat(p,q);                    /* Concatenate to new directory */
  1561.         s = p;
  1562.         debug(F110,"zrename dir",s,0);
  1563.     } else debug(F110,"zrename no dir",s,0);
  1564. /*
  1565.   Atomic, preferred, uses a single system call, rename(), if available.
  1566.   OS/2 rename() returns nonzero, but not necessarily -1 (?), on failure.
  1567. */
  1568.     x = rename(old,s);
  1569.     if (p) free(p);
  1570.     return(x ? -1 : 0);
  1571. }
  1572.  
  1573. #else /* RENAME */
  1574.  
  1575. /*  Z R E N A M E  --  Rename a file  */
  1576.  
  1577. /*  Call with old and new names */
  1578. /*  Returns 0 on success, -1 on failure. */
  1579.  
  1580. zrename(old,new) register char *old, *new;
  1581. {
  1582. char buffer[256];
  1583.         sprintf(buffer,"rename %s %s",old,new);
  1584.         if (zsyscmd(buffer) != 0)
  1585.         {
  1586.           debug(F111,"Can't rename:",old,errno);
  1587.           return(-1);
  1588.         }
  1589.         return(0);
  1590. }
  1591. #endif /* !RENAME */
  1592.  
  1593. /* Sorry...gotta avoid namespace pollution! */
  1594. #ifdef _UCC
  1595. #define environ    _environ
  1596. #endif /* _UCC */
  1597. /*
  1598.   Functions for executing system commands.
  1599.   zsyscmd() executes the system command in the normal, default way for
  1600.   the system.  In UNIX, it does what system() does.  Thus, its results
  1601.   are always predictable.
  1602.   zshcmd() executes the command using the user's preferred shell.
  1603. */
  1604. zsyscmd(s) char *s;
  1605. {
  1606.   unsigned int status;
  1607.   extern int os9forkc();
  1608.   extern char **environ;
  1609.   char *(argblk[3]);
  1610.   int pid,wstat;
  1611.  
  1612.   debug(F110,"zsyscmd:try:",s,0);
  1613.                  /* chaining (shell ex command) would save a process but */
  1614.   argblk[2] = 0; /* f$chain does not use PATH */
  1615.   argblk[1] = s;
  1616.   argblk[0] = "shell";
  1617.   if ((pid = os9exec(os9forkc,argblk[0],argblk,environ,0,0,3)) > 0)
  1618.   {
  1619.     while ((wstat = wait(&status)) != pid && wstat != -1) ;
  1620.     if (wstat == -1) {
  1621.       debug(F111," can't wait:",s,errno);
  1622.       return -1;
  1623.     }
  1624.     if (status != 0)
  1625.       debug(F111," can't execute:",s,status);
  1626.     else
  1627.       debug(F110," success:",s,0);
  1628.     return(status);
  1629.   }
  1630.   debug(F111," can't fork:",s,errno);
  1631.   return(-1);
  1632. }
  1633.  
  1634. zshcmd(s) register char *s;
  1635. {
  1636.   unsigned int status;
  1637.   extern int os9forkc();
  1638.   extern char **environ;
  1639.   char *(argblk[3]);
  1640.   int pid,wstat;
  1641.  
  1642.   debug(F110,"zshcmd:try:",s,0);
  1643.                  /* chaining (shell ex command) would save a process but */
  1644.   argblk[2] = 0; /* f$chain does not use PATH */
  1645.   argblk[1] = s;
  1646.   argblk[0] = getenv("SHELL");
  1647.   if (argblk[0] == (char *)0) argblk[0] = "shell";
  1648.   if ((pid = os9exec(os9forkc,argblk[0],argblk,environ,0,0,3)) > 0)
  1649.   {
  1650.     while ((wstat = wait(&status)) != pid && wstat != -1) ;
  1651.     if (wstat == -1) {
  1652.       debug(F111," can't wait:",s,errno);
  1653.       return -1;
  1654.     }
  1655.     if (status != 0)
  1656.       debug(F111," can't execute:",s,status);
  1657.     else
  1658.       debug(F110," success:",s,0);
  1659.     return(status == 0 ? 1 : 0);
  1660.   }
  1661.   debug(F111," can't fork:",s,errno);
  1662.   return(-1);
  1663. }
  1664.  
  1665. /*  Z S I N L  --  Read a line from a file  */
  1666.  
  1667. /*
  1668.   Writes the line into the address provided by the caller.
  1669.   n is the Kermit "channel number".
  1670.   Writing terminates when newline is encountered, newline is not copied.
  1671.   Writing also terminates upon EOF or if length x is exhausted.
  1672.   Returns 0 on success, -1 on EOF or error.
  1673. */
  1674. zsinl(n,s,x) int n, x; char *s; {
  1675.     int a, z = 0;
  1676.  
  1677.     if (chkfn(n) < 1) {                 /* Make sure file is open */
  1678.           return(-1);
  1679.     }
  1680.     a = -1;
  1681.     while (x--) {
  1682.       if (zchin(n,&a) < 0) {       /* Read a character from the file */
  1683.         z = -1;
  1684.         break;
  1685.       }
  1686.       if ( a == (char) NLCHAR) break; /* Single-character line terminator */
  1687.       *s = a;
  1688.       s++;
  1689.     }
  1690.     *s = '\0';
  1691.     return(z);
  1692. }
  1693.  
  1694. static char
  1695. *get_gmtime(file_desc) struct fildes *file_desc;
  1696. /* returns UCT/GMT yyyymmdd hh:mm:00 time out of the file descriptor
  1697.    if impossible to get GMT it takes the time from the file descriptor
  1698.    without converion */
  1699. {
  1700.   static char datbuf[18]; /* must be static cause returned!!! */
  1701.   struct tm *gmt = NULL, tp;
  1702.   time_t local_file_date;
  1703.  
  1704.   tp.tm_sec  = 0;
  1705.   tp.tm_min  = file_desc->fd_date[4];
  1706.   tp.tm_hour = file_desc->fd_date[3];
  1707.   tp.tm_mday = file_desc->fd_date[2];
  1708.   tp.tm_mon  = file_desc->fd_date[1]-1;
  1709.   tp.tm_year = ((unsigned char *)file_desc->fd_date)[0];
  1710.   if (tp.tm_year < 70) tp.tm_year += 100;
  1711.  
  1712.   /* If TZ not defined send modification date literally */
  1713.   if (getenv("TZ") != (char *)NULL) { 
  1714.     local_file_date = mktime(&tp);
  1715.     if (local_file_date != (time_t)-1) /* Take time literally */
  1716.       gmt = gmtime(&local_file_date);
  1717.   }
  1718.  
  1719.   if (gmt == NULL) gmt = &tp;
  1720.  
  1721.   sprintf(datbuf,"%4d%02d%02d %02d:%02d:00",
  1722.           1900+(unsigned int)gmt->tm_year,
  1723.           gmt->tm_mon+1,gmt->tm_mday,gmt->tm_hour,gmt->tm_min);
  1724.  
  1725.   return(datbuf);
  1726. }
  1727.  
  1728. static VOID
  1729. convert_to_local_time(year,month,day,hour,minute,second)
  1730. unsigned char *year,*month,*day,*hour,*minute,*second;
  1731. /* will convert to local time if timezone information is available assuming
  1732.    UCT/GMT time as input , otherwise just return.
  1733.    year must be since 1900 */
  1734. {
  1735.   struct tm *tp;
  1736.   time_t cal_date;
  1737.   int time,date;
  1738.   char *getenv();
  1739.   int y;
  1740.  
  1741.   if (getenv("TZ") == (char *)NULL) return;
  1742.   y = *year + 1900;
  1743.   if (*year < (unsigned char)70) y += 100;
  1744.   date = (y<<16)+(*month<<8)+*day;
  1745.   time = (*hour<<16)+(*minute<<8)+*second;
  1746.   if (_julian(&time,&date) == -1) return;
  1747.   cal_date = (date-2440587)*86400+time; /* 2440587 = 1st of Jan 1970 */
  1748.  
  1749.   tp = localtime(&cal_date);
  1750.  
  1751.   if (tp == (struct tm*)NULL) return;
  1752.  
  1753.   *second = tp->tm_sec;
  1754.   *minute = tp->tm_min;
  1755.   *hour = tp->tm_hour;
  1756.   *day = tp->tm_mday;
  1757.   *month = tp->tm_mon+1;
  1758.   *year = tp->tm_year % 100;
  1759.  
  1760. }
  1761.  
  1762. FILE *
  1763. pipeopen(command,access_type) char *command,*access_type;
  1764. {
  1765.   extern int os9forkc();
  1766.   extern char **environ;
  1767.   int duped,dupederr,stdinout;
  1768.   FILE *pipe;
  1769.   char *argv[3];
  1770.  
  1771.     if (*access_type=='r') stdinout = 1; /* redirect stdout and stderr*/
  1772.     else if (*access_type=='w') stdinout = 0; /* redirect stdin */
  1773.     else return((FILE *)NULL);
  1774.  
  1775.     if((duped = dup(stdinout)) <= 0) return((FILE *)NULL);
  1776.     if(stdinout == 1)
  1777.     {
  1778.       if((dupederr = dup(2)) <= 0)
  1779.       {
  1780.         close(duped);
  1781.         return((FILE *)NULL);
  1782.       }
  1783.     }
  1784.     if((pipe = fopen("/pipe", "r+")) == NULL)
  1785.     {
  1786.         close(duped);
  1787.         if(stdinout == 1) close(dupederr);
  1788.         return((FILE *)NULL);
  1789.     }
  1790.     close(stdinout);
  1791.     dup(fileno(pipe));
  1792.     if (stdinout == 1) /* also dupe stderr */
  1793.     {
  1794.       close(2);
  1795.       dup(fileno(pipe));
  1796.     }
  1797.     argv[0] = "shell";
  1798.     argv[1] = command;
  1799.     argv[2] = (char *)NULL;
  1800.     if((pipe_pid = os9exec(os9forkc,argv[0],argv,environ,0,0,3)) < 0)
  1801.     {
  1802.         pipe_pid = 0;
  1803.         fclose(pipe);
  1804.  
  1805.         close(stdinout);
  1806.         dup(duped); /* restore old stdinout */
  1807.         close(duped);
  1808.         if(stdinout == 1) /* also restore old sterr */
  1809.         {
  1810.           close(2);
  1811.           dup(dupederr);
  1812.           close(dupederr);
  1813.         }
  1814.         return (FILE *)NULL;
  1815.     }
  1816.     debug(F101," pipeopen success id:","",pipe_pid);
  1817.     close(stdinout);
  1818.     dup(duped);
  1819.     close(duped);
  1820.     if(stdinout == 1)
  1821.     {
  1822.       close(2);
  1823.       dup(dupederr);
  1824.       close(dupederr);
  1825.     }
  1826.     return(pipe);
  1827. }
  1828.  
  1829. /*
  1830.    Tell if string pointer s is the name of an existing directory.
  1831.    Returns 1 if directory, 0 if not a directory.
  1832. */
  1833. int
  1834. isdir(s) char *s; {
  1835.     int x;
  1836. #ifndef OSK
  1837.     struct stat statbuf;
  1838. #endif /* !OSK */
  1839.  
  1840.     if (!s) return(0);
  1841.     if (!*s) return(0);
  1842.  
  1843. #ifdef OS2
  1844.     /* Disk letter like A: is top-level directory on a disk */
  1845.     if (((int)strlen(s) == 2) && (isalpha(*s)) && (*(s+1) == ':'))
  1846.       return(1);
  1847. #endif /* OS2 */
  1848. #ifdef OSK
  1849.     x = access(s, S_IFDIR);
  1850. #else
  1851.     x = stat(s,&statbuf);
  1852. #endif /* OSK */
  1853.     debug(F111,"isdir stat",s,x);
  1854.     if (x == -1) {
  1855.         debug(F101,"isdir errno","",errno);
  1856.         return(0);
  1857.     } else {
  1858. #ifdef OSK
  1859.     return 1;
  1860. #else
  1861.         debug(F101,"isdir statbuf.st_mode","",statbuf.st_mode);
  1862.         return( S_ISDIR (statbuf.st_mode) ? 1 : 0 );
  1863. #endif /* OSK */
  1864.     }
  1865. }
  1866.  
  1867. #ifdef CK_MKDIR
  1868. /* Some systems don't have mkdir(), e.g. Tandy Xenix 3.2.. */
  1869.  
  1870. /* Z M K D I R  --  Create directory(s) if necessary */
  1871. /*
  1872.    Call with:
  1873.     A pointer to a file specification that might contain directory
  1874.     information.  The filename is expected to be included.
  1875.     If the file specification does not include any directory separators,
  1876.     then it is assumed to be a plain file.
  1877.     If one or more directories are included in the file specification,
  1878.     this routine tries to create them if they don't already exist.
  1879.    Returns:
  1880.     0 on success, i.e. the directory was created
  1881.    -1 on failure to create the directory
  1882. */
  1883. int
  1884. zmkdir(path) char *path; {
  1885.     char *xp, *tp, c;
  1886.     int x;
  1887.  
  1888.     x = strlen(path);
  1889.     debug(F111,"zmkdir",path,x);
  1890.     if (x < 1 || x > MAXPATH)           /* Check length */
  1891.       return(-1);
  1892.     if (!(tp = malloc(x+1)))            /* Make a temporary copy */
  1893.       return(-1);
  1894.     strcpy(tp,path);
  1895. #ifdef DTILDE
  1896.     if (*tp == '~') {                   /* Starts with tilde? */
  1897.         xp = tilde_expand(tp);          /* Attempt to expand tilde */
  1898.         if (*xp) {
  1899.             char *zp;
  1900.             debug(F110,"zmkdir tilde_expand",xp,0);
  1901.             if (!(zp = malloc(strlen(xp) + 1))) { /* Make a place for it */
  1902.                 free(tp);
  1903.                 return(-1);
  1904.             }
  1905.             free(tp);                   /* Free previous buffer */
  1906.             tp = zp;                    /* Point to new one */
  1907.             strcpy(tp,xp);              /* Copy expanded name to new buffer */
  1908.         }
  1909.         debug(F110,"zmkdir tp after tilde_expansion",tp,0);
  1910.     }
  1911. #endif /* DTILDE */
  1912.     xp = tp;
  1913.     if (ISDIRSEP(*xp))                  /* Don't create root directory! */
  1914.       xp++;
  1915.  
  1916.     /* Go thru filespec from left to right... */
  1917.  
  1918.     for (; *xp; xp++) {                 /* Create parts that don't exist */
  1919.         if (!ISDIRSEP(*xp))             /* Find next directory separator */
  1920.           continue;
  1921.         c = *xp;                        /* Got one. */
  1922.         *xp = NUL;                      /* Make this the end of the string. */
  1923.         if (!isdir(tp)) {               /* This directory exists already? */
  1924.             debug(F110,"zmkdir making",tp,0);
  1925.             x =                         /* No, try to create it */
  1926. #ifdef NOMKDIR
  1927.                -1                       /* Systems without mkdir() */
  1928. #else
  1929. #ifdef OS2                              /* OS/2 */
  1930. #ifdef __32BIT__
  1931.                _mkdir(tp)               /* The IBM way */
  1932. #else
  1933.                mkdir(tp)                /* The Microsoft way */
  1934. #endif /* __32BIT__ */
  1935. #else
  1936. #ifdef OSK
  1937.                makdir(tp,0,077)
  1938. #else
  1939.                mkdir(tp,0777)           /* UNIX */
  1940. #endif /* OSK* */
  1941. #endif /* OS2 */
  1942. #endif /* NOMKDIR */
  1943.                  ;
  1944.             if (x < 0) {
  1945.                 debug(F101,"zmkdir failed, errno","",errno);
  1946.                 free(tp);               /* Free temporary buffer. */
  1947.                 return(-1);             /* Freturn failure code. */
  1948.             }
  1949.         }
  1950.         *xp = c;                        /* Replace the separator. */
  1951.     }
  1952.     free(tp);                           /* Free temporary buffer. */
  1953.     return(0);                          /* Return success code. */
  1954. }
  1955. #endif /* CK_MKDIR */
  1956.  
  1957. /* Z F S E E K  --  Position input file pointer */
  1958. /*
  1959.    Call with:
  1960.     Long int, 0-based, indicating desired position.
  1961.    Returns:
  1962.     0 on success.
  1963.    -1 on failure.
  1964. */
  1965. #ifndef NORESEND
  1966. int
  1967. #ifdef CK_ANSIC
  1968. zfseek(long pos)
  1969. #else
  1970. zfseek(pos) long pos;
  1971. #endif /* CK_ANSIC */
  1972. /* zfseek */ {
  1973.     debug(F101,"zfseek","",pos);
  1974.     return(fseek(fp[ZIFILE], pos, 0));
  1975. }
  1976. #endif /* NORESEND */
  1977.