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

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

unix.superglobalmegacorp.com

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