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
chkfn defined in line 935; used 14 times
fgen defined in line 2378; used 3 times
match defined in line 2658; used 8 times
os2stat defined in line 2999; used 2 times
shxpand defined in line 2210; used 3 times
splitpath defined in line 2297; used 3 times
traverse defined in line 2485; used 4 times
whoami defined in line 2715; used 2 times
xindex defined in line 2950; used 6 times
zchdsk defined in line 2992; used 1 times
zchin defined in line 721; used 1 times
zchko defined in line 1021; used 1 times
zchkspa defined in line 1554; used 2 times
zclosf defined in line 1441; used 2 times
zfcdat defined in line 1769; used 1 times
zhome defined in line 1251; used 4 times
zinfill defined in line 803; used 1 times
zkermini defined in line 2102; used 2 times
zkself defined in line 544; never used
zltor defined in line 1147; used 1 times
zmail defined in line 2110; used 1 times
znewn defined in line 1588; used 3 times
zoutdump defined in line 897; used 2 times
zrtol defined in line 1092; used 3 times
zsattr defined in line 1715; used 1 times
zsinl defined in line 751; used 1 times
zsoutx defined in line 859; used 1 times
zstrip defined in line 1126; used 2 times
zxcmd defined in line 1308; used 5 times

Defined variables

DELCMD defined in line 253; used 1 times
DIRCM2 defined in line 260; never used
DIRCMD defined in line 259; used 2 times
SPACM2 defined in line 278; used 1 times
SPACMD defined in line 274; used 3 times
TYPCMD defined in line 262; used 1 times
WHOCMD defined in line 290; used 2 times
bslash defined in line 2268; used 11 times
ckzsys defined in line 214; used 2 times
ckzv defined in line 7; used 2 times
cwdbuf defined in line 1273; used 4 times
datbuf defined in line 1766; used 6 times
fcount defined in line 517; used 16 times
freeptr defined in line 2282; used 5 times
iflen defined in line 514; used 8 times
ispipe defined in line 499; used 3 times
lscmd defined in line 2207; used 2 times
maxnam defined in line 493; used 1 times
maxpath defined in line 494; used 1 times
monlens defined in line 159; never used
mtchptr defined in line 525; used 4 times
mtchs defined in line 524; used 8 times
nambuf defined in line 518; used 15 times
numfnd defined in line 2284; used 5 times
oldmtchs defined in line 2203; used 2 times
out defined in line 1325; used 3 times
pipes defined in line 1324; used 11 times
remlen defined in line 2283; used 3 times
resptr defined in line 2282; used 2 times
scratch defined in line 2200; used 10 times
sspace defined in line 2278; used 4 times
ssplen defined in line 2280; used 8 times
work defined in line 1123; used 7 times
zmbuf defined in line 520; used 12 times

Defined struct's

path defined in line 463; used 22 times
utimbuf defined in line 1890; used 3 times

Defined macros

BSD4 defined in line 281; used 8 times
BSD42 defined in line 235; used 2 times
BUFLEN defined in line 2779; used 3 times
CWDBL defined in line 1270; used 3 times
DCLPOPEN defined in line 1343; used 1 times
DIRENT defined in line 85; used 2 times
DIRSEP defined in line 59; used 6 times
ISDIRSEP defined in line 60; used 14 times
LONGFN defined in line 2499; used 3 times
MAXNAMLEN defined in line 408; used 15 times
MAXPATH defined in line 434; used 4 times
MAXWLD defined in line 451; used 5 times
NAMEENV defined in line 227; used 1 times
NOFILEH defined in line 316; used 1 times
OPENDIR defined in line 2514; used 2 times
O_RDONLY defined in line 488; used 2 times
R_OK defined in line 480; used 2 times
SPOOLER defined in line 2174; used 1 times
SSPACE defined in line 2277; used 2 times
S_ISDIR defined in line 384; used 5 times
S_ISREG defined in line 381; used 5 times
TIMESTAMP defined in line 141; used 2 times
WHOLEN defined in line 2721; never used
W_OK defined in line 484; used 2 times
ZNEWNBL defined in line 1594; used 4 times
ZNEWNMD defined in line 1595; used 1 times
fopen defined in line 110; used 3 times
leap defined in line 152; never used
nleap defined in line 155; never used
pclose defined in line 108; used 3 times
popen defined in line 107; used 5 times
stat defined in line 170; used 8 times
Last modified: 1992-11-24
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 14963
Valid CSS Valid XHTML 1.0 Strict