# 2.11BSD#431 - /usr/src/new/kermit5.188/ckufio.c

##### Functions

    chkfn             X
    iswild            X
    os2stat           X
    shxpand           X
    splitpath         X
    tilde_expand      X
    zchdir            X
    zchdsk            X
    zchin             X
    zchki             X
    zchko             X
    zchkspa           X
    zchout            X
    zclose            X
    zclosf            X
    zdelet            X
    zfcdat            X
    zgtdir            X
    zhome             X
    zinfill           X
    zkermini          X
    zkself            X
    zltor             X
    zmail             X
    znewn             X
    znext             X
    zopeni            X
    zopeno            X
    zoutdump          X
    zprint            X
    zrename           X
    zrtol             X
    zsattr            X
    zshcmd            X
    zsinl             X
    zsout             X
    zsoutl            X
    zsoutx            X
    zstime            X
    zstrip            X
    zsyscmd           X
    zxcmd             X
    zxpand            X

##### Variables

    DELCMD            X
    DIRCM2            X
    DIRCMD            X
    PWDCMD            X
    SPACM2            X
    SPACMD            X
    TYPCMD            X
    WHOCMD            X
    ckzsys            X
    ckzv              X
    ispipe            X
    maxnam            X
    maxpath           X
    mtchptr           X
    mtchs             X
    out               X
    pipes             X

##### Macros

    BSD4              X
    BSD42             X
    BUFLEN            X
    CWDBL             X
    DCLPOPEN          X
    DIRENT            X
    DIRSEP            X
    ISDIRSEP          X
    LONGFN            X
    MAXNAMLEN         X
    MAXPATH           X
    MAXWLD            X
    NAMEENV           X
    NOFILEH           X
    OPENDIR           X
    O_RDONLY          X
    R_OK              X
    SPOOLER           X
    SSPACE            X
    S_ISDIR           X
    S_ISREG           X
    TIMESTAMP         X
    WHOLEN            X
    W_OK              X
    ZNEWNBL           X
    ZNEWNMD           X
    fopen             X
    leap              X
    nleap             X
    pclose            X
    popen             X
    stat              X

##### struct's

    path              X
    utimbuf           X

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

#### Defined functions

addresult defined in line 2627; used 2 times

- in line 470, 2528

chkfn defined in line 935; used 14 times

- in line 587, 646, 694, 755, 838, 862, 1311, 1327
- in /usr/src/new/kermit5.188/ckuus5.c line 1566
- in /usr/src/new/kermit5.188/ckuus6.c line 269, 1039, 1061, 1077, 1105

fgen defined in line 2378; used 3 times

- in line 468, 1507, 1524

iswild defined in line 2968; used 6 times

- in line 2531
- in /usr/src/new/kermit5.188/ckcfns.c line 1003
- in /usr/src/new/kermit5.188/ckucmd.c line 638, 723, 1018
- in /usr/src/new/kermit5.188/ckuusy.c line 180

match defined in line 2658; used 8 times

- in line 471, 2566, 2576-2590(6)

os2stat defined in line 2999; used 2 times

- in line 169-170(2)

shxpand defined in line 2210; used 3 times

- in line 467, 1504, 1521

splitpath defined in line 2297; used 3 times

- in line 475, 2408-2411(2)

tilde_expand defined in line 2773; used 14 times

- in line 297, 1213, 1239, 1497
- in /usr/src/new/kermit5.188/ckcfns.c line 1092, 1101
- in /usr/src/new/kermit5.188/ckucmd.c line 633, 675, 716, 795, 893, 965, 1005, 1014

traverse defined in line 2485; used 4 times

- in line 469, 2440, 2543, 2607

whoami defined in line 2715; used 2 times

- in line 472, 2801

xindex defined in line 2950; used 6 times

- in line 473, 1156-1157(2), 2387-2389(3)

zchdir defined in line 1202; used 2 times

- in /usr/src/new/kermit5.188/ckcfns.c line 1902
- in /usr/src/new/kermit5.188/ckuus5.c line 3715

zchdsk defined in line 2992; used 1 times

- in line 1225

zchin defined in line 721; used 1 times

- in line 764

zchki defined in line 976; used 11 times

- in line 2231
- in /usr/src/new/kermit5.188/ckcfns.c line 1135, 1149, 1819
- in /usr/src/new/kermit5.188/ckcmai.c line 829
- in /usr/src/new/kermit5.188/ckucmd.c line 752
- in /usr/src/new/kermit5.188/ckuus6.c line 731, 1602
- in /usr/src/new/kermit5.188/ckuusy.c line 38, 67, 177

zchko defined in line 1021; used 1 times

- in /usr/src/new/kermit5.188/ckucmd.c line 642

zchkspa defined in line 1554; used 2 times

