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