Annotation of 43BSD/contrib/kermit/ckufio.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.