- in /usr/src/new/kermit5.188/ckcfn3.c line 1033-1038(2)

zchout defined in line 873; used 11 times

- in /usr/src/new/kermit5.188/ckcfns.c line 293
- in /usr/src/new/kermit5.188/ckcnet.c line 1076-1077(2), 1092, 1154
- in /usr/src/new/kermit5.188/ckucon.c line 1328
- in /usr/src/new/kermit5.188/ckuscr.c line 216, 276
- in /usr/src/new/kermit5.188/ckuus4.c line 804, 1646
- in /usr/src/new/kermit5.188/ckuus5.c line 1110

zclose defined in line 691; used 26 times

- in /usr/src/new/kermit5.188/ckcfn3.c line 1372, 1407
- in /usr/src/new/kermit5.188/ckuus4.c line 636, 718, 817-818(2), 894, 916, 945, 966
- in /usr/src/new/kermit5.188/ckuus5.c line 1530, 1540, 1549, 1559, 1568
- in /usr/src/new/kermit5.188/ckuus6.c line 277
- in /usr/src/new/kermit5.188/ckuusx.c line 540-541(2), 605-606(2), 1165, 1171-1176(2), 1183, 1189-1190(2)

zclosf defined in line 1441; used 2 times

- in line 703, 2246

zdelet defined in line 1082; used 4 times

- in /usr/src/new/kermit5.188/ckcfn3.c line 1412
- in /usr/src/new/kermit5.188/ckcfns.c line 1258, 1265
- in /usr/src/new/kermit5.188/ckuus6.c line 727

zfcdat defined in line 1769; used 1 times

- in line 1725

zgtdir defined in line 1275; used 5 times

- in /usr/src/new/kermit5.188/ckcfns.c line 1897, 1903
- in /usr/src/new/kermit5.188/ckuus4.c line 2259
- in /usr/src/new/kermit5.188/ckuus5.c line 3720
- in /usr/src/new/kermit5.188/ckuusx.c line 1881

zhome defined in line 1251; used 4 times

- in line 1208
- in /usr/src/new/kermit5.188/ckuus4.c line 2351-2354(2)
- in /usr/src/new/kermit5.188/ckuus5.c line 424

zinfill defined in line 803; used 1 times

- in /usr/src/new/kermit5.188/ckcker.h line 196

zkermini defined in line 2102; used 2 times

- in /usr/src/new/kermit5.188/ckuus5.c line 474-477(2)

zkself defined in line 544; never used
zltor defined in line 1147; used 1 times

- in /usr/src/new/kermit5.188/ckcfns.c line 1307

zmail defined in line 2110; used 1 times

- in /usr/src/new/kermit5.188/ckcfns.c line 1254

znewn defined in line 1588; used 3 times

- in /usr/src/new/kermit5.188/ckcfns.c line 1136, 1159, 1172

znext defined in line 1539; used 7 times

- in line 1673, 2975
- in /usr/src/new/kermit5.188/ckcfns.c line 1787, 1807
- in /usr/src/new/kermit5.188/ckucmd.c line 751, 922
- in /usr/src/new/kermit5.188/ckuus4.c line 1970

zopeni defined in line 583; used 6 times

- in /usr/src/new/kermit5.188/ckcfn3.c line 1288, 1294
- in /usr/src/new/kermit5.188/ckuus4.c line 421, 665, 749
- in /usr/src/new/kermit5.188/ckuus6.c line 1056

zopeno defined in line 625; used 13 times

- in /usr/src/new/kermit5.188/ckcfn3.c line 1317, 1334, 1357
- in /usr/src/new/kermit5.188/ckuus4.c line 764, 900-901(2), 922-923(2), 951-952(2), 972-973(2)
- in /usr/src/new/kermit5.188/ckuus6.c line 1115

zoutdump defined in line 897; used 2 times

- in line 697
- in /usr/src/new/kermit5.188/ckcker.h line 203

zprint defined in line 2152; used 2 times

- in /usr/src/new/kermit5.188/ckcfns.c line 1260
- in /usr/src/new/kermit5.188/ckuusr.c line 1293

zrename defined in line 1691; used 2 times

- in /usr/src/new/kermit5.188/ckcfns.c line 1162
- in /usr/src/new/kermit5.188/ckuus6.c line 967

zrtol defined in line 1092; used 3 times

- in line 1518
- in /usr/src/new/kermit5.188/ckcfn3.c line 1293
- in /usr/src/new/kermit5.188/ckcfns.c line 1127

zsattr defined in line 1715; used 1 times

- in /usr/src/new/kermit5.188/ckcfn3.c line 644

zshcmd defined in line 2866; used 3 times

- in /usr/src/new/kermit5.188/ckucon.c line 1281
- in /usr/src/new/kermit5.188/ckuusr.c line 915, 1706

