Annotation of coherent/e/bin/cku179/ckufio.c, revision 1.1

1.1     ! root        1: char *ckzv = "File support, 5A(058) 21 Jan 92";
        !             2: 
        !             3: /* C K U F I O  --  Kermit file system support for UNIX, OS/2, and Aegis */
        !             4: 
        !             5: /*
        !             6:  Author: Frank da Cruz ([email protected], [email protected]),
        !             7:  Columbia University Center for Computing Activities.  Many other contributors.
        !             8:  First released January 1985.
        !             9:  Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
        !            10:  York.  Permission is granted to any individual or institution to use, copy, or
        !            11:  redistribute this software so long as it is not sold for profit, provided this
        !            12:  copyright notice is retained.
        !            13: */
        !            14: 
        !            15: /* Include Files */
        !            16: 
        !            17: #include "ckcdeb.h"
        !            18: 
        !            19: #include <signal.h>
        !            20: #ifdef MINIX
        !            21: #include <limits.h>
        !            22: #endif /* MINIX */
        !            23: #ifdef POSIX
        !            24: #include <limits.h>
        !            25: #endif /* POSIX */
        !            26: 
        !            27: /* Directory structure header file */
        !            28: 
        !            29: #ifdef OS2
        !            30: /*
        !            31:   C-Kermit's OS/2 support originally by Chris Adie <[email protected]>
        !            32:   for C-Kermit 4F, Copyright (C) 1988 Edinburgh University Computing Service,
        !            33:   Scotland.  Permission is granted to any individual or institution to use,
        !            34:   copy, or redistribute this software so long as it is not sold for profit,
        !            35:   provided this copyright notice is retained.
        !            36: 
        !            37:   Adapted to C-Kermit 5A and integrated into the UNIX support module
        !            38:   by Kai Uwe Rommel <[email protected]>, Muenchen, Germany,
        !            39:   December 1991.
        !            40: */
        !            41: 
        !            42: /*
        !            43:   Directory Separator macros, to allow this module to work with both UNIX and
        !            44:   OS/2: Because of ambiguity with the command line editor escape \ character,
        !            45:   the directory separator is currently left as / for OS/2 too, because the
        !            46:   OS/2 kernel accepts / as directory separatore too. But this is subject to
        !            47:   change in future versions to conform with the normal OS/2 style.
        !            48: */
        !            49: #define DIRSEP       '/'
        !            50: /* #define DIRSEP       '\\' */
        !            51: #define ISDIRSEP(c)  ((c)=='/'||(c)=='\\')
        !            52: #else /* not OS2 */
        !            53: #define DIRSEP       '/'
        !            54: #define ISDIRSEP(c)  ((c)=='/')
        !            55: #endif /* OS2 */
        !            56: 
        !            57: #ifdef SDIRENT
        !            58: #define DIRENT
        !            59: #endif /* SDIRENT */
        !            60: 
        !            61: #ifdef XNDIR
        !            62: #include <sys/ndir.h>
        !            63: #else /* !XNDIR */
        !            64: #ifdef NDIR
        !            65: #include <ndir.h>
        !            66: #else /* !NDIR, !XNDIR */
        !            67: #ifdef RTU
        !            68: #include "/usr/lib/ndir.h"
        !            69: #else /* !RTU, !NDIR, !XNDIR */
        !            70: #ifdef DIRENT
        !            71: #ifdef SDIRENT
        !            72: #include <sys/dirent.h>
        !            73: #else
        !            74: #include <dirent.h>
        !            75: #endif /* SDIRENT */
        !            76: #else
        !            77: #ifdef OS2
        !            78: #define OPENDIR
        !            79: #define DIRENT
        !            80: #include "ckodir.h"
        !            81: #else/* !RTU, !NDIR, !XNDIR, !DIRENT, !OS2, i.e. all others */
        !            82: #include <sys/dir.h>
        !            83: #endif /* OS2 */
        !            84: #endif /* DIRENT */
        !            85: #endif /* RTU */
        !            86: #endif /* NDIR */
        !            87: #endif /* XNDIR */
        !            88: 
        !            89: #ifdef OS2                             /* OS/2 file system interface */
        !            90: #define BSD4                           /* is like Berkeley UNIX */
        !            91: #define NOFILEH                                /* with no <file.h> */
        !            92: #include <sys/utime.h>
        !            93: #include <stdlib.h>
        !            94: #include <process.h>
        !            95: extern int binary;                     /* We need to know this for open() */
        !            96: #define popen    _popen
        !            97: #define pclose   _pclose
        !            98: #else
        !            99: #include <pwd.h>                       /* Password file for shell name */
        !           100: #endif /* OS2 */
        !           101: 
        !           102: #ifdef BSD4                            /* BSD 4.x */
        !           103: #define TIMESTAMP                      /* Can do file dates */
        !           104: #include <time.h>                      /* Need this */
        !           105: #include <sys/timeb.h>                 /* Need this if really BSD */
        !           106: #endif /* BSD4 */
        !           107: 
        !           108: #ifdef ATTSV
        !           109: #define TIMESTAMP
        !           110: #include <time.h>
        !           111: /* void tzset(); (the "void" type upsets some compilers) */
        !           112: #ifndef ultrix
        !           113: extern long timezone;
        !           114: #endif /* ultrix */
        !           115: #endif /* ATTSV */
        !           116: 
        !           117: /* Is `y' a leap year? */
        !           118: #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
        !           119: 
        !           120: /* Number of leap years from 1970 to `y' (not including `y' itself). */
        !           121: #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
        !           122: 
        !           123: #ifdef COMMENT /* not used */
        !           124: /* Number of days in each month of the year. */
        !           125: static char monlens[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        !           126: #endif /* COMMENT */
        !           127: 
        !           128: #ifdef CIE
        !           129: #include <stat.h>                      /* File status */
        !           130: #else
        !           131: #include <sys/stat.h>
        !           132: #ifdef OS2
        !           133: #include <sys/types.h>
        !           134: /* because standard stat has trouble with trailing /'s we have to wrap it */
        !           135: int os2stat(char *, struct stat *);
        !           136: #define stat(path, buf) os2stat(path, buf)
        !           137: #endif /* OS2 */
        !           138: #endif /* CIE */
        !           139: 
        !           140: /*
        !           141:   Functions (n is one of the predefined file numbers from ckcker.h):
        !           142: 
        !           143:    zopeni(n,name)   -- Opens an existing file for input.
        !           144:    zopeno(n,name,attr,fcb) -- Opens a new file for output.
        !           145:    zclose(n)        -- Closes a file.
        !           146:    zchin(n,&c)      -- Gets the next character from an input file.
        !           147:    zsinl(n,&s,x)    -- Read a line from file n, max len x, into address s.
        !           148:    zsout(n,s)       -- Write a null-terminated string to output file, buffered.
        !           149:    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
        !           150:    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
        !           151:    zchout(n,c)      -- Add a character to an output file, unbuffered.
        !           152:    zchki(name)      -- Check if named file exists and is readable, return size.
        !           153:    zchko(name)      -- Check if named file can be created.
        !           154:    zchkspa(name,n)  -- Check if n bytes available to create new file, name.
        !           155:    znewn(name,s)    -- Make a new unique file name based on the given name.
        !           156:    zdelet(name)     -- Delete the named file.
        !           157:    zxpand(string)   -- Expands the given wildcard string into a list of files.
        !           158:    znext(string)    -- Returns the next file from the list in "string".
        !           159:    zxcmd(n,cmd)     -- Execute the command in a lower fork on file number n.
        !           160:    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
        !           161:    zrtol(n1,n2)     -- Convert remote filename into local form.
        !           162:    zltor(n1,n2)     -- Convert local filename into remote form.
        !           163:    zchdir(dirnam)   -- Change working directory.
        !           164:    zhome()          -- Return pointer to home directory name string.
        !           165:    zkself()         -- Kill self, log out own job.
        !           166:    zsattr(struct zattr *) -- Return attributes for file which is being sent.
        !           167:    zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
        !           168:    zrename(old, new) -- Rename a file.
        !           169:  */
        !           170: 
        !           171: /* Kermit-specific includes */
        !           172: /*
        !           173:   Definitions here supersede those from system include files.
        !           174:   ckcdeb.h is included above.
        !           175: */
        !           176: #include "ckcker.h"                    /* Kermit definitions */
        !           177: #include "ckucmd.h"                    /* For sys-dependent keyword tables */
        !           178: #include "ckuver.h"                    /* Version herald */
        !           179: 
        !           180: char *ckzsys = HERALD;
        !           181: 
        !           182: /* Support for tilde-expansion in file and directory names */
        !           183: 
        !           184: #ifdef POSIX
        !           185: #define NAMEENV "LOGNAME"
        !           186: #endif /* POSIX */
        !           187: 
        !           188: #ifdef BSD4
        !           189: #define NAMEENV "USER"
        !           190: #endif /* BSD4 */
        !           191: 
        !           192: #ifdef ATTSV
        !           193: #define NAMEENV "LOGNAME"
        !           194: #endif /* ATTSV */
        !           195: 
        !           196: /* Berkeley Unix Version 4.x */
        !           197: /* 4.1bsd support from Charles E Brooks, EDN-VAX */
        !           198: 
        !           199: #ifdef BSD4
        !           200: #ifdef MAXNAMLEN
        !           201: #define BSD42
        !           202: #endif /* MAXNAMLEN */
        !           203: #endif /* BSD4 */
        !           204: 
        !           205: /* Definitions of some system commands */
        !           206: 
        !           207: #ifdef OS2
        !           208: char *DELCMD = "del ";                 /* For file deletion */
        !           209: char *PWDCMD = "chdir ";               /* For saying where I am */
        !           210: char *TYPCMD = "type ";                        /* For typing a file */
        !           211: char *DIRCMD = "dir ";                 /* For directory listing */
        !           212: char *DIRCM2 = "dir ";                 /* For directory listing, no args */
        !           213: char *WHOCMD = "";                     /* Who's there? */
        !           214: char *SPACMD = "chkdsk ";              /* For space on disk */
        !           215: char *SPACM2 = "chkdsk ";              /* For space on disk */
        !           216: #else
        !           217: char *DELCMD = "rm -f ";               /* For file deletion */
        !           218: char *PWDCMD = "pwd ";                 /* For saying where I am */
        !           219: #ifdef COMMENT
        !           220: char *DIRCMD = "/bin/ls -ld ";         /* For directory listing */
        !           221: char *DIRCM2 = "/bin/ls -ld *";                /* For directory listing, no args */
        !           222: #else
        !           223: char *DIRCMD = "/bin/ls -l ";          /* For directory listing */
        !           224: char *DIRCM2 = "/bin/ls -l ";          /* For directory listing, no args */
        !           225: #endif
        !           226: char *TYPCMD = "cat ";                 /* For typing a file */
        !           227: 
        !           228: #ifdef FT18                            /* Fortune For:Pro 1.8 */
        !           229: #undef BSD4
        !           230: #endif /* FT18 */
        !           231: 
        !           232: #ifdef BSD4
        !           233: char *SPACMD = "pwd ; df .";           /* Space in current directory */
        !           234: #else
        !           235: #ifdef FT18
        !           236: char *SPACMD = "pwd ; du ; df .";
        !           237: #else
        !           238: char *SPACMD = "df ";
        !           239: #endif /* FT18 */
        !           240: #endif /* BSD4 */
        !           241: 
        !           242: char *SPACM2 = "df ";                  /* For space in specified directory */
        !           243: 
        !           244: #ifdef FT18
        !           245: #define BSD4
        !           246: #endif /* FT18 */
        !           247: 
        !           248: #ifdef BSD4
        !           249: char *WHOCMD = "finger ";              /* For seeing who's logged in */
        !           250: #else
        !           251: char *WHOCMD = "who ";                 /* For seeing who's logged in */
        !           252: #endif /* BSD4 */
        !           253: #endif /* OS2 */
        !           254: 
        !           255: #ifdef DTILDE                          /* For tilde expansion */
        !           256: _PROTOTYP( char * tilde_expand, (char *) );
        !           257: #endif /* DTILDE */
        !           258: 
        !           259: /* More system-dependent includes, which depend on symbols defined */
        !           260: /* in the Kermit-specific includes.  Oh what a tangled web we weave... */
        !           261: 
        !           262: #ifdef COHERENT
        !           263: #define NOFILEH
        !           264: #endif /* COHERENT */
        !           265: 
        !           266: #ifdef MINIX
        !           267: #define NOFILEH
        !           268: #endif /* MINIX */
        !           269: 
        !           270: #ifdef aegis                           /* <sys/file.h> */
        !           271: #define NOFILEH
        !           272: #endif /* aegis */
        !           273: 
        !           274: #ifdef unos
        !           275: #define NOFILEH
        !           276: #endif /* unos */
        !           277: 
        !           278: #ifndef NOFILEH
        !           279: #include <sys/file.h>
        !           280: #endif /* NOFILEH */
        !           281: 
        !           282: 
        !           283: #ifndef is68k                          /* Whether to include <fcntl.h> */
        !           284: #ifndef BSD41                          /* All but a couple UNIXes have it. */
        !           285: #ifndef FT18
        !           286: #include <fcntl.h>
        !           287: #endif /* FT18  */
        !           288: #endif /* BSD41 */
        !           289: #endif /* not is68k */
        !           290: 
        !           291: #ifndef _POSIX_SOURCE
        !           292: #ifndef NEXT
        !           293: #ifndef SVR4
        !           294: /* POSIX <pwd.h> already gave prototypes for these. */
        !           295: #ifdef IRIX40
        !           296: _PROTOTYP( struct passwd * getpwnam, (const char *) );
        !           297: #else
        !           298: _PROTOTYP( struct passwd * getpwnam, (char *) );
        !           299: #endif /* IRIX40 */
        !           300: _PROTOTYP( struct passwd * getpwuid, (PWID_T) );
        !           301: _PROTOTYP( struct passwd * getpwent, (void) );
        !           302: #endif /* SVR4 */
        !           303: #endif /* NEXT */
        !           304: #endif /* _POSIX_SOURCE */
        !           305: 
        !           306: /* Define macros for getting file type */
        !           307: 
        !           308: #ifdef OXOS
        !           309: /*
        !           310:   Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined
        !           311:   incorrectly, so we force their redefinition.
        !           312: */
        !           313: #undef S_ISREG
        !           314: #undef S_ISDIR
        !           315: #endif /* OXOS */
        !           316: 
        !           317: #ifdef UTSV                            /* Same deal for Amdah UTSV */
        !           318: #undef S_ISREG
        !           319: #undef S_ISDIR
        !           320: #endif /* UTSV */
        !           321: 
        !           322: #ifndef S_ISREG
        !           323: #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
        !           324: #endif /* S_ISREG */
        !           325: #ifndef S_ISDIR
        !           326: #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
        !           327: #endif /* S_ISDIR */
        !           328: 
        !           329: /* Define maximum length for a file name if not already defined */
        !           330: 
        !           331: #ifndef MAXNAMLEN
        !           332: #ifdef sun
        !           333: #define MAXNAMLEN 255
        !           334: #else
        !           335: #ifdef FILENAME_MAX
        !           336: #define MAXNAMLEN FILENAME_MAX
        !           337: #else
        !           338: #ifdef NAME_MAX
        !           339: #define MAXNAMLEN NAME_MAX
        !           340: #else
        !           341: #ifdef _POSIX_NAME_MAX
        !           342: #define MAXNAMLEN _POSIX_NAME_MAX
        !           343: #else
        !           344: #ifdef _D_NAME_MAX
        !           345: #define MAXNAMLEN _D_NAME_MAX
        !           346: #else
        !           347: #ifdef DIRSIZ
        !           348: #define MAXNAMLEN DIRSIZ
        !           349: #else
        !           350: #define MAXNAMLEN 14
        !           351: #endif /* DIRSIZ */
        !           352: #endif /* _D_NAME_MAX */
        !           353: #endif /* _POSIX_NAME_MAX */
        !           354: #endif /* NAME_MAX */
        !           355: #endif /* FILENAME_MAX */
        !           356: #endif /* sun */
        !           357: #endif /* MAXNAMLEN */
        !           358: 
        !           359: /* Longest pathname */
        !           360: 
        !           361: #ifdef MAXPATHLEN
        !           362: #ifdef MAXPATH
        !           363: #undef MAXPATH
        !           364: #endif /* MAXPATH */
        !           365: #define MAXPATH MAXPATHLEN
        !           366: #else
        !           367: #ifdef PATH_MAX
        !           368: #define MAXPATH PATH_MAX
        !           369: #else
        !           370: #ifdef _POSIX_PATH_MAX
        !           371: #define MAXPATH _POSIX_PATH_MAX
        !           372: #else
        !           373: #ifdef BSD42
        !           374: #define MAXPATH 1024
        !           375: #else
        !           376: #define MAXPATH 255
        !           377: #endif /* BSD42 */
        !           378: #endif /* _POSIX_PATH_MAX */
        !           379: #endif /* PATH_MAX */
        !           380: #endif /* MAXPATHLEN */
        !           381: 
        !           382: /* Maximum number of filenames for wildcard expansion */
        !           383: 
        !           384: #ifdef PROVX1
        !           385: #define MAXWLD 50
        !           386: #else
        !           387: #ifdef BSD29
        !           388: #define MAXWLD 50
        !           389: #else
        !           390: #ifdef pdp11
        !           391: #define MAXWLD 50
        !           392: #else
        !           393: #define MAXWLD 1000
        !           394: #endif /* pdp11 */
        !           395: #endif /* BSD29 */
        !           396: #endif /* PROVX1 */
        !           397: 
        !           398: /* More internal function prototypes */
        !           399: /*
        !           400:  * The path structure is used to represent the name to match.
        !           401:  * Each slash-separated segment of the name is kept in one
        !           402:  * such structure, and they are linked together, to make
        !           403:  * traversing the name easier.
        !           404:  */
        !           405: struct path {
        !           406:     char npart[MAXNAMLEN+4];           /* name part of path segment */
        !           407:     struct path *fwd;                  /* forward ptr */
        !           408: };
        !           409: _PROTOTYP( int shxpand, (char *, char **, int ) );
        !           410: _PROTOTYP( static int fgen, (char *, char **, int ) );
        !           411: _PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
        !           412: _PROTOTYP( static VOID addresult, (char *) );
        !           413: _PROTOTYP( static int match, (char *, char *) );
        !           414: _PROTOTYP( static char * whoami, (void) );
        !           415: _PROTOTYP( char * xindex, (char *, char) );
        !           416: _PROTOTYP( UID_T real_uid, (void) );
        !           417: _PROTOTYP( struct path *splitpath, (char *p) );
        !           418: 
        !           419: /* Some systems define these symbols in include files, others don't... */
        !           420: 
        !           421: #ifndef R_OK
        !           422: #define R_OK 4                         /* For access */
        !           423: #endif
        !           424: 
        !           425: #ifndef W_OK
        !           426: #define W_OK 2
        !           427: #endif
        !           428: 
        !           429: #ifndef O_RDONLY
        !           430: #define O_RDONLY 000
        !           431: #endif
        !           432: 
        !           433: /* Declarations */
        !           434: 
        !           435: int maxnam = MAXNAMLEN;                        /* Available to the outside */
        !           436: int maxpath = MAXPATH;
        !           437: 
        !           438: FILE *fp[ZNFILS] = {                   /* File pointers */
        !           439:     NULL, NULL, NULL, NULL, NULL, NULL, NULL };
        !           440: #ifdef OS2
        !           441: int ispipe[ZNFILS];                    /* Flag for file is a pipe */
        !           442: #endif /* OS2 */
        !           443: 
        !           444: /* Buffers and pointers used in buffered file input and output. */
        !           445: #ifdef DYNAMIC
        !           446: extern char *zinbuffer, *zoutbuffer;
        !           447: #else
        !           448: extern char zinbuffer[], zoutbuffer[];
        !           449: #endif /* DYNAMIC */
        !           450: extern char *zinptr, *zoutptr;
        !           451: extern int zincnt, zoutcnt;
        !           452: extern int wildxpand;
        !           453: 
        !           454: extern UID_T real_uid();
        !           455: 
        !           456: static long iflen = -1L;               /* Input file length */
        !           457: 
        !           458: static PID_T pid = 0;                  /* pid of child fork */
        !           459: static int fcount;                     /* Number of files in wild group */
        !           460: static char nambuf[MAXNAMLEN+4];       /* Buffer for a filename */
        !           461: static char zmbuf[200];                        /* For mail, remote print strings */
        !           462: 
        !           463: /* static */                           /* Not static, must be global now. */
        !           464: char *mtchs[MAXWLD],                   /* Matches found for filename */
        !           465:      **mtchptr;                                /* Pointer to current match */
        !           466: 
        !           467: /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
        !           468: 
        !           469: /* Note, should get current pid, but if your system doesn't have */
        !           470: /* getppid(), then just kill(0,9)...  */
        !           471: 
        !           472: #ifndef SVR3
        !           473: #ifndef POSIX
        !           474: /* Already declared in unistd.h for SVR3 and POSIX */
        !           475: #ifdef CK_ANSIC
        !           476: extern PID_T getppid(void);
        !           477: #else
        !           478: #ifndef PS2AIX10
        !           479: extern PID_T getppid();
        !           480: #endif /* PS2AIX10 */
        !           481: #endif /* CK_ANSIC */
        !           482: #endif /* POSIX */
        !           483: #endif /* SVR3 */
        !           484: int
        !           485: zkself() {                             /* For "bye", but no guarantee! */
        !           486: #ifdef PROVX1
        !           487:     return(kill(0,9));
        !           488: #else
        !           489: #ifdef V7
        !           490:     return(kill(0,9));
        !           491: #else
        !           492: #ifdef TOWER1
        !           493:     return(kill(0,9));
        !           494: #else
        !           495: #ifdef FT18
        !           496:     return(kill(0,9));
        !           497: #else
        !           498: #ifdef aegis
        !           499:     return(kill(0,9));
        !           500: #else
        !           501: #ifdef COHERENT
        !           502:     return(kill(getpid(),1));
        !           503: #else
        !           504: #ifdef OS2
        !           505:     exit(3);
        !           506: #else
        !           507:     exit(kill(getppid(),1));
        !           508: #endif
        !           509: #endif
        !           510: #endif
        !           511: #endif
        !           512: #endif
        !           513: #endif
        !           514: #endif
        !           515: }
        !           516: 
        !           517: /*  Z O P E N I  --  Open an existing file for input. */
        !           518: 
        !           519: int
        !           520: zopeni(n,name) int n; char *name; {
        !           521:     debug(F111," zopeni",name,n);
        !           522:     debug(F101,"  fp","", fp[n]);
        !           523:     if (chkfn(n) != 0) return(0);
        !           524:     zincnt = 0;                                /* Reset input buffer */
        !           525:     if (n == ZSYSFN) {                 /* Input from a system function? */
        !           526: /*** Note, this function should not be called with ZSYSFN ***/
        !           527: /*** Always call zxcmd() directly, and give it the real file number ***/
        !           528: /*** you want to use.  ***/
        !           529:         debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
        !           530:        *nambuf = '\0';                 /* No filename. */
        !           531:        return(0);                      /* fail. */
        !           532: #ifdef COMMENT
        !           533:        return(zxcmd(n,name));          /* Try to fork the command */
        !           534: #endif
        !           535:     }
        !           536:     if (n == ZSTDIO) {                 /* Standard input? */
        !           537:        if (isatty(0)) {
        !           538:            fprintf(stderr,"Terminal input not allowed");
        !           539:            debug(F110,"zopeni: attempts input from unredirected stdin","",0);
        !           540:            return(0);
        !           541:        }
        !           542:        fp[ZIFILE] = stdin;
        !           543: #ifdef OS2
        !           544:        setmode(fileno(stdin),O_BINARY);
        !           545: #endif /* OS2 */
        !           546:        return(1);
        !           547:     }
        !           548: #ifdef OS2
        !           549:     if (n == ZIFILE)
        !           550:       fp[n] = fopen(name,"rb");                /* Binary mode */
        !           551:     else
        !           552: #endif /* OS2 */
        !           553:       fp[n] = fopen(name,"r");         /* Real file, open it. */
        !           554:     debug(F111," zopeni", name, fp[n]);
        !           555:     if (fp[n] == NULL) perror("zopeni");
        !           556:     return((fp[n] != NULL) ? 1 : 0);
        !           557: }
        !           558: 
        !           559: /*  Z O P E N O  --  Open a new file for output.  */
        !           560: 
        !           561: int
        !           562: zopeno(n,name,zz,fcb)
        !           563: /* zopeno */  int n; char *name; struct zattr *zz; struct filinfo *fcb; {
        !           564: 
        !           565:     char p[8];                         /* (===OS2 change===) */
        !           566: /*  char *p; */                                /* Local-use pointer */
        !           567: 
        !           568: /* As of Version 5A, the attribute structure and the file information */
        !           569: /* structure are included in the arglist. */
        !           570: 
        !           571:     debug(F111,"zopeno",name,n);
        !           572:     if (fcb) {
        !           573:        debug(F101,"zopeno fcb disp","",fcb->dsp);
        !           574:        debug(F101,"zopeno fcb type","",fcb->typ);
        !           575:        debug(F101,"zopeno fcb char","",fcb->cs);
        !           576:     } else {
        !           577:        debug(F100,"zopeno fcb is NULL","",0);
        !           578:     }
        !           579:     if (n != ZDFILE)
        !           580:       debug(F111," zopeno",name,n);
        !           581:     if (chkfn(n) != 0) return(0);
        !           582:     if ((n == ZCTERM) || (n == ZSTDIO)) {   /* Terminal or standard output */
        !           583:        fp[ZOFILE] = stdout;
        !           584:        if (n != ZDFILE)
        !           585:          debug(F101," fp[]=stdout", "", fp[n]);
        !           586:        zoutcnt = 0;
        !           587:        zoutptr = zoutbuffer;
        !           588:        return(1);
        !           589:     }
        !           590: 
        !           591: /* A real file.  Open it in desired mode (create or append). */
        !           592: 
        !           593:     strcpy(p,"w");                     /* Assume write/create mode */
        !           594:     if (fcb) {                         /* If called with an FCB... */
        !           595:        if (fcb->dsp == XYFZ_A)         /* Does it say Append? */
        !           596:          strcpy(p,"a");                /* Yes. */
        !           597:     }
        !           598: #ifdef OS2
        !           599:     if (n == ZOFILE) strcat(p,"b");    /* Binary mode */
        !           600: #endif /* OS2 */
        !           601:     fp[n] = fopen(name,p);             /* Open the file */
        !           602: 
        !           603:     if (fp[n] == NULL) {
        !           604:         perror("zopeno can't open");
        !           605:     } else {
        !           606:         if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */
        !           607:     }
        !           608:     zoutcnt = 0;               /* (PWP) reset output buffer */
        !           609:     zoutptr = zoutbuffer;
        !           610:     if (n != ZDFILE)
        !           611:       debug(F101, " fp[n]", "", fp[n]);
        !           612:     return((fp[n] != NULL) ? 1 : 0);
        !           613: }
        !           614: 
        !           615: /*  Z C L O S E  --  Close the given file.  */
        !           616: 
        !           617: /*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */
        !           618: 
        !           619: int
        !           620: zclose(n) int n; {
        !           621:     int x, x2;
        !           622:     if (chkfn(n) < 1) return(0);       /* Check range of n */
        !           623: 
        !           624:     if ((n == ZOFILE) && (zoutcnt > 0))        /* (PWP) output leftovers */
        !           625:       x2 = zoutdump();
        !           626:     else
        !           627:       x2 = 0;
        !           628: 
        !           629:     x = 0;                             /* Initialize return code */
        !           630:     if (fp[ZSYSFN]) {                  /* If file is really pipe */
        !           631:        x = zclosf(n);                  /* do it specially */
        !           632:     } else {
        !           633:        if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
        !           634:        fp[n] = NULL;
        !           635:     }
        !           636:     iflen = -1L;                       /* Invalidate file length */
        !           637:     if (x == EOF)                      /* if we got a close error */
        !           638:        return (-1);
        !           639:     else if (x2 < 0)           /* or an error flushing the last buffer */
        !           640:        return (-1);            /* then return an error */
        !           641:     else
        !           642:        return (1);
        !           643: }
        !           644: 
        !           645: /*  Z C H I N  --  Get a character from the input file.  */
        !           646: 
        !           647: /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
        !           648: 
        !           649: int
        !           650: zchin(n,c) int n; int *c; {
        !           651:     int a, x;
        !           652: 
        !           653:     /* (PWP) Just in case this gets called when it shouldn't. */
        !           654:     if (n == ZIFILE) {
        !           655:        x = zminchar();
        !           656:        *c = x;
        !           657:        return(x);
        !           658:     }
        !           659:     /* if (chkfn(n) < 1) return(-1); */
        !           660:     a = getc(fp[n]);
        !           661:     if (a == EOF) return(-1);
        !           662: #ifdef OS2
        !           663:     if (!binary && a == 0x1A)          /* Ctrl-Z marks EOF for text mode*/
        !           664:       return(-1);
        !           665: #endif
        !           666:     *c = (CHAR) a & 0377;
        !           667:     return(0);
        !           668: }
        !           669: 
        !           670: /*  Z S I N L  --  Read a line from a file  */
        !           671: 
        !           672: /*
        !           673:   Writes the line into the address provided by the caller.
        !           674:   n is the Kermit "channel number".
        !           675:   Writing terminates when newline is encountered, newline is not copied.
        !           676:   Writing also terminates upon EOF or if length x is exhausted.
        !           677:   Returns 0 on success, -1 on EOF or error.
        !           678: */
        !           679: int
        !           680: zsinl(n,s,x) int n, x; char *s; {
        !           681:     int a, z = 0;
        !           682: 
        !           683:     if (chkfn(n) < 1) {                        /* Make sure file is open */
        !           684:        return(-1);
        !           685:     }
        !           686:     a = -1;
        !           687:     while (x--) {
        !           688: #ifndef NLCHAR
        !           689:        int old;
        !           690:        old = a;                        /* Previous character */
        !           691: #endif
        !           692:        if (zchin(n,&a) < 0) {          /* Read a character from the file */
        !           693:            z = -1;
        !           694:            break;
        !           695:        }
        !           696: #ifdef NLCHAR
        !           697:        if (a == (char) NLCHAR) break;  /* Single-character line terminator */
        !           698: #else
        !           699:        if (a == '\r') continue;        /* CRLF line terminator */
        !           700:        if (old == '\r') {
        !           701:            if (a == '\n') break;
        !           702:            else *s++ = '\r';
        !           703:        }
        !           704: #endif /* NLCHAR */
        !           705:        *s = a;
        !           706:        s++;
        !           707:     }
        !           708:     *s = '\0';
        !           709:     return(z);
        !           710: }
        !           711: 
        !           712: /*
        !           713:  * (PWP) (re)fill the buffered input buffer with data.  All file input
        !           714:  * should go through this routine, usually by calling the zminchar()
        !           715:  * macro (in ckcker.h).
        !           716:  */
        !           717: 
        !           718: /*
        !           719:  * Suggestion: if fread() returns 0, call ferror to find out what the
        !           720:  * problem was.  If it was not EOF, then return -2 instead of -1.
        !           721:  * Upper layers (getpkt function in ckcfns.c) should set cxseen flag
        !           722:  * if it gets -2 return from zminchar macro.
        !           723:  */
        !           724: int
        !           725: zinfill() {
        !           726:     int x;
        !           727: 
        !           728:     errno = 0;
        !           729:     zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
        !           730: #ifdef COMMENT
        !           731:     debug(F101,"zinfill fp","",fp[ZIFILE]);
        !           732:     debug(F101,"zinfill zincnt","",zincnt);
        !           733: #endif
        !           734:     if (zincnt == 0) {
        !           735: #ifndef UTEK
        !           736: #ifdef ferror
        !           737:        x = ferror(fp[ZIFILE]);
        !           738:        debug(F101,"zinfill errno","",errno);
        !           739:        debug(F101,"zinfill ferror","",x);
        !           740:        if (x) return(-2);
        !           741: #endif /* ferror */
        !           742: #else
        !           743:        x = feof(fp[ZIFILE]);
        !           744:        debug(F101,"zinfill errno","",errno);
        !           745:        debug(F101,"zinfill feof","",x);
        !           746:        if (!x && ferror(fp[ZIFILE])) return(-2);
        !           747: #endif /* UTEK */
        !           748:        return(-1);
        !           749:     }
        !           750:     zinptr = zinbuffer;           /* set pointer to beginning, (== &zinbuffer[0]) */
        !           751:     zincnt--;                  /* one less char in buffer */
        !           752:     return((int)(*zinptr++) & 0377); /* because we return the first */
        !           753: }
        !           754: 
        !           755: /*  Z S O U T  --  Write a string out to the given file, buffered.  */
        !           756: 
        !           757: int
        !           758: zsout(n,s) int n; char *s; {
        !           759:     if (chkfn(n) < 1) return(-1); /* Keep this here, prevents memory faults */
        !           760: #ifdef COMMENT
        !           761:     while (*s) {                       /* (unbuffered for debugging) */
        !           762:        write(fileno(fp[n]),s,1); ++s;
        !           763:     }
        !           764: #endif
        !           765: #ifdef COMMENT
        !           766:     return(fputs(s,fp[n]) == EOF ? -1 : 0);
        !           767: #else
        !           768:     if (n == ZSFILE)
        !           769:        return(write(fileno(fp[n]),s,(int)strlen(s)));
        !           770:     else
        !           771:         return(fputs(s,fp[n]) == EOF ? -1 : 0);
        !           772: #endif
        !           773: }
        !           774: 
        !           775: /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
        !           776: 
        !           777: int
        !           778: zsoutl(n,s) int n; char *s; {
        !           779:     /* if (chkfn(n) < 1) return(-1); */
        !           780:     if (fputs(s,fp[n]) == EOF) return(-1);
        !           781:     if (fputs("\n",fp[n]) == EOF) return(-1); /* (===OS2 ? \r\n) */
        !           782:     return(0);
        !           783: }
        !           784: 
        !           785: /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
        !           786: 
        !           787: int
        !           788: zsoutx(n,s,x) int n, x; char *s; {
        !           789: #ifdef COMMENT
        !           790:     if (chkfn(n) < 1) return(-1);
        !           791:     return(write(fp[n]->_file,s,x));
        !           792: #endif
        !           793:     return(write(fileno(fp[n]),s,x) == x ? x : -1);
        !           794: }
        !           795: 
        !           796: 
        !           797: /*  Z C H O U T  --  Add a character to the given file.  */
        !           798: 
        !           799: /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
        !           800: 
        !           801: int
        !           802: #ifdef CK_ANSIC
        !           803: zchout(register int n, char c)
        !           804: #else
        !           805: zchout(n,c) register int n; char c;
        !           806: #endif /* CK_ANSIC */
        !           807: /* zchout() */ {
        !           808:     /* if (chkfn(n) < 1) return(-1); */
        !           809:     if (n == ZSFILE) {                 /* Use unbuffered for session log */
        !           810:        return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
        !           811:     } else {                           /* Buffered for everything else */
        !           812:        if (putc(c,fp[n]) == EOF)       /* If true, maybe there was an error */
        !           813:          return(ferror(fp[n])?-1:0);   /* Check to make sure */
        !           814:        else                            /* Otherwise... */
        !           815:          return(0);                    /* There was no error. */
        !           816:     }
        !           817: }
        !           818: 
        !           819: /* (PWP) buffered character output routine to speed up file IO */
        !           820: 
        !           821: int
        !           822: zoutdump() {
        !           823:     int x;
        !           824:     zoutptr = zoutbuffer;              /* Reset buffer pointer in all cases */
        !           825:     debug(F101,"zoutdump chars","",zoutcnt);
        !           826:     if (zoutcnt == 0) {                        /* Nothing to output */
        !           827:        return(0);
        !           828:     } else if (zoutcnt < 0) {          /* Unexpected negative argument */
        !           829:        zoutcnt = 0;                    /* Reset output buffer count */
        !           830:        return(-1);                     /* and fail. */
        !           831:     }
        !           832: 
        !           833: /* Frank Prindle suggested that replacing this fwrite() by an fflush() */
        !           834: /* followed by a write() would improve the efficiency, especially when */
        !           835: /* writing to stdout.  Subsequent tests showed a 5-fold improvement!   */
        !           836: /* if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) {              */
        !           837: 
        !           838:     fflush(fp[ZOFILE]);
        !           839:     if ((x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) == zoutcnt) {
        !           840:        debug(F101,"zoutdump write ok","",zoutcnt);
        !           841:        zoutcnt = 0;                    /* Reset output buffer count */
        !           842:        return(0);                      /* write() worked OK */
        !           843:     } else {
        !           844:        debug(F101,"zoutdump write error","",errno);
        !           845:        debug(F101,"zoutdump write returns","",x);
        !           846:        zoutcnt = 0;                    /* Reset output buffer count */
        !           847:        return(-1);                     /* write() failed */
        !           848:     }
        !           849: }
        !           850: 
        !           851: /*  C H K F N  --  Internal function to verify file number is ok  */
        !           852: 
        !           853: /*
        !           854:  Returns:
        !           855:   -1: File number n is out of range
        !           856:    0: n is in range, but file is not open
        !           857:    1: n in range and file is open
        !           858: */
        !           859: int
        !           860: chkfn(n) int n; {
        !           861:     switch (n) {
        !           862:        case ZCTERM:
        !           863:        case ZSTDIO:
        !           864:        case ZIFILE:
        !           865:        case ZOFILE:
        !           866:        case ZDFILE:
        !           867:        case ZTFILE:
        !           868:        case ZPFILE:
        !           869:        case ZSFILE:
        !           870:        case ZSYSFN:
        !           871:         case ZRFILE:
        !           872:         case ZWFILE: break;
        !           873:        default:
        !           874:            debug(F101,"chkfn: file number out of range","",n);
        !           875:            fprintf(stderr,"?File number out of range - %d\n",n);
        !           876:            return(-1);
        !           877:     }
        !           878:     return( (fp[n] == NULL) ? 0 : 1 );
        !           879: }
        !           880: 
        !           881: /*  Z C H K I  --  Check if input file exists and is readable  */
        !           882: 
        !           883: /*
        !           884:   Returns:
        !           885:    >= 0 if the file can be read (returns the size).
        !           886:      -1 if file doesn't exist or can't be accessed,
        !           887:      -2 if file exists but is not readable (e.g. a directory file).
        !           888:      -3 if file exists but protected against read access.
        !           889: */
        !           890: /*
        !           891:  For Berkeley Unix, a file must be of type "regular" to be readable.
        !           892:  Directory files, special files, and symbolic links are not readable.
        !           893: */
        !           894: long
        !           895: zchki(name) char *name; {
        !           896:     struct stat buf;
        !           897:     int x;
        !           898: 
        !           899:     x = stat(name,&buf);
        !           900:     if (x < 0) {
        !           901:        debug(F111,"zchki stat fails",name,errno);
        !           902:        return(-1);
        !           903:     }
        !           904:     if (!S_ISREG (buf.st_mode)) {      /* Must be regular file */
        !           905:        debug(F111,"zchki skipping:",name,x);
        !           906:        return(-2);
        !           907:     }
        !           908:     debug(F111,"zchki stat ok:",name,x);
        !           909: 
        !           910:     if ((x = access(name,R_OK)) < 0) {         /* Is the file accessible? */
        !           911:        debug(F111," access failed:",name,x); /* No */
        !           912:        return(-3);
        !           913:     } else {
        !           914:        iflen = buf.st_size;                  /* Yes, remember size */
        !           915:        strncpy(nambuf,name,MAXNAMLEN);       /* and name globally. */
        !           916:        debug(F111," access ok:",name,(int) iflen);
        !           917:        return( (iflen > -1L) ? iflen : 0L );
        !           918:     }
        !           919: }
        !           920: 
        !           921: /*  Z C H K O  --  Check if output file can be created  */
        !           922: 
        !           923: /*
        !           924:  Returns -1 if write permission for the file would be denied, 0 otherwise.
        !           925: */
        !           926: int
        !           927: zchko(name) char *name; {
        !           928:     int i, x;
        !           929:     char *s;
        !           930: 
        !           931:     if (!name) return(-1);             /* Watch out for null pointer. */
        !           932:     x = (int)strlen(name);             /* Get length of filename */
        !           933:     debug(F101," length","",x);
        !           934:     s = malloc(x+3);                   /* Must copy because we can't */
        !           935:     if (!s) {                          /* write into our argument. */
        !           936:        fprintf(stderr,"Malloc error 46\n");
        !           937:        return(-1);
        !           938:     }
        !           939:     strcpy(s,name);
        !           940: 
        !           941:     for (i = x; i > 0; i--)            /* Strip filename from right. */
        !           942:       if (ISDIRSEP(s[i-1])) break;
        !           943:     debug(F101," i","",i);
        !           944: 
        !           945: #ifdef COMMENT
        !           946: /* X/OPEN XPG3-compliant systems fail if argument ends with "/"...  */
        !           947:     if (i == 0)                                /* If no path, use current directory */
        !           948:       strcpy(s,"./");
        !           949:     else                               /* Otherwise, use given one. */
        !           950:       s[i] = '\0';
        !           951: #else
        !           952: /* So now we use "path/." if path given, or "." if no path given. */
        !           953:     s[i++] = '.';                      /* Append "." to path. */
        !           954:     s[i] = '\0';
        !           955: #endif /* COMMENT */
        !           956: 
        !           957:     x = access(s,W_OK);                        /* Check access of path. */
        !           958:     if (x < 0)
        !           959:       debug(F111,"zchko access failed:",s,errno);
        !           960:     else
        !           961:       debug(F111,"zchko access ok:",s,x);
        !           962:     free(s);                           /* Free temporary storage */
        !           963:     return((x < 0) ? -1 : 0);          /* and return. */
        !           964: }
        !           965: 
        !           966: /*  Z D E L E T  --  Delete the named file.  */
        !           967: 
        !           968: int
        !           969: zdelet(name) char *name; {
        !           970:     return(unlink(name));
        !           971: }
        !           972: 
        !           973: 
        !           974: /*  Z R T O L  --  Convert remote filename into local form  */
        !           975: 
        !           976: /*  For UNIX, this means changing uppercase letters to lowercase.  */
        !           977: 
        !           978: VOID
        !           979: zrtol(name,name2) char *name, *name2; {
        !           980:     for ( ; *name != '\0'; name++) {
        !           981:        *name2++ = isupper(*name) ? tolower(*name) : *name;
        !           982:     }
        !           983:     *name2 = '\0';
        !           984:     debug(F110,"zrtol:",name2,0);
        !           985: }
        !           986: 
        !           987: 
        !           988: /*  Z S T R I P  --  Strip device & directory name from file specification */
        !           989: 
        !           990: /*  Strip pathname from filename "name", return pointer to result in name2 */
        !           991: 
        !           992: static char work[257];         /* buffer for use by zstrip and zltor */
        !           993: 
        !           994: VOID
        !           995: zstrip(name,name2) char *name, **name2; {
        !           996:     char *cp, *pp;
        !           997:     debug(F110,"zstrip before",name,0);
        !           998:     pp = work;
        !           999: #ifdef DTILDE
        !          1000:     if (*name == '~') name++;
        !          1001: #endif /* DTILDE */
        !          1002:     for (cp = name; *cp != '\0'; cp++) {
        !          1003:        if (ISDIRSEP(*cp))
        !          1004:          pp = work;
        !          1005:        else
        !          1006:          *pp++ = *cp;
        !          1007:     }
        !          1008:     *pp = '\0';                                /* Terminate the string */
        !          1009:     *name2 = work;
        !          1010:     debug(F110,"zstrip after",*name2,0);
        !          1011: }
        !          1012: 
        !          1013: /*  Z L T O R  --  Local TO Remote */
        !          1014: 
        !          1015: VOID
        !          1016: zltor(name,name2) char *name, *name2; {
        !          1017:     char *cp, *pp;
        !          1018:     int dc = 0;
        !          1019: #ifdef aegis
        !          1020:     char *namechars;
        !          1021:     int tilde = 0, bslash = 0;
        !          1022: 
        !          1023:     if ((namechars = getenv("NAMECHARS")) != NULL) {
        !          1024:        if (xindex(namechars, '~' ) != NULL) tilde  = '~';
        !          1025:        if (xindex(namechars, '\\') != NULL) bslash = '\\';
        !          1026:     } else {
        !          1027:         tilde = '~';
        !          1028:         bslash = '\\';
        !          1029:     }
        !          1030: #endif /* aegis */
        !          1031: 
        !          1032:     debug(F110,"zltor",name,0);
        !          1033:     pp = work;
        !          1034: #ifdef aegis
        !          1035:     cp = name;
        !          1036:     if (tilde && *cp == tilde)
        !          1037:        ++cp;
        !          1038:     for (; *cp != '\0'; cp++) {
        !          1039:        if (*cp == '/' || *cp == bslash) {      /* strip path name */
        !          1040: #else
        !          1041:     for (cp = name; *cp != '\0'; cp++) {       /* strip path name */
        !          1042:        if (ISDIRSEP(*cp)) {
        !          1043: #endif /* aegis */
        !          1044:            dc = 0;
        !          1045:            pp = work;
        !          1046:        }
        !          1047:        else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
        !          1048:        else if (*cp == '~') *pp++ = 'X';       /* Change tilde to 'X' */
        !          1049:        else if (*cp == '#') *pp++ = 'X';       /* Change number sign to 'X' */
        !          1050:        else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
        !          1051:        else *pp++ = *cp;
        !          1052:     }
        !          1053:     *pp = '\0';                                /* Tie it off. */
        !          1054:     cp = name2;                                /* If nothing before dot, */
        !          1055:     if (*work == '.') *cp++ = 'X';     /* insert 'X' */
        !          1056:     strcpy(cp,work);
        !          1057:     debug(F110," name2",name2,0);
        !          1058: }
        !          1059: 
        !          1060: 
        !          1061: /*  Z C H D I R  --  Change directory  */
        !          1062: /*
        !          1063:   Call with:
        !          1064:     dirnam = pointer to name of directory to change to,
        !          1065:       which may be "" or NULL to indicate user's home directory.
        !          1066:   Returns:
        !          1067:     0 on failure
        !          1068:     1 on success
        !          1069: */
        !          1070: int
        !          1071: zchdir(dirnam) char *dirnam; {
        !          1072:     char *hd, *sp, *p;
        !          1073: 
        !          1074:     debug(F110,"zchdir",dirnam,0);
        !          1075:     if (dirnam == NULL || dirnam == "" || *dirnam == '\0') /* If arg is null */
        !          1076:       dirnam = getenv("HOME");         /* use user's home directory. */
        !          1077:     sp = dirnam;
        !          1078:     debug(F110,"zchdir 2",dirnam,0);
        !          1079: 
        !          1080: #ifdef DTILDE
        !          1081:     hd = tilde_expand(dirnam);         /* Attempt to expand tilde */
        !          1082:     if (*hd == '\0') hd = dirnam;      /* in directory name. */
        !          1083: #else
        !          1084:     hd = dirnam;
        !          1085: #endif /* DTILDE */
        !          1086:     debug(F110,"zchdir 3",hd,0);
        !          1087:     if (chdir(hd) == 0) return(1);     /* Try to cd */ /* (===OS2===) */
        !          1088:     p = sp;                            /* Failed, lowercase it. */
        !          1089:     while (*p) {
        !          1090:        if (isupper(*p)) *p = tolower(*p);
        !          1091:        p++;
        !          1092:     }
        !          1093:     debug(F110,"zchdir 4",hd,0);
        !          1094: #ifdef DTILDE
        !          1095:     hd = tilde_expand(sp);             /* Try again to expand tilde */
        !          1096:     if (*hd == '\0') hd = sp;
        !          1097: #else
        !          1098:     hd = sp;                           /* Point to result */
        !          1099: #endif
        !          1100:     debug(F110,"zchdir 5",hd,0);
        !          1101: /*  return((chdir(hd) > -1) ? 1 : 0); (===OS2===)  */
        !          1102:     return((chdir(hd) == 0) ? 1 : 0);
        !          1103: }
        !          1104: 
        !          1105: 
        !          1106: /*  Z H O M E  --  Return pointer to user's home directory  */
        !          1107: 
        !          1108: char *
        !          1109: zhome() {
        !          1110:     char *home = NULL;
        !          1111:     home = getenv("HOME");
        !          1112:     return(home ? home : ".");         /* (===OS2===) */
        !          1113: }
        !          1114: 
        !          1115: /*  Z G T D I R  --  Return pointer to user's current directory  */
        !          1116: 
        !          1117: #ifdef MAXPATHLEN
        !          1118: #define CWDBL MAXPATHLEN
        !          1119: #else
        !          1120: #define CWDBL 100
        !          1121: #endif
        !          1122: static char cwdbuf[CWDBL+1];
        !          1123: 
        !          1124: char *
        !          1125: zgtdir() {
        !          1126:     char *buf;
        !          1127: 
        !          1128: #ifdef SVORPOSIX
        !          1129:     extern char *getcwd();
        !          1130:     buf = cwdbuf;
        !          1131:     return(getcwd(buf,CWDBL));
        !          1132: #else
        !          1133: #ifdef OS2
        !          1134:     extern char *getcwd();
        !          1135:     buf = cwdbuf;
        !          1136:     return(getcwd(buf,CWDBL));
        !          1137: #else
        !          1138: #ifdef BSD4
        !          1139:     extern char *getwd();
        !          1140:     buf = cwdbuf;
        !          1141:     return(getwd(buf));
        !          1142: #else
        !          1143:     return("directory unknown");
        !          1144: #endif /* BSD4 */
        !          1145: #endif /* OS2 */
        !          1146: #endif /* SYSVORPOSIX */
        !          1147: }
        !          1148: 
        !          1149: /*  Z X C M D -- Run a system command so its output can be read like a file */
        !          1150: 
        !          1151: int
        !          1152: zxcmd(filnum,comand) int filnum; char *comand; {
        !          1153: #ifdef OS2
        !          1154:     if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
        !          1155:     if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
        !          1156:       return(0);
        !          1157:     if (filnum == ZIFILE || filnum == ZRFILE) { /* Input from a command */
        !          1158:        if (priv_chk() || ((fp[filnum] = popen(comand,"r")) == NULL))
        !          1159:          return(0);
        !          1160:     } else { /* Output to a command */
        !          1161:        if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL))
        !          1162:          return(0);
        !          1163:     }
        !          1164:     ispipe[filnum] = 1;
        !          1165:     return(1);
        !          1166: #else /* Not OS2 */
        !          1167:     int pipes[2];
        !          1168:     int out;
        !          1169: 
        !          1170:     if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
        !          1171:     if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
        !          1172:       return(0);
        !          1173: 
        !          1174:     out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
        !          1175: 
        !          1176: /* Output to a command */
        !          1177: 
        !          1178:     if (out) {                         /* Need popen() to do this. */
        !          1179: #ifdef NOPOPEN
        !          1180:        return(0);                      /* no popen(), fail. */
        !          1181: #else
        !          1182: /* Use popen() to run the command. */
        !          1183: 
        !          1184: #ifdef _POSIX_SOURCE
        !          1185: /* Strictly speaking, popen() is not available in POSIX.1 */
        !          1186: #define DCLPOPEN
        !          1187: #endif /* _POSIX_SOURCE */
        !          1188: 
        !          1189: #ifdef DCLPOPEN
        !          1190: /* popen() needs declaring because it's not declared in <stdio.h> */
        !          1191:        FILE *popen();
        !          1192: #endif /* DCLPOPEN */
        !          1193: 
        !          1194:        if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL))
        !          1195:          return(0);
        !          1196:        else return(1);
        !          1197: #endif /* NOPOPEN */
        !          1198:     }
        !          1199: 
        !          1200: /* Input from a command */
        !          1201: 
        !          1202:     if (pipe(pipes) != 0) {
        !          1203:        debug(F100,"zxcmd pipe failure","",0);
        !          1204:        return(0);                      /* can't make pipe, fail */
        !          1205:     }
        !          1206: 
        !          1207: /* Create a fork in which to run the named process */
        !          1208: 
        !          1209: #ifdef aegis
        !          1210:     if ((pid = vfork()) == 0) {                /* child */
        !          1211: #else
        !          1212:     if ((pid = fork()) == 0) {         /* child */
        !          1213: #endif
        !          1214: 
        !          1215: /* We're in the fork. */
        !          1216: 
        !          1217:        char *shpath, *shname, *shptr;  /* Find user's preferred shell */
        !          1218: #ifndef aegis
        !          1219:        struct passwd *p;
        !          1220:        char *defshell = "/bin/sh";     /* default shell */
        !          1221: #endif /* aegis */
        !          1222:        if (priv_can()) exit(1);        /* Turn off any privileges! */
        !          1223:        debug(F101,"zxcmd pid","",pid);
        !          1224:        close(pipes[0]);                /* close input side of pipe */
        !          1225:        close(0);                       /* close stdin */
        !          1226:        if (open("/dev/null",0) < 0) return(0); /* replace input by null */
        !          1227: #ifndef SVORPOSIX
        !          1228:        dup2(pipes[1],1);               /* BSD: replace stdout & stderr */
        !          1229:        dup2(pipes[1],2);               /* by the pipe */
        !          1230: #else
        !          1231:        close(1);                       /* AT&T: close stdout */
        !          1232:        if ( dup(pipes[1]) != 1 )       /* Send stdout to the pipe */
        !          1233:          return(0);
        !          1234:        close(2);                       /* Send stderr to the pipe */
        !          1235:        if ( dup(pipes[1]) != 2 )
        !          1236:          return(0);
        !          1237: #endif /* SVORPOSIX */
        !          1238:        close(pipes[1]);                /* Don't need this any more. */
        !          1239: 
        !          1240: #ifdef aegis
        !          1241:        if ((shpath = getenv("SERVERSHELL")) == NULL) shpath = "/bin/sh";
        !          1242: #else
        !          1243:        shpath = getenv("SHELL");       /* What shell? */
        !          1244:        if (shpath == NULL) {
        !          1245:            p = getpwuid( real_uid() ); /* Get login data */
        !          1246:            if (p == (struct passwd *)NULL || !*(p->pw_shell))
        !          1247:              shpath = defshell;
        !          1248:            else shpath = p->pw_shell;
        !          1249:         }
        !          1250: #endif /* aegis */
        !          1251:        shptr = shname = shpath;
        !          1252:        while (*shptr != '\0')
        !          1253:          if (*shptr++ == '/')
        !          1254:            shname = shptr;
        !          1255:        debug(F100,"zxcmd...","",0);
        !          1256:        debug(F110,shpath,shname,0);
        !          1257: 
        !          1258:        execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
        !          1259:        exit(0);                        /* just punt if it failed. */
        !          1260:     } else if (pid == -1) {
        !          1261:        debug(F100,"zxcmd fork failure","",0);
        !          1262:        return(0);
        !          1263:     }
        !          1264:     debug(F101,"zxcmd pid","",pid);
        !          1265:     if (out) {
        !          1266:        close(pipes[0]);                /* Don't need the input side */
        !          1267:        fp[filnum] = fdopen(pipes[1],"w"); /* Open a stream for output. */
        !          1268:        fp[ZSYSFN] = fp[filnum];        /* Remember. */
        !          1269:        zoutcnt = 0;                    /* (PWP) reset input buffer */
        !          1270:        zoutptr = zoutbuffer;
        !          1271:     } else {
        !          1272:        close(pipes[1]);                /* Don't need the output side */
        !          1273:        fp[filnum] = fdopen(pipes[0],"r"); /* Open a stream for input. */
        !          1274:        fp[ZSYSFN] = fp[filnum];        /* Remember. */
        !          1275:        zincnt = 0;                     /* (PWP) reset input buffer */
        !          1276:        zinptr = zinbuffer;
        !          1277:     }
        !          1278:     return(1);
        !          1279: #endif /* OS2 */
        !          1280: }
        !          1281: 
        !          1282: /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
        !          1283: 
        !          1284: int
        !          1285: zclosf(filnum) int filnum; {
        !          1286:     int wstat;
        !          1287:     debug(F101,"zclosf filnum","",filnum);
        !          1288: #ifndef NOPOPEN
        !          1289: #ifdef OS2
        !          1290:     if (ispipe[filnum]) {
        !          1291:        int x;
        !          1292:        x = pclose(fp[filnum]);
        !          1293:        fp[filnum] = NULL;
        !          1294:        ispipe[filnum] = 0;
        !          1295: #else
        !          1296:     if (filnum == ZWFILE) {
        !          1297:        int x;
        !          1298:        x = pclose(fp[filnum]);
        !          1299:        fp[filnum] = fp[ZSYSFN] = NULL;
        !          1300: #endif /* OS2 */
        !          1301:        return((x < 0) ? 0 : 1);
        !          1302:     }
        !          1303: #endif /* NOPOPEN */
        !          1304:     debug(F101,"zclosf fp[filnum]","", fp[filnum]);
        !          1305:     debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
        !          1306: #ifdef OS2
        !          1307:     fclose(fp[filnum]);
        !          1308:     fp[filnum] = NULL;
        !          1309: #else
        !          1310:     if (pid != 0) {
        !          1311:        debug(F101,"zclosf killing pid","",pid);
        !          1312:        kill(pid,9);
        !          1313:         while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ;
        !          1314:         pid = 0;
        !          1315:     }
        !          1316:     fclose(fp[filnum]);
        !          1317:     fp[filnum] = fp[ZSYSFN] = NULL;
        !          1318: #endif /* OS2 */
        !          1319:     return(1);
        !          1320: }
        !          1321: 
        !          1322: /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
        !          1323: /*
        !          1324:   Returns the number of files that match fn1, with data structures set up
        !          1325:   so that first file (if any) will be returned by the next znext() call.
        !          1326:   Depends on external variable wildxpand: 0 means we expand wildcards
        !          1327:   internally, nonzero means we call the shell to do it.
        !          1328: */
        !          1329: 
        !          1330: int
        !          1331: zxpand(fn) char *fn; {
        !          1332:     char *p;
        !          1333: 
        !          1334: #ifdef DTILDE                          /* Built with tilde-expansion? */
        !          1335:     char *tnam;
        !          1336: #endif /* DTILDE */
        !          1337:     debug(F111,"zxpand entry",fn,wildxpand);
        !          1338: #ifdef DTILDE                          /* Built with tilde-expansion? */
        !          1339:     if (*fn == '~') {                  /* Starts with tilde? */
        !          1340:        tnam = tilde_expand(fn);        /* Try to expand it. */
        !          1341:        if (tnam) fn = tnam;
        !          1342:     }
        !          1343:     debug(F110,"zxpand after tilde_x",fn,0);
        !          1344: #endif /* DTILDE */
        !          1345: #ifndef OS2
        !          1346:     if (wildxpand)                     /* Who is expanding wildcards? */
        !          1347:       fcount = shxpand(fn,mtchs,MAXWLD); /* Shell */
        !          1348:     else
        !          1349: #endif /* OS2 */
        !          1350:       fcount = fgen(fn,mtchs,MAXWLD);  /* Kermit */
        !          1351:     if (fcount > 0) {
        !          1352:        mtchptr = mtchs;                /* Save pointer for next. */
        !          1353:     }
        !          1354:     if (fcount > 0) {
        !          1355:        debug(F111,"zxpand ok",mtchs[0],fcount);
        !          1356:        return(fcount);
        !          1357:     }
        !          1358:     debug(F111,"zxpand fgen1",fn,fcount); /* Didn't get one, or got too many */
        !          1359:     p = malloc((int)strlen(fn) + 10);  /* Make space */
        !          1360:     if (!p) return(0);
        !          1361:     zrtol(fn,p);                       /* Try again, maybe lowercase */
        !          1362: #ifndef OS2
        !          1363:     if (wildxpand)
        !          1364:       fcount = shxpand(p,mtchs,MAXWLD); /* Shell */
        !          1365:     else
        !          1366: #endif /* OS2 */
        !          1367:       fcount = fgen(p,mtchs,MAXWLD);   /* Kermit */
        !          1368:     if (fcount > 0) {                  /* Got one? */
        !          1369:        mtchptr = mtchs;                /* Save pointer for next. */
        !          1370:        debug(F111,"zxpand fgen2 ok",mtchs[0],fcount);
        !          1371:     } else debug(F111,"zxpand 2 not ok",p,fcount);
        !          1372:     free(p);
        !          1373:     return(fcount);
        !          1374: }
        !          1375: 
        !          1376: 
        !          1377: /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
        !          1378: /*
        !          1379:  Returns >0 if there's another file, with its name copied into the arg string,
        !          1380:  or 0 if no more files in list.
        !          1381: */
        !          1382: int
        !          1383: znext(fn) char *fn; {
        !          1384:     if (fcount-- > 0) strcpy(fn,*mtchptr++);
        !          1385:     else *fn = '\0';
        !          1386:     debug(F111,"znext",fn,fcount+1);
        !          1387:     return(fcount+1);
        !          1388: }
        !          1389: 
        !          1390: 
        !          1391: /*  Z C H K S P A  --  Check if there is enough space to store the file  */
        !          1392: 
        !          1393: /*
        !          1394:  Call with file specification f, size n in bytes.
        !          1395:  Returns -1 on error, 0 if not enough space, 1 if enough space.
        !          1396: */
        !          1397: int
        !          1398: zchkspa(f,n) char *f; long n; {                /* Just dummy for now. */
        !          1399:     return(1);                         /* Always say OK. */
        !          1400: }
        !          1401: 
        !          1402: 
        !          1403: /*  Z N E W N  --  Make a new name for the given file  */
        !          1404: 
        !          1405: /*
        !          1406:   Given the name, fn, of a file that already exists, this function builds a
        !          1407:   new name of the form "<oldname>.~<n>~", where <oldname> is argument name
        !          1408:   (fn), and <n> is a version number, one higher than any existing version
        !          1409:   number for that file, up to 9999.  This format is consistent with that used
        !          1410:   by GNU EMACS.  If the constructed name is too long for the system's maximum,
        !          1411:   enough characters are truncated from the end of <fn> to allow the version
        !          1412:   number to fit.  If no free version numbers exist between 1 and 9999, a
        !          1413:   version number of "xxxx" is used.  Returns a pointer to the new name in
        !          1414:   argument s.
        !          1415: */
        !          1416: 
        !          1417: VOID
        !          1418: znewn(fn,s) char *fn, **s; {
        !          1419: #define ZNEWNBL 255                    /* Name buffer length */
        !          1420: #define ZNEWNMD 4                      /* Max digits for version number */
        !          1421:     static char buf[ZNEWNBL+1];
        !          1422: #ifdef OS2
        !          1423: /*
        !          1424:   Well, OS/2 should be able to handle 8.3 FAT names still,
        !          1425:   although HPFS is so much easier to live with ...
        !          1426:   This code should be checked out with long names.
        !          1427: */
        !          1428:     char *bp, *xp, *yp, *zp, ch, temp[14];
        !          1429:     int d, i, n;
        !          1430:     xp = bp = buf;
        !          1431:     while (*fn) {                      /* Copy name into buf */
        !          1432:        ch = *bp++ = *fn++;
        !          1433:        if (ISDIRSEP(ch) || (ch == ':')) xp=bp;
        !          1434:     }
        !          1435:     *bp = '\0';
        !          1436:     yp = xp;
        !          1437:     i = 1;
        !          1438:     while (*yp && (*yp != '.')) {
        !          1439:        yp++;
        !          1440:        if (++i<=6) zp=yp;
        !          1441:     }
        !          1442:     /* zp points to 6th character in name, or yp, whichever occurs first. */
        !          1443:     strcpy(temp,yp);                   /* Copy extension, if any */
        !          1444:     while (zp != xp+8) {
        !          1445:        if ( zp < xp+5 ) *zp++='0';
        !          1446:        else *zp++='?';                 /* Pad out with wild cards */
        !          1447:     }
        !          1448:     strcpy(zp,temp);                   /* Get the extension back */
        !          1449:     n = zxpand(buf);                   /* Expand the resulting wild name */
        !          1450:     d = 0;                             /* Index number */
        !          1451:     while (znext(temp)) {
        !          1452:        i = atoi(temp+5);
        !          1453:        if (i > d) d = i;
        !          1454:     }
        !          1455:     sprintf(temp,"%03d",d+1);          /* get the number into a string */
        !          1456:     memcpy(xp+5, temp, 3);
        !          1457: #else /* Not OS2 */
        !          1458:     char *bp, *xp;
        !          1459:     int len = 0, d = 0, n, t, i, j, k, power = 1;
        !          1460: 
        !          1461:     int max = MAXNAMLEN;               /* Maximum name length */
        !          1462: 
        !          1463:     if (max < 14) max = 14;            /* Make it reasonable */
        !          1464:     if (max > ZNEWNBL) max = ZNEWNBL;
        !          1465:     bp = buf;                          /* Buffer for building new name */
        !          1466:     while (*fn) {                      /* Copy old name into buffer */
        !          1467:        *bp++ = *fn++;
        !          1468:        if (len++ > ZNEWNBL) break;     /* ...up to buffer length */
        !          1469:     }
        !          1470:     for (i = 1; i < ZNEWNMD + 1; i++) {        /* Version numbers up to 10**i - 1 */
        !          1471:        power *= 10;                    /* Next power of 10 */
        !          1472:        j = max - len;                  /* Space left for version number */
        !          1473:        k = 3 + i;                      /* Space needed for it */
        !          1474:        if (j < k) {                    /* Make room if necessary */
        !          1475:            len -= (k - j);             /* Adjust length of filename */
        !          1476:            bp = buf + len;             /* Point to new end */
        !          1477:        }
        !          1478:        *bp++ = '*';                    /* Put a star on the end (UNIX) */
        !          1479:        *bp-- = '\0';                   /* Terminate with null */
        !          1480: 
        !          1481:        n = zxpand(buf);                /* Expand the resulting wild name */
        !          1482:                                        /* n is the number of matches */
        !          1483:        while (n-- > 0) {               /* Find any existing name.~n~ files */
        !          1484:            xp = *mtchptr++;            /* Point at matching name */
        !          1485:            xp += len;                  /* Look for .~<n>~ at the end of it */
        !          1486:            if (*xp == '.' && *(xp+1) == '~') { /* Has a version number */
        !          1487:                t = atoi(xp+2);                 /* Get it */
        !          1488:                if (t > d) d = t;       /* Save d = highest version number */
        !          1489:            }
        !          1490:        }
        !          1491:        if (d < power-1) {              /* Less than maximum possible? */
        !          1492:            sprintf(bp,".~%d~",d+1);    /* Yes, make "name.~<d+1>~" */
        !          1493:            *s = buf;                   /* Point to new name */
        !          1494:            return;                     /* Done, return it */
        !          1495:        }
        !          1496:     }
        !          1497:     sprintf(bp,".~xxxx~");             /* Too many, use xxxx. */
        !          1498: #endif /* OS2 */
        !          1499:     *s = buf;
        !          1500:     return;
        !          1501: }
        !          1502: 
        !          1503: /*  Z R E N A M E  --  Rename a file  */
        !          1504: 
        !          1505: /*  Note, link() and unlink() are used because rename() is not available  */
        !          1506: /*  in some versions of UNIX.   */
        !          1507: /*  Call with old and new names */
        !          1508: /*  Returns 0 on success, -1 on failure. */
        !          1509: 
        !          1510: int
        !          1511: zrename(old,new) char *old, *new; {
        !          1512: #ifdef OS2
        !          1513:    return rename(old, new);
        !          1514: #else
        !          1515:    if (link(old,new) < 0) {            /* Make a link with the new name. */
        !          1516:        debug(F110," link fails",old,0);
        !          1517:        return(-1);
        !          1518:     }
        !          1519:     if (unlink(old) < 0) {             /* Unlink the old name. */
        !          1520:        debug(F110," link fails",old,0);
        !          1521:        return(-1);
        !          1522:     }
        !          1523:     return(0);
        !          1524: #endif /* OS2 */
        !          1525: }
        !          1526: 
        !          1527: /*  Z S A T T R */
        !          1528: /*
        !          1529:  Fills in a Kermit file attribute structure for the file which is to be sent.
        !          1530:  Returns 0 on success with the structure filled in, or -1 on failure.
        !          1531:  If any string member is null, then it should be ignored.
        !          1532:  If any numeric member is -1, then it should be ignored.
        !          1533: */
        !          1534: int
        !          1535: zsattr(xx) struct zattr *xx; {
        !          1536:     long k;
        !          1537: 
        !          1538:     k = iflen % 1024L;                 /* File length in K */
        !          1539:     if (k != 0L) k = 1L;
        !          1540:     xx->lengthk = (iflen / 1024L) + k;
        !          1541:     xx->type.len = 0;                  /* File type can't be filled in here */
        !          1542:     xx->type.val = "";
        !          1543:     if (*nambuf) {
        !          1544:        xx->date.val = zfcdat(nambuf);  /* File creation date */
        !          1545:        xx->date.len = (int)strlen(xx->date.val);
        !          1546:     } else {
        !          1547:        xx->date.len = 0;
        !          1548:        xx->date.val = "";
        !          1549:     }
        !          1550:     xx->creator.len = 0;               /* File creator */
        !          1551:     xx->creator.val = "";
        !          1552:     xx->account.len = 0;               /* File account */
        !          1553:     xx->account.val = "";
        !          1554:     xx->area.len = 0;                  /* File area */
        !          1555:     xx->area.val = "";
        !          1556:     xx->passwd.len = 0;                        /* Area password */
        !          1557:     xx->passwd.val = "";
        !          1558:     xx->blksize = -1L;                 /* File blocksize */
        !          1559:     xx->access.len = 0;                        /* File access */
        !          1560:     xx->access.val = "";
        !          1561:     xx->encoding.len = 0;              /* Transfer syntax */
        !          1562:     xx->encoding.val = 0;
        !          1563:     xx->disp.len = 0;                  /* Disposition upon arrival */
        !          1564:     xx->disp.val = "";
        !          1565:     xx->lprotect.len = 0;              /* Local protection */
        !          1566:     xx->lprotect.val = "";
        !          1567:     xx->gprotect.len = 0;              /* Generic protection */
        !          1568:     xx->gprotect.val = "";
        !          1569:     xx->systemid.len = 2;              /* System ID */
        !          1570:     xx->systemid.val = "U1";
        !          1571:     xx->recfm.len = 0;                 /* Record format */
        !          1572:     xx->recfm.val = "";
        !          1573:     xx->sysparam.len = 0;              /* System-dependent parameters */
        !          1574:     xx->sysparam.val = "";
        !          1575:     xx->length = iflen;                        /* Length */
        !          1576:     return(0);
        !          1577: }
        !          1578: 
        !          1579: #ifdef COMMENT
        !          1580: int
        !          1581: zfree(f) char *f; {                    /* Check free space */
        !          1582:     /* How??? */
        !          1583:     return(0);
        !          1584: }
        !          1585: #endif /* COMMENT */
        !          1586: 
        !          1587: /* Z F C D A T  --  Get file creation date */
        !          1588: /*
        !          1589:   Call with pointer to filename.
        !          1590:   On success, returns pointer to creation date in yyyymmdd hh:mm:ss format.
        !          1591:   On failure, returns pointer to null string.
        !          1592: */
        !          1593: static char datbuf[40];
        !          1594: 
        !          1595: /* static */                           /* (===OS2 change===) */
        !          1596: char *
        !          1597: zfcdat(name) char *name; {
        !          1598: 
        !          1599: #ifdef TIMESTAMP
        !          1600:     struct stat buffer;
        !          1601:     struct tm *time_stamp, *localtime();
        !          1602:     int yy, ss;
        !          1603: 
        !          1604:     datbuf[0] = '\0';
        !          1605:     if(stat(name,&buffer) != 0) {
        !          1606:        debug(F110,"zfcdat stat failed",name,0);
        !          1607:        return("");
        !          1608:     }
        !          1609:     time_stamp = localtime(&(buffer.st_mtime));
        !          1610:     yy = time_stamp->tm_year;
        !          1611:     if (yy < 100)                      /* In case it returns 2-digit year? */
        !          1612:       yy += 1900;
        !          1613:     if (yy < 0 || yy > 9999) {         /* Make sure year is ok */
        !          1614:        debug(F110,"zfcdat date failed",name,0);
        !          1615:        return("");
        !          1616:     }
        !          1617:     if (time_stamp->tm_mon  < 0 || time_stamp->tm_mon  > 11)
        !          1618:       return("");
        !          1619:     if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
        !          1620:       return("");
        !          1621:     if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
        !          1622:       return("");
        !          1623:     if (time_stamp->tm_min  < 0 || time_stamp->tm_min  > 59)
        !          1624:       return("");
        !          1625:     ss = time_stamp->tm_sec;           /* Seconds */
        !          1626:     if (ss < 0 || ss  > 59)            /* Some systems give a BIG number */
        !          1627:       ss = 0;
        !          1628:     sprintf(datbuf,
        !          1629: #ifdef pdp11
        !          1630: /* For some reason, 2.1x BSD sprintf gets the last field wrong. */
        !          1631:            "%04d%02d%02d %02d:%02d:00",
        !          1632: #else
        !          1633:            "%04d%02d%02d %02d:%02d:%02d",
        !          1634: #endif /* pdp11 */
        !          1635:            yy,
        !          1636:            time_stamp->tm_mon + 1,
        !          1637:            time_stamp->tm_mday,
        !          1638:            time_stamp->tm_hour,
        !          1639:            time_stamp->tm_min
        !          1640: #ifndef pdp11
        !          1641:            , ss
        !          1642: #endif /* pdp11 */
        !          1643:            );
        !          1644:     yy = (int)strlen(datbuf);
        !          1645:     debug(F111,"zfcdat",datbuf,yy);
        !          1646:     if (yy > 17) datbuf[17] = '\0';
        !          1647:     return(datbuf);
        !          1648: #else
        !          1649:     return("");
        !          1650: #endif /* timestamp */
        !          1651: }
        !          1652: 
        !          1653: /* Z S T I M E  --  Set creation date for incoming file */
        !          1654: /*
        !          1655:  Call with:
        !          1656:  f  = pointer to name of existing file.
        !          1657:  yy = pointer to a Kermit file attribute structure in which yy->date.val
        !          1658:       is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
        !          1659:  x  = is a function code: 0 means to set the file's creation date as given.
        !          1660:       1 means compare the given date with the file creation date.
        !          1661:  Returns:
        !          1662:  -1 on any kind of error.
        !          1663:   0 if x is 0 and the file date was set successfully.
        !          1664:   0 if x is 1 and date from attribute structure <= file creation date.
        !          1665:   1 if x is 1 and date from attribute structure > file creation date.
        !          1666: */
        !          1667: int
        !          1668: zstime(f,yy,x) char *f; struct zattr *yy; int x; {
        !          1669:     int r = -1;                                /* return code */
        !          1670: /*
        !          1671:   It is ifdef'd TIMESTAMP because it might not work on V7. [email protected].
        !          1672: */
        !          1673: #ifdef TIMESTAMP
        !          1674: /*
        !          1675:   To do: adapt code from OS-9 Kermit's ck9fio.c zstime function, which
        !          1676:   is more flexible, allowing [yy]yymmdd[ hh:mm[:ss]].
        !          1677: */
        !          1678: #ifndef OS2
        !          1679:     extern int ftime(), stat(), utime();
        !          1680:     /* at least, the declarations for int functions are not needed anyway */
        !          1681:     extern struct tm *localtime();
        !          1682:     /* and this should have been declared always through a header file */
        !          1683: #endif /* OS2 */
        !          1684:     long tm, days;
        !          1685:     int i, n, isleapyear;
        !          1686:                    /*       J  F  M  A   M   J   J   A   S   O   N   D   */
        !          1687:                    /*      31 28 31 30  31  30  31  31  30  31  30  31   */
        !          1688:     static
        !          1689:     int monthdays [13] = {  0,0,31,59,90,120,151,181,212,243,273,304,334 };
        !          1690:     char s[5];
        !          1691:     struct stat sb;
        !          1692: #ifdef OS2
        !          1693:     struct utimbuf tp;
        !          1694: #else
        !          1695: #ifdef V7
        !          1696:     struct utimbuf {
        !          1697:       time_t timep[2];         /* New access and modificaton time */
        !          1698:     } tp;
        !          1699:     char *tz;
        !          1700:     long timezone;             /* In case timezone not defined in .h file */
        !          1701: #else
        !          1702:    struct utimbuf {
        !          1703:       time_t atime;            /* New access time */
        !          1704:       time_t mtime;            /* New modification time */
        !          1705:     } tp;
        !          1706: #endif /* V7 */
        !          1707: #endif /* OS2 */
        !          1708: 
        !          1709: #ifdef ANYBSD
        !          1710:     long timezone;
        !          1711:     static struct timeb tbp;
        !          1712: #endif
        !          1713: 
        !          1714:     debug(F110,"zstime",f,0);
        !          1715: 
        !          1716:     if ((yy->date.len == 0)
        !          1717:         || (yy->date.len != 17)
        !          1718:         || (yy->date.val[8] != ' ')
        !          1719:         || (yy->date.val[11] != ':')
        !          1720:         || (yy->date.val[14] != ':') ) {
        !          1721:         debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
        !          1722:         return(-1);
        !          1723:     }
        !          1724:     debug(F111,"zstime date check 1",yy->date.val,yy->date.len);
        !          1725:     for(i = 0; i < 8; i++) {
        !          1726:        if (!isdigit(yy->date.val[i])) {
        !          1727:            debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
        !          1728:            return(-1);
        !          1729:        }
        !          1730:     }
        !          1731:     debug(F111,"zstime date check 2",yy->date.val,yy->date.len);
        !          1732:     i++;
        !          1733: 
        !          1734:     for (; i < 16; i += 3) {
        !          1735:        if ((!isdigit(yy->date.val[i])) || (!isdigit(yy->date.val[i + 1]))) {
        !          1736:            debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
        !          1737:            return(-1);
        !          1738:        }
        !          1739:     }
        !          1740:     debug(F111,"zstime date check 3",yy->date.val,yy->date.len);
        !          1741: 
        !          1742: #ifdef ANYBSD
        !          1743:     debug(F100,"ztime BSD calling ftime","",0);
        !          1744:     ftime(&tbp);
        !          1745:     debug(F100,"ztime BSD back from ftime","",0);
        !          1746:     timezone = tbp.timezone * 60L;
        !          1747:     debug(F101,"ztime BSD timezone","",timezone);
        !          1748: #endif
        !          1749: 
        !          1750: #ifdef ATTSV
        !          1751:     tzset();                           /* Set `timezone'. */
        !          1752: #endif /* ATTSV */
        !          1753: 
        !          1754: #ifdef V7
        !          1755:     if ((tz = getenv("TZ")) == NULL)
        !          1756:       timezone = 0;            /* UTC/GMT */
        !          1757:     else
        !          1758:       timezone = atoi(&tz[3]); /* Set 'timezone'. */
        !          1759:     timezone *= 60L;
        !          1760: #endif
        !          1761: 
        !          1762:     debug(F100,"zstime so far so good","",0);
        !          1763: 
        !          1764:     s[4] = '\0';
        !          1765:     for (i = 0; i < 4; i++)    /* Fix the year */
        !          1766:       s[i] = yy->date.val[i];
        !          1767: 
        !          1768:     debug(F110,"zstime year",s,0);
        !          1769: 
        !          1770:     n = atoi(s);
        !          1771: 
        !          1772:     debug(F111,"zstime year",s,n);
        !          1773: 
        !          1774: /* Previous year's leap days. This won't work after year 2100, */
        !          1775: /* I don't care about that! */
        !          1776:     isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
        !          1777:     days = (long) (n - 1970) * 365;
        !          1778:     days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
        !          1779: 
        !          1780:     s[2] = '\0';
        !          1781: 
        !          1782:     for (i = 4 ; i < 16; i += 2) {
        !          1783:        s[0] = yy->date.val[i];
        !          1784:        s[1] = yy->date.val[i + 1];
        !          1785:        n = atoi(s);
        !          1786:     debug(F110,"zstime entering switch",s,0);
        !          1787:        switch (i) {
        !          1788:          case 4:                       /* MM: month */
        !          1789:            if ((n < 1 ) || ( n > 12)) {
        !          1790:                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
        !          1791:                return(-1);
        !          1792:            }
        !          1793:            days += monthdays [n];
        !          1794:            if (isleapyear && n > 2)
        !          1795:              ++days;
        !          1796:            continue;
        !          1797: 
        !          1798:          case 6:                       /* DD: day */
        !          1799:            if ((n < 1 ) || ( n > 31)) {
        !          1800:                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
        !          1801:                return(-1);
        !          1802:            }
        !          1803:            tm = (days + n - 1) * 24L * 60L * 60L;
        !          1804:            i++;                        /* Skip the space */
        !          1805:            continue;
        !          1806: 
        !          1807:          case 9:                       /* hh: hour */
        !          1808:            if ((n < 0 ) || ( n > 23)) {
        !          1809:                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
        !          1810:                return(-1);
        !          1811:            }
        !          1812:            tm += n * 60L * 60L;
        !          1813:            i++;                        /* Skip the colon */
        !          1814:            continue;
        !          1815: 
        !          1816:          case 12:                      /* mm: minute */
        !          1817:            if ((n < 0 ) || ( n > 59)) {
        !          1818:                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
        !          1819:                return(-1);
        !          1820:            }
        !          1821: #ifdef ANYBSD                          /* Correct for time zone */
        !          1822:            tm += timezone;
        !          1823: #else
        !          1824: #ifdef ultrix
        !          1825:            tm += (long) timezone;
        !          1826: #else
        !          1827:            tm += timezone;
        !          1828: #endif /* ultrix */
        !          1829: #endif /* ANYBSD */
        !          1830:            tm += n * 60L;
        !          1831:            i++;                        /* Skip the colon */
        !          1832:            continue;
        !          1833: 
        !          1834:          case 15:                      /* ss: second */
        !          1835:            if ((n < 0 ) || ( n > 59)) {
        !          1836:                debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
        !          1837:                return(-1);
        !          1838:            }
        !          1839:            tm += n;
        !          1840:        }
        !          1841: 
        !          1842:        if (localtime(&tm)->tm_isdst)
        !          1843:          tm -= 60L * 60L;              /* Adjust for daylight savings time */
        !          1844:     }
        !          1845: 
        !          1846:     debug(F111,"Attribute creation date ok ",yy->date.val,yy->date.len);
        !          1847: 
        !          1848:     if (stat(f,&sb)) {                 /* Get the time for the file */
        !          1849:        debug(F110,"Can't stat file:",f,0);
        !          1850:        return(-1);
        !          1851:     }
        !          1852: #ifdef OS2
        !          1853:     tp.modtime = tm;                   /* Set modif. time to creation date */
        !          1854:     tp.actime = sb.st_atime;           /* Don't change the access time */
        !          1855: #else
        !          1856: #ifdef V7
        !          1857:     tp.timep[0] = tm;                  /* Set modif. time to creation date */
        !          1858:     tp.timep[1] = sb.st_atime;         /* Don't change the access time */
        !          1859: #else
        !          1860:     tp.mtime = tm;                     /* Set modif. time to creation date */
        !          1861:     tp.atime = sb.st_atime;            /* Don't change the access time */
        !          1862: #endif /* V7 */
        !          1863: #endif /* OS2 */
        !          1864: 
        !          1865:     switch (x) {                       /* Execute desired function */
        !          1866:       case 0:                          /* Set the creation date of the file */
        !          1867:        if (utime(f,&tp)) {             /* Fix modification time */
        !          1868:            debug(F110,"Can't set modification time for file: ",f,0);
        !          1869:            r = -1;
        !          1870:        } else  {
        !          1871:            debug(F110,"Modification time is set for file: ",f,0);
        !          1872:            r = 0;
        !          1873:        }
        !          1874:        break;
        !          1875:       case 1:                          /* Compare the dates */
        !          1876:        debug(F111,"zstime compare",f,sb.st_atime);
        !          1877:        debug(F111,"zstime compare","packet",tm);
        !          1878:        if (sb.st_atime < tm) r = 0; else r = 1;
        !          1879:        break;
        !          1880:       default:                         /* Error */
        !          1881:        r = -1;
        !          1882:     }
        !          1883: #endif /* TIMESTAMP */
        !          1884:     return(r);
        !          1885: }
        !          1886: 
        !          1887: /* Find initialization file. */
        !          1888: 
        !          1889: #ifdef NOTUSED
        !          1890: int
        !          1891: zkermini() {
        !          1892: /*  nothing here for Unix.  This function added for benefit of VMS Kermit.  */
        !          1893:     return(0);
        !          1894: }
        !          1895: #endif /* NOTUSED */
        !          1896: 
        !          1897: #ifndef NOFRILLS
        !          1898: int
        !          1899: zmail(p,f) char *p; char *f; {         /* Send file f as mail to address p */
        !          1900: /*
        !          1901:   Returns 0 on success
        !          1902:    2 if mail delivered but temp file can't be deleted
        !          1903:   -2 if mail can't be delivered
        !          1904:   The UNIX version always returns 0 because it can't get a good return
        !          1905:   code from zsyscmd.
        !          1906: */
        !          1907: #ifdef BSD4
        !          1908: /* The idea is to use /usr/ucb/mail, rather than regular mail, so that   */
        !          1909: /* a subject line can be included with -s.  Since we can't depend on the */
        !          1910: /* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
        !          1911: /* and even if Mail has been moved to somewhere else, this should still  */
        !          1912: /* find it...  The search could be made more reliable by actually using  */
        !          1913: /* access() to see if /usr/ucb/Mail exists. */
        !          1914: 
        !          1915: /* Should also make some check on zmbuf overflow... */
        !          1916: 
        !          1917: #ifdef OXOS
        !          1918:     sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
        !          1919: #else
        !          1920:     sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f);
        !          1921: #endif /* OXOS */
        !          1922:     zsyscmd(zmbuf);
        !          1923: #else
        !          1924: #ifdef SVORPOSIX
        !          1925:     sprintf(zmbuf,"mail %s < %s", p, f);
        !          1926:     zsyscmd(zmbuf);
        !          1927: #else
        !          1928:     *zmbuf = '\0';
        !          1929: #endif
        !          1930: #endif
        !          1931:     return(0);
        !          1932: }
        !          1933: #endif /* NOFRILLS */
        !          1934: 
        !          1935: #ifndef NOFRILLS
        !          1936: int
        !          1937: zprint(p,f) char *p; char *f; {                /* Print file f with options p */
        !          1938: 
        !          1939: #ifdef OS2
        !          1940:     sprintf(zmbuf,"print %s %s", p, f); /* Construct print command */
        !          1941:     zsyscmd(zmbuf);
        !          1942: #else
        !          1943: #ifdef UNIX
        !          1944: #ifdef ANYBSD                          /* BSD uses lpr to spool */
        !          1945: #ifndef OXOS                           /* Except Olivetti... */
        !          1946: #define SPOOLER "lpr"
        !          1947: #else
        !          1948: #define SPOOLER "lp"
        !          1949: #endif /* OXOS */
        !          1950: #else                                  /* Sys V uses lp */
        !          1951: #ifdef TRS16                           /* except for Tandy-16/6000... */
        !          1952: #define SPOOLER "lpr"
        !          1953: #else
        !          1954: #define SPOOLER "lp"
        !          1955: #endif
        !          1956: #endif
        !          1957: /*
        !          1958:   Note use of standard input redirection.  In some systems, lp[r] runs
        !          1959:   setuid to lp (or ...?), so if user has sent a file into a directory
        !          1960:   that lp does not have read access to, it can't be printed unless it is
        !          1961:   feed to lp[r] as standard input.
        !          1962: */
        !          1963:     sprintf(zmbuf,"%s %s < %s", SPOOLER, p, f); /* Construct print command */
        !          1964:     zsyscmd(zmbuf);
        !          1965: #else /* Not UNIX */
        !          1966:     *zmbuf = '\0';
        !          1967: #endif /* UNIX */
        !          1968: #endif /* OS2 */
        !          1969:     return(0);
        !          1970: }
        !          1971: #endif /* NOFRILLS */
        !          1972: 
        !          1973: /*
        !          1974:   Wildcard expansion functions.  C-Kermit used to do this itself (see #else
        !          1975:   part...).  New code (version 5A, 1990-91) just asks UNIX to do it.
        !          1976:   This lets users use the wildcard expansion features of their favorite shell.
        !          1977:   Operation is slower because of the forking & piping, but flexibility is
        !          1978:   greater and program is smaller.  For OS/2, C-Kermit still does this itself.
        !          1979: */
        !          1980: 
        !          1981: static char scratch[MAXPATH+4];                /* Used by both methods */
        !          1982: 
        !          1983: #ifndef OS2
        !          1984: static int oldmtchs = 0;               /* Let shell (ls) expand them. */
        !          1985: #ifdef COMMENT
        !          1986: static char *lscmd = "/bin/ls -d";     /* Command to use. */
        !          1987: #else
        !          1988: static char *lscmd = "echo";           /* Command to use. */
        !          1989: #endif /* COMMENT */
        !          1990: 
        !          1991: int
        !          1992: shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
        !          1993:     char *fgbuf = NULL;                        /* Buffer for forming ls command */
        !          1994:     char *p, *q;                       /* Workers */
        !          1995:     int i, x, retcode; char c;         /* ... */
        !          1996: 
        !          1997:     x = (int)strlen(pat) + (int)strlen(lscmd) + 3; /* Length of ls command */
        !          1998:     for (i = 0; i < oldmtchs; i++)     /* Free previous file list */
        !          1999:       free(namlst[i]);
        !          2000:     fgbuf = malloc(x);                 /* Get buffer for command */
        !          2001:     if (!fgbuf) return(-1);            /* Fail if cannot */
        !          2002:     sprintf(fgbuf,"%s %s",lscmd,pat);  /* Form the command */
        !          2003:     zxcmd(ZIFILE,fgbuf);               /* Start the command */
        !          2004:     i = 0;                             /* File counter */
        !          2005:     p = scratch;                       /* Point to scratch area */
        !          2006:     retcode = -1;                      /* Assume failure */
        !          2007:     while ((x = zminchar()) != -1) {   /* Read characters from command */
        !          2008:        c = (char) x;
        !          2009:        if (c == ' ' || c == '\n') {    /* Got newline or space? */
        !          2010:            *p = '\0';                  /* Yes, terminate string */
        !          2011:            p = scratch;                /* Point back to beginning */
        !          2012:            if (zchki(p) == -1)         /* Does file exist? */
        !          2013:              continue;                 /* No, continue */
        !          2014:            x = (int)strlen(p);         /* Yes, get length of name */
        !          2015:            q = malloc(x+1);            /* Allocate space for it */
        !          2016:            if (!q) goto shxfin;        /* Fail if space can't be obtained */
        !          2017:            strcpy(q,scratch);          /* Copy name to space */
        !          2018:            namlst[i++] = q;            /* Copy pointer to name into array */
        !          2019:            if (i > len) goto shxfin;   /* Fail if too many */
        !          2020:        } else {                        /* Regular character */
        !          2021:            *p++ = c;                   /* Copy it into scratch area */
        !          2022:        }
        !          2023:     }
        !          2024:     retcode = i;                       /* Return number of matching files */
        !          2025: shxfin:                                        /* Common exit point */
        !          2026:     free(fgbuf);                       /* Free command buffer */
        !          2027:     zclosf(ZIFILE);                    /* Delete the command fork. */
        !          2028:     oldmtchs = i;                      /* Remember how many files */
        !          2029:     return(retcode);
        !          2030: }
        !          2031: #endif /* OS2 */
        !          2032: 
        !          2033: /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
        !          2034: 
        !          2035: /* Define the size of the string space for filename expansion. */
        !          2036: 
        !          2037: #ifndef DYNAMIC
        !          2038: #ifdef PROVX1
        !          2039: #define SSPACE 500
        !          2040: #else
        !          2041: #ifdef BSD29
        !          2042: #define SSPACE 500
        !          2043: #else
        !          2044: #ifdef pdp11
        !          2045: #define SSPACE 500
        !          2046: #else
        !          2047: #ifdef aegis
        !          2048: #define SSPACE 10000                   /* size of string-generating buffer */
        !          2049: static char bslash;                    /* backslash character if active */
        !          2050: #else                                  /* Default static buffer size */
        !          2051: #define SSPACE 2000                    /* size of string-generating buffer */
        !          2052: #endif /* aegis */
        !          2053: #endif /* pdp11 */
        !          2054: #endif /* BSD29 */
        !          2055: #endif /* PROVX1 */
        !          2056: static char sspace[SSPACE];             /* buffer for generating filenames */
        !          2057: #else /* DYNAMIC */
        !          2058: #define SSPACE 10000
        !          2059: static char *sspace = (char *)0;
        !          2060: #endif /* DYNAMIC */
        !          2061: static int ssplen = SSPACE;            /* length of string space buffer */
        !          2062: 
        !          2063: static char *freeptr,**resptr;                 /* copies of caller's arguments */
        !          2064: static int remlen;                      /* remaining length in caller's array*/
        !          2065: static int numfnd;                      /* number of matches found */
        !          2066: 
        !          2067: /*
        !          2068:  * splitpath:
        !          2069:  *  takes a string and splits the slash-separated portions into
        !          2070:  *  a list of path structures.  Returns the head of the list.  The
        !          2071:  *  structures are allocated by malloc, so they must be freed.
        !          2072:  *  Splitpath is used internally by the filename generator.
        !          2073:  *
        !          2074:  * Input: A string.
        !          2075:  * Returns: A linked list of the slash-separated segments of the input.
        !          2076:  */
        !          2077: 
        !          2078: struct path *
        !          2079: splitpath(p) char *p; {
        !          2080:     struct path *head,*cur,*prv;
        !          2081:     int i;
        !          2082: 
        !          2083:     debug(F110,"splitpath",p,0);
        !          2084: 
        !          2085:     head = prv = NULL;
        !          2086:     if (ISDIRSEP(*p)) p++;                     /* skip leading slash */
        !          2087:     while (*p != '\0') {
        !          2088:        cur = (struct path *) malloc(sizeof (struct path));
        !          2089:        debug(F101,"splitpath malloc","",cur);
        !          2090:        if (cur == NULL)
        !          2091:          fatal("malloc fails in splitpath()");
        !          2092:        cur -> fwd = NULL;
        !          2093:        if (head == NULL)
        !          2094:          head = cur;
        !          2095:        else
        !          2096:          prv -> fwd = cur;             /* link into chain */
        !          2097:        prv = cur;
        !          2098: #ifdef aegis
        !          2099:        /* treat backslash as "../" */
        !          2100:        if (bslash && *p == bslash) {
        !          2101:            strcpy(cur->npart, "..");
        !          2102:            ++p;
        !          2103:        } else {
        !          2104:            for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
        !          2105:              cur -> npart[i] = *p++;
        !          2106:            cur -> npart[i] = '\0';     /* end this segment */
        !          2107:            if (i >= MAXNAMLEN)
        !          2108:              while (*p && *p != '/' && *p != bslash)
        !          2109:                p++;
        !          2110:        }
        !          2111:        if (*p == '/') p++;
        !          2112: #else
        !          2113: #ifdef OS2
        !          2114:        for (i = 0;
        !          2115:             i < MAXNAMLEN && !ISDIRSEP(*p) && *p != ':' && *p != '\0';
        !          2116:             i++ )
        !          2117:            cur -> npart[i] = *p++;
        !          2118:         if ( *p == ':' ) {
        !          2119:             cur -> npart[i++] = *p++;
        !          2120:             if ( !ISDIRSEP(*p) )
        !          2121:                 cur -> npart[i++] = '.';
        !          2122:         }
        !          2123: #else
        !          2124:        for (i=0; i < MAXNAMLEN && !ISDIRSEP(*p) && *p != '\0'; i++) {
        !          2125:            cur -> npart[i] = *p++;
        !          2126:        }
        !          2127: #endif /* OS2 */
        !          2128:        cur -> npart[i] = '\0';         /* end this segment */
        !          2129:        if (i >= MAXNAMLEN)
        !          2130:          while (!ISDIRSEP(*p) && *p != '\0') p++;
        !          2131:        if (ISDIRSEP(*p))
        !          2132:          p++;
        !          2133: 
        !          2134: #endif /* aegis */
        !          2135:     }
        !          2136:     return(head);
        !          2137: }
        !          2138: 
        !          2139: /*
        !          2140:  * fgen:
        !          2141:  *  This is the actual name generator.  It is passed a string,
        !          2142:  *  possibly containing wildcards, and an array of character pointers.
        !          2143:  *  It finds all the matching filenames and stores them into the array.
        !          2144:  *  The returned strings are allocated from a static buffer local to
        !          2145:  *  this module (so the caller doesn't have to worry about deallocating
        !          2146:  *  them); this means that successive calls to fgen will wipe out
        !          2147:  *  the results of previous calls.  This isn't a problem here
        !          2148:  *  because we process one wildcard string at a time.
        !          2149:  *
        !          2150:  * Input: a wildcard string, an array to write names to, the
        !          2151:  *        length of the array.
        !          2152:  * Returns: the number of matches.  The array is filled with filenames
        !          2153:  *          that matched the pattern.  If there wasn't enough room in the
        !          2154:  *         array, -1 is returned.
        !          2155:  * By: Jeff Damens, CUCCA, 1984.
        !          2156:  */
        !          2157: static int
        !          2158: fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
        !          2159:     struct path *head;
        !          2160:     char *sptr;
        !          2161: #ifdef aegis
        !          2162:     char *namechars;
        !          2163:     int tilde = 0, bquote = 0;
        !          2164: 
        !          2165:     if ((namechars = getenv("NAMECHARS")) != NULL) {
        !          2166:        if (xindex(namechars, '~' ) != NULL) tilde  = '~';
        !          2167:        if (xindex(namechars, '\\') != NULL) bslash = '\\';
        !          2168:        if (xindex(namechars, '`' ) != NULL) bquote = '`';
        !          2169:     } else {
        !          2170:        tilde = '~'; bslash = '\\'; bquote = '`';
        !          2171:     }
        !          2172: 
        !          2173:     sptr = scratch;
        !          2174: 
        !          2175:     /* copy "`node_data", etc. anchors */
        !          2176:     if (bquote && *pat == bquote)
        !          2177:       while (*pat && *pat != '/' && *pat != bslash)
        !          2178:        *sptr++ = *pat++;
        !          2179:     else if (tilde && *pat == tilde)
        !          2180:       *sptr++ = *pat++;
        !          2181:     while (*pat == '/')
        !          2182:       *sptr++ = *pat++;
        !          2183:     if (sptr == scratch) {
        !          2184:        strcpy(scratch,"./");
        !          2185:        sptr = scratch+2;
        !          2186:     }                                  /* init buffer correctly */
        !          2187:     head = splitpath(pat);
        !          2188: #else /* not aegis */
        !          2189:     debug(F110,"fgen pat",pat,0);
        !          2190:     head = splitpath(pat);
        !          2191:     sptr = scratch;
        !          2192:     if (!ISDIRSEP(*pat))
        !          2193:        *sptr++ = '.';                  /* init buffer correctly */
        !          2194:     *sptr++ = DIRSEP;
        !          2195: #ifdef OS2
        !          2196:     if (isalpha(pat[0]) && pat[1] == ':')
        !          2197:         sptr = scratch;                 /* reset in case of leading drive: */
        !          2198: #endif
        !          2199: #endif /* aegis */
        !          2200:     numfnd = 0;                                /* none found yet */
        !          2201: #ifdef DYNAMIC
        !          2202:     if (!sspace) {                     /* Need to allocate string space? */
        !          2203:        while (ssplen > 50) {
        !          2204:            if ((sspace = malloc(ssplen+2))) { /* Got it. */
        !          2205:                debug(F101,"fgen string space","",ssplen);
        !          2206:                break;
        !          2207:            }
        !          2208:            ssplen = (ssplen / 2) + (ssplen / 4); /* Didn't, reduce by 3/4 */
        !          2209:        }
        !          2210:        if (ssplen < 50) {              /* Did we get it? */
        !          2211:            fprintf(stderr,"fgen can't malloc string space\n");
        !          2212:            return(-1);
        !          2213:        }
        !          2214:     }
        !          2215: #endif /* DYNAMIC */
        !          2216:     freeptr = sspace;                  /* this is where matches are copied */
        !          2217:     resptr = resarry;                  /* static copies of these so */
        !          2218:     remlen = len;                      /* recursive calls can alter them */
        !          2219:     traverse(head,scratch,sptr);       /* go walk the directory tree */
        !          2220: #ifdef COMMENT
        !          2221: /*
        !          2222:   This code, circa 1984, has never worked right - it references the head
        !          2223:   pointer after it has already been freed.  Lord knows what might have been
        !          2224:   happening because of this.  Thanks to Steve Walton for finding & fixing this
        !          2225:   bug.
        !          2226: */
        !          2227:     for (; head != NULL; head = head -> fwd)
        !          2228:       free(head);                      /* return the path segments */
        !          2229: #else
        !          2230:     while (head != NULL) {
        !          2231:        struct path *next = head -> fwd;
        !          2232:        free(head);
        !          2233:        head = next;
        !          2234:     }
        !          2235: #endif /* COMMENT */
        !          2236:     return(numfnd);                    /* and return the number of matches */
        !          2237: }
        !          2238: 
        !          2239: /* traverse:
        !          2240:  *  Walks the directory tree looking for matches to its arguments.
        !          2241:  *  The algorithm is, briefly:
        !          2242:  *   If the current pattern segment contains no wildcards, that
        !          2243:  *   segment is added to what we already have.  If the name so far
        !          2244:  *   exists, we call ourselves recursively with the next segment
        !          2245:  *   in the pattern string; otherwise, we just return.
        !          2246:  *
        !          2247:  *   If the current pattern segment contains wildcards, we open the name
        !          2248:  *   we've accumulated so far (assuming it is really a directory), then read
        !          2249:  *   each filename in it, and, if it matches the wildcard pattern segment, add
        !          2250:  *   that filename to what we have so far and call ourselves recursively on the
        !          2251:  *   next segment.
        !          2252:  *
        !          2253:  *   Finally, when no more pattern segments remain, we add what's accumulated
        !          2254:  *   so far to the result array and increment the number of matches.
        !          2255:  *
        !          2256:  * Input: a pattern path list (as generated by splitpath), a string
        !          2257:  *       pointer that points to what we've traversed so far (this
        !          2258:  *       can be initialized to "/" to start the search at the root
        !          2259:  *       directory, or to "./" to start the search at the current
        !          2260:  *       directory), and a string pointer to the end of the string
        !          2261:  *       in the previous argument.
        !          2262:  * Returns: nothing.
        !          2263:  */
        !          2264: static VOID
        !          2265: traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
        !          2266: 
        !          2267: /* Define LONGFN (long file names) automatically for BSD 2.9 and 4.2 */
        !          2268: /* LONGFN can also be defined on the cc command line. */
        !          2269: 
        !          2270: #ifdef BSD29
        !          2271: #ifndef LONGFN
        !          2272: #define LONGFN
        !          2273: #endif
        !          2274: #endif
        !          2275: 
        !          2276: #ifdef BSD42
        !          2277: #ifndef LONGFN
        !          2278: #define LONGFN
        !          2279: #endif
        !          2280: #endif
        !          2281: 
        !          2282: /* Appropriate declarations for directory routines and structures */
        !          2283: /* #define OPENDIR means to use opendir(), readdir(), closedir()  */
        !          2284: /* If OPENDIR not defined, we use open(), read(), close() */
        !          2285: 
        !          2286: #ifdef DIRENT                          /* New way, <dirent.h> */
        !          2287: #define OPENDIR
        !          2288:     DIR *fd, *opendir();
        !          2289:     struct dirent *dirbuf;
        !          2290:     struct dirent *readdir();
        !          2291: #else /* !DIRENT */
        !          2292: #ifdef LONGFN                          /* Old way, <dir.h> with opendir() */
        !          2293: #define OPENDIR
        !          2294:     DIR *fd, *opendir();
        !          2295:     struct direct *dirbuf;
        !          2296: #else /* !LONGFN */
        !          2297:     int fd;                            /* Old way, <dir.h> with open() */
        !          2298:     struct direct dir_entry;
        !          2299:     struct direct *dirbuf = &dir_entry;
        !          2300: #endif /* LONGFN */
        !          2301: #endif /* DIRENT */
        !          2302: 
        !          2303:     struct stat statbuf;               /* for file info */
        !          2304: 
        !          2305:     if (pl == NULL) {
        !          2306:        *--endcur = '\0';               /* end string, overwrite trailing / */
        !          2307:        addresult(sofar);
        !          2308:        return;
        !          2309:     }
        !          2310:     if (!iswild(pl -> npart)) {
        !          2311:        strcpy(endcur,pl -> npart);
        !          2312:        endcur += (int)strlen(pl -> npart);
        !          2313:        *endcur = '\0';                 /* end current string */
        !          2314:        if (stat(sofar,&statbuf) == 0) { /* if current piece exists */
        !          2315: #ifdef OS2
        !          2316:            if (endcur - sofar == 3 && endcur[-1] == '.' && endcur[-2] == ':')
        !          2317:              endcur--;
        !          2318:            else
        !          2319: #endif /* OS2 */
        !          2320:              *endcur++ = DIRSEP;       /* add slash to end */
        !          2321:            *endcur = '\0';             /* and end the string */
        !          2322:            traverse(pl -> fwd,sofar,endcur);
        !          2323:        }
        !          2324:        return;
        !          2325:     }
        !          2326: 
        !          2327:     /* Segment contains wildcards, have to search directory */
        !          2328: 
        !          2329:     *endcur = '\0';                            /* end current string */
        !          2330:     if (stat(sofar,&statbuf) == -1) return;    /* doesn't exist, forget it */
        !          2331:     if (!S_ISDIR (statbuf.st_mode)) return;    /* not a directory, skip */
        !          2332: 
        !          2333: #ifdef OPENDIR
        !          2334:     if ((fd = opendir(sofar)) == NULL) return; /* Can't open, fail. */
        !          2335:     while (dirbuf = readdir(fd))
        !          2336: #else /* !OPENDIR */
        !          2337:     if ((fd = open(sofar,O_RDONLY)) < 0) return; /* Can't open, fail. */
        !          2338:     while (read(fd, (char *)dirbuf, sizeof dir_entry))
        !          2339: #endif /* OPENDIR */
        !          2340:       {
        !          2341:          /* Get null-terminated copy!!! */
        !          2342:          strncpy(nambuf,dirbuf->d_name,MAXNAMLEN);
        !          2343:          nambuf[MAXNAMLEN] = '\0';
        !          2344: #ifdef unos
        !          2345:          if (dirbuf->d_ino != -1 && match(pl -> npart,nambuf))
        !          2346: #else
        !          2347: /* #ifdef _POSIX_SOURCE */
        !          2348: /*
        !          2349:   This is not specified in POSIX.1.  In POSIX.2, there will be
        !          2350:   some kind of filename matching facility, but it will not be done this way.
        !          2351:   Therefore, we should not even be looking in the directory at all.
        !          2352:   Maybe POSIX implementations should force "set wildcard shell"?
        !          2353: */
        !          2354: 
        !          2355: #ifdef sun
        !          2356:          if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
        !          2357: #else
        !          2358: #ifdef ultrix
        !          2359:          if (dirbuf->gd_ino != 0 && match(pl -> npart,nambuf))
        !          2360: #else
        !          2361:          if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf))
        !          2362: #endif /* ultrix */
        !          2363: #endif /* sun */
        !          2364: 
        !          2365: /* #else */ /* not _POSIX_SOURCE */
        !          2366: /*       if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) */
        !          2367: /* #endif */ /* _POSIX_SOURCE */
        !          2368: 
        !          2369: #endif /* unos */
        !          2370:          {
        !          2371:              char *eos;
        !          2372:              strcpy(endcur,nambuf);
        !          2373:              eos = endcur + (int)strlen(nambuf);
        !          2374:              *eos++ = DIRSEP;          /* end this segment */
        !          2375:              traverse(pl -> fwd,sofar,eos);
        !          2376:          }
        !          2377:       }
        !          2378: #ifdef OPENDIR
        !          2379:     closedir(fd);
        !          2380: #else /* !OPENDIR */
        !          2381:     close(fd);
        !          2382: #endif /* OPENDIR */
        !          2383: }
        !          2384: 
        !          2385: /*
        !          2386:  * addresult:
        !          2387:  *  Adds a result string to the result array.  Increments the number
        !          2388:  *  of matches found, copies the found string into our string
        !          2389:  *  buffer, and puts a pointer to the buffer into the caller's result
        !          2390:  *  array.  Our free buffer pointer is updated.  If there is no
        !          2391:  *  more room in the caller's array, the number of matches is set to -1.
        !          2392:  * Input: a result string.
        !          2393:  * Returns: nothing.
        !          2394:  */
        !          2395: static VOID
        !          2396: addresult(str) char *str; {
        !          2397:     int l;
        !          2398:     debug(F111,"addresult",str,remlen);
        !          2399:     if (str[0] == '.' && ISDIRSEP(str[1])) str += 2; /* (===OS2 change===) */
        !          2400:     if (--remlen < 0) {
        !          2401:        numfnd = -1;
        !          2402:        return;
        !          2403:     }
        !          2404:     l = (int)strlen(str) + 1;          /* size this will take up */
        !          2405:     if ((freeptr + l) > (sspace + ssplen)) {
        !          2406:        numfnd = -1;                    /* do not record if not enough space */
        !          2407:        return;
        !          2408:     }
        !          2409:     strcpy(freeptr,str);
        !          2410:     *resptr++ = freeptr;
        !          2411:     freeptr += l;
        !          2412:     numfnd++;
        !          2413: }
        !          2414: 
        !          2415: /*
        !          2416:  * match:
        !          2417:  *  pattern matcher.  Takes a string and a pattern possibly containing
        !          2418:  *  the wildcard characters '*' and '?'.  Returns true if the pattern
        !          2419:  *  matches the string, false otherwise.
        !          2420:  * by: Jeff Damens, CUCCA, 1984
        !          2421:  * skipping over dot files and backslash quoting added by fdc, 1990.
        !          2422:  *
        !          2423:  * Input: a string and a wildcard pattern.
        !          2424:  * Returns: 1 if match, 0 if no match.
        !          2425:  */
        !          2426: static int
        !          2427: match(pattern,string) char *pattern,*string; {
        !          2428:     char *psave,*ssave;                        /* back up pointers for failure */
        !          2429:     int q = 0;                         /* quote flag */
        !          2430: 
        !          2431:     debug(F110,"match str",string,0);
        !          2432:     psave = ssave = NULL;
        !          2433: #ifndef MATCHDOT
        !          2434:     if (*string == '.' && *pattern != '.') {
        !          2435:        debug(F110,"match skip",string,0);
        !          2436:        return(0);
        !          2437:     }
        !          2438: #endif
        !          2439:     while (1) {
        !          2440:        for (; *pattern == *string; pattern++,string++)  /* skip first */
        !          2441:            if (*string == '\0') return(1);     /* end of strings, succeed */
        !          2442: 
        !          2443:        if (*pattern == '\\' && q == 0) { /* Watch out for quoted */
        !          2444:            q = 1;                      /* metacharacters */
        !          2445:            pattern++;                  /* advance past quote */
        !          2446:            if (*pattern != *string) return(0);
        !          2447:            continue;
        !          2448:        } else q = 0;
        !          2449: 
        !          2450:        if (q) {
        !          2451:            return(0);
        !          2452:        } else {
        !          2453:            if (*string != '\0' && *pattern == '?') {
        !          2454:                pattern++;              /* '?', let it match */
        !          2455:                string++;
        !          2456:            } else if (*pattern == '*') { /* '*' ... */
        !          2457:                psave = ++pattern;      /* remember where we saw it */
        !          2458:                ssave = string;         /* let it match 0 chars */
        !          2459:            } else if (ssave != NULL && *ssave != '\0') { /* if not at end  */
        !          2460:                                        /* ...have seen a star */
        !          2461:                string = ++ssave;       /* skip 1 char from string */
        !          2462:                pattern = psave;        /* and back up pattern */
        !          2463:            } else return(0);           /* otherwise just fail */
        !          2464:        }
        !          2465:     }
        !          2466: }
        !          2467: 
        !          2468: /*
        !          2469:   The following two functions are for expanding tilde in filenames
        !          2470:   Contributed by Howie Kaye, CUCCA, developed for CCMD package.
        !          2471: */
        !          2472: 
        !          2473: /*  W H O A M I  --  Get user's username.  */
        !          2474: 
        !          2475: /*
        !          2476:   1) Get real uid
        !          2477:   2) See if the $USER environment variable is set ($LOGNAME on AT&T)
        !          2478:   3) If $USER's uid is the same as ruid, realname is $USER
        !          2479:   4) Otherwise get logged in user's name
        !          2480:   5) If that name has the same uid as the real uid realname is loginname
        !          2481:   6) Otherwise, get a name for ruid from /etc/passwd
        !          2482: */
        !          2483: static char *
        !          2484: whoami () {
        !          2485: #ifdef DTILDE
        !          2486:     static char realname[256];         /* user's name */
        !          2487:     static int ruid = -1;              /* user's real uid */
        !          2488:     char loginname[256], envname[256]; /* temp storage */
        !          2489:     char *c;
        !          2490:     struct passwd *p;
        !          2491:     _PROTOTYP(extern char * getlogin, (void) );
        !          2492: 
        !          2493:     if (ruid != -1)
        !          2494:       return(realname);
        !          2495: 
        !          2496:     ruid = real_uid();                 /* get our uid */
        !          2497: 
        !          2498:   /* how about $USER or $LOGNAME? */
        !          2499:     if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
        !          2500:        strcpy (envname, c);
        !          2501:        p = getpwnam(envname);
        !          2502:        if (p->pw_uid == ruid) {        /* get passwd entry for envname */
        !          2503:            strcpy (realname, envname); /* if the uid's are the same */
        !          2504:            return(realname);
        !          2505:        }
        !          2506:     }
        !          2507: 
        !          2508:   /* can we use loginname() ? */
        !          2509: 
        !          2510:     if ((c =  getlogin()) != NULL) {   /* name from utmp file */
        !          2511:        strcpy (loginname, c);
        !          2512:        if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
        !          2513:          if (p->pw_uid == ruid) {      /* for loginname */
        !          2514:              strcpy (realname, loginname); /* if the uid's are the same */
        !          2515:              return(realname);
        !          2516:          }
        !          2517:     }
        !          2518: 
        !          2519:   /* Use first name we get for ruid */
        !          2520: 
        !          2521:     if ((p = getpwuid(ruid)) == NULL) { /* name for uid */
        !          2522:        realname[0] = '\0';             /* no user name */
        !          2523:        ruid = -1;
        !          2524:        return(NULL);
        !          2525:     }
        !          2526:     strcpy (realname, p->pw_name);
        !          2527:     return(realname);
        !          2528: #else
        !          2529:     return(NULL);
        !          2530: #endif /* DTILDE */
        !          2531: }
        !          2532: 
        !          2533: /*  T I L D E _ E X P A N D  --  expand ~user to the user's home directory. */
        !          2534: 
        !          2535: char *
        !          2536: tilde_expand(dirname) char *dirname; {
        !          2537: #define BUFLEN 256
        !          2538: #ifdef DTILDE
        !          2539:     struct passwd *user;
        !          2540:     static char olddir[BUFLEN];
        !          2541:     static char oldrealdir[BUFLEN];
        !          2542:     static char temp[BUFLEN];
        !          2543:     int i, j;
        !          2544: 
        !          2545:     debug(F111,"tilde_expand",dirname,dirname[0]);
        !          2546: 
        !          2547:     if (dirname[0] != '~')             /* Not a tilde...return param */
        !          2548:       return(dirname);
        !          2549:     if (!strcmp(olddir,dirname)) {     /* Same as last time */
        !          2550:       return(oldrealdir);              /* so return old answer. */
        !          2551:     } else {
        !          2552:        j = (int)strlen(dirname);
        !          2553:        for (i = 0; i < j; i++)         /* find username part of string */
        !          2554:          if (!ISDIRSEP(dirname[i]))
        !          2555:            temp[i] = dirname[i];
        !          2556:          else break;
        !          2557:        temp[i] = '\0';                 /* tie off with a NULL */
        !          2558:        if (i == 1) {                   /* if just a "~" */
        !          2559:            user = getpwnam(whoami());  /*  get info on current user */
        !          2560:        } else {
        !          2561:            user = getpwnam(&temp[1]);  /* otherwise on the specified user */
        !          2562:        }
        !          2563:     }
        !          2564:     if (user != NULL) {                        /* valid user? */
        !          2565:        strcpy(olddir, dirname);        /* remember the directory */
        !          2566:        strcpy(oldrealdir,user->pw_dir); /* and their home directory */
        !          2567:        strcat(oldrealdir,&dirname[i]);
        !          2568:        return(oldrealdir);
        !          2569:     } else {                           /* invalid? */
        !          2570:        strcpy(olddir, dirname);        /* remember for next time */
        !          2571:        strcpy(oldrealdir, dirname);
        !          2572:        return(oldrealdir);
        !          2573:     }
        !          2574: #else
        !          2575:     return(NULL);
        !          2576: #endif /* DTILDE */
        !          2577: }
        !          2578: 
        !          2579: /*
        !          2580:   Functions for executing system commands.
        !          2581:   zsyscmd() executes the system command in the normal, default way for
        !          2582:   the system.  In UNIX, it does what system() does.  Thus, its results
        !          2583:   are always predictable.
        !          2584:   zshcmd() executes the command using the user's preferred shell.
        !          2585: */
        !          2586: int
        !          2587: zsyscmd(s) char *s; {
        !          2588: #ifdef OS2
        !          2589:     if (!priv_chk()) system(s);
        !          2590: #else
        !          2591:     PID_T shpid;
        !          2592: #ifdef COMMENT
        !          2593: /* This doesn't work... */
        !          2594:     WAIT_T status;
        !          2595: #else
        !          2596:     int status;
        !          2597: #endif /* COMMENT */
        !          2598: 
        !          2599:     if (shpid = fork()) {
        !          2600:        if (shpid < (PID_T)0) return(-1); /* Parent */
        !          2601:        while (shpid != (PID_T) wait(&status))
        !          2602:          ;
        !          2603:        return(status);
        !          2604:     }
        !          2605:     if (priv_can()) {                  /* Child: cancel any priv's */
        !          2606:        printf("?Privilege cancellation failure\n");
        !          2607:        _exit(255);
        !          2608:     }
        !          2609:     execl("/bin/sh","sh","-c",s,NULL);
        !          2610:     perror("/bin/sh");
        !          2611:     _exit(255);
        !          2612:     return(0);                         /* Shut up ANSI compilers. */
        !          2613: #endif /* OS2 */
        !          2614: }
        !          2615: 
        !          2616: /*
        !          2617:   UNIX code by H. Fischer; copyright rights assigned to Columbia Univ.
        !          2618:   Adapted to use getpwuid to find login shell because many systems do not
        !          2619:   have SHELL in environment, and to use direct calling of shell rather
        !          2620:   than intermediate system() call. -- H. Fischer
        !          2621:   Call with s pointing to command to execute.
        !          2622: */
        !          2623: 
        !          2624: int
        !          2625: zshcmd(s) char *s; {
        !          2626:     PID_T pid;
        !          2627: 
        !          2628: #ifdef OS2
        !          2629:     char *shell = getenv("COMSPEC");
        !          2630:     if (!priv_chk())
        !          2631:       if (*s == '\0')
        !          2632:         spawnl(P_WAIT, shell, shell, NULL);
        !          2633:       else
        !          2634:         system(s);
        !          2635: #else
        !          2636: #ifdef AMIGA
        !          2637:     if (!priv_chk()) system(s);
        !          2638: #else
        !          2639: #ifdef datageneral
        !          2640:     if (priv_chk) return(1);
        !          2641:     if (*s == '\0')                    /* Interactive shell requested? */
        !          2642: #ifdef mvux
        !          2643:        system("/bin/sh ");
        !          2644: #else
        !          2645:         system("x :cli prefix Kermit_Baby:");
        !          2646: #endif /* mvux */
        !          2647:     else                               /* Otherwise, */
        !          2648:         system(s);                     /* Best for aos/vs?? */
        !          2649: 
        !          2650: #else
        !          2651: #ifdef aegis
        !          2652:     if ((pid = vfork()) == 0) {                /* Make child quickly */
        !          2653:        char *shpath, *shname, *shptr;  /* For finding desired shell */
        !          2654: 
        !          2655:        if (priv_can()) exit(1);        /* Turn off privs. */
        !          2656:         if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
        !          2657: 
        !          2658: #else                                  /* All Unix systems */
        !          2659:     if ((pid = fork()) == 0) {         /* Make child */
        !          2660:        char *shpath, *shname, *shptr;  /* For finding desired shell */
        !          2661:        struct passwd *p;
        !          2662:        char *defshell = "/bin/sh";     /* Default */
        !          2663: 
        !          2664:        if (priv_can()) exit(1);        /* Turn off privs. */
        !          2665:        p = getpwuid(real_uid());       /* Get login data */
        !          2666:        if (p == (struct passwd *) NULL || !*(p->pw_shell))
        !          2667:          shpath = defshell;
        !          2668:        else
        !          2669:          shpath = p->pw_shell;
        !          2670: #endif /* aegis */
        !          2671:        shptr = shname = shpath;
        !          2672:        while (*shptr != '\0')
        !          2673:          if (*shptr++ == DIRSEP)
        !          2674:            shname = shptr;
        !          2675:        if (s == NULL || *s == '\0') {  /* Interactive shell requested? */
        !          2676:            execl(shpath,shname,"-i",NULL); /* Yes, do that */
        !          2677:        } else {                        /* Otherwise, */
        !          2678:            execl(shpath,shname,"-c",s,NULL); /* exec the given command */
        !          2679:        }                               /* If execl() failed, */
        !          2680:        exit(BAD_EXIT);                 /* return bad return code. */
        !          2681: 
        !          2682:     } else {                           /* Parent */
        !          2683: 
        !          2684:        int wstat;                      /* ... must wait for child */
        !          2685:        SIGTYP (*istat)(), (*qstat)();
        !          2686: 
        !          2687:        if (pid == -1) return(0);       /* fork() failed? */
        !          2688: 
        !          2689:        istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
        !          2690:        qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
        !          2691: 
        !          2692:        while (((wstat = wait((WAIT_T *)0)) != pid) && (wstat != -1))
        !          2693:          ;                             /* Wait for fork */
        !          2694:        signal(SIGINT,istat);           /* Restore interrupts */
        !          2695:        signal(SIGQUIT,qstat);
        !          2696:     }
        !          2697: #endif
        !          2698: #endif
        !          2699: #endif
        !          2700:     return(1);
        !          2701: }
        !          2702: 
        !          2703: #ifdef aegis
        !          2704: /*
        !          2705:  Replacement for strchr() and index(), neither of which seem to be universal.
        !          2706: */
        !          2707: 
        !          2708: static char *
        !          2709: #ifdef CK_ANSIC
        !          2710: xindex(char * s, char c)
        !          2711: #else
        !          2712: xindex(s,c) char *s, c;
        !          2713: #endif /* CK_ANSIC */
        !          2714: /* xindex */ {
        !          2715:     while (*s != '\0' && *s != c) s++;
        !          2716:     if (*s == c) return(s); else return(NULL);
        !          2717: }
        !          2718: #endif /* aegis */
        !          2719: 
        !          2720: /*  I S W I L D  --  Check if filespec is "wild"  */
        !          2721: 
        !          2722: /*
        !          2723:   Returns 0 if it is a single file, 1 if it contains wildcard characters.
        !          2724:   Note: must match the algorithm used by match(), hence no [a-z], etc.
        !          2725: */
        !          2726: int
        !          2727: iswild(filespec) char *filespec; {
        !          2728:     char c; int x; char *p;
        !          2729:     if (wildxpand) {
        !          2730:        if ((x = zxpand(filespec)) > 1) return(1);
        !          2731:        p = malloc(MAXNAMLEN + 20);
        !          2732:        znext(p);
        !          2733:        x = (strcmp(filespec,p) != 0);
        !          2734:        free(p);
        !          2735:        return(x);
        !          2736:     } else {
        !          2737:        while ((c = *filespec++) != '\0')
        !          2738:          if (c == '*' || c == '?') return(1);
        !          2739:        return(0);
        !          2740:     }
        !          2741: }
        !          2742: 
        !          2743: #ifdef OS2
        !          2744: 
        !          2745: /*  Z C H D S K  --  Change currently selected disk device */
        !          2746: 
        !          2747: /* Returns -1 if error, otherwise 0 */
        !          2748: 
        !          2749: zchdsk(c) char c; {
        !          2750:     int i = toupper(c) - 64;
        !          2751:     return( _chdrive(i) ? 0 : -1 );
        !          2752: }
        !          2753: 
        !          2754: #undef stat
        !          2755: 
        !          2756: os2stat(char *path, struct stat *st) {
        !          2757:     char local[MAXPATHLEN];
        !          2758:     int len;
        !          2759: 
        !          2760:     strcpy(local, path);
        !          2761:     len = strlen(local);
        !          2762: 
        !          2763:     if ( len == 2 && local[1] == ':' )
        !          2764:         local[2] = DIRSEP, local[3] = 0; /* if drive only, append / */
        !          2765:     else if ( len == 0 )
        !          2766:         local[0] = DIRSEP, local[1] = 0; /* if empty path, take / instead */
        !          2767:     else if ( len > 1 && ISDIRSEP(local[len - 1]) && local[len - 2] != ':' )
        !          2768:         local[len - 1] = 0; /* strip trailing / except after d: */
        !          2769: 
        !          2770:     return stat(local, st);
        !          2771: }
        !          2772: 
        !          2773: #endif /* OS2 */

unix.superglobalmegacorp.com

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