Annotation of coherent/e/bin/ckermit/ckufio.c, revision 1.1.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.