zsinl defined in line 751; used 1 times

- in /usr/src/new/kermit5.188/ckuus6.c line 274

zsout defined in line 836; used 28 times

- in /usr/src/new/kermit5.188/ckcfn2.c line 1515
- in /usr/src/new/kermit5.188/ckcfn3.c line 556, 569, 575, 608, 614, 620
- in /usr/src/new/kermit5.188/ckuscr.c line 255, 262, 270, 392
- in /usr/src/new/kermit5.188/ckuusr.c line 2022
- in /usr/src/new/kermit5.188/ckuusx.c line 1347-1351(2), 1357, 1363, 1372, 1378, 1384-1388(2), 1414-1418(2), 1426, 1434, 1443, 1451, 1459-1463(2)

zsoutl defined in line 849; used 7 times

- in /usr/src/new/kermit5.188/ckcfn2.c line 1516
- in /usr/src/new/kermit5.188/ckcfn3.c line 534-539(2), 587-591(2)
- in /usr/src/new/kermit5.188/ckuusx.c line 1366, 1437

zsoutx defined in line 859; used 1 times

- in /usr/src/new/kermit5.188/ckucon.c line 998

zstime defined in line 1840; used 2 times

- in /usr/src/new/kermit5.188/ckcfn3.c line 894
- in /usr/src/new/kermit5.188/ckcfns.c line 1245

zstrip defined in line 1126; used 2 times

- in /usr/src/new/kermit5.188/ckcfn3.c line 1275, 1326

zsyscmd defined in line 2828; used 12 times

- in line 2138-2142(2), 2157, 2184
- in /usr/src/new/kermit5.188/ckutio.c line 1337, 2502, 5773, 5784
- in /usr/src/new/kermit5.188/ckuus5.c line 2707, 3723
- in /usr/src/new/kermit5.188/ckuus6.c line 212
- in /usr/src/new/kermit5.188/ckuusr.c line 214

zxcmd defined in line 1308; used 5 times

- in line 597, 2222
- in /usr/src/new/kermit5.188/ckcfns.c line 1931
- in /usr/src/new/kermit5.188/ckuus6.c line 1074, 1090

zxpand defined in line 1487; used 10 times

- in line 1627, 1671, 2972
- in /usr/src/new/kermit5.188/ckcfns.c line 1784
- in /usr/src/new/kermit5.188/ckucmd.c line 734, 753, 811, 910
- in /usr/src/new/kermit5.188/ckuus4.c line 1961
- in /usr/src/new/kermit5.188/ckuusy.c line 180

#### Defined variables

DELCMD defined in line 253; used 1 times

- in /usr/src/new/kermit5.188/ckuus6.c line 718

DIRCM2 defined in line 260; never used
DIRCMD defined in line 259; used 2 times

- in /usr/src/new/kermit5.188/ckuus6.c line 604, 627

PWDCMD defined in line 254; used 3 times

- in /usr/src/new/kermit5.188/ckuus5.c line 2707, 3723
- in /usr/src/new/kermit5.188/ckuusr.c line 1304

SPACM2 defined in line 278; used 1 times

- in /usr/src/new/kermit5.188/ckuusr.c line 1761

SPACMD defined in line 274; used 3 times

- in /usr/src/new/kermit5.188/ckuusr.c line 1726, 1759, 1766

TYPCMD defined in line 262; used 1 times

- in /usr/src/new/kermit5.188/ckuusr.c line 1868

WHOCMD defined in line 290; used 2 times

- in /usr/src/new/kermit5.188/ckuusr.c line 1965-1968(2)

bslash defined in line 2268; used 11 times

- in line 1153-1160(3), 1171, 2321-2329(4), 2388-2391(2), 2398

ckzsys defined in line 214; used 2 times

- in /usr/src/new/kermit5.188/ckuus5.c line 1593(2)

ckzv defined in line 7; used 2 times

- in /usr/src/new/kermit5.188/ckuus5.c line 1593(2)

cwdbuf defined in line 1273; used 4 times

- in line 1281-1296(4)

datbuf defined in line 1766; used 6 times

- in line 1777, 1801, 1817-1820(4)

fcount defined in line 517; used 16 times

- in line 1504-1515(7), 1521-1530(6), 1541-1544(3)

freeptr defined in line 2282; used 5 times

- in line 2437, 2637-2643(4)

iflen defined in line 514; used 8 times

- in line 708, 1009-1012(4), 1719-1721(2), 1756

ispipe defined in line 499; used 3 times

- in line 1321, 1447-1451(2)

lscmd defined in line 2207; used 2 times

- in line 2216-2221(2)

maxnam defined in line 493; used 1 times

- in /usr/src/new/kermit5.188/ckuus4.c line 1301

