home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc095.zip / ck9fio.c < prev    next >
C/C++ Source or Header  |  1989-07-28  |  29KB  |  951 lines

  1. char *ckzv = "OS-9 file support, 17 Jul 89";
  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.  
  15.  adapted from Unix C-Kermit
  16.  Author: Frank da Cruz (SY.FDC@CU20B),
  17.  Columbia University Center for Computing Activities, January 1985.
  18.  Copyright (C) 1985, Trustees of Columbia University in the City of New York.
  19.  
  20.  Permission is granted to any individual or institution to use, copy, or
  21.  redistribute this software so long as it is not sold for profit, provided this
  22.  copyright notice is retained.
  23. */
  24. /* Includes */
  25.  
  26. #include "ckcker.h"        /* Kermit definitions */
  27. #include "ckcdeb.h"        /* Typedefs, debug formats, etc */
  28. #include <ctype.h>        /* Character types */
  29. #include <stdio.h>        /* Standard i/o */
  30. #include <dir.h>        /* Directory structure */
  31. #include <direct.h>
  32. #include <modes.h>
  33.  
  34. /* Definitions of some system commands */
  35.  
  36. char *DIRCMD = "dir ";        /* For directory listing */
  37. char *DELCMD = "del ";        /* For file deletion */
  38. char *TYPCMD = "list ";        /* For typing a file */
  39. char *PWDCMD = "pd ";        /* For saying where I am */
  40.  
  41. char *SPACMD = "free ";
  42. char *SPACM2 = "free ";        /* For space in specified directory */
  43.  
  44. char *WHOCMD = "procs ";    /* we have no who yet*/
  45.  
  46. /*
  47.   Functions (n is one of the predefined file numbers from ckermi.h):
  48.  
  49.    zopeni(n,name)   -- Opens an existing file for input.
  50.    zopeno(n,name)   -- Opens a new file for output.
  51.    zclose(n)        -- Closes a file.
  52.    zchin(n,&c)      -- Gets the next character from an input file.
  53.    zsout(n,s)       -- Write a null-terminated string to output file, buffered.
  54.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  55.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  56.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  57.    zchki(name)      -- Check if named file exists and is readable, return size.
  58.    zchko(name)      -- Check if named file can be created.
  59.    znewn(name,s)    -- Make a new unique file name based on the given name.
  60.    zdelet(name)     -- Delete the named file.
  61.    zxpand(string)   -- Expands the given wildcard string into a list of files.
  62.    znext(string)    -- Returns the next file from the list in "string".
  63.    zxcmd(cmd)       -- Execute the command in a lower fork.
  64.    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
  65.    zrtol(n1,n2)     -- Convert remote filename into local form.
  66.    zltor(n1,n2)     -- Convert local filename into remote form.
  67.    zchdir(dirnam)   -- Change working directory.
  68.    zhome()          -- Return pointer to home directory name string.
  69.    zkself()         -- Kill self, log out own job.
  70.    zsattr(struc zattr *) -- Return attributes for file which is being sent.
  71.  */
  72.  
  73.  
  74. /* Some systems define these in include files, others don't... */
  75. #define R_OK S_IREAD        /* For access */
  76. #define W_OK S_IWRITE
  77. #define O_RDONLY 000
  78.  
  79. #ifndef    MAXNAMLEN
  80. #define MAXNAMLEN 28        /* If still not defined... */
  81. #endif
  82.  
  83. #define MAXWLD 500
  84.  
  85. /* Declarations */
  86.  
  87. FILE *fp[ZNFILS] = {    /* File pointers */
  88.     NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  89.  
  90. /* (PWP) external def. of things used in buffered file input and output */
  91. extern CHAR zinbuffer[], zoutbuffer[];
  92. extern CHAR *zinptr, *zoutptr;
  93. extern int zincnt, zoutcnt;
  94.  
  95. static long iflen = -1;            /* Input file length */
  96. static long oflen = -1;            /* Output file length */
  97.  
  98. static int pid;                /* pid of child fork */
  99. static int fcount;            /* Number of files in wild group */
  100. static char nambuf[MAXNAMLEN+2];    /* Buffer for a filename */
  101. char *malloc(), *getenv(), *strcpy();    /* System functions */
  102. extern errno;                /* System error code */
  103.  
  104. static char *mtchs[MAXWLD],        /* Matches found for filename */
  105.      **mtchptr;                /* Pointer to current match */
  106.  
  107. /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
  108.  
  109. zkself() {                /* For "bye", but no guarantee! */
  110.     return(kill(getpid(),0));
  111. }
  112.  
  113. #define MAXPATH 128
  114.  
  115. char *zgtdir() {
  116.     /* I'm sure this can be done better... */
  117.     static char cwd[MAXPATH];
  118.     char backpath[MAXPATH];
  119.     char *bpp = backpath, *path = cwd;
  120.     DIR *dirp;
  121.     struct direct *dp;
  122.     long inode, inode2;
  123.     char dots[MAXPATH];
  124.  
  125.     if((dirp = opendir(".")) == NULL || readdir(dirp) == NULL ||
  126.         (dp = readdir(dirp)) == NULL) {
  127.     closedir(dirp);
  128.     return (char *)NULL;
  129.     }
  130.     inode = dp->d_addr;
  131.     *path++ = '/';
  132.     _gs_devn(dirp->dd_fd, path);
  133.     path += strlen(path);
  134.     closedir(dirp);
  135.     strcpy(dots, "..");
  136.     for(;;) {
  137.     if((dirp = opendir(dots)) == NULL || readdir(dirp) == NULL ||
  138.             (dp = readdir(dirp)) == NULL) {
  139.         closedir(dirp);
  140.         return (char *)NULL;
  141.     }
  142.     inode2 = dp->d_addr;
  143.     if(inode == inode2) break;    /* .. and . are same, we are done */
  144.     do {
  145.         if((dp = readdir(dirp)) == NULL) {
  146.         closedir(dirp);
  147.         return (char *)NULL;
  148.         }
  149.     } while(dp->d_addr != inode);
  150.     *bpp++ = '/';
  151.     strcpy(bpp, dp->d_name);
  152.     bpp += strlen(bpp);
  153.     closedir(dirp);
  154.     inode = inode2;
  155.     strcat(dots, "/..");
  156.     }
  157.     while(bpp > backpath) {
  158.     *bpp = '\0';
  159.     while(*--bpp != '/') {}
  160.     strcpy(path, bpp);
  161.     path += strlen(path);
  162.     }
  163.     return cwd;
  164. }
  165.  
  166.  
  167. /*  Z O P E N I  --  Open an existing file for input. */
  168.  
  169. zopeni(n,name) int n; char *name; {
  170.     debug(F111," zopeni",name,n);
  171.     debug(F101,"  fp","",(int) fp[n]);
  172.     if (chkfn(n) != 0) return(0);
  173.     zincnt = 0;                /* Reset input buffer */
  174.     if (n == ZSYSFN) {           /* Input from a system function? */
  175.         debug(F110," invoking zxcmd",name,0);
  176.     *nambuf = '\0';            /* No file name this time... */
  177.     return(zxcmd(name));        /* Try to fork the command */
  178.     }
  179.     if (n == ZSTDIO) {   /* Standard input? */
  180.     if (isatty(0)) {
  181.         ermsg("Terminal input not allowed");
  182.         debug(F110,"zopeni: attempts input from unredirected stdin","",0);
  183.         return(0);
  184.     }
  185.     fp[ZIFILE] = stdin;
  186.     return(1);
  187.     }
  188.     fp[n] = fopen(name,"r");        /* Real file. */
  189.     debug(F111," zopeni", name, (int) fp[n]);
  190.     if (fp[n] == NULL) perror("zopeni");
  191.     return((fp[n] != NULL) ? 1 : 0);
  192. }
  193.  
  194. /*  Z O P E N O  --  Open a new file for output.  */
  195.  
  196. zopeno(n,name) int n; char *name; {
  197.     debug(F111," zopeno",name,n);
  198.     if (chkfn(n) != 0) return(0);
  199.     if ((n == ZCTERM) || (n == ZSTDIO)) {   /* Terminal or standard output */
  200.     fp[ZOFILE] = stdout;
  201.     debug(F101," fp[]=stdout", "", (int) fp[n]);
  202.     zoutcnt = 0;
  203.     zoutptr = zoutbuffer;
  204.     return(1);
  205.     }
  206.     fp[n] = fopen(name,"w");  /* A real file, try to open */
  207.     if (fp[n] == NULL) {
  208.         perror("zopeno can't open");
  209.     } else {
  210.     /* chown(name, getuid(), getgid());     In case set[gu]id */
  211.         if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */
  212.     }
  213.     zoutcnt = 0;        /* (PWP) reset output buffer */
  214.     zoutptr = zoutbuffer;
  215.     debug(F101, " fp[n]", "", (int) fp[n]);
  216.     return((fp[n] != NULL) ? 1 : 0);
  217. }
  218.  
  219. /*  Z C L O S E  --  Close the given file.  */
  220.  
  221. /*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */
  222.  
  223. zclose(n) int n; {
  224.     int x, x2;
  225.     if (chkfn(n) < 1) return(0); /* Check range of n */
  226.  
  227.     if ((n == ZOFILE) && (zoutcnt > 0))    /* (PWP) output leftovers */
  228.     x2 = zoutdump();
  229.  
  230.     if ((n == ZIFILE) && fp[ZSYSFN]) { /* If system function */
  231.     x = zclosf();   /* do it specially */
  232.     } else {
  233.     if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
  234.     fp[n] = NULL;
  235.     }
  236.     iflen = -1;                /* Invalidate file length */
  237.     return ((x == EOF) || (x2 < 0)) ? -1 : 1;
  238. }
  239.  
  240. /*  Z C H I N  --  Get a character from the input file.  */
  241.  
  242. /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
  243.  
  244. zchin(n,c) int n; char *c; {
  245.     int a;
  246.  
  247.     /* (PWP) Just in case this gets called when it shoudn't */
  248.     if (n == ZIFILE)
  249.     return (zminchar());
  250.  
  251.     /* if (chkfn(n) < 1) return(-1); */
  252.     a = getc(fp[n]);
  253.     if (a == EOF) return(-1);
  254.     *c = a & 0377;
  255.     return(0);
  256. }
  257.  
  258. /*  Z I N F I L L  --  Get a character from the input file.
  259.  * (PWP) (re)fill the buffered input buffer with data.  All file input
  260.  * should go through this routine, usually by calling the zminchar()
  261.  * macro (in ckcker.h).
  262.  */
  263.  
  264. zinfill() {
  265.     zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
  266.     if (zincnt == 0) return (-1);    /* end of file */
  267.     zinptr = zinbuffer;       /* set pointer to beginning, (== &zinbuffer[0]) */
  268.     zincnt--;                /* one less char in buffer */
  269.     return((int)(*zinptr++) & 0377);    /* because we return the first */
  270. }
  271.  
  272. /*  Z S O U T  --  Write a string to the given file, buffered.  */
  273.  
  274. zsout(n,s) int n; char *s; {
  275.     if (chkfn(n) < 1) return(-1);
  276.     fputs(s,fp[n]);
  277.     return(0);
  278. }
  279.  
  280. /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
  281.  
  282. zsoutl(n,s) int n; char *s; {
  283.     /* if (chkfn(n) < 1) return(-1); */
  284.     fputs(s,fp[n]);
  285.     fputs("\n",fp[n]);
  286.     return(0);
  287. }
  288.  
  289. /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
  290.  
  291. zsoutx(n,s,x) int n, x; char *s; {
  292.     /* if (chkfn(n) < 1) return(-1); */
  293.     return(write(fileno(fp[n]),s,x));
  294. }
  295.  
  296.  
  297. /*  Z C H O U T  --  Add a character to the given file.  */
  298.  
  299. /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
  300.  
  301. zchout(n,c) register int n; char c; {
  302.     /* if (chkfn(n) < 1) return(-1); */
  303.     if (n == ZSFILE)
  304.     return(write(fileno(fp[n]),&c,1)); /* Use unbuffered for session log */
  305.     else {    /* Buffered for everything else */
  306.     if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
  307.         return(ferror(fp[n])); /* Check to make sure */
  308.     else return(0);   /* There was no error. */
  309.     }
  310. }
  311.  
  312. /* (PWP) buffered character output routine to speed up file IO */
  313. zoutdump()
  314. {
  315.     if (zoutcnt <= 0) return (0); /* nothing to output */
  316.  
  317.     if (fwrite (zoutbuffer, 1, zoutcnt, fp[ZOFILE])) {
  318.     zoutcnt = 0;        /* reset output buffer */
  319.     zoutptr = zoutbuffer;
  320.     return(0);        /* things worked OK */
  321.     } else {
  322.     return(ferror(fp[ZOFILE])?-1:0); /* Check to make sure */
  323.     }
  324. }
  325.  
  326. /*  C H K F N  --  Internal function to verify file number is ok  */
  327.  
  328. /*
  329.  Returns:
  330.   -1: File number n is out of range
  331.    0: n is in range, but file is not open
  332.    1: n in range and file is open
  333. */
  334. chkfn(n) int n; {
  335.     switch (n) {
  336.     case ZCTERM:
  337.     case ZSTDIO:
  338.     case ZIFILE:
  339.     case ZOFILE:
  340.     case ZDFILE:
  341.     case ZTFILE:
  342.     case ZPFILE:
  343.     case ZSFILE:
  344.     case ZSYSFN: break;
  345.  
  346.     default:
  347.         debug(F101,"chkfn: file number out of range","",n);
  348.         fprintf(stderr,"?File number out of range - %d\n",n);
  349.         return(-1);
  350.     }
  351.     return( (fp[n] == NULL) ? 0 : 1 );
  352. }
  353.  
  354. /*  Z C H K I  --  Check if input file exists and is readable  */
  355.  
  356. /*
  357.   Returns:
  358.    >= 0 if the file can be read (returns the size).
  359.      -1 if file doesn't exist or can't be accessed,
  360.      -2 if file exists but is not readable (e.g. a directory file).
  361.      -3 if file exists but protected against read access.
  362. */
  363. long
  364. zchki(name) char *name; {
  365.     struct fildes buf;
  366.     int x;   
  367.  
  368.     if (access(name,0) < 0) {
  369.     if(access(name,S_IFDIR)>=0) {
  370.         debug(F111,"zchki skipping:",name,errno);
  371.         return(-2);
  372.     }
  373.     debug(F111,"zchki can't access",name,errno);
  374.     return(-1);
  375.     }
  376.     debug(F111,"zchki stat ok:",name,x);
  377.  
  378.     if ((x = access(name,R_OK)) < 0) {  /* Is the file accessible? */
  379.     debug(F111," access failed:",name,x); /* No */
  380.     return(-3);   
  381.     }
  382.     if((x = open(name,S_IREAD)) < 0) {
  383.     debug(F111,"zchki can't open:",name,errno);
  384.     return(-2);
  385.     }
  386.     iflen = _gs_size(x);        /* remember size */
  387.     strncpy(nambuf,name,MAXNAMLEN);    /* and name globally */
  388.     close(x);
  389.     debug(F111," access ok:",name,(int) iflen); /* Yes */
  390.     return( (iflen > -1) ? iflen : 0 );
  391. }
  392.  
  393. /*  Z C H K O  --  Check if output file can be created  */
  394.  
  395. /*
  396.  Returns -1 if write permission for the file would be denied, 0 otherwise.
  397. */
  398. zchko(name) char *name; {
  399.     int i, x;
  400.     char s[50], *sp; 
  401.  
  402.     if(access(name,S_IFDIR)>=0) return -1;    /* it's a directory */
  403.     sp = s;    /* Make a copy, get length */
  404.     x = 0;
  405.     while ((*sp++ = *name++) != '\0')
  406.     x++;
  407.     if (x == 0) return(-1);        /* If no filename, fail. */
  408.  
  409.     debug(F101," length","",x);
  410.     for (i = x; i > 0; i--) {        /* Strip filename. */
  411.     if(!isalnum(s[i-1])) {
  412.         switch(s[i-1]) {
  413.             case '.':
  414.         case '$':
  415.         case '_': continue;
  416.            case '/': break;
  417.             default: return -1;    /* bad character */
  418.         }
  419.         break;
  420.     }
  421.     }
  422.     debug(F101," i","",i);
  423.     if (i == 0)                /* If no path, use current directory */
  424.     strcpy(s,".");   
  425.     else {                /* Otherwise, use given one. */
  426.         if(i==x) return -1;        /* no filename! */
  427.         s[--i] = '\0';
  428.     }
  429.     x = access(s,S_IFDIR|S_IWRITE);    /* Check access of path. */
  430.     if (x < 0) {
  431.     fprintf(stderr,"access failed %s   errno:%d\n",s,errno);
  432.     debug(F111,"zchko access failed:",s,errno);
  433.     return(-1);
  434.     } else {
  435.     debug(F111,"zchko access ok:",s,x);
  436.     return(0);
  437.     }
  438. }
  439.  
  440. /*  Z D E L E T  --  Delete the named file.  */
  441.  
  442. zdelet(name) char *name; {
  443.     unlink(name);
  444. }
  445.  
  446.  
  447. /*  Z R T O L  --  Convert remote filename into local form  */
  448.  
  449. /*  For OS9, this means changing uppercase letters to lowercase.  */
  450.  
  451. zrtol(name,name2) char *name, *name2; {
  452.     for ( ; *name != '\0'; name++) {
  453.     *name2++ = isupper(*name) ? tolower(*name) : *name;
  454.     }
  455.     *name2 = '\0';
  456.     debug(F110,"zrtol:",name2,0);
  457. }
  458.  
  459.  
  460. /*  Z L T O R  --  Local TO Remote */
  461.  
  462. /*  Convert filename from local format to common (remote) form.  */
  463.  
  464. zltor(name,name2) char *name, *name2; {
  465.     char work[100], *cp, *pp;
  466.     int dc = 0;
  467.  
  468.     debug(F110,"zltor",name,0);
  469.     pp = work;
  470.     for (cp = name; *cp != '\0'; cp++) { /* strip path name */
  471.     if (*cp == '/') {
  472.         dc = 0;
  473.         pp = work;
  474.     }
  475.     else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
  476.     else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
  477.     else *pp++ = *cp;
  478.     }
  479.     *pp = '\0';    /* Tie it off. */
  480.     cp = name2;    /* If nothing before dot, */
  481.     if (*work == '.') *cp++ = 'X'; /* insert 'X' */
  482.     strcpy(cp,work);
  483.     debug(F110," name2",name2,0);
  484. }
  485.  
  486.  
  487. /*  Z C H D I R  --  Change directory  */
  488.  
  489. zchdir(dirnam) char *dirnam; {
  490.     char *hd;
  491.     if (*dirnam == '\0') hd = getenv("HOME");
  492.     else hd = dirnam;
  493.     return((chdir(hd) == 0) ? 1 : 0);
  494. }
  495.  
  496.  
  497. /*  Z H O M E  --  Return pointer to user's home directory  */
  498.  
  499. char *
  500. zhome() {
  501.     return(getenv("HOME"));
  502. }
  503.  
  504. /*  Z X C M D -- Run a system command so its output can be read like a file */
  505.  
  506. zxcmd(comand) char *comand; {
  507.     int pipes[2];
  508.     int i,stdio[3],os9fork();
  509.     if ((pipes[0]=open("/pipe",_READ))<0) return(0);
  510.     if((pipes[1]=dup(pipes[0]))<0) {
  511.     close(pipes[0]);
  512.         return(0);
  513.     }
  514.     for(i=0;i<3;i++)
  515.     stdio[i] = dup(i);
  516.     close(0);   /* close stdin */
  517.     if (open("/nil",_READ) < 0) return(0); /* replace input by null */
  518.  
  519.     close(1);   /* simulate dup2 */
  520.     if (dup(pipes[1]) != 1 )
  521.     conol("trouble duping stdout in routine zxcmd\n");
  522.     close(2);   /* simulate dup2 */
  523.     if (dup(pipes[1]) != 2 )
  524.     conol("trouble duping stderr in routine zxcmd\n");
  525.  
  526.     pid = os9fork("shell",strlen(comand),comand,0,0,0,0);
  527.  
  528.     fp[ZIFILE] = fdopen(pipes[0],"r"); /* open a stream for it */
  529.     close(pipes[1]);   /* don't need the output side */
  530.     for(i=0;i<3;i++) {
  531.     close(i);
  532.     dup(stdio[i]);
  533.     }
  534.     fp[ZSYSFN] = fp[ZIFILE];  /* Remember. */
  535.     return(1);
  536. }
  537.  
  538. /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
  539.  
  540. zclosf() {
  541.     int wstat;
  542.     fclose(fp[ZIFILE]);
  543.     fp[ZIFILE] = fp[ZSYSFN] = NULL;
  544.     while ((wstat = wait(0)) != pid && wstat != -1) ;
  545.     return(1);
  546. }
  547.  
  548. /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
  549. /*
  550.   Returns the number of files that match fn1, with data structures set up
  551.   so that first file (if any) will be returned by the next znext() call.
  552. */
  553. zxpand(fn) char *fn; {
  554.     fcount = fgen(fn,mtchs,MAXWLD); /* Look up the file. */
  555.     if (fcount > 0) {
  556.     mtchptr = mtchs;  /* Save pointer for next. */
  557.     }
  558.     debug(F111,"zxpand",mtchs[0],fcount);
  559.     return(fcount);
  560. }
  561.  
  562.  
  563. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  564. /*
  565.  Returns >0 if there's another file, with its name copied into the arg string,
  566.  or 0 if no more files in list.
  567. */
  568. znext(fn) char *fn; {
  569.     if (fcount-- > 0) strcpy(fn,*mtchptr++);
  570.     else *fn = '\0';
  571.     debug(F111,"znext",fn,fcount+1);
  572.     return(fcount+1);
  573. }
  574.  
  575.  
  576. /*  Z N E W N  --  Make a new name for the given file  */
  577.  
  578. znewn(fn,s) char *fn, **s; {
  579.     static char buf[256];
  580.     char *bp, *xp;
  581.     int len = 0, n = 0, d = 0, t, i, power = 1;
  582. #ifdef MAXNAMLEN
  583.     int max = MAXNAMLEN;
  584. #else
  585.     int max = 14;
  586. #endif
  587.     bp = buf;
  588.     while (*fn) {   /* Copy name into buf */
  589.     *bp++ = *fn++;
  590.     len++;
  591.     }
  592.     if (len > max-2) {    /* Don't let it get too long */
  593.     bp = buf + max-2;
  594.     len = max - 2;
  595.     }
  596.  
  597.     for (i = 1; i < 4; i++) {  /* Try up to 999 times */
  598.     power *= 10;
  599.     *bp++ = '*';   /* Put a star on the end */
  600.     *bp-- = '\0';
  601.  
  602.     n = zxpand(buf);  /* Expand the resulting wild name */
  603.  
  604.     while (n-- > 0) {  /* Find any existing name_d files */
  605.         xp = *mtchptr++;
  606.         xp += len;
  607.         if (*xp == '_') {
  608.         t = atoi(xp+1);
  609.         if (t > d) d = t; /* Get maximum d */
  610.         }
  611.     }
  612.     if (d < power-1) {
  613.         sprintf(bp,"_%d",d+1); /* Make name_(d+1) */
  614.         *s = buf;
  615.         return;
  616.     }
  617.     bp--; len--;
  618.     }
  619. /* If we ever get here, we'll overwrite the xxx~100 file... */
  620. }
  621.  
  622. /*  Z S A T T R */
  623. /*
  624.  Fills in a Kermit file attribute structure for the file which is to be sent.
  625.  Returns 0 on success with the structure filled in, or -1 on failure.
  626.  If any string member is null, then it should be ignored.
  627.  If any numeric member is -1, then it should be ignored.
  628. */
  629. zsattr(xx) struct zattr *xx; {
  630.     long k;
  631.     char *zfcdat();
  632.  
  633.     k = iflen % 1024L;            /* File length in K */
  634.     if (k != 0L) k = 1L;
  635.     xx->lengthk = (iflen / 1024L) + k;
  636.     xx->type.len = 0;            /* File type can't be filled in here */
  637.     xx->type.val = "";
  638. debug(F110,"before calling zfcdat",nambuf,0);
  639.     if (nambuf) {
  640.     xx->date.val = zfcdat(nambuf);    /* File creation date */
  641.     xx->date.len = strlen(xx->date.val);
  642.     } else {
  643.     xx->date.len = 0;
  644.     xx->date.val = "";
  645.     }
  646. debug(F111,"attr date",xx->date.val,xx->date.len);
  647.     xx->creator.len = 0;        /* File creator */
  648.     xx->creator.val = "";
  649.     xx->account.len = 0;        /* File account */
  650.     xx->account.val = "";
  651.     xx->area.len = 0;            /* File area */
  652.     xx->area.val = "";
  653.     xx->passwd.len = 0;            /* Area password */
  654.     xx->passwd.val = "";
  655.     xx->blksize = -1L;            /* File blocksize */
  656.     xx->access.len = 0;            /* File access */
  657.     xx->access.val = "";
  658.     xx->encoding.len = 0;        /* Transfer syntax */
  659.     xx->encoding.val = 0;
  660.     xx->disp.len = 0;            /* Disposition upon arrival */
  661.     xx->disp.val = "";
  662.     xx->lprotect.len = 0;        /* Local protection */
  663.     xx->lprotect.val = "";
  664.     xx->gprotect.len = 0;        /* Generic protection */
  665.     xx->gprotect.val = "";
  666.     xx->systemid.len = 2;        /* System ID */
  667.     xx->systemid.val = "UD";
  668.     xx->recfm.len = 0;            /* Record format */
  669.     xx->recfm.val = "";
  670.     xx->sysparam.len = 0;        /* System-dependent parameters */
  671.     xx->sysparam.val = "";
  672.     xx->length = iflen;            /* Length */
  673.     return(0);
  674. }
  675.  
  676. /* Z F C D A T -- Return a string containing the time stamp for a file */
  677.  
  678. char *
  679. zfcdat(name) char *name; {
  680.     int fp;
  681.     struct fildes fd;
  682.     static char datbuf[9];
  683.  
  684.     if((fp = open(name, 0)) < 0) return "";
  685.     if(_gs_gfd(fp, &fd, sizeof fd) >= 0) {
  686.         sprintf(datbuf,"%4d%02d%02d",fd.fd_dcr[0],fd.fd_dcr[1],fd.fd_dcr[2]);
  687.     } else datbuf[0] = '\0';
  688.     close(fp);
  689.     debug(F111,"zcfdat",datbuf,strlen(datbuf));
  690.     return datbuf;
  691. }
  692.  
  693. /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
  694.  
  695. /*
  696.  * The path structure is used to represent the name to match.
  697.  * Each slash-separated segment of the name is kept in one
  698.  * such structure, and they are linked together, to make
  699.  * traversing the name easier.
  700.  */
  701.  
  702. struct path {
  703.               char npart[MAXNAMLEN]; /* name part of path segment */
  704.               struct path *fwd;  /* forward ptr */
  705.             };
  706.  
  707. #define SSPACE 2000   /* size of string-generating buffer */
  708. static char sspace[SSPACE];             /* buffer to generate names in */
  709. static char *freeptr,**resptr;          /* copies of caller's arguments */
  710. static int remlen;                      /* remaining length in caller's array*/
  711. static int numfnd;                      /* number of matches found */
  712.  
  713. /*
  714.  * splitpath:
  715.  *  takes a string and splits the slash-separated portions into
  716.  *  a list of path structures.  Returns the head of the list.  The
  717.  *  structures are allocated by malloc, so they must be freed.
  718.  *  Splitpath is used internally by the filename generator.
  719.  *
  720.  * Input: A string.
  721.  * Returns: A linked list of the slash-separated segments of the input.
  722.  */
  723.  
  724. struct path *
  725. splitpath(p)
  726. char *p;
  727. {
  728.     struct path *head,*cur,*prv;
  729.     int i;
  730.     head = prv = NULL;
  731.     if (*p == '/') p++;            /* skip leading slash */
  732.     while (*p != '\0') {
  733.     cur = (struct path *) malloc(sizeof (struct path));
  734.     debug(F101,"splitpath malloc","",cur);
  735.     if (cur == NULL) fatal("malloc fails in splitpath()");
  736.     cur -> fwd = NULL;
  737.     if (head == NULL) head = cur;
  738.     else prv -> fwd = cur;       /* link into chain */
  739.     prv = cur;
  740.     for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++)
  741.         cur -> npart[i] = *p++;
  742.     cur -> npart[i] = '\0';      /* end this segment */
  743.     if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++;
  744.     if (*p == '/') p++;
  745.     }
  746.     return(head);
  747. }
  748.  
  749. /*
  750.  * fgen:
  751.  *  This is the actual name generator.  It is passed a string,
  752.  *  possibly containing wildcards, and an array of character pointers.
  753.  *  It finds all the matching filenames and stores them into the array.
  754.  *  The returned strings are allocated from a static buffer local to
  755.  *  this module (so the caller doesn't have to worry about deallocating
  756.  *  them); this means that successive calls to fgen will wipe out
  757.  *  the results of previous calls.  This isn't a problem here
  758.  *  because we process one wildcard string at a time.
  759.  *
  760.  * Input: a wildcard string, an array to write names to, the
  761.  *        length of the array.
  762.  * Returns: the number of matches.  The array is filled with filenames
  763.  *          that matched the pattern.  If there wasn't enough room in the
  764.  *     array, -1 is returned.
  765.  * By: Jeff Damens, CUCCA, 1984.
  766.  */
  767.  
  768. fgen(pat,resarry,len)
  769. char *pat,*resarry[];
  770. int len;
  771. {
  772.     struct path *head;
  773.     char scratch[100+MAXNAMLEN],*sptr;
  774.     head = splitpath(pat);
  775.     if (*pat == '/') {
  776.     scratch[0] = '/';
  777.     sptr = scratch+1;
  778.     *sptr = '\0';
  779.     } else {
  780.     strcpy(scratch,"./");
  781.     sptr = scratch+2;
  782.     }     /* init buffer correctly */
  783.     numfnd = 0;                            /* none found yet */
  784.     freeptr = sspace;   /* this is where matches are copied */
  785.     resptr = resarry;   /* static copies of these so*/
  786.     remlen = len;    /* recursive calls can alter them */
  787.     traverse(head,scratch,sptr);  /* go walk the directory tree */
  788.     for (; head != NULL; head = head -> fwd)
  789.     free(head);    /* return the path segments */
  790.     return(numfnd);   /* and return the number of matches */
  791. }
  792.  
  793. /* traverse:
  794.  *  Walks the directory tree looking for matches to its arguments.
  795.  *  The algorithm is, briefly:
  796.  *   If the current pattern segment contains no wildcards, that
  797.  *   segment is added to what we already have.  If the name so far
  798.  *   exists, we call ourselves recursively with the next segment
  799.  *   in the pattern string; otherwise, we just return.
  800.  *
  801.  *   If the current pattern segment contains wildcards, we open the name
  802.  *   we've accumulated so far (assuming it is really a directory), then read
  803.  *   each filename in it, and, if it matches the wildcard pattern segment, add
  804.  *   that filename to what we have so far and call ourselves recursively on the
  805.  *   next segment.
  806.  *
  807.  *   Finally, when no more pattern segments remain, we add what's accumulated
  808.  *   so far to the result array and increment the number of matches.
  809.  *
  810.  * Input: a pattern path list (as generated by splitpath), a string
  811.  *   pointer that points to what we've traversed so far (this
  812.  *   can be initialized to "/" to start the search at the root
  813.  *   directory, or to "./" to start the search at the current
  814.  *   directory), and a string pointer to the end of the string
  815.  *   in the previous argument.
  816.  * Returns: nothing.
  817.  */
  818. traverse(pl,sofar,endcur)
  819. struct path *pl;
  820. register char *sofar,*endcur;
  821. {
  822.     DIR *fd, *opendir();
  823.     struct direct *dirbuf;
  824.     debug(F110,"traverse ",sofar,0);
  825.     if (pl == NULL) {
  826.     *--endcur = '\0';        /* end string, overwrite trailing / */
  827.     addresult(sofar);
  828.     return;
  829.     }
  830.     if (!iswild(pl -> npart)) {
  831.     strcpy(endcur,pl -> npart);
  832.     endcur += strlen(endcur);
  833.     if (access(sofar,S_IFDIR) == 0) { /* if current piece exists & dir */
  834.         *endcur++ = '/';        /* add slash to end */
  835.         *endcur = '\0';        /* and end the string */
  836.         traverse(pl -> fwd,sofar,endcur);
  837.     } else if(access(sofar,0) == 0 && pl->fwd==NULL) {
  838.         addresult(sofar);
  839.     }
  840.     return;
  841.     }
  842.  
  843. /* segment contains wildcards, have to search directory */
  844.     *--endcur = '\0';            /* end current string */
  845.     if (access(sofar,S_IFDIR) < 0) {
  846.         debug(F111,"traverse can't access directory",sofar,errno);
  847.     return;    /* doesn't exist, forget it */
  848.     }
  849.     if ((fd = opendir(sofar)) == NULL) {
  850.         debug(F111,"traverse can't open directory",sofar,errno);
  851.         return;    /* can't open, forget it */
  852.     }
  853.     *endcur++ = '/';
  854.     while (dirbuf = readdir(fd)) {
  855.     if (dirbuf->d_addr != 0) {
  856.         strncpy(endcur,dirbuf->d_name,MAXNAMLEN); /* Get a null terminated copy!!! */
  857.         if(match(pl -> npart,endcur)) {
  858.             char *eos;
  859.             eos = endcur + strlen(endcur);
  860.             *eos++ = '/';            /* end this segment */
  861.             *eos = '\0';
  862.             traverse(pl -> fwd,sofar,eos);
  863.         }
  864.     }
  865.     }
  866.     closedir(fd);
  867. }
  868.  
  869. /*
  870.  * addresult:
  871.  *  Adds a result string to the result array.  Increments the number
  872.  *  of matches found, copies the found string into our string
  873.  *  buffer, and puts a pointer to the buffer into the caller's result
  874.  *  array.  Our free buffer pointer is updated.  If there is no
  875.  *  more room in the caller's array, the number of matches is set to -1.
  876.  * Input: a result string.
  877.  * Returns: nothing.
  878.  */
  879.  
  880. addresult(str)
  881. register char *str;
  882. {
  883.     register int l;
  884.     if (strncmp(str,"./",2) == 0) str += 2;
  885.     if (--remlen < 0) {
  886.     numfnd = -1;
  887.     return;
  888.     }
  889.     l = strlen(str) + 1;   /* size this will take up */
  890.     if ((freeptr + l) > &sspace[SSPACE]) {
  891.     numfnd = -1;   /* do not record if not enough space */
  892.     return;
  893.     }
  894.     strcpy(freeptr,str);
  895.     *resptr++ = freeptr;
  896.     freeptr += l;
  897.     numfnd++;
  898. }
  899.  
  900. iswild(str)
  901. register char *str;
  902. {
  903.     register char c;
  904.     while ((c = *str++) != '\0')
  905.     if (c == '*' || c == '?') return(1);
  906.     return(0);
  907. }
  908.  
  909. /*
  910.  * match:
  911.  *  pattern matcher.  Takes a string and a pattern possibly containing
  912.  *  the wildcard characters '*' and '?'.  Returns true if the pattern
  913.  *  matches the string, false otherwise.
  914.  * Input: a string and a wildcard pattern.
  915.  * Returns: 1 if match, 0 if no match.
  916.  */
  917.  
  918. match(pattern,string) char *pattern,*string; {
  919.     int i;
  920.     i = _cmpnam(string,pattern,strlen(pattern))==0;
  921.     debug(F111,"Match ",string,i);
  922.     return i;
  923. }
  924.  
  925. /* emulate unix perror function */
  926.  
  927. perror(string)
  928. char *string;
  929. {
  930.     extern int errno;
  931.     fprintf(stderr,"%s ERRNO: %d\n",string,errno);
  932. }
  933.  
  934. #ifdef DTILDE
  935. char *
  936. tilde_expand(dirname)
  937. register char *dirname;
  938. {
  939.     static char *home = NULL;
  940.     static char temp[MAXNAMLEN];
  941.  
  942.     debug(F111,"tilde_expand dirname", dirname, dirname[0]);
  943.     if(*dirname++ != '~' || (*dirname != '\0' && *dirname != '/')) return --dirname;
  944.     if(home == NULL && (home = getenv("HOME")) == NULL) return --dirname;
  945.     if(*dirname == '\0') return home;
  946.     strcpy(temp, home);
  947.     strcat(temp, dirname);
  948.     return temp;
  949. }
  950. #endif
  951.