home *** CD-ROM | disk | FTP | other *** search
/ Windows NT Super Tune-Up Kit / PIE-WindowsNTSuperTuneUpKit-1997.iso / COMPRESS / NTZIP201 / FILEIO.C < prev    next >
C/C++ Source or Header  |  1994-05-13  |  69KB  |  2,512 lines

  1. /*
  2.  
  3.  Copyright (C) 1990-1993 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  4.  Kai Uwe Rommel and Igor Mandrichenko.
  5.  Permission is granted to any individual or institution to use, copy, or
  6.  redistribute this software so long as all of the original files are included,
  7.  that it is not sold for profit, and that this copyright notice is retained.
  8.  
  9. */
  10.  
  11. /*
  12.  *  fileio.c by Mark Adler.
  13.  *
  14.  *  This file has become a big mess over time, and will be split in the
  15.  *  next version, one file per operating system.
  16.  */
  17.  
  18. #include "zip.h"
  19.  
  20. #include <time.h>
  21.  
  22. #ifdef WIN32
  23. #  include <sys/utime.h>
  24. #  include <windows.h> /* for findfirst/findnext */
  25.    char *GetLongPathEA OF((char *name));
  26. #endif
  27.  
  28. #ifdef MACOS
  29. #  define EXDEV 1
  30. #endif
  31.  
  32. #ifdef OSF
  33. #  define EXDEV 18    /* avoid a bug in the DEC OSF/1 header files. */
  34. #else
  35. #  include <errno.h>
  36. #endif
  37.  
  38. #ifdef MINIX
  39. #  ifdef S_IWRITE
  40. #    undef S_IWRITE
  41. #  endif /* S_IWRITE */
  42. #  define S_IWRITE S_IWUSR
  43. #endif /* S_IWUSR */
  44.  
  45. #ifdef ATARI_ST
  46. #  undef MSDOS
  47. #endif
  48.  
  49. #if defined(MSDOS) && !defined(__GO32__)
  50. #  include <io.h>
  51. #  ifdef __TURBOC__
  52. #    include <dir.h>
  53. #  else /* !__TURBOC__ */
  54. #    if !defined(__EMX__) && !defined(__WATCOMC__)
  55. #      include <direct.h>
  56. #    endif
  57. #  endif /* ?__TURBOC__ */
  58. #  define link rename
  59. // lgk bug here because for win32 we want to use dosmatch so that we can zip *.
  60. //#  if defined(OS2) || defined(WIN32)
  61. #if defined(OS2)
  62. #    define MATCH shmatch
  63. #  else
  64. #    define MATCH dosmatch
  65. #  endif
  66. #else /* !MSDOS */
  67.    extern int errno;    /* error number from system functions */
  68. #  ifdef TOPS20
  69. #    define PATH_START '<'
  70. #    define PATH_END   '>'
  71. #    define link rename
  72. #  endif
  73. #  ifdef VMS
  74. #    define PATH_START '['
  75. #    define PATH_END ']'
  76. #    define RMDIR
  77. #    define link rename
  78. #    include "VMSmunch.h"
  79. #  endif /* VMS */
  80. #  ifdef MACOS
  81. #    define link rename
  82. #    define mktemp tmpnam
  83. #  endif
  84. #  define MATCH shmatch
  85. #endif /* ?MSDOS */
  86.  
  87. #ifdef ATARI_ST
  88. #  define MSDOS 1
  89. #endif
  90.  
  91. #ifdef UTS
  92. #  define RMDIR
  93. #endif /* UTS */
  94.  
  95. #ifdef AMIGA
  96. #  define link rename
  97. #  define utime FileDate
  98. #  ifdef __SASC_60
  99. #    include <dos.h>               /* SAS/C 6.x , pulled by wild() */
  100. #    include <sys/dir.h>
  101. #    define direct dirent
  102. #    define disk_not_mounted 0  
  103. #  else
  104. #    define dirent direct
  105. #  endif
  106. #  ifdef MODERN
  107. #    include <clib/exec_protos.h>
  108. #    include <clib/dos_protos.h>
  109. #  endif
  110. #  ifdef AZTEC_C
  111. #    include <pragmas/exec_lib.h>
  112. #    include <pragmas/dos_lib.h>
  113. #  endif
  114. #endif 
  115.  
  116. #ifdef __human68k__
  117. #  include <jctype.h>
  118. #  define link rename
  119. #endif
  120.  
  121. /* Extra malloc() space in names for cutpath() */
  122. #if (defined(VMS) || defined(TOPS20))
  123. #  define PAD 5         /* may have to change .FOO] to ]FOO.DIR;1 */
  124. #else
  125. #  define PAD 0
  126. #  define PATH_END '/'
  127. #endif
  128.  
  129.  
  130. #ifdef VMS
  131. #  include <descrip.h>
  132. #  include <rms.h>
  133. #endif
  134.  
  135. /* For directory access. */
  136.  
  137. #ifndef UTIL
  138.  
  139. #ifdef __human68k__
  140. #include <sys/dos.h>
  141. #endif
  142.  
  143. #if defined(SYSV) || defined(__GO32__) || defined(__386BSD__) || defined(__human68k__)
  144. /* use readdir() */
  145. #  include <dirent.h>
  146. #  define dstrm DIR
  147. #  define direct dirent
  148. #else /* !SYSV && !__GO32__ && !__386BSD__ && !__human68k__*/
  149.  
  150. #ifdef DIRENT                   /* use getdents() */
  151. #ifndef TOPS20
  152. #  if defined(MINIX) || defined(OSF)
  153. #    include <dirent.h>
  154. #  else /* !MINIX */
  155. #    include <sys/dirent.h>
  156. #  endif /* ?MINIX */
  157. #  define direct dirent
  158. #  ifdef MINIX
  159.      int getdents OF((int, char *, unsigned));
  160. #  else /* !MINIX */
  161.      int getdents OF((int, char *, int));
  162. #  endif /* ?MINIX */
  163. #  define DBSZ 4096     /* This has to be bigger than a directory block */
  164.    typedef struct {     /* directory stream buffer */
  165.      int f;             /* file descriptor for the directory "file" */
  166.      char *p;           /* pointer to next entry in buffer */
  167.      char *q;           /* pointer after end of buffer contents */
  168.      char b[DBSZ];              /* buffer */
  169.    } dstrm;
  170.  
  171. #else /* TOPS20 */
  172. #  define TRUE 1
  173. #  define FALSE 0
  174. #  define O_RDONLY (0)
  175. #  define O_T20_WILD (1<<18)
  176. #  include <monsym.h>    /* Get amazing monsym() macro */
  177.    extern int jsys(), fstat();
  178.    extern char *getcwd();
  179.    extern int _gtjfn(), _rljfn();
  180. #  define JSYS_CLASS    0070000000000
  181. #  define FLD(val,mask) (((unsigned)(val)*((mask)&(-(mask))))&(mask))
  182. #  define _DEFJS(name,class) (FLD(class, JSYS_CLASS) | (monsym(name)&0777777))
  183. #  define JFNS  _DEFJS("JFNS%", 1)
  184. #  define GNJFN _DEFJS("GNJFN%", 0)
  185.    static int wfopen(), wfnext(), strlower(), strupper();
  186.    static char *wfname();
  187.    typedef struct {
  188.      int  wfjfn;
  189.      int  more;
  190.    } dstrm;
  191. #endif /* ?TOPS20 */
  192.  
  193. #else /* !DIRENT */             /* use opendir(), etc. */
  194. #  if defined(CONVEX) || defined(ultrix)
  195. #    include <dirent.h>
  196. #    ifdef direct
  197. #      undef direct /* ultrix 4.2, at least if !__POSIX */
  198. #    endif
  199. #    define direct dirent
  200. #  endif /* CONVEX || ultrix */
  201. #  ifdef NDIR
  202. #    include "ndir.h"           /* for HPUX */
  203. #  else /* !NDIR */
  204. #    ifdef MSDOS
  205. #     ifdef OS2
  206. #      include "os2zip.h"
  207. #     else /* !OS2 */
  208. #      ifdef WIN32
  209. #        include "ntzip.h"
  210. #      endif
  211. #      ifndef ATARI_ST
  212. #        include <dos.h>
  213. #      endif
  214. #      ifdef __TURBOC__
  215. #        define FATTR (hidden_files ? FA_HIDDEN+FA_SYSTEM+FA_DIREC : FA_DIREC)
  216. #        define FFIRST(n,d,a)   findfirst(n,(struct ffblk *)d,a)
  217. #        define FNEXT(d)        findnext((struct ffblk *)d)
  218. #      else /* !__TURBOC__ */
  219. #        define FATTR (hidden_files ? _A_HIDDEN+_A_SYSTEM+_A_SUBDIR :_A_SUBDIR)
  220. #        define FA_LABEL _A_VOLID
  221. #        define FFIRST(n,d,a)   _dos_findfirst(n,a,(struct find_t *)d)
  222. #        define FNEXT(d)        _dos_findnext((struct find_t *)d)
  223. #      endif /* ?__TURBOC__ */
  224.        typedef struct direct {
  225.          char   reserved [21];
  226.          char   ff_attrib;
  227.          short  ff_ftime;
  228.          short  ff_fdate;
  229.          long   size;
  230. #      ifndef WIN32
  231.          char d_name[13];
  232.          int d_first;
  233. #      else
  234.          char d_name[MAX_PATH];
  235.          int d_first;
  236.          HANDLE d_hFindFile;
  237. #      endif /* WIN32 */
  238.        } DIR;
  239.        typedef DIR ff_dir;
  240. #      define ff_name d_name /* ff_name is used by DJGPP */
  241. #     endif /* ?OS2 */
  242. #    else /* !MSDOS */
  243. #      ifdef VMS
  244. #        include <ssdef.h>
  245.          typedef struct direct {
  246.              int d_wild;                /* flag for wildcard vs. non-wild */
  247.              struct FAB fab;
  248.              struct NAM nam;
  249.              char d_qualwildname[NAM$C_MAXRSS + 1];
  250.              char d_name[NAM$C_MAXRSS + 1];
  251.          } DIR;
  252. #      else /* !VMS */
  253. #        ifdef MACOS
  254.            typedef struct direct {
  255.              int d_wild;                /* flag for wildcard vs. non-wild */
  256.              char *d_name;
  257.           } DIR;
  258. #        endif
  259. #        if defined(M_XENIX) || defined(SYSNDIR)
  260. #          include <sys/ndir.h>
  261. #        else /* !M_XENIX */
  262. #          ifndef AZTEC_C
  263. #            include <sys/dir.h>
  264. #          endif
  265. #        endif /* ?M_XENIX */
  266. #        ifdef NODIR                    /* for AT&T 3B1 + Amiga non SAS */
  267. #          define dirent direct
  268.            typedef FILE DIR;
  269. #        endif /* NODIR */
  270. #      endif /* ?VMS */
  271. #    endif /* ?MSDOS */
  272. #  endif /* ?NDIR */
  273. #  define dstrm DIR
  274. #  if defined(MSDOS) && !defined(OS2)
  275. #    ifndef __GO32__
  276.        DIR *opendir OF((const char *));
  277.        struct direct *readdir OF((DIR *));
  278. #    endif
  279. #    ifndef WIN32
  280.        char *getVolumeLabel OF((int drive, ulg *vtime, ulg *vmode));
  281. #    endif
  282. #  endif
  283. #endif /* ?DIRENT */
  284. #endif /* ?SYSV */
  285. #endif /* !UTIL */
  286.  
  287. #ifdef __GO32__
  288.    typedef struct ffblk ff_dir;
  289. #  define FFIRST(n,d,a)   findfirst(n,(struct ffblk *)d,a)
  290. #endif
  291.  
  292. #define MSDOS_DIR_ATTR 0x10
  293.  
  294. /* Library functions not in (most) header files */
  295.  
  296. #ifdef TOPS20
  297.    extern int stat(), chmod(), toupper(), tolower();
  298. #endif
  299.  
  300. #if defined(__IBMC__) || defined(__WATCOMC__)
  301. #  define NO_MKTEMP
  302. #endif
  303. char *mktemp OF((char *));
  304.  
  305. #ifdef __GO32__
  306. #  include <dos.h>
  307. #else
  308.   /* int link OF((const char *, const char *)); */
  309.   /* int unlink OF((const char *)); */
  310.   /* int chmod OF((const char *, int)); */
  311.   /* For many targets, chmod is already defined by sys/stat.h, and second
  312.    * parameter is an unsigned long.
  313.    */
  314. #endif
  315.  
  316.  
  317. #ifndef UTIL    /* the companion #endif is a bit of ways down ... */
  318.  
  319. #if !defined(__TURBOC__) && !defined(WIN32) && !defined(sgi)
  320.    int utime OF((char *, time_t *));
  321. #endif
  322. #ifndef MSDOS
  323.    /* int open OF((char *, int, ...)); */
  324.    /* int close OF((int)); */
  325. #  ifndef RMDIR
  326.      /* int rmdir OF((const char *)); */
  327. #  endif /* !RMDIR */
  328. #endif /* !MSDOS */
  329.  
  330.  
  331. /* Local globals (kinda like "military intelligence" or "broadcast quality") */
  332. local struct stat zipstatb;
  333. local int zipstate = -1;
  334. /* -1 unknown, 0 old zip file exists, 1 new zip file */
  335.  
  336. local char *label = NULL;
  337. local ulg label_time = 0;
  338. local ulg label_mode = 0;
  339.  
  340. #ifdef VMS
  341.   typedef int statime;
  342. #else /* !VMS */
  343.   typedef time_t statime;
  344. #endif /* ?VMS */
  345.  
  346. /* Local functions */
  347. #ifdef PROTO
  348. #  ifdef VMS
  349.      local void vms_wild(char *, dstrm *);
  350. #  endif /* VMS */
  351. #  ifdef DIRENT
  352.      local dstrm *opend(char *);
  353.      local void closed(dstrm *);
  354. #  endif /* DIRENT */
  355.    local char *readd(dstrm *);
  356.    local int fqcmp(const voidp *, const voidp *);
  357.    local int fqcmpz(const voidp *, const voidp *);
  358.    local char *last(char *);
  359.    local char *msname(char *);
  360. #  ifdef VMS
  361.      local char *strlower(char *);
  362.      local char *strupper(char *);
  363. #  endif /* VMS */
  364.    local int newname(char *, int);
  365.    local void inctime(struct tm *);
  366.    local ulg unix2dostime(statime *);
  367. #  if !defined(__TURBOC__) && !defined(OS2) && !defined(__GO32__)
  368.      local int cmptime(struct tm *, struct tm *);
  369.      local time_t invlocal(struct tm *);
  370. #  endif /* !__TURBOC__ */
  371. #endif /* PROTO */
  372.  
  373.  
  374. #if defined(MSDOS) && !defined(OS2) && !defined(__GO32__)
  375. dstrm *opendir(n)
  376. const char *n;                /* directory to open */
  377. /* Start searching for files in the MSDOS directory n */
  378. {
  379.   dstrm *d;             /* malloc'd return value */
  380.   char *p;              /* malloc'd temporary string */
  381.  
  382.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
  383.       (p = malloc(strlen(n) + 5)) == NULL) {
  384.     if (d != NULL) free((void *) d);
  385.     return NULL;
  386.   }
  387.   strcat(strcpy(p, n), "/");
  388.   strcat(p, "*.*"); /* don't use strcat in one step, TOPS20 is confused */
  389.  
  390. #ifdef WIN32
  391.   {
  392.     WIN32_FIND_DATA fd;
  393.     DWORD dwAttr;
  394.  
  395.     if ( INVALID_HANDLE_VALUE == (d->d_hFindFile = FindFirstFile(p, &fd)))
  396.     {
  397.       free((voidp *)p);
  398.       return NULL;
  399.     }
  400.     strcpy(d->d_name, fd.cFileName);
  401.  
  402.     if (-1 != (dwAttr = GetFileAttributes(fd.cFileName)))
  403.     {
  404.       if (!hidden_files &&
  405.          (FILE_ATTRIBUTE_SYSTEM == (dwAttr & FILE_ATTRIBUTE_SYSTEM) ||
  406.           FILE_ATTRIBUTE_HIDDEN == (dwAttr & FILE_ATTRIBUTE_HIDDEN)))
  407.       {
  408.           free ((voidp *)p);
  409.           d->d_first = 0;
  410.           return d;
  411.       }
  412.     }
  413.   }
  414. #else
  415.   if (FFIRST(p, d, FATTR))
  416.   {
  417.     free((voidp *)p);
  418.     return NULL;
  419.   }
  420.   free((voidp *)p);
  421. #endif
  422.   d->d_first = 1;
  423.   return d;
  424. }
  425.  
  426. struct direct *readdir(d)
  427. dstrm *d;               /* directory stream to read from */
  428. /* Return pointer to first or next directory entry, or NULL if end. */
  429. {
  430.   if (d->d_first)
  431.     d->d_first = 0;
  432.   else
  433. #ifdef WIN32
  434.   {
  435.     WIN32_FIND_DATA fd;
  436.     DWORD dwAttr;
  437.  
  438.     if (!FindNextFile(d->d_hFindFile, &fd))
  439.         return NULL;
  440.  
  441.     strcpy(d->d_name, fd.cFileName);
  442.  
  443.     if (!hidden_files &&
  444.        (-1 != (dwAttr = GetFileAttributes(fd.cFileName))) &&
  445.        (FILE_ATTRIBUTE_SYSTEM == (dwAttr & FILE_ATTRIBUTE_SYSTEM) ||
  446.         FILE_ATTRIBUTE_HIDDEN == (dwAttr & FILE_ATTRIBUTE_HIDDEN)))
  447.     {
  448.         return (readdir(d));
  449.     }
  450.   }
  451. #else /* !WIN32 */
  452.     if (FNEXT(d))
  453.       return NULL;
  454. #endif
  455.   return (struct direct *)d;
  456.  
  457. }
  458. #ifdef WIN32
  459. void closedir(d)
  460. dstrm *d;
  461. {
  462.         FindClose(d->d_hFindFile);
  463.         free(d);
  464. }
  465. #else
  466. #  define closedir free
  467. #endif
  468.  
  469. #endif /* MSDOS && !OS2 && !__GO32__ */
  470.  
  471.  
  472. #ifdef VMS
  473.  
  474. /*---------------------------------------------------------------------------
  475.  
  476.     _vms_findfirst() and _vms_findnext(), based on public-domain DECUS C
  477.     fwild() and fnext() routines (originally written by Martin Minow, poss-
  478.     ibly modified by Jerry Leichter for bintnxvms.c), were written by Greg
  479.     Roelofs and are still in the public domain.  Routines approximate the
  480.     behavior of MS-DOS (MSC and Turbo C) findfirst and findnext functions.
  481.  
  482.   ---------------------------------------------------------------------------*/
  483.  
  484. static char wild_version_part[10]="\0";
  485.  
  486. local void vms_wild(p, d)
  487. char *p;
  488. dstrm *d;
  489. {
  490.   /*
  491.    * Do wildcard setup
  492.    */
  493.   /* set up the FAB and NAM blocks. */
  494.   d->fab = cc$rms_fab;             /* initialize fab */
  495.   d->nam = cc$rms_nam;             /* initialize nam */
  496.  
  497.   d->fab.fab$l_nam = &d->nam;           /* fab -> nam */
  498.   d->fab.fab$l_fna = p;                 /* argument wild name */
  499.   d->fab.fab$b_fns = strlen(p);         /* length */
  500.  
  501.   d->nam.nam$l_esa = d->d_qualwildname; /* qualified wild name */
  502.   d->nam.nam$b_ess = NAM$C_MAXRSS;      /* max length */
  503.   d->nam.nam$l_rsa = d->d_name;         /* matching file name */
  504.   d->nam.nam$b_rss = NAM$C_MAXRSS;      /* max length */
  505.  
  506.   /* parse the file name */
  507.   if (sys$parse(&d->fab) != RMS$_NORMAL)
  508.     return;
  509.   /* Does this replace d->fab.fab$l_fna with a new string in its own space?
  510.      I sure hope so, since p is free'ed before this routine returns. */
  511.  
  512.   /* have qualified wild name (i.e., disk:[dir.subdir]*.*); null-terminate
  513.    * and set wild-flag */
  514.   d->d_qualwildname[d->nam.nam$b_esl] = '\0';
  515.   d->d_wild = (d->nam.nam$l_fnb & NAM$M_WILDCARD)? 1 : 0;   /* not used... */
  516. #ifdef DEBUG
  517.   fprintf(mesg, "  incoming wildname:  %s\n", p);
  518.   fprintf(mesg, "  qualified wildname:  %s\n", d->d_qualwildname);
  519. #endif /* DEBUG */
  520. }
  521.  
  522. dstrm *opendir(n)
  523. char *n;                /* directory to open */
  524. /* Start searching for files in the VMS directory n */
  525. {
  526.   char *c;              /* scans VMS path */
  527.   dstrm *d;             /* malloc'd return value */
  528.   int m;                /* length of name */
  529.   char *p;              /* malloc'd temporary string */
  530.  
  531.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
  532.       (p = malloc((m = strlen(n)) + 4)) == NULL)
  533.     return NULL;
  534.   /* Directory may be in form "[DIR.SUB1.SUB2]" or "[DIR.SUB1]SUB2.DIR;1".
  535.      If latter, convert to former. */
  536.   if (m > 0  &&  *(c = strcpy(p,n)+m-1) != ']')
  537.   {
  538.     while (--c > p  &&  *c != ';')
  539.       ;
  540.     if (c-p < 5  ||  strncmp(c-4, ".DIR", 4))
  541.     {
  542.       free((voidp *)d);  free((voidp *)p);
  543.       return NULL;
  544.     }
  545.     c -= 3;
  546.     *c-- = '\0';        /* terminate at "DIR;#" */
  547.     *c = ']';           /* "." --> "]" */
  548.     while (c > p  &&  *--c != ']')
  549.       ;
  550.     *c = '.';           /* "]" --> "." */
  551.   }
  552.   strcat(p, "*.*");
  553.   strcat(p, wild_version_part);
  554.   vms_wild(p, d);       /* set up wildcard */
  555.   free((voidp *)p);
  556.   return d;
  557. }
  558.  
  559. struct direct *readdir(d)
  560. dstrm *d;               /* directory stream to read from */
  561. /* Return pointer to first or next directory entry, or NULL if end. */
  562. {
  563.   int r;                /* return code */
  564.  
  565.   do {
  566.     d->fab.fab$w_ifi = 0;       /* internal file index:  what does this do? */
  567.  
  568.     /* get next match to possible wildcard */
  569.     if ((r = sys$search(&d->fab)) == RMS$_NORMAL)
  570.     {
  571.         d->d_name[d->nam.nam$b_rsl] = '\0';   /* null terminate */
  572.         return (struct direct *)d;   /* OK */
  573.     }
  574.   } while (r == RMS$_PRV);
  575.   return NULL;
  576. }
  577. #  define closedir free
  578. #endif /* VMS */
  579.  
  580.  
  581. #ifdef NODIR                    /* for AT&T 3B1 */
  582. /*
  583. **  Apparently originally by Rich Salz.
  584. **  Cleaned up and modified by James W. Birdsall.
  585. */
  586.  
  587. #  define opendir(path) fopen(path, "r")
  588.  
  589. struct direct *readdir(dirp)
  590. DIR *dirp;
  591. {
  592.   static struct direct entry;
  593.  
  594.   if (dirp == NULL) 
  595.     return NULL;
  596.   for (;;)
  597.     if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) 
  598.       return NULL;
  599.     else if (entry.d_ino) 
  600.       return (&entry);
  601. } /* end of readdir() */
  602.  
  603. #  define closedir(dirp) fclose(dirp)
  604. #endif /* NODIR */
  605.  
  606.  
  607. #ifdef DIRENT
  608. # ifdef TOPS20
  609. local dstrm *opend(n)
  610. char *n;                /* directory name to open */
  611. /* Open the directory *n, returning a pointer to an allocated dstrm, or
  612.    NULL if error. */
  613. {
  614.     dstrm *d;             /* pointer to malloc'ed directory stream */
  615.     char    *c;                         /* scans TOPS20 path */
  616.     int     m;                          /* length of name */
  617.     char    *p;                         /* temp string */
  618.  
  619.     if (((d = (dstrm *)malloc(sizeof(dstrm))) == NULL) ||
  620.         ((p = (char *)malloc((m = strlen(n)) + 4)) == NULL)) {
  621.             return NULL;
  622.     }
  623.  
  624. /* Directory may be in form "<DIR.SUB1.SUB2>" or "<DIR.SUB1>SUB2.DIRECTORY".
  625. ** If latter, convert to former. */
  626.  
  627.     if ((m > 0)  &&  (*(c = strcpy(p,n) + m-1) != '>')) {
  628.         c -= 10;
  629.         *c-- = '\0';        /* terminate at "DIRECTORY.1" */
  630.         *c = '>';           /* "." --> ">" */
  631.         while ((c > p)  &&  (*--c != '>'));
  632.         *c = '.';           /* ">" --> "." */
  633.     }
  634.     strcat(p, "*.*");
  635.     if ((d->wfjfn = wfopen(p)) == 0) {
  636.         free((voidp *)d);
  637.         free((voidp *)p);
  638.         return NULL;
  639.     }
  640.     free((voidp *)p);
  641.     d->more = TRUE;
  642.     return (d);
  643. }
  644. #else /* !TOPS20 */
  645.  
  646. local dstrm *opend(n)
  647. char *n;                /* directory name to open */
  648. /* Open the directory *n, returning a pointer to an allocated dstrm, or
  649.    NULL if error. */
  650. {
  651.     dstrm *d;             /* pointer to malloc'ed directory stream */
  652.  
  653.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
  654.     return NULL;
  655.   if ((d->f = open(n, 0, 0)) < 0)               /* open directory */
  656.     return NULL;
  657.   d->p = d->q = d->b;                           /* buffer is empty */
  658.   return d;
  659. }
  660. # endif /* ?TOPS20 */
  661. #else /* !DIRENT */
  662. #  define opend opendir                         /* just use opendir() */
  663. #endif /* ?DIRENT */
  664.  
  665.  
  666. local char *readd(d)
  667. dstrm *d;               /* directory stream to read from */
  668. /* Return a pointer to the next name in the directory stream d, or NULL if
  669.    no more entries or an error occurs. */
  670. {
  671. #ifdef TOPS20
  672.   char    *p;
  673.   if ((d->more == FALSE) || ((p = wfname(d->wfjfn)) == NULL)) {
  674.       return NULL;
  675.   }
  676.   if (wfnext(d->wfjfn) == 0) {
  677.       d->more = FALSE;
  678.   }
  679.   return p;
  680.  
  681. #else /* !TOPS20 */
  682.   struct direct *e;     /* directory entry read */
  683.  
  684. # ifdef DIRENT
  685.   int n;                /* number of entries read by getdents */
  686.  
  687.   if (d->p >= d->q)                             /* if empty, fill buffer */
  688.     if ((n = getdents(d->f, d->b, DBSZ)) <= 0)
  689.       return NULL;
  690.     else
  691.       d->q = n + (d->p = d->b);
  692.   e = (struct direct *)(d->p);                  /* point to entry */
  693.   d->p += ((struct direct *)(d->p))->d_reclen;  /* advance */
  694.   return e->d_name;                             /* return name */
  695. # else /* !DIRENT */
  696.   e = readdir(d);
  697.   return e == NULL ? (char *)NULL : e->d_name;
  698. # endif /* ?DIRENT */
  699. #endif /* ?TOPS20 */
  700. }
  701.  
  702.  
  703. #ifdef DIRENT
  704. local void closed(d)
  705. dstrm *d;               /* directory stream to close */
  706. /* Close the directory stream */
  707. {
  708. #ifndef TOPS20
  709.   close(d->f);
  710. #endif
  711.   free((voidp *)d);
  712. }
  713. #else /* !DIRENT */
  714. #  define closed closedir
  715. #endif /* ?DIRENT */
  716.  
  717. #ifdef TOPS20
  718. /* Wildcard filename routines */
  719.  
  720. /* WFOPEN - open wild card filename
  721. **      Returns wild JFN for filespec, 0 if failure.
  722. */
  723. static int
  724. wfopen(name)
  725. char *name;
  726. {
  727.     return (_gtjfn(name, (O_RDONLY | O_T20_WILD)));
  728. }
  729.  
  730. /* WFNAME - Return filename for wild JFN
  731. **      Returns pointer to dynamically allocated filename string
  732. */
  733. static char *
  734. wfname(jfn)
  735. int jfn;
  736. {
  737.     char *fp, fname[200];
  738.     int ablock[5];
  739.  
  740.     ablock[1] = (int) (fname - 1);
  741.     ablock[2] = jfn & 0777777;  /* jfn, no flags */
  742.     ablock[3] = 0111110000001;  /* DEV+DIR+NAME+TYPE+GEN, punctuate */
  743.     if (!jsys(JFNS, ablock))
  744.         return NULL;            /* something bad happened */
  745.     if ((fp = (char *)malloc(strlen(fname) + 1)) == NULL) {
  746.         return NULL;
  747.     }
  748.     strcpy(fp, fname);          /* copy the file name here */
  749.     return fp;
  750. }
  751.  
  752. /* WFNEXT - Make wild JFN point to next real file
  753. **      Returns success or failure (not JFN)
  754. */
  755. static int
  756. wfnext(jfn)
  757. int jfn;
  758. {
  759.     int ablock[5];
  760.  
  761.     ablock[1] = jfn;            /* save jfn and flags */
  762.     return jsys(GNJFN, ablock);
  763. }
  764. #endif /* TOPS20 */
  765.   
  766.  
  767. #ifdef __human68k__
  768. int wild(w)
  769. char *w;
  770. {
  771.   struct _filbuf inf;
  772.   int r;
  773.   extern int _hupair;
  774.   char name[FNMAX];
  775.   char *p;
  776.  
  777.   if (_hupair)
  778.     return procname(w);         /* if argv's passed hupair, don't glob */
  779.   strcpy(name, w);
  780.   _toslash(name);
  781.   if ((p = strrchr(name, '/')) == NULL && (p = strrchr(name, ':')) == NULL)
  782.     p = name;
  783.   else
  784.     p++;
  785.   if (_dos_files (&inf, w, 0xff) < 0)
  786.     return ZE_MISS;
  787.   do {
  788.     strcpy(p, inf.name);
  789.     r = procname(name);
  790.     if (r != ZE_OK)
  791.       return r;
  792.   } while (_dos_nfiles(&inf) >= 0);
  793.  
  794.   return ZE_OK;
  795. }
  796. #endif
  797.  
  798. #if defined(MSDOS) && !defined(OS2) && !defined(WIN32)
  799.  
  800. char *getVolumeLabel(drive, vtime, vmode)
  801.   int drive;  /* drive name: 'A' .. 'Z' or '\0' for current drive */
  802.   ulg *vtime; /* volume label creation time (DOS format) */
  803.   ulg *vmode; /* volume label file mode */
  804.  
  805. /* If a volume label exists for the given drive, return its name and
  806.    set its time and mode. The returned name must be static data. */
  807. {
  808.   static char vol[14];
  809.   ff_dir d;
  810.  
  811.   if (drive) {
  812.     vol[0] = (char)drive;
  813.     strcpy(vol+1, ":/");
  814.   } else {
  815.     strcpy(vol, "/");
  816.   }
  817.   strcat(vol, "*.*");
  818.   if (FFIRST(vol, &d, FA_LABEL) == 0) {
  819.     strncpy(vol, d.ff_name, sizeof(vol)-1);
  820.     *vtime = ((ulg)d.ff_fdate << 16) | ((ulg)d.ff_ftime & 0xffff);
  821.     *vmode = (ulg)d.ff_attrib;
  822.     return vol;
  823.   }
  824.   return NULL;
  825. }
  826.  
  827. #endif /*  MSDOS && !OS2 && !WIN32 */
  828.  
  829.  
  830. #if defined(MSDOS) || defined(OS2)
  831.  
  832. int wild(w)
  833. char *w;                /* path/pattern to match */
  834. /* If not in exclude mode, expand the pattern based on the contents of the
  835.    file system.  Return an error code in the ZE_ class. */
  836. {
  837. # ifndef __GO32__
  838.   dstrm *d;             /* stream for reading directory */
  839.   char *e;              /* name found in directory */
  840.   int r;                /* temporary variable */
  841.   char *n;              /* constructed name from directory */
  842. # endif /* __GO32__ */
  843.   int f;                /* true if there was a match */
  844.   char *a;              /* alloc'ed space for name */
  845.   char *p;              /* path */
  846.   char *q;              /* name */
  847.   char v[5];            /* space for device current directory */
  848.  
  849. # ifndef WIN32
  850.   if (volume_label == 1) {
  851.     volume_label = 2;
  852.     label = getVolumeLabel(w[1] == ':' ? to_up(w[0]) : '\0',
  853.                            &label_time, &label_mode);
  854.     if (label != NULL) {
  855.        newname(label, 0);
  856.     }
  857.     if (w[1] == ':' && w[2] == '\0') return ZE_OK;
  858.     /* "zip -$ foo a:" can be used to force drive name */
  859.   }
  860. # endif
  861.   /* Allocate and copy pattern */
  862.   if ((p = a = malloc(strlen(w) + 1)) == NULL)
  863.     return ZE_MEM;
  864.   strcpy(p, w);
  865.  
  866.   /* Normalize path delimiter as '/'. */
  867.   for (q = p; *q; q++)                  /* use / consistently */
  868.     if (*q == '\\')
  869.       *q = '/';
  870.  
  871.   /* Only name can have special matching characters */
  872.   if ((q = isshexp(p)) != NULL &&
  873.       (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
  874.   {
  875.     free((voidp *)a);
  876.     return ZE_PARMS;
  877.   }
  878.  
  879.   /* Separate path and name into p and q */
  880.   if ((q = strrchr(p, '/')) != NULL && (q == p || q[-1] != ':'))
  881.   {
  882.     *q++ = 0;                           /* path/name -> path, name */
  883.     if (*p == 0)                        /* path is just / */
  884.       p = strcpy(v, "/.");
  885.   }
  886.   else if ((q = strrchr(p, ':')) != NULL)
  887.   {                                     /* has device and no or root path */
  888.     *q++ = 0;
  889.     p = strcat(strcpy(v, p), ":");      /* copy device as path */
  890.     if (*q == '/')                      /* -> device:/., name */
  891.     {
  892.       strcat(p, "/");
  893.       q++;
  894.     }
  895.     strcat(p, ".");
  896.   }
  897.   else                                  /* no path or device */
  898.   {
  899.     q = p;
  900.     p = strcpy(v, ".");
  901.   }
  902.   /* I can't understand Mark's code so I am adding a hack here to get
  903.    * "zip -r foo ." to work. Allow the dubious "zip -r foo .." but
  904.    * reject "zip -rm foo ..".
  905.    */
  906.   if (recurse && (strcmp(q, ".") == 0 ||  strcmp(q, "..") == 0)) {
  907.      if (dispose && strcmp(q, "..") == 0)
  908.         err(ZE_PARMS, "cannot remove parent directory");
  909.      return procname(p);
  910.   }
  911. # ifdef __GO32__
  912.   /* expansion already done by DJGPP */
  913.   f = 1;
  914.   if (strcmp(q, ".") != 0 && strcmp(q, "..") != 0 && procname(w) != ZE_OK) {
  915.      f = 0;
  916.   }
  917. # else
  918.   /* Search that level for matching names */
  919.   if ((d = opend(p)) == NULL)
  920.   {
  921.     free((voidp *)a);
  922.     return ZE_MISS;
  923.   }
  924.   if ((r = strlen(p)) > 1 &&
  925.       (strcmp(p + r - 2, ":.") == 0 || strcmp(p + r - 2, "/.") == 0))
  926.     *(p + r - 1) = 0;
  927.   f = 0;
  928.   while ((e = readd(d)) != NULL) {
  929.     if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e))
  930.     {
  931.       f = 1;
  932.       if (strcmp(p, ".") == 0) {                /* path is . */
  933.         r = procname(e);                        /* name is name */
  934.         if (r) {
  935.            f = 0;
  936.            break;
  937.         }
  938.       } else
  939.       {
  940.         if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
  941.         {
  942.           free((voidp *)a);
  943.           closed(d);
  944.           return ZE_MEM;
  945.         }
  946.         n = strcpy(n, p);
  947.         if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
  948.           strcat(n, "/");
  949.         r = procname(strcat(n, e));             /* name is path/name */
  950.         free((voidp *)n);
  951.         if (r) {
  952.           f = 0;
  953.           break;
  954.         }
  955.       }
  956.     }
  957.   }
  958.   closed(d);
  959. # endif /* __GO32__ */
  960.  
  961.   /* Done */
  962.   free((voidp *)a);
  963.   return f ? ZE_OK : ZE_MISS;
  964. }
  965. #endif /* MSDOS || OS2 */
  966.  
  967. #if defined(MSDOS) && !defined(OS2) && !defined(WIN32)
  968. #  if defined(__TURBOC__) || defined(__GO32__) || defined(__BORLANDC__)
  969. #   define GetFileMode(name) bdosptr(0x43, (name), 0)
  970. #  else
  971.     int GetFileMode(char *name)
  972.     {
  973.        unsigned int attr = 0;
  974.        _dos_getfileattr(name, &attr);
  975.        return attr;
  976.     }
  977. #  endif/* __TURBOC__  || __GO32__ */
  978. # endif /* MSDOS && !OS2 */
  979.  
  980. #ifdef __human68k__
  981. #  define GetFileMode(name) (_dos_chmod((name), -1) & 0x3f)
  982. #endif
  983.  
  984. #ifdef AMIGA
  985.  
  986. /* What we have here is a mostly-generic routine using opend()/readd() and */
  987. /* isshexp()/MATCH() to find all the files matching a multi-part filespec  */
  988. /* using the portable pattern syntax.  It shouldn't take too much fiddling */
  989. /* to make it usable for any other platform that has directory hierarchies */
  990. /* but no shell-level pattern matching.  It works for patterns throughout  */
  991. /* the pathname, such as "foo:*.?/source/x*.[ch]".                         */
  992.  
  993. /* whole is a pathname with wildcards, wildtail points somewhere in the  */
  994. /* middle of it.  All wildcards to be expanded must come AFTER wildtail. */
  995.  
  996. local int wild_recurse(whole, wildtail) char *whole; char *wildtail;
  997. {
  998.     dstrm *dir;
  999.     char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
  1000.     ush newlen, amatch = 0;
  1001.     BPTR lok;
  1002.     int e = ZE_MISS;
  1003.  
  1004.     if (!isshexp(wildtail))
  1005.         if (lok = Lock(whole, ACCESS_READ)) {       /* p exists? */
  1006.             UnLock(lok);
  1007.             return procname(whole);
  1008.         } else
  1009.             return ZE_MISS;                     /* woops, no wildcards! */
  1010.  
  1011.     /* back up thru path components till existing dir found */
  1012.     do {
  1013.         name = wildtail + strlen(wildtail) - 1;
  1014.         for (;;)
  1015.             if (name-- <= wildtail || *name == '/') {
  1016.                 subwild = name + 1;
  1017.                 plug2 = *subwild;
  1018.                 *subwild = 0;
  1019.                 break;
  1020.             }
  1021.         if (glue)
  1022.             *glue = plug;
  1023.         glue = subwild;
  1024.         plug = plug2;
  1025.         dir = opend(whole);
  1026.     } while (!dir && !disk_not_mounted && subwild > wildtail);
  1027.     wildtail = subwild;                 /* skip past non-wild components */
  1028.  
  1029.     if (subwild = strchr(wildtail + 1, '/')) {
  1030.         /* this "+ 1" dodges the  ^^^ hole left by *glue == 0 */
  1031.         *(subwild++) = 0;               /* wildtail = one component pattern */
  1032.         newlen = strlen(whole) + strlen(subwild) + 32;
  1033.     } else
  1034.         newlen = strlen(whole) + 31;
  1035.     if (!dir || !(newwhole = malloc(newlen))) {
  1036.         if (glue)
  1037.             *glue = plug;
  1038.         e = dir ? ZE_MEM : ZE_MISS;
  1039.         goto ohforgetit;
  1040.     }
  1041.     strcpy(newwhole, whole);
  1042.     newlen = strlen(newwhole);
  1043.     if (glue)
  1044.         *glue = plug;                           /* repair damage to whole */
  1045.     if (!isshexp(wildtail)) {
  1046.         e = ZE_MISS;                            /* non-wild name not found */
  1047.         goto ohforgetit;
  1048.     }
  1049.  
  1050.     while (name = readd(dir)) {
  1051.         if (MATCH(wildtail, name)) {
  1052.             strcpy(newwhole + newlen, name);
  1053.             if (subwild) {
  1054.                 name = newwhole + strlen(newwhole);
  1055.                 *(name++) = '/';
  1056.                 strcpy(name, subwild);
  1057.                 e = wild_recurse(newwhole, name);
  1058.             } else
  1059.                 e = procname(newwhole);
  1060.             newwhole[newlen] = 0;
  1061.             if (e == ZE_OK)
  1062.                 amatch = 1;
  1063.             else if (e != ZE_MISS)
  1064.                 break;
  1065.         }
  1066.     }
  1067.  
  1068.   ohforgetit:
  1069.     if (dir) closed(dir);
  1070.     if (subwild) *--subwild = '/';
  1071.     if (newwhole) free(newwhole);
  1072.     if (e == ZE_MISS && amatch)
  1073.         e = ZE_OK;
  1074.     return e;
  1075. }
  1076.  
  1077. int wild(p) char *p;
  1078. {
  1079.     char *use;
  1080.  
  1081.     /* wild_recurse() can't handle colons in wildcard part: */
  1082.     if (use = strchr(p, ':')) {
  1083.         if (strchr(++use, ':'))
  1084.             return ZE_PARMS;
  1085.     } else
  1086.         use = p;
  1087.  
  1088.     return wild_recurse(p, use);
  1089. }
  1090. #endif /* AMIGA */
  1091.                                           
  1092.  
  1093. #ifdef VMS
  1094. int wild(p)
  1095. char *p;                /* path/pattern to match */
  1096. /* Expand the pattern based on the contents of the file system.  Return an
  1097.    error code in the ZE_ class. */
  1098. {
  1099.   dstrm *d;             /* stream for reading directory */
  1100.   char *e;              /* name found in directory */
  1101.   int f;                /* true if there was a match */
  1102.  
  1103.   /* Search given pattern for matching names */
  1104.   if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
  1105.     return ZE_MEM;
  1106.   vms_wild(p, d);       /* pattern may be more than just directory name */
  1107.  
  1108.   /*
  1109.    * Save version specified by user to use in recursive drops into
  1110.    * subdirectories.
  1111.    */
  1112.   strncpy(wild_version_part,d->nam.nam$l_ver,d->nam.nam$b_ver);
  1113.   wild_version_part[d->nam.nam$b_ver] = 0;
  1114.  
  1115.   f = 0;
  1116.   while ((e = readd(d)) != NULL)        /* "dosmatch" is already built in */
  1117.     if (procname(e) == ZE_OK)
  1118.       f = 1;
  1119.   closed(d);
  1120.  
  1121.   /* Done */
  1122.   return f ? ZE_OK : ZE_MISS;
  1123. }
  1124. #endif /* VMS */
  1125.  
  1126.  
  1127. char *getnam(n)
  1128. char *n;                /* where to put name (must have >=FNMAX+1 bytes) */
  1129. /* Read a space, \n, \r, or \t delimited name from stdin into n, and return
  1130.    n.  If EOF, then return NULL.  Also, if the name read is too big, return
  1131.    NULL. */
  1132. {
  1133.   int c;                /* last character read */
  1134.   char *p;              /* pointer into name area */
  1135.  
  1136.   p = n;
  1137.   while ((c = getchar()) == ' ' || c == '\n' || c == '\r' || c == '\t')
  1138.     ;
  1139.   if (c == EOF)
  1140.     return NULL;
  1141.   do {
  1142.     if (p - n >= FNMAX)
  1143.       return NULL;
  1144.     *p++ = (char)c;
  1145.     c = getchar();
  1146.   } while (c != EOF && c != ' ' && c != '\n' && c != '\r' && c != '\t');
  1147.   *p = 0;
  1148.   return n;
  1149. }
  1150.  
  1151.  
  1152. struct flist far *fexpel(f)
  1153. struct flist far *f;    /* entry to delete */
  1154. /* Delete the entry *f in the doubly-linked found list.  Return pointer to
  1155.    next entry to allow stepping through list. */
  1156. {
  1157.   struct flist far *t;  /* temporary variable */
  1158.  
  1159.   t = f->nxt;
  1160.   *(f->lst) = t;                        /* point last to next, */
  1161.   if (t != NULL)
  1162.     t->lst = f->lst;                    /* and next to last */
  1163.   if (f->name != NULL)                  /* free memory used */
  1164.     free((voidp *)(f->name));
  1165.   if (f->zname != NULL)
  1166.     free((voidp *)(f->zname));
  1167.   farfree((voidp far *)f);
  1168.   fcount--;                             /* decrement count */
  1169.   return t;                             /* return pointer to next */
  1170. }
  1171.  
  1172.  
  1173. local int fqcmp(a, b)
  1174. const voidp *a, *b;           /* pointers to pointers to found entries */
  1175. /* Used by qsort() to compare entries in the found list by name. */
  1176. {
  1177.   return strcmp((*(struct flist far **)a)->name,
  1178.                 (*(struct flist far **)b)->name);
  1179. }
  1180.  
  1181.  
  1182. local int fqcmpz(a, b)
  1183. const voidp *a, *b;           /* pointers to pointers to found entries */
  1184. /* Used by qsort() to compare entries in the found list by zname. */
  1185. {
  1186.   return strcmp((*(struct flist far **)a)->zname,
  1187.                 (*(struct flist far **)b)->zname);
  1188. }
  1189.  
  1190.  
  1191. local char *last(p)
  1192. char *p;                /* sequence of / delimited path components */
  1193. /* Return a pointer to the start of the last path component. For a
  1194.  * directory name terminated by /, the return value is an empty string.
  1195.  */
  1196. {
  1197.   char *t;              /* temporary variable */
  1198.  
  1199.   if ((t = strrchr(p, PATH_END)) != NULL)
  1200.     return t + 1;
  1201.   else
  1202.     return p;
  1203. }
  1204.  
  1205.  
  1206. local char *msname(n)
  1207. char *n;
  1208. /* Reduce all path components to MSDOS upper case 8.3 style names.  Probably
  1209.    should also check for invalid characters, but I don't know which ones
  1210.    those are. */
  1211. {
  1212.   int c;                /* current character */
  1213.   int f;                /* characters in current component */
  1214.   char *p;              /* source pointer */
  1215.   char *q;              /* destination pointer */
  1216.  
  1217.   p = q = n;
  1218.   f = 0;
  1219.   while ((c = (unsigned char)*p++) != 0)
  1220.     if (c == '/')
  1221.     {
  1222.       *q++ = (char)c;
  1223.       f = 0;                            /* new component */
  1224.     }
  1225. #ifdef __human68k__
  1226.     else if (iskanji(c))
  1227.     {
  1228.       if (f == 7 || f == 11)
  1229.         f++;
  1230.       else if (*p != '\0' && f < 12 && f != 8)
  1231.       {
  1232.         *q++ = c;
  1233.         *q++ = *p++;
  1234.         f += 2;
  1235.       }
  1236.     }
  1237. #endif
  1238.     else if (c == '.')
  1239.       if (f < 9)
  1240.       {
  1241.         *q++ = (char)c;
  1242.         f = 9;                          /* now in file type */
  1243.       }
  1244.       else
  1245.         f = 12;                         /* now just excess characters */
  1246.     else
  1247.       if (f < 12 && f != 8)
  1248.       {
  1249.         *q++ = (char)(to_up(c));
  1250.         f++;                            /* do until end of name or type */
  1251.       }
  1252.   *q = 0;
  1253.   return n;
  1254. }
  1255.  
  1256.  
  1257. #ifdef VMS
  1258. local char *strlower(s)
  1259. char *s;                /* string to convert */
  1260. /* Convert all uppercase letters to lowercase in string s */
  1261. {
  1262.   char *p;              /* scans string */
  1263.  
  1264.   for (p = s; *p; p++)
  1265.     if (*p >= 'A' && *p <= 'Z')
  1266.       *p += 'a' - 'A';
  1267.   return s;
  1268. }
  1269.  
  1270. local char *strupper(s)
  1271. char *s;                /* string to convert */
  1272. /* Convert all lowercase letters to uppercase in string s */
  1273. {
  1274.   char *p;              /* scans string */
  1275.  
  1276.   for (p = s; *p; p++)
  1277.     if (*p >= 'a' && *p <= 'z')
  1278.       *p -= 'a' - 'A';
  1279.   return s;
  1280. }
  1281. #endif /* VMS */
  1282.  
  1283. char *ex2in(x, isdir, pdosflag)
  1284. char *x;                /* external file name */
  1285. int isdir;              /* input: x is a directory */
  1286. int *pdosflag;          /* output: force MSDOS file attributes? */
  1287. /* Convert the external file name to a zip file name, returning the malloc'ed
  1288.    string or NULL if not enough memory. */
  1289. {
  1290.   char *n;              /* internal file name (malloc'ed) */
  1291.   char *t;              /* shortened name */
  1292.   int dosflag;
  1293.  
  1294. #ifdef TOPS20
  1295.   int jfn;
  1296.   char *fp, fname[200];
  1297.   int ablock[5];
  1298.  
  1299.   jfn = _gtjfn(x, (O_RDONLY));
  1300.   ablock[1] = (int) (fname - 1);
  1301.   ablock[2] = jfn & 0777777;    /* jfn, no flags */
  1302.   ablock[3] = 0111100000001;    /* DEV+DIR+NAME+TYPE, punctuate */
  1303.   if (!jsys(JFNS, ablock)) {
  1304.       _rljfn(jfn);
  1305.       return NULL;              /* something bad happened */
  1306.   }
  1307.   _rljfn(jfn);
  1308.   if ((fp = (char *)malloc(strlen(fname) + 1)) == NULL) {
  1309.       return NULL;
  1310.   }
  1311.   strcpy(fp, fname);            /* copy the file name here */
  1312.   x = fp;
  1313. #endif /* TOPS20 */
  1314.  
  1315. #if defined(OS2) || defined(WIN32)
  1316.   dosflag = dosify || IsFileSystemFAT(x);
  1317.   if (!dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL)
  1318.   {
  1319.     x = t;
  1320.     dosflag = 0;
  1321.   }
  1322. #else /* !OS2 */
  1323. # ifdef MSDOS
  1324.   dosflag = 1;
  1325. # else /* !MSDOS */
  1326.   dosflag = dosify; /* default for non-DOS and non-OS/2 */
  1327. # endif /* ?MSDOS */
  1328. #endif /* ?OS2 */
  1329.  
  1330.   /* Find starting point in name before doing malloc */
  1331. #if defined(MSDOS) || defined(__human68k__) /* msdos */
  1332.   t = *x && *(x + 1) == ':' ? x + 2 : x;
  1333.   while (*t == '/' || *t == '\\')
  1334.     t++;
  1335. #else /* !MSDOS */
  1336. #  if (defined(VMS) || defined(TOPS20))
  1337.   t = x;
  1338.   if ((n = strrchr(t, ':')) != NULL)
  1339.     t = n + 1;
  1340.   if (*t == PATH_START && (n = strrchr(t, PATH_END)) != NULL)
  1341.     if ((x = strchr(t, '.')) != NULL && x < n)
  1342.       t = x + 1;
  1343.     else
  1344.       t = n + 1;
  1345. #  else /* !(VMS || TOPS20) */
  1346. #    ifdef AMIGA
  1347.   if ((t = strrchr(x, ':')) != NULL)    /* reject ":" */
  1348.     t++;
  1349.   else
  1350.     t = x;
  1351.   {                                     /* reject "//" */
  1352.     char *tt = t;
  1353.     while (tt = strchr(tt, '/'))
  1354.       while (*++tt == '/')
  1355.         t = tt;
  1356.   }
  1357.   while (*t == '/')             /* reject leading "/" on what's left */
  1358.     t++;
  1359. #    else /* !AMIGA */                      /* unix */
  1360.   for (t = x; *t == '/'; t++)
  1361.     ;
  1362. #    endif /* ?AMIGA */
  1363. #  endif /* ?(VMS || TOPS20) */
  1364. #endif /* ?MSDOS */
  1365.  
  1366.   /* Make changes, if any, to the copied name (leave original intact) */
  1367. #ifdef __human68k__
  1368.   _toslash(t);
  1369. #endif /* !__human68k__ */
  1370. #ifdef MSDOS
  1371.   for (n = t; *n; n++)
  1372.     if (*n == '\\')
  1373.       *n = '/';
  1374. #endif /* MSDOS */
  1375.  
  1376.   if (!pathput)
  1377.     t = last(t);
  1378.  
  1379.   /* Discard directory names with zip -rj */
  1380.   if (*t == '\0')
  1381.     return t;
  1382.  
  1383.   /* Malloc space for internal name and copy it */
  1384.   if ((n = malloc(strlen(t) + 1)) == NULL)
  1385.     return NULL;
  1386.   strcpy(n, t);
  1387.  
  1388. #if (defined(VMS) || defined(TOPS20))
  1389.   if ((t = strrchr(n, PATH_END)) != NULL)
  1390.   {
  1391.     *t = '/';
  1392.     while (--t > n)
  1393.       if (*t == '.')
  1394.         *t = '/';
  1395.   }
  1396.  
  1397.   /* Fix from Greg Roelofs: */
  1398.   /* Get current working directory and strip from n (t now = n) */
  1399.   {
  1400.     char cwd[256], *p, *q;
  1401.     int c;
  1402.  
  1403.     if (getcwd(cwd, 256) && ((p = strchr(cwd, '.')) != NULL))
  1404.     {
  1405.       ++p;
  1406.       if ((q = strrchr(p, PATH_END)) != NULL)
  1407.       {
  1408.         *q = '/';
  1409.         while (--q > p)
  1410.           if (*q == '.')
  1411.             *q = '/';
  1412.  
  1413.         /* strip bogus path parts from n */
  1414.         if (strncmp(n, p, (c=strlen(p))) == 0)
  1415.         {
  1416.           q = n + c;
  1417.           while (*t++ = *q++)
  1418.             ;
  1419.         }
  1420.       }
  1421.     }
  1422.   }
  1423. /* lgk fix for making all files lower case */
  1424. #ifndef WIN32  
  1425.   strlower(n);
  1426. #endif
  1427.  
  1428.   if (isdir)
  1429.   {
  1430.     if (strcmp((t=n+strlen(n)-6), ".dir;1"))
  1431.       error("directory not version 1");
  1432.     else
  1433.       strcpy(t, "/");
  1434.   }
  1435. #ifdef VMS
  1436.   else if (!vmsver)
  1437.     if ((t = strrchr(n, ';')) != NULL)
  1438.       *t = 0;
  1439. #endif /* VMS */
  1440.  
  1441.   if ((t = strrchr(n, '.')) != NULL)
  1442.   {
  1443.     if ( t[1] == 0)                /* "filename." -> "filename" */
  1444.       *t = 0;
  1445. #ifdef VMS
  1446.     else if (t[1] == ';')         /* "filename.;vvv" -> "filename;vvv" */
  1447.     {
  1448.       char *f = t+1;
  1449.       while (*t++ = *f++) ;
  1450.     }
  1451. #endif /* VMS */
  1452.   }
  1453. #else
  1454.   if (isdir == 42) return n;      /* avoid warning on unused variable */
  1455. #endif /* ?(VMS || TOPS20) */
  1456.  
  1457.   if (dosify)
  1458.     msname(n);
  1459. #if defined(MSDOS) && !defined(OS2) && !defined(WIN32)
  1460.   else
  1461.     strlwr(n);
  1462. #endif
  1463.   /* Returned malloc'ed name */
  1464.   if (pdosflag) 
  1465.     *pdosflag = dosflag;
  1466.   return n;
  1467. }
  1468.  
  1469.  
  1470. char *in2ex(n)
  1471. char *n;                /* internal file name */
  1472. /* Convert the zip file name to an external file name, returning the malloc'ed
  1473.    string or NULL if not enough memory. */
  1474. {
  1475.   char *x;              /* external file name */
  1476. #if (defined(VMS) || defined(TOPS20))
  1477.   char *t;              /* scans name */
  1478.  
  1479.   if ((t = strrchr(n, '/')) == NULL)
  1480. #endif
  1481.   {
  1482.     if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
  1483.       return NULL;
  1484.     strcpy(x, n);
  1485.   }
  1486. #if (defined(VMS) || defined(TOPS20))
  1487.   else
  1488.   {
  1489.     if ((x = malloc(strlen(n) + 3 + PAD)) == NULL)
  1490.       return NULL;
  1491.     x[0] = PATH_START;
  1492.     x[1] = '.';
  1493.     strcpy(x + 2, n);
  1494.     *(t = x + 2 + (t - n)) = PATH_END;
  1495.     while (--t > x)
  1496.       if (*t == '/')
  1497.         *t = '.';
  1498.   }
  1499.   strupper(x);
  1500. #endif /* ?(VMS || TOPS20) */
  1501.  
  1502. #if defined(OS2) || defined(WIN32)
  1503.   if ( !IsFileNameValid(x) )
  1504.     ChangeNameForFAT(x);
  1505. #endif /* !OS2 */
  1506.   return x;
  1507. }
  1508.  
  1509.  
  1510. int check_dup()
  1511. /* Sort the found list and remove duplicates.
  1512.    Return an error code in the ZE_ class. */
  1513. {
  1514.   struct flist far *f;          /* steps through found linked list */
  1515.   extent j;                     /* index for s */
  1516.   struct flist far **s;         /* sorted table */
  1517.  
  1518.   /* sort found list, remove duplicates */
  1519.   if (fcount)
  1520.   {
  1521.     if ((s = (struct flist far **)malloc(
  1522.          fcount * sizeof(struct flist far *))) == NULL)
  1523.       return ZE_MEM;
  1524.     for (j = 0, f = found; f != NULL; f = f->nxt)
  1525.       s[j++] = f;
  1526.     qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
  1527.     for (j = fcount - 1; j > 0; j--)
  1528.       if (strcmp(s[j - 1]->name, s[j]->name) == 0)
  1529.         fexpel(s[j]);           /* fexpel() changes fcount */
  1530.     qsort((char *)s, fcount, sizeof(struct flist far *), fqcmpz);
  1531.     for (j = 1; j < fcount; j++)
  1532.       if (strcmp(s[j - 1]->zname, s[j]->zname) == 0)
  1533.       {
  1534.         warn("name in zip file repeated: ", s[j]->zname);
  1535.         warn("  first full name: ", s[j - 1]->name);
  1536.         warn(" second full name: ", s[j]->name);
  1537.         return ZE_PARMS;
  1538.       }
  1539.     free((voidp *)s);
  1540.   }
  1541.   return ZE_OK;
  1542. }
  1543.  
  1544. int filter(name)
  1545.   char *name;
  1546.   /* Scan the -i and -x lists for matches to the given name.
  1547.      Return true if the name must be included, false otherwise.
  1548.      Give precedence to -x over -i.
  1549.    */
  1550. {
  1551.    int n;
  1552.    int include = icount ? 0 : 1;
  1553. #ifdef MATCH_LASTNAME_ONLY
  1554.    char *p = last(name);
  1555.    if (*p) name = p;
  1556. #endif
  1557.  
  1558.    if (pcount == 0) return 1;
  1559.  
  1560.    for (n = 0; n < pcount; n++) {
  1561.       if (MATCH(patterns[n].zname, name)) {
  1562.          if (patterns[n].select == 'x') return 0;
  1563.          include = 1;
  1564.       }
  1565.    }
  1566.    return include;
  1567. }
  1568.  
  1569. local int newname(n, isdir)
  1570. char *n;                /* name to add (or exclude) */
  1571. int  isdir;             /* true for a directory */
  1572. /* Add (or exclude) the name of an existing disk file.  Return an error
  1573.    code in the ZE_ class. */
  1574. {
  1575.   char *m;
  1576.   struct flist far *f;  /* where in found, or new found entry */
  1577.   struct zlist far *z;  /* where in zfiles (if found) */
  1578.   int dosflag;
  1579.  
  1580.   /* Search for name in zip file.  If there, mark it, else add to
  1581.      list of new names to do (or remove from that list). */
  1582.   if ((m = ex2in(n, isdir, &dosflag)) == NULL)
  1583.     return ZE_MEM;
  1584.  
  1585.   /* Discard directory names with zip -rj */
  1586.   if (*m == '\0') {
  1587. #ifndef AMIGA
  1588. /* A null string is a legitimate external directory name in AmigaDOS; also,
  1589.  * a command like "zip -r zipfile FOO:" produces an empty internal name.
  1590.  */
  1591.     if (pathput) error("empty name without -j");
  1592. #endif
  1593.     free((voidp *)m);
  1594.     return ZE_OK;
  1595.   }
  1596.   if ((z = zsearch(m)) != NULL) {
  1597.     z->mark = pcount ? filter(m) : 1;
  1598.     if (z->mark == 0) {
  1599.       free((voidp *)m);
  1600.       if (verbose)
  1601.         fprintf(mesg, "zip diagnostic: excluding %s\n", z->name);
  1602.     } else {
  1603.       free((voidp *)(z->name));
  1604.       if ((z->name = malloc(strlen(n) + 1 + PAD)) == NULL)
  1605.         return ZE_MEM;
  1606.       strcpy(z->name, n);
  1607. #ifdef FORCE_NEWNAME
  1608.       free((voidp *)(z->zname));
  1609.       z->zname = m;
  1610. #else
  1611.       /* Better keep the old name. Useful when updating on MSDOS a zip file
  1612.        * made on Unix.
  1613.        */
  1614.       free((voidp *)m);
  1615. #endif
  1616.       z->dosflag = dosflag;
  1617.       if (verbose)
  1618.         fprintf(mesg, "zip diagnostic: including %s\n", z->name);
  1619.     }
  1620.     if (n == label) {
  1621.        label = z->name;
  1622.     }
  1623.   } else if (pcount == 0 || filter(m)) {
  1624.  
  1625.     /* Check that we are not adding the zip file to itself. This
  1626.      * catches cases like "zip -m foo ../dir/foo.zip".
  1627.      */
  1628.     struct stat statb;
  1629.     if (zipstate == -1)
  1630.        zipstate = strcmp(zipfile, "-") != 0 &&
  1631.                    stat(zipfile, &zipstatb) == 0;
  1632.     if (zipstate == 1 && (statb = zipstatb, stat(n, &statb) == 0
  1633.       && zipstatb.st_mode  == statb.st_mode
  1634.       && zipstatb.st_ino   == statb.st_ino
  1635.       && zipstatb.st_dev   == statb.st_dev
  1636.       && zipstatb.st_uid   == statb.st_uid
  1637.       && zipstatb.st_gid   == statb.st_gid
  1638.       && zipstatb.st_size  == statb.st_size
  1639.       && zipstatb.st_mtime == statb.st_mtime
  1640.       && zipstatb.st_ctime == statb.st_ctime))
  1641.       /* Don't compare a_time since we are reading the file */
  1642.          return ZE_OK;
  1643.  
  1644.     /* allocate space and add to list */
  1645.     if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
  1646.         (f->name = malloc(strlen(n) + 1 + PAD)) == NULL)
  1647.     {
  1648.       if (f != NULL)
  1649.         farfree((voidp far *)f);
  1650.       return ZE_MEM;
  1651.     }
  1652.     strcpy(f->name, n);
  1653.     f->zname = m;
  1654.     f->dosflag = dosflag;
  1655.     *fnxt = f;
  1656.     f->lst = fnxt;
  1657.     f->nxt = NULL;
  1658.     fnxt = &f->nxt;
  1659.     fcount++;
  1660.     if (n == label) {
  1661.       label = f->name;
  1662.     }
  1663.   }
  1664.   return ZE_OK;
  1665. }
  1666.  
  1667.  
  1668. int procname(n)
  1669. char *n;                /* name to process */
  1670. /* Process a name or sh expression to operate on (or exclude).  Return
  1671.    an error code in the ZE_ class. */
  1672. {
  1673. #if (!defined(VMS) && !defined(TOPS20))
  1674.   char *a;              /* path and name for recursion */
  1675. #endif
  1676.   dstrm *d;             /* directory stream from opend() */
  1677.   char *e;              /* pointer to name from readd() */
  1678.   int m;                /* matched flag */
  1679.   char *p;              /* path for recursion */
  1680.   struct stat s;        /* result of stat() */
  1681.   struct zlist far *z;  /* steps through zfiles list */
  1682.  
  1683.   if (strcmp(n, "-") == 0)   /* if compressing stdin */
  1684.     return newname(n, 0);
  1685.   else if (
  1686. #ifdef S_IFLNK          /* if symbolic links exist ... */
  1687.       linkput ? lstat(n, &s) :
  1688. #endif /* S_IFLNK */
  1689.       SSTAT(n, &s)
  1690. #if defined(__TURBOC__) || defined(VMS) || defined(__WATCOMC__)
  1691.        /* For these 3 compilers, stat() succeeds on wild card names! */
  1692.       || isshexp(n)
  1693. #endif
  1694.      )
  1695.   {
  1696.     /* Not a file or directory--search for shell expression in zip file */
  1697.     p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
  1698.     m = 1;
  1699.     for (z = zfiles; z != NULL; z = z->nxt) {
  1700.       if (MATCH(p, z->zname))
  1701.       {
  1702.         z->mark = pcount ? filter(z->zname) : 1;
  1703.         if (verbose)
  1704.             fprintf(mesg, "zip diagnostic: %scluding %s\n",
  1705.                z->mark ? "in" : "ex", z->name);
  1706.         m = 0;
  1707.       }
  1708.     }
  1709.     free((voidp *)p);
  1710.     return m ? ZE_MISS : ZE_OK;
  1711.   }
  1712.  
  1713.   /* Live name--use if file, recurse if directory */
  1714. #ifdef __human68k__
  1715.   _toslash(n);
  1716. #endif
  1717. #ifdef MSDOS
  1718.   for (p = n; *p; p++)          /* use / consistently */
  1719.     if (*p == '\\')
  1720.       *p = '/';
  1721. #endif /* MSDOS */
  1722.   if ((s.st_mode & S_IFDIR) == 0)
  1723.   {
  1724.     /* add or remove name of file */
  1725.     if ((m = newname(n, 0)) != ZE_OK)
  1726.       return m;
  1727.   } else {
  1728. #if defined(VMS) || defined(TOPS20)
  1729.     if (dirnames && (m = newname(n, 1)) != ZE_OK) {
  1730.       return m;
  1731.     }
  1732.     /* recurse into directory */
  1733.     if (recurse && (d = opend(n)) != NULL)
  1734.     {
  1735.       while ((e = readd(d)) != NULL) {
  1736.         if ((m = procname(e)) != ZE_OK)     /* recurse on name */
  1737.         {
  1738.           closed(d);
  1739.           return m;
  1740.         }
  1741.       }
  1742.       closed(d);
  1743.     }
  1744. #else /* (VMS || TOPS20) */
  1745.     /* Add trailing / to the directory name */
  1746.     if ((p = malloc(strlen(n)+2)) == NULL)
  1747.       return ZE_MEM;
  1748.     if (strcmp(n, ".") == 0) {
  1749.       *p = 0;  /* avoid "./" prefix and do not create zip entry */
  1750.     } else {
  1751.       strcpy(p, n);
  1752.       a = p + strlen(p);
  1753. #ifdef AMIGA
  1754.       if (*p && a[-1] != '/' && a[-1] != ':')
  1755. #else
  1756.       if (a[-1] != '/')
  1757. #endif
  1758.         strcpy(a, "/");
  1759.       if (dirnames && (m = newname(p, 1)) != ZE_OK) {
  1760.         free((voidp *)p);
  1761.         return m;
  1762.       }
  1763.     }
  1764.     /* recurse into directory */
  1765.     if (recurse && (d = opend(n)) != NULL)
  1766.     {
  1767.       while ((e = readd(d)) != NULL) {
  1768.         if (strcmp(e, ".") && strcmp(e, ".."))
  1769.         {
  1770.           if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
  1771.           {
  1772.             free((voidp *)p);
  1773.             closed(d);
  1774.             return ZE_MEM;
  1775.           }
  1776.           strcat(strcpy(a, p), e);
  1777.           if ((m = procname(a)) != ZE_OK)   /* recurse on name */
  1778.           {
  1779.             if (m == ZE_MISS)
  1780.               warn("name not matched: ", a);
  1781.             else
  1782.               err(m, a);
  1783.           }
  1784.           free((voidp *)a);
  1785.         }
  1786.       }
  1787.       free((voidp *)p);
  1788.       closed(d);
  1789.     }
  1790. #endif /* ? (VMS || TOPS20) */
  1791.   } /* (s.st_mode & S_IFDIR) == 0) */
  1792.   return ZE_OK;
  1793. }
  1794.  
  1795.  
  1796. #if !defined(CRAY) && !defined(__TURBOC__) && !defined(OS2) /* and ... */
  1797. #if !defined( __GO32__)
  1798.  
  1799. local int cmptime(p, q)
  1800. struct tm *p, *q;       /* times to compare */
  1801. /* Return negative if time p is before time q, positive if after, and
  1802.    zero if the same */
  1803. {
  1804.   int r;                /* temporary variable */
  1805.  
  1806.   if (p == NULL)
  1807.     return -1;
  1808.   else if ((r = p->tm_year - q->tm_year) != 0)
  1809.     return r;
  1810.   else if ((r = p->tm_mon - q->tm_mon) != 0)
  1811.     return r;
  1812.   else if ((r = p->tm_mday - q->tm_mday) != 0)
  1813.     return r;
  1814.   else if ((r = p->tm_hour - q->tm_hour) != 0)
  1815.     return r;
  1816.   else if ((r = p->tm_min - q->tm_min) != 0)
  1817.     return r;
  1818.   else
  1819.     return p->tm_sec - q->tm_sec;
  1820. }
  1821.  
  1822.  
  1823. local time_t invlocal(t)
  1824. struct tm *t;           /* time to convert */
  1825. /* Find inverse of localtime() using bisection.  This routine assumes that
  1826.    time_t is an integer type, either signed or unsigned.  The expectation
  1827.    is that sometime before the year 2038, time_t will be made a 64-bit
  1828.    integer, and this routine will still work. */
  1829. {
  1830.   time_t i;             /* midpoint of current root range */
  1831.   time_t l;             /* lower end of root range */
  1832.   time_t u;             /* upper end of root range */
  1833.  
  1834.   /* Bracket the root [0,largest time_t].  Note: if time_t is a 32-bit signed
  1835.      integer, then the upper bound is GMT 1/19/2038 03:14:07, after which all
  1836.      the Unix systems in the world come to a grinding halt.  Either that, or
  1837.      all those systems will suddenly find themselves transported to December
  1838.      of 1901 ... */
  1839.   l = 0;
  1840.   u = 1;
  1841.   while (u < (u << 1))
  1842.     u = (u << 1) + 1;
  1843.  
  1844.   /* Find the root */
  1845.   while (u - l > 1)
  1846.   {
  1847.     i = l + ((u - l) >> 1);
  1848.     if (cmptime(localtime(&i), t) <= 0)
  1849.       l = i;
  1850.     else
  1851.       u = i;
  1852.   }
  1853.   return l;
  1854. }
  1855. #endif
  1856. #endif
  1857.  
  1858.  
  1859. void stamp(f, d)
  1860. char *f;                /* name of file to change */
  1861. ulg d;                  /* dos-style time to change it to */
  1862. /* Set last updated and accessed time of file f to the DOS time d. */
  1863. {
  1864. #if defined(MACOS)
  1865.   warn("timestamp not implemented yet", "");
  1866. #else
  1867. #ifdef __TURBOC__
  1868.   int h;                /* file handle */
  1869.  
  1870.   if ((h = open(f, 0)) != -1)
  1871.   {
  1872. #ifdef ATARI_ST
  1873.     d = ( d >> 16 ) | ( d << 16 );
  1874. #endif
  1875.     setftime(h, (struct ftime *)&d);
  1876.     close(h);
  1877.   }
  1878. #else /* !__TURBOC__ */
  1879. #ifdef VMS
  1880.   int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year;
  1881.   char timbuf[24];
  1882.   static char *month[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  1883.                           "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  1884.   struct VMStimbuf {
  1885.       char *actime;           /* VMS revision date, ASCII format */
  1886.       char *modtime;          /* VMS creation date, ASCII format */
  1887.   } ascii_times = {timbuf, timbuf};
  1888.  
  1889.   /* Convert DOS time to ASCII format for VMSmunch */
  1890.   tm_sec = (int)(d << 1) & 0x3e;
  1891.   tm_min = (int)(d >> 5) & 0x3f;
  1892.   tm_hour = (int)(d >> 11) & 0x1f;
  1893.   tm_mday = (int)(d >> 16) & 0x1f;
  1894.   tm_mon = ((int)(d >> 21) & 0xf) - 1;
  1895.   tm_year = ((int)(d >> 25) & 0x7f) + 1980;
  1896.   sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", tm_mday, month[tm_mon],
  1897.     tm_year, tm_hour, tm_min, tm_sec);
  1898.  
  1899.   /* Set updated and accessed times of f */
  1900.   if (VMSmunch(f, SET_TIMES, &ascii_times) != RMS$_NMF)
  1901.     warn("can't set zipfile time: ", f);
  1902.  
  1903. #else /* !VMS */
  1904. #ifdef OS2
  1905.   SetFileTime(f, d);
  1906. #else /* !OS2 */
  1907.   struct tm t;          /* argument for mktime() or invlocal() */
  1908. #if defined(WIN32) || defined(sgi)
  1909.   struct utimbuf u;     /* argument for utime() */
  1910. #else
  1911.   time_t u[2];          /* argument for utime() */
  1912. #endif
  1913. #ifndef __GO32__
  1914.   extern time_t mktime OF((struct tm *));
  1915. #endif
  1916.  
  1917.   /* Convert DOS time to time_t format in u[0] and u[1] */
  1918.   t.tm_sec = (int)(d << 1) & 0x3e;
  1919.   t.tm_min = (int)(d >> 5) & 0x3f;
  1920.   t.tm_hour = (int)(d >> 11) & 0x1f;
  1921.   t.tm_mday = (int)(d >> 16) & 0x1f;
  1922.   t.tm_mon = ((int)(d >> 21) & 0xf) - 1;
  1923.   t.tm_year = ((int)(d >> 25) & 0x7f) + 80;
  1924. #if defined(WIN32) || defined (sgi)
  1925.   u.actime = u.modtime = mktime(&t);
  1926. #else
  1927. # if defined(MSDOS) || defined(OS2) || defined(CRAY)
  1928.   /* mktime() is more reliable than invlocal() because the time range is
  1929.    * wider on MSDOS than on Unix; required for Cray because invlocal assumes
  1930.    * 32-bit ints
  1931.    */
  1932.   u[0] = u[1] = mktime(&t);
  1933. # else
  1934.   u[0] = u[1] = invlocal(&t);
  1935. # endif
  1936. #endif
  1937.  
  1938.   /* Set updated and accessed times of f */
  1939. #if defined(WIN32) || defined(sgi)
  1940.   utime(f, &u);
  1941. #else
  1942.   utime(f, u);
  1943. #endif
  1944. #endif /* ?OS2 */
  1945. #endif /* ?VMS */
  1946. #endif /* ?__TURBOC__ */
  1947. #endif /* ?MACOS */
  1948. }
  1949.  
  1950.  
  1951. local void inctime(s)
  1952. struct tm *s;           /* time to increment in place */
  1953. /* Increment the time structure *s by one second, return the result in
  1954.    place. */
  1955. {
  1956.   int y;                /* temporary variable */
  1957.  
  1958.   /* days in each month, except for February */
  1959.   static int days[] = {31,0,31,30,31,30,31,31,30,31,30,31};
  1960.  
  1961.   /* Set days in February from year (1900 is a leap year, 2000 is not) */
  1962.   y = s->tm_year + 1900;
  1963.   days[1] = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) ? 29 : 28;
  1964.  
  1965.   /* Increment time with carry */
  1966.   if (s->tm_sec != 59)
  1967.     s->tm_sec++;
  1968.   else if (s->tm_sec = 0, s->tm_min != 59)
  1969.     s->tm_min++;
  1970.   else if (s->tm_min = 0, s->tm_hour != 23)
  1971.     s->tm_hour++;
  1972.   else if (s->tm_hour = 0, s->tm_mday != days[s->tm_mon])
  1973.     s->tm_mday++;
  1974.   else if (s->tm_mday = 1, s->tm_mon != 11)
  1975.     s->tm_mon++;
  1976.   else
  1977.   {
  1978.     s->tm_mon = 0;
  1979.     s->tm_year++;
  1980.   }
  1981. }
  1982.  
  1983.  
  1984. ulg dostime(y, n, d, h, m, s)
  1985. int y;                  /* year */
  1986. int n;                  /* month */
  1987. int d;                  /* day */
  1988. int h;                  /* hour */
  1989. int m;                  /* minute */
  1990. int s;                  /* second */
  1991. /* Convert the date y/n/d and time h:m:s to a four byte DOS date and
  1992.    time (date in high two bytes, time in low two bytes allowing magnitude
  1993.    comparison). */
  1994. {
  1995.   return y < 1980 ? dostime(1980, 1, 1, 0, 0, 0) :
  1996.         (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
  1997.         ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
  1998. }
  1999.  
  2000.  
  2001. local ulg unix2dostime(t)
  2002. statime *t;             /* unix time to convert */
  2003. /* Return the Unix time t in DOS format, rounded up to the next two
  2004.    second boundary. */
  2005. {
  2006.   struct tm *s;         /* result of localtime() */
  2007.  
  2008.   s = localtime(t);             /* Use local time since MSDOS does */
  2009.   inctime(s);                   /* Add one second to round up */
  2010.   return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
  2011.                  s->tm_hour, s->tm_min, s->tm_sec);
  2012. }
  2013.  
  2014.  
  2015. ulg filetime(f, a, n)
  2016. char *f;                /* name of file to get info on */
  2017. ulg *a;                 /* return value: file attributes */
  2018. long *n;                /* return value: file size */
  2019. /* If file *f does not exist, return 0.  Else, return the file's last
  2020.    modified date and time as an MSDOS date and time.  The date and
  2021.    time is returned in a long with the date most significant to allow
  2022.    unsigned integer comparison of absolute times.  Also, if a is not
  2023.    a NULL pointer, store the file attributes there, with the high two
  2024.    bytes being the Unix attributes, and the low byte being a mapping
  2025.    of that to DOS attributes.  If n is not NULL, store the file size
  2026.    there.
  2027.    If f is "-", use standard input as the file. If f is a device, return
  2028.    a file size of -1 */
  2029. {
  2030.   struct stat s;        /* results of stat() */
  2031.   char name[FNMAX];
  2032.   int len = strlen(f);
  2033.  
  2034.   if (f == label) {
  2035.     if (a != NULL)
  2036.       *a = label_mode;
  2037.     if (n != NULL)
  2038.       *n = -2L; /* convention for a label name */
  2039.     return label_time;  /* does not work for unknown reason */
  2040.   }
  2041.   strcpy(name, f);
  2042.   if (name[len - 1] == '/')
  2043.     name[len - 1] = 0; 
  2044.   /* not all systems allow stat'ing a file with / appended */
  2045.  
  2046.   if (strcmp(f, "-") == 0) {
  2047. #if defined(AMIGA) && !defined(__SASC_60)
  2048.   /* forge stat values for stdin since Amiga has no fstat() */
  2049.     s.st_mode = (S_IREAD|S_IWRITE|S_IFREG); 
  2050.     s.st_size = -1;
  2051.     s.st_mtime = time(&s.st_mtime);
  2052. #else /* !AMIGA */
  2053.     if (fstat(fileno(stdin), &s) != 0)
  2054.       error("fstat(stdin)");
  2055. #endif /* ?AMIGA */
  2056.   } else if ((
  2057. #ifdef S_IFLNK
  2058.              linkput ? lstat(name, &s) :
  2059. #endif
  2060.              SSTAT(name, &s)) != 0)
  2061.              /* Accept about any file kind including directories
  2062.               * (stored with trailing / with -r option)
  2063.               */
  2064.     return 0;
  2065.  
  2066.   if (a != NULL) {
  2067. #if defined(MSDOS) || defined(OS2) || defined(__human68k__)
  2068.     *a = ((ulg)s.st_mode << 16) | (ulg)GetFileMode(name);
  2069. #else
  2070.     *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
  2071.     if ((s.st_mode & S_IFDIR) != 0) {
  2072.       *a |= MSDOS_DIR_ATTR;
  2073.     }
  2074. #endif
  2075.   }
  2076.   if (n != NULL)
  2077.     *n = (s.st_mode & S_IFMT) != S_IFREG ? -1L : s.st_size;
  2078.  
  2079. #ifdef OS2
  2080.   return GetFileTime(name);
  2081. #else /* !OS2 */
  2082. #  ifdef VMS
  2083.      return unix2dostime(&s.st_ctime);   /* Use creation time in VMS */
  2084. #  else /* !VMS */
  2085. #    ifdef ATARI_ST
  2086.        return s.st_mtime; /* Turbo C doesn't use UNIX times */
  2087. #    else
  2088. #      ifdef WIN32
  2089.          return GetTheFileTime(name);
  2090. #      else
  2091.          return unix2dostime((statime*)&s.st_mtime);
  2092. #      endif /* WIN32 */
  2093. #    endif
  2094. #  endif /* ?VMS */
  2095. #endif /* ?OS2 */
  2096. }
  2097.  
  2098. #ifdef TOPS20
  2099. #  include <monsym.h>   /* Get amazing monsym() macro */
  2100. #  define       _FBBYV  monsym(".FBBYV")
  2101. #  define         FBBSZ_S       -24     /* Obsolete, replace by FLDGET! */
  2102. #  define         FBBSZ_M       077     /* ditto */
  2103.  
  2104. extern int _gtjfn(), _rljfn(), _gtfdb(), stat();
  2105.  
  2106. int set_extra_field(z)
  2107.   struct zlist *z;
  2108.   /* create extra field and change z->att if desired */
  2109. {
  2110.   int jfn;
  2111.  
  2112.   translate_eol = 0;
  2113.   jfn = _gtjfn(z->name, O_RDONLY);
  2114.   z->att = (((_gtfdb (jfn, _FBBYV) << FBBSZ_S) & FBBSZ_M) != 8) ?
  2115.            ASCII :BINARY;
  2116.   _rljfn(jfn);
  2117.   return 0;
  2118. }
  2119. #else /* !TOPS20 */
  2120. # if !defined(OS2) && !defined(VMS)
  2121.  
  2122. int set_extra_field(z)
  2123.   struct zlist *z;
  2124.   /* create extra field and change z->att if desired */
  2125. {
  2126.   return (int)(z-z);
  2127. }
  2128. # endif /* !OS2 && !VMS */
  2129. #endif /* TOPS20 */
  2130.  
  2131.  
  2132.  
  2133. int issymlnk(a)
  2134. ulg a;                  /* Attributes returned by filetime() */
  2135. /* Return true if the attributes are those of a symbolic link */
  2136. {
  2137. #ifdef S_IFLNK
  2138.   return ((a >> 16) & S_IFMT) == S_IFLNK;
  2139. #else /* !S_IFLNK */
  2140.   return (int)a & 0;    /* avoid warning on unused parameter */
  2141. #endif /* ?S_IFLNK */
  2142. }
  2143.  
  2144.  
  2145. int deletedir(d)
  2146. char *d;                /* directory to delete */
  2147. /* Delete the directory *d if it is empty, do nothing otherwise.
  2148.    Return the result of rmdir(), delete(), or system().
  2149.    For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
  2150.  */
  2151. {
  2152. #if (defined(MACOS) || defined(TOPS20))
  2153.     warn("deletedir not implemented yet", "");
  2154.     return 127;
  2155. #else
  2156. # ifdef RMDIR
  2157.     /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
  2158.     int r, len;
  2159.     char *s;              /* malloc'd string for system command */
  2160.  
  2161.     len = strlen(d);
  2162.     if ((s = malloc(len + 34)) == NULL)
  2163.       return 127;
  2164.  
  2165. #  ifdef VMS
  2166.     system(strcat(strcpy(s, "set prot=(o:rwed) "), d));
  2167.     r = delete(d);
  2168. #  else /* !VMS */
  2169.     sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
  2170.     r = system(s);
  2171. #  endif /* ?VMS */
  2172.     free(s);
  2173.     return r;
  2174. # else /* !RMDIR */
  2175.     return rmdir(d);
  2176. # endif /* ?RMDIR */
  2177. #endif /* ? MACOS || TOPS20 */
  2178. }
  2179.  
  2180.  
  2181. #endif /* !UTIL */
  2182.  
  2183. int destroy(f)
  2184. char *f;                /* file to delete */
  2185. /* Delete the file *f, returning non-zero on failure. */
  2186. {
  2187.   return unlink(f);
  2188. }
  2189.  
  2190.  
  2191. int replace(d, s)
  2192. char *d, *s;            /* destination and source file names */
  2193. /* Replace file *d by file *s, removing the old *s.  Return an error code
  2194.    in the ZE_ class. This function need not preserve the file attributes,
  2195.    this will be done by setfileattr() later.
  2196.  */
  2197. {
  2198.   struct stat t;        /* results of stat() */
  2199.   int copy = 0;
  2200.   int d_exists;
  2201.  
  2202. #ifdef VMS
  2203.   /* stat() is broken on VMS remote files (accessed through Decnet).
  2204.    * This patch allows creation of remote zip files, but is not sufficient
  2205.    * to update them or compress remote files */
  2206.   unlink(d);
  2207. #else
  2208.   d_exists = (LSTAT(d, &t) == 0);
  2209.   if (d_exists)
  2210.   {
  2211.     /*
  2212.      * respect existing soft and hard links!
  2213.      */
  2214.     if (t.st_nlink > 1
  2215. # ifdef S_IFLNK
  2216.         || (t.st_mode & S_IFMT) == S_IFLNK
  2217. # endif
  2218.         )
  2219.        copy = 1;
  2220.     else if (unlink(d))
  2221.        return ZE_CREAT;                 /* Can't erase zip file--give up */
  2222.   }
  2223. #endif /* VMS */
  2224.   if (!copy) {
  2225.       if (link(s, d)) {               /* Just move s on top of d */
  2226.           copy = 1;                     /* failed ? */
  2227. #if !defined(VMS) && !defined(ATARI_ST) && !defined(AMIGA)
  2228.     /* For VMS & ATARI & AMIGA assume failure is EXDEV */
  2229.           if (errno != EXDEV
  2230. #  ifdef ENOTSAM
  2231.            && errno != ENOTSAM /* Used at least on Turbo C */
  2232. #  endif
  2233.               ) return ZE_CREAT;
  2234. #endif
  2235.       }
  2236. #ifndef link    /* UNIX link() */
  2237.       /*
  2238.        * Assuming a UNIX link(2), we still have to remove s.
  2239.        * If link has been #defined to rename(), nothing to do.
  2240.        */
  2241.       else {
  2242. # ifdef KEEP_OWNER
  2243.           if (d_exists)
  2244.               /* this will fail if the user isn't priviledged */
  2245.               chown(d, t.st_uid, t.st_gid);
  2246. # endif
  2247.           unlink(s);
  2248.       }
  2249. #endif          /* ?UNIX link() */
  2250.   }
  2251.  
  2252.   if (copy) {
  2253.     FILE *f, *g;      /* source and destination files */
  2254.     int r;            /* temporary variable */
  2255.  
  2256.     if ((f = fopen(s, FOPR)) == NULL) {
  2257.       fprintf(stderr," replace: can't open %s\n", s);
  2258.       return ZE_TEMP;
  2259.     }
  2260.     if ((g = fopen(d, FOPW)) == NULL)
  2261.     {
  2262.       fclose(f);
  2263.       return ZE_CREAT;
  2264.     }
  2265.     r = fcopy(f, g, (ulg)-1L);
  2266.     fclose(f);
  2267.     if (fclose(g) || r != ZE_OK)
  2268.     {
  2269.       unlink(d);
  2270.       return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
  2271.     }
  2272.     unlink(s);
  2273.   }
  2274.   return ZE_OK;
  2275. }
  2276.  
  2277.  
  2278. int getfileattr(f)
  2279. char *f;                /* file path */
  2280. /* Return the file attributes for file f or 0 if failure */
  2281. {
  2282.   struct stat s;
  2283.  
  2284.   return SSTAT(f, &s) == 0 ? s.st_mode : 0;
  2285. }
  2286.  
  2287.  
  2288. int setfileattr(f, a)
  2289. char *f;                /* file path */
  2290. int a;                  /* attributes returned by getfileattr() */
  2291. /* Give the file f the attributes a, return non-zero on failure */
  2292. {
  2293. #if defined(MACOS) || defined(TOPS20)
  2294.   return 0;
  2295. #else
  2296.   return chmod(f, a);
  2297. #endif
  2298. }
  2299.  
  2300.  
  2301. char *tempname(zip)
  2302.   char *zip;              /* path name of zip file to generate temp name for */
  2303.  
  2304. /* Return a temporary file name in its own malloc'ed space, using tempath. */
  2305. {
  2306.   char *t = zip;   /* malloc'ed space for name (use zip to avoid warning) */
  2307.  
  2308.   if (tempath != NULL)
  2309.   {
  2310.     if ((t = malloc(strlen(tempath)+12)) == NULL)
  2311.       return NULL;
  2312.     strcpy(t, tempath);
  2313. #if (!defined(VMS) && !defined(TOPS20))
  2314. #  ifdef AMIGA
  2315.     {
  2316.           char c = t[strlen(t)-1];
  2317.           if (c != '/' && c != ':')
  2318.             strcat(t, "/");
  2319.     }
  2320. #  else /* !AMIGA */
  2321.           
  2322.     if (t[strlen(t)-1] != '/')
  2323.       strcat(t, "/");
  2324. #  endif  /* ?AMIGA */            
  2325. #endif
  2326.   }
  2327.   else
  2328.   {
  2329.     if ((t = malloc(12)) == NULL)
  2330.       return NULL;
  2331.     *t = 0;
  2332.   }
  2333. #ifdef NO_MKTEMP
  2334.   {
  2335.     char *p = t + strlen(t);
  2336.     sprintf(p, "%08lx", (ulg)time(NULL));
  2337.     return t;
  2338.   }
  2339. #else
  2340.   strcat(t, "_ZXXXXXX");
  2341.   return mktemp(t);
  2342. #endif
  2343. }
  2344.  
  2345.  
  2346. int fcopy(f, g, n)
  2347. FILE *f, *g;            /* source and destination files */
  2348. ulg n;                  /* number of bytes to copy or -1 for all */
  2349. /* Copy n bytes from file *f to file *g, or until EOF if n == -1.  Return
  2350.    an error code in the ZE_ class. */
  2351. {
  2352.   char *b;              /* malloc'ed buffer for copying */
  2353.   extent k;             /* result of fread() */
  2354.   ulg m;                /* bytes copied so far */
  2355.  
  2356.   if ((b = malloc(CBSZ)) == NULL)
  2357.     return ZE_MEM;
  2358.   m = 0;
  2359.   while (n == -1L || m < n)
  2360.   {
  2361.     if ((k = fread(b, 1, n == -1 ?
  2362.                    CBSZ : (n - m < CBSZ ? (extent)(n - m) : CBSZ), f)) == 0)
  2363.       if (ferror(f))
  2364.       {
  2365.         free((voidp *)b);
  2366.         return ZE_READ;
  2367.       }
  2368.       else
  2369.         break;
  2370.     if (fwrite(b, 1, k, g) != k)
  2371.     {
  2372.       free((voidp *)b);
  2373.       fprintf(stderr," fcopy: write error\n");
  2374.       return ZE_TEMP;
  2375.     }
  2376.     m += k;
  2377.   }
  2378.   free((voidp *)b);
  2379.   return ZE_OK;
  2380. }
  2381.  
  2382.  
  2383. #ifdef ZMEM
  2384.  
  2385. /************************/
  2386. /*  Function memset()  */
  2387. /************************/
  2388.  
  2389. /*
  2390.  * memset - for systems without it
  2391.  *  bill davidsen - March 1990
  2392.  */
  2393.  
  2394. char *
  2395. memset(buf, init, len)
  2396. register char *buf;     /* buffer loc */
  2397. register int init;      /* initializer */
  2398. register unsigned int len;   /* length of the buffer */
  2399. {
  2400.     char *start;
  2401.  
  2402.     start = buf;
  2403.     while (len--) *(buf++) = init;
  2404.     return(start);
  2405. }
  2406.  
  2407.  
  2408. /************************/
  2409. /*  Function memcpy()  */
  2410. /************************/
  2411.  
  2412. char *
  2413. memcpy(dst,src,len)           /* v2.0f */
  2414. register char *dst, *src;
  2415. register unsigned int len;
  2416. {
  2417.     char *start;
  2418.  
  2419.     start = dst;
  2420.     while (len--)
  2421.         *dst++ = *src++;
  2422.     return(start);
  2423. }
  2424.  
  2425.  
  2426. /************************/
  2427. /*  Function memcmp()  */
  2428. /************************/
  2429.  
  2430. int
  2431. memcmp(b1,b2,len)                     /* jpd@usl.edu -- 11/16/90 */
  2432. register char *b1, *b2;
  2433. register unsigned int len;
  2434. {
  2435.  
  2436.     if (len) do {             /* examine each byte (if any) */
  2437.       if (*b1++ != *b2++)
  2438.         return (*((uch *)b1-1) - *((uch *)b2-1));  /* exit when miscompare */
  2439.        } while (--len);
  2440.  
  2441.     return(0);        /* no miscompares, yield 0 result */
  2442. }
  2443.  
  2444. #endif  /* ZMEM */
  2445.  
  2446. #ifdef TOPS20
  2447.  
  2448. int
  2449. strupper(s)     /* Returns s in uppercase */
  2450. char *s;        /* String to be uppercased */
  2451. {
  2452.     char    *p;
  2453.  
  2454.     p = s;
  2455.     for (; *p; p++)
  2456.         *p = toupper (*p);
  2457. }
  2458.  
  2459. int
  2460. strlower(s)     /* Returns s in lowercase. */
  2461. char *s;        /* String to be lowercased */
  2462. {
  2463.     char    *p;
  2464.  
  2465.     p = s;
  2466.     for (; *p; p++)
  2467.         *p = tolower (*p);
  2468. }
  2469. #endif /* TOPS20 */
  2470.  
  2471. #if defined(__TURBOC__) && !defined(OS2)
  2472.  
  2473. /************************/
  2474. /*  Function fcalloc()  */
  2475. /************************/
  2476.  
  2477. /* Turbo C malloc() does not allow dynamic allocation of 64K bytes
  2478.  * and farmalloc(64K) returns a pointer with an offset of 8, so we
  2479.  * must fix the pointer. Warning: the pointer must be put back to its
  2480.  * original form in order to free it, use fcfree().
  2481.  * For MSC, use halloc instead of this function (see tailor.h).
  2482.  */
  2483. static ush ptr_offset = 0;
  2484.  
  2485. void * fcalloc(items, size)
  2486.     unsigned items; /* number of items */
  2487.     unsigned size;  /* item size */
  2488. {
  2489.     void * buf = farmalloc((ulg)items*size + 16L);
  2490.     if (buf == NULL) return NULL;
  2491.     /* Normalize the pointer to seg:0 */
  2492.     if (ptr_offset == 0) {
  2493.         ptr_offset = (ush)((uch*)buf-0);
  2494.     } else if (ptr_offset != (ush)((uch*)buf-0)) {
  2495.         err(ZE_LOGIC, "inconsistent ptr_offset");
  2496.     }
  2497.     *((ush*)&buf+1) += (ptr_offset + 15) >> 4;
  2498.     *(ush*)&buf = 0;
  2499.     return buf;
  2500. }
  2501.  
  2502. void fcfree(ptr)
  2503.     void *ptr; /* region allocated with fcalloc() */
  2504. {
  2505.     /* Put the pointer back to its original form: */
  2506.     *((ush*)&ptr+1) -= (ptr_offset + 15) >> 4;
  2507.     *(ush*)&ptr = ptr_offset;
  2508.     farfree(ptr);
  2509.  }
  2510.  
  2511. #endif /* __TURBOC__ && !OS2 */
  2512.