maxpath defined in line 494; used 1 times

- in /usr/src/new/kermit5.188/ckuus4.c line 1323

monlens defined in line 159; never used
mtchptr defined in line 525; used 4 times

- in line 1509, 1526, 1541, 1630

mtchs defined in line 524; used 8 times

- in line 1504-1512(4), 1521-1527(4)

nambuf defined in line 518; used 15 times

- in line 594, 1010, 1724-1725(2), 2563-2566(3), 2576-2590(6), 2604-2605(2)

numfnd defined in line 2284; used 5 times

- in line 2421, 2457, 2633-2638(2), 2644

oldmtchs defined in line 2203; used 2 times

- in line 2217, 2247

out defined in line 1325; used 3 times

- in line 1331-1335(2), 1422

pipes defined in line 1324; used 11 times

- in line 1359, 1381-1395(6), 1423-1430(4)

remlen defined in line 2283; used 3 times

- in line 2439, 2630-2632(2)

resptr defined in line 2282; used 2 times

- in line 2438, 2642

scratch defined in line 2200; used 10 times

- in line 2224, 2230, 2236, 2394, 2404-2406(3), 2412, 2418, 2440

sspace defined in line 2278; used 4 times

- in line 2423-2425(2), 2437, 2637

ssplen defined in line 2280; used 8 times

- in line 2424-2431(7), 2637

work defined in line 1123; used 7 times

- in line 1130, 1136-1141(2), 1165, 1177, 1187-1188(2)

zmbuf defined in line 520; used 12 times

- in line 2130-2144(7), 2156-2157(2), 2183-2186(3)

#### Defined struct's

path defined in line 463; used 22 times

- in line 465-469(4), 475(2), 2297-2299(4), 2307-2311(6), 2380(2), 2452(2), 2486(2)

utimbuf defined in line 1890; used 3 times

- in line 1874, 1888(2)

#### Defined macros

BSD4 defined in line 281; used 8 times

- in line 130, 222, 233, 265-268(2), 287, 1294, 2119

BSD42 defined in line 235; used 2 times

- in line 431, 2497

BUFLEN defined in line 2779; used 3 times

- in line 2782-2784(3)

CWDBL defined in line 1270; used 3 times

- in line 1273, 1287-1292(2)

DCLPOPEN defined in line 1343; used 1 times

- in line 1346

DIRENT defined in line 85; used 2 times

- in line 76, 2507

DIRSEP defined in line 59; used 6 times

- in line 2415, 2541, 2606, 2915, 3007-3009(2)

ISDIRSEP defined in line 60; used 14 times

- in line 1046, 1135, 1174, 1655, 2305, 2336-2345(3), 2351-2352(2), 2413, 2631, 2796, 3010

LONGFN defined in line 2499; used 3 times

- in line 2492, 2498, 2513

MAXNAMLEN defined in line 408; used 15 times

- in line 234, 389, 464, 493, 518, 1010, 1605, 2325-2328(2), 2336, 2345-2350(2), 2563-2564(2), 2974

MAXPATH defined in line 434; used 4 times

- in line 420-421(2), 494, 2200

MAXWLD defined in line 451; used 5 times

- in line 524, 1504-1507(2), 1521-1524(2)

NAMEENV defined in line 227; used 1 times

- in line 2736

NOFILEH defined in line 316; used 1 times

- in line 319

OPENDIR defined in line 2514; used 2 times

- in line 2554, 2610

O_RDONLY defined in line 488; used 2 times

- in line 487, 2558

R_OK defined in line 480; used 2 times

- in line 479, 1001

SPOOLER defined in line 2174; used 1 times

- in line 2183

SSPACE defined in line 2277; used 2 times

- in line 2275-2280(2)

S_ISDIR defined in line 384; used 5 times

- in line 367-377(3), 383, 2552

S_ISREG defined in line 381; used 5 times

- in line 366-380(4), 992

TIMESTAMP defined in line 141; used 2 times

- in line 1772, 1846

WHOLEN defined in line 2721; never used
W_OK defined in line 484; used 2 times

- in line 483, 1067

ZNEWNBL defined in line 1594; used 4 times

- in line 1598, 1608-1613(3)

ZNEWNMD defined in line 1595; used 1 times

- in line 1616

fopen defined in line 110; used 3 times

- in line 614-617(2), 669

leap defined in line 152; never used
nleap defined in line 155; never used
pclose defined in line 108; used 3 times

- in line 104, 1449, 1455

popen defined in line 107; used 5 times

- in line 103, 1315-1318(2), 1348-1351(2)

stat defined in line 170; used 8 times

- in line 987, 1778, 1852, 2044, 2535, 2551, 2997, 3013

Last modified: 1992-11-24 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 7798 |