1/*
2  fileio.c - Zip 3
3
4  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
5
6  See the accompanying file LICENSE, version 2007-Mar-4 or later
7  (the contents of which are also included in zip.h) for terms of use.
8  If, for some reason, all these files are missing, the Info-ZIP license
9  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
10*/
11/*
12 *  fileio.c by Mark Adler
13 */
14#define __FILEIO_C
15
16#include "zip.h"
17#include "crc32.h"
18
19#ifdef MACOS
20#  include "helpers.h"
21#endif
22
23#ifdef VMS
24#  include "vms/vms.h"
25#endif /* def VMS */
26
27#include <time.h>
28
29#ifdef NO_MKTIME
30time_t mktime OF((struct tm *));
31#endif
32
33#ifdef OSF
34#define EXDEV 18   /* avoid a bug in the DEC OSF/1 header files. */
35#else
36#include <errno.h>
37#endif
38
39#ifdef NO_ERRNO
40extern int errno;
41#endif
42
43/* -----------------------
44   For long option support
45   ----------------------- */
46#include <ctype.h>
47
48
49#if defined(VMS) || defined(TOPS20)
50#  define PAD 5
51#else
52#  define PAD 0
53#endif
54
55#ifdef NO_RENAME
56int rename OF((ZCONST char *, ZCONST char *));
57#endif
58
59
60/* Local functions */
61local int optionerr OF((char *, ZCONST char *, int, int));
62local unsigned long get_shortopt OF((char **, int, int *, int *, char **, int *, int));
63local unsigned long get_longopt OF((char **, int, int *, int *, char **, int *, int));
64
65#ifdef UNICODE_SUPPORT
66local int utf8_char_bytes OF((ZCONST char *utf8));
67local long ucs4_char_from_utf8 OF((ZCONST char **utf8 ));
68local int utf8_from_ucs4_char OF((char *utf8buf, ulg ch));
69local int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *usc4buf,
70                                  int buflen));
71local int ucs4_string_to_utf8 OF((ZCONST ulg *ucs4, char *utf8buf,
72                                  int buflen));
73#if 0
74  local int utf8_chars OF((ZCONST char *utf8));
75#endif
76#endif /* UNICODE_SUPPORT */
77
78#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
79
80local int fqcmp  OF((ZCONST zvoid *, ZCONST zvoid *));
81local int fqcmpz OF((ZCONST zvoid *, ZCONST zvoid *));
82
83
84/* Local module level variables. */
85char *label = NULL;                /* global, but only used in `system'.c */
86local z_stat zipstatb;             /* now use z_stat globally - 7/24/04 EG */
87#if defined(UNICODE_SUPPORT) && defined(WIN32)
88 local zw_stat zipstatbw;
89#endif
90#if (!defined(MACOS) && !defined(WINDLL))
91local int zipstate = -1;
92#else
93int zipstate;
94#endif
95/* -1 unknown, 0 old zip file exists, 1 new zip file */
96
97#if 0
98char *getnam(n, fp)
99char *n;                /* where to put name (must have >=FNMAX+1 bytes) */
100#endif
101
102/* converted to return string pointer from malloc to avoid
103   size limitation - 11/8/04 EG */
104#define GETNAM_MAX 9000 /* hopefully big enough for now */
105char *getnam(fp)
106  FILE *fp;
107  /* Read a \n or \r delimited name from stdin into n, and return
108     n.  If EOF, then return NULL.  Also, if problem return NULL. */
109{
110  char name[GETNAM_MAX + 1];
111  int c;                /* last character read */
112  char *p;              /* pointer into name area */
113
114
115  p = name;
116  while ((c = getc(fp)) == '\n' || c == '\r')
117    ;
118  if (c == EOF)
119    return NULL;
120  do {
121    if (p - name >= GETNAM_MAX)
122      return NULL;
123    *p++ = (char) c;
124    c = getc(fp);
125  } while (c != EOF && (c != '\n' && c != '\r'));
126#ifdef WIN32
127/*
128 * WIN32 strips off trailing spaces and periods in filenames
129 * XXX what about a filename that only consists of spaces ?
130 *     Answer: on WIN32, a filename must contain at least one non-space char
131 */
132  while (p > name) {
133    if ((c = p[-1]) != ' ' && c != '.')
134      break;
135    --p;
136  }
137#endif
138  *p = 0;
139  /* malloc a copy */
140  if ((p = malloc(strlen(name) + 1)) == NULL) {
141    return NULL;
142  }
143  strcpy(p, name);
144  return p;
145}
146
147struct flist far *fexpel(f)
148struct flist far *f;    /* entry to delete */
149/* Delete the entry *f in the doubly-linked found list.  Return pointer to
150   next entry to allow stepping through list. */
151{
152  struct flist far *t;  /* temporary variable */
153
154  t = f->nxt;
155  *(f->lst) = t;                        /* point last to next, */
156  if (t != NULL)
157    t->lst = f->lst;                    /* and next to last */
158  if (f->name != NULL)                  /* free memory used */
159    free((zvoid *)(f->name));
160  if (f->zname != NULL)
161    free((zvoid *)(f->zname));
162  if (f->iname != NULL)
163    free((zvoid *)(f->iname));
164#ifdef UNICODE_SUPPORT
165  if (f->uname)
166    free((zvoid *)f->uname);
167# ifdef WIN32
168  if (f->namew)
169    free((zvoid *)f->namew);
170  if (f->inamew)
171    free((zvoid *)f->inamew);
172  if (f->znamew)
173    free((zvoid *)f->znamew);
174# endif
175#endif
176  farfree((zvoid far *)f);
177  fcount--;                             /* decrement count */
178  return t;                             /* return pointer to next */
179}
180
181local int fqcmp(a, b)
182  ZCONST zvoid *a, *b;          /* pointers to pointers to found entries */
183/* Used by qsort() to compare entries in the found list by name. */
184{
185  return strcmp((*(struct flist far **)a)->name,
186                (*(struct flist far **)b)->name);
187}
188
189local int fqcmpz(a, b)
190  ZCONST zvoid *a, *b;          /* pointers to pointers to found entries */
191/* Used by qsort() to compare entries in the found list by iname. */
192{
193  return strcmp((*(struct flist far **)a)->iname,
194                (*(struct flist far **)b)->iname);
195}
196
197char *last(p, c)
198  char *p;                /* sequence of path components */
199  int c;                  /* path components separator character */
200/* Return a pointer to the start of the last path component. For a directory
201 * name terminated by the character in c, the return value is an empty string.
202 */
203{
204  char *t;              /* temporary variable */
205
206  if ((t = strrchr(p, c)) != NULL)
207    return t + 1;
208  else
209#ifndef AOS_VS
210    return p;
211#else
212/* We want to allow finding of end of path in either AOS/VS-style pathnames
213 * or Unix-style pathnames.  This presents a few little problems ...
214 */
215  {
216    if (*p == '='  ||  *p == '^')      /* like ./ and ../ respectively */
217      return p + 1;
218    else
219      return p;
220  }
221#endif
222}
223
224#if defined(UNICODE_SUPPORT) && defined(WIN32)
225wchar_t *lastw(pw, c)
226  wchar_t *pw;            /* sequence of path components */
227  wchar_t c;              /* path components separator character */
228/* Return a pointer to the start of the last path component. For a directory
229 * name terminated by the character in c, the return value is an empty string.
230 */
231{
232  wchar_t *tw;            /* temporary variable */
233
234  if ((tw = wcsrchr(pw, c)) != NULL)
235    return tw + 1;
236  else
237# ifndef AOS_VS
238    return pw;
239# else
240/* We want to allow finding of end of path in either AOS/VS-style pathnames
241 * or Unix-style pathnames.  This presents a few little problems ...
242 */
243  {
244    if (*pw == (wchar_t)'='  ||  *pw == (wchar_t)'^')      /* like ./ and ../ respectively */
245      return pw + 1;
246    else
247      return pw;
248  }
249# endif
250}
251#endif
252
253
254char *msname(n)
255  char *n;
256/* Reduce all path components to MSDOS upper case 8.3 style names. */
257{
258  int c;                /* current character */
259  int f;                /* characters in current component */
260  char *p;              /* source pointer */
261  char *q;              /* destination pointer */
262
263  p = q = n;
264  f = 0;
265  while ((c = (unsigned char)*POSTINCSTR(p)) != 0)
266    if (c == ' ' || c == ':' || c == '"' || c == '*' || c == '+' ||
267        c == ',' || c == ';' || c == '<' || c == '=' || c == '>' ||
268        c == '?' || c == '[' || c == ']' || c == '|')
269      continue;                         /* char is discarded */
270    else if (c == '/')
271    {
272      *POSTINCSTR(q) = (char)c;
273      f = 0;                            /* new component */
274    }
275#ifdef __human68k__
276    else if (ismbblead(c) && *p)
277    {
278      if (f == 7 || f == 11)
279        f++;
280      else if (*p && f < 12 && f != 8)
281      {
282        *q++ = c;
283        *q++ = *p++;
284        f += 2;
285      }
286    }
287#endif /* __human68k__ */
288    else if (c == '.')
289    {
290      if (f == 0)
291        continue;                       /* leading dots are discarded */
292      else if (f < 9)
293      {
294        *POSTINCSTR(q) = (char)c;
295        f = 9;                          /* now in file type */
296      }
297      else
298        f = 12;                         /* now just excess characters */
299    }
300    else
301      if (f < 12 && f != 8)
302      {
303        f += CLEN(p);                   /* do until end of name or type */
304        *POSTINCSTR(q) = (char)(to_up(c));
305      }
306  *q = 0;
307  return n;
308}
309
310#ifdef UNICODE_SUPPORT
311wchar_t *msnamew(nw)
312  wchar_t *nw;
313/* Reduce all path components to MSDOS upper case 8.3 style names. */
314{
315  wchar_t c;            /* current character */
316  int f;                /* characters in current component */
317  wchar_t *pw;          /* source pointer */
318  wchar_t *qw;          /* destination pointer */
319
320  pw = qw = nw;
321  f = 0;
322  while ((c = (unsigned char)*pw++) != 0)
323    if (c == ' ' || c == ':' || c == '"' || c == '*' || c == '+' ||
324        c == ',' || c == ';' || c == '<' || c == '=' || c == '>' ||
325        c == '?' || c == '[' || c == ']' || c == '|')
326      continue;                         /* char is discarded */
327    else if (c == '/')
328    {
329      *qw++ = c;
330      f = 0;                            /* new component */
331    }
332#ifdef __human68k__
333    else if (ismbblead(c) && *pw)
334    {
335      if (f == 7 || f == 11)
336        f++;
337      else if (*pw && f < 12 && f != 8)
338      {
339        *qw++ = c;
340        *qw++ = *pw++;
341        f += 2;
342      }
343    }
344#endif /* __human68k__ */
345    else if (c == '.')
346    {
347      if (f == 0)
348        continue;                       /* leading dots are discarded */
349      else if (f < 9)
350      {
351        *qw++ = c;
352        f = 9;                          /* now in file type */
353      }
354      else
355        f = 12;                         /* now just excess characters */
356    }
357    else
358      if (f < 12 && f != 8)
359      {
360        f++;                            /* do until end of name or type */
361        *qw++ = towupper(c);
362      }
363  *qw = 0;
364  return nw;
365}
366#endif
367
368
369int proc_archive_name(n, caseflag)
370  char *n;             /* name to process */
371  int caseflag;         /* true to force case-sensitive match */
372/* Process a name or sh expression in existing archive to operate
373   on (or exclude).  Return an error code in the ZE_ class. */
374{
375  int m;                /* matched flag */
376  char *p;              /* path for recursion */
377  struct zlist far *z;  /* steps through zfiles list */
378
379  if (strcmp(n, "-") == 0) {   /* if compressing stdin */
380    zipwarn("Cannot select stdin when selecting archive entries", "");
381    return ZE_MISS;
382  }
383  else
384  {
385    /* Search for shell expression in zip file */
386    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
387    m = 1;
388    for (z = zfiles; z != NULL; z = z->nxt) {
389      if (MATCH(p, z->iname, caseflag))
390      {
391        z->mark = pcount ? filter(z->zname, caseflag) : 1;
392        if (verbose)
393            fprintf(mesg, "zip diagnostic: %scluding %s\n",
394               z->mark ? "in" : "ex", z->oname);
395        m = 0;
396      }
397    }
398#ifdef UNICODE_SUPPORT
399    /* also check escaped Unicode names */
400    for (z = zfiles; z != NULL; z = z->nxt) {
401      if (z->zuname) {
402#ifdef WIN32
403        /* It seems something is lost in going from a listed
404           name from zip -su in a console window to using that
405           name in a command line.  This kluge may fix it
406           and just takes zuname, converts to oem (i.e. ouname),
407           then converts it back which ends up not the same as
408           started with.
409         */
410        char *zuname = z->wuname;
411#else
412        char *zuname = z->zuname;
413#endif
414        if (MATCH(p, zuname, caseflag))
415        {
416          z->mark = pcount ? filter(zuname, caseflag) : 1;
417          if (verbose) {
418              fprintf(mesg, "zip diagnostic: %scluding %s\n",
419                 z->mark ? "in" : "ex", z->oname);
420              fprintf(mesg, "     Escaped Unicode:  %s\n",
421                 z->ouname);
422          }
423          m = 0;
424        }
425      }
426    }
427#endif
428    free((zvoid *)p);
429    return m ? ZE_MISS : ZE_OK;
430  }
431}
432
433
434int check_dup()
435/* Sort the found list and remove duplicates.
436   Return an error code in the ZE_ class. */
437{
438  struct flist far *f;          /* steps through found linked list */
439  extent j, k;                  /* indices for s */
440  struct flist far **s;         /* sorted table */
441  struct flist far **nodup;     /* sorted table without duplicates */
442
443  /* sort found list, remove duplicates */
444  if (fcount)
445  {
446    extent fl_size = fcount * sizeof(struct flist far *);
447    if ((fl_size / sizeof(struct flist far *)) != fcount ||
448        (s = (struct flist far **)malloc(fl_size)) == NULL)
449      return ZE_MEM;
450    for (j = 0, f = found; f != NULL; f = f->nxt)
451      s[j++] = f;
452    /* Check names as given (f->name) */
453    qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
454    for (k = j = fcount - 1; j > 0; j--)
455      if (strcmp(s[j - 1]->name, s[j]->name) == 0)
456        /* remove duplicate entry from list */
457        fexpel(s[j]);           /* fexpel() changes fcount */
458      else
459        /* copy valid entry into destination position */
460        s[k--] = s[j];
461    s[k] = s[0];                /* First entry is always valid */
462    nodup = &s[k];              /* Valid entries are at end of array s */
463
464    /* sort only valid items and check for unique internal names (f->iname) */
465    qsort((char *)nodup, fcount, sizeof(struct flist far *), fqcmpz);
466    for (j = 1; j < fcount; j++)
467      if (strcmp(nodup[j - 1]->iname, nodup[j]->iname) == 0)
468      {
469        char tempbuf[FNMAX+4081];
470
471        sprintf(errbuf, "  first full name: %s\n", nodup[j - 1]->name);
472        sprintf(tempbuf, " second full name: %s\n", nodup[j]->name);
473        strcat(errbuf, "                     ");
474        strcat(errbuf, tempbuf);
475#ifdef EBCDIC
476        strtoebc(nodup[j]->iname, nodup[j]->iname);
477#endif
478        sprintf(tempbuf, "name in zip file repeated: %s", nodup[j]->iname);
479        strcat(errbuf, "                     ");
480        strcat(errbuf, tempbuf);
481        if (pathput == 0) {
482          strcat(errbuf, "\n                     this may be a result of using -j");
483        }
484#ifdef EBCDIC
485        strtoasc(nodup[j]->iname, nodup[j]->iname);
486#endif
487        zipwarn(errbuf, "");
488        return ZE_PARMS;
489      }
490    free((zvoid *)s);
491  }
492  return ZE_OK;
493}
494
495int filter(name, casesensitive)
496  char *name;
497  int casesensitive;
498  /* Scan the -R, -i and -x lists for matches to the given name.
499     Return TRUE if the name must be included, FALSE otherwise.
500     Give precedence to -x over -i and -R.
501     Note that if both R and i patterns are given then must
502     have a match for both.
503     This routine relies on the following global variables:
504       patterns                 array of match pattern structures
505       pcount                   total number of patterns
506       icount                   number of -i patterns
507       Rcount                   number of -R patterns
508     These data are set up by the command line parsing code.
509   */
510{
511   unsigned int n;
512   int slashes;
513   char *p, *q;
514   /* without -i patterns, every name matches the "-i select rules" */
515   int imatch = (icount == 0);
516   /* without -R patterns, every name matches the "-R select rules" */
517   int Rmatch = (Rcount == 0);
518
519   if (pcount == 0) return TRUE;
520
521   for (n = 0; n < pcount; n++) {
522      if (!patterns[n].zname[0])        /* it can happen... */
523         continue;
524      p = name;
525      switch (patterns[n].select) {
526       case 'R':
527         if (Rmatch)
528            /* one -R match is sufficient, skip this pattern */
529            continue;
530         /* With -R patterns, if the pattern has N path components (that is,
531            N-1 slashes), then we test only the last N components of name.
532          */
533         slashes = 0;
534         for (q = patterns[n].zname; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
535            slashes++;
536         /* The name may have M path components (M-1 slashes) */
537         for (q = p; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
538            slashes--;
539         /* Now, "slashes" contains the difference "N-M" between the number
540            of path components in the pattern (N) and in the name (M).
541          */
542         if (slashes < 0)
543            /* We found "M > N"
544                --> skip the first (M-N) path components of the name.
545             */
546            for (q = p; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
547               if (++slashes == 0) {
548                  p = q + 1;    /* q points at '/', mblen("/") is 1 */
549                  break;
550               }
551         break;
552       case 'i':
553         if (imatch)
554            /* one -i match is sufficient, skip this pattern */
555            continue;
556         break;
557      }
558      if (MATCH(patterns[n].zname, p, casesensitive)) {
559         switch (patterns[n].select) {
560            case 'x':
561               /* The -x match takes precedence over everything else */
562               return FALSE;
563            case 'R':
564               Rmatch = TRUE;
565               break;
566            default:
567               /* this must be a type -i match */
568               imatch = TRUE;
569               break;
570         }
571      }
572   }
573   return imatch && Rmatch;
574}
575
576
577#ifdef UNICODE_SUPPORT
578# ifdef WIN32
579
580int newnamew(namew, isdir, casesensitive)
581  wchar_t *namew;             /* name to add (or exclude) */
582  int  isdir;                 /* true for a directory */
583  int  casesensitive;         /* true for case-sensitive matching */
584/* Add (or exclude) the name of an existing disk file.  Return an error
585   code in the ZE_ class. */
586{
587  wchar_t *inamew = NULL;     /* internal name */
588  wchar_t *znamew = NULL;     /* external version of iname */
589  wchar_t *undosmw = NULL;    /* zname version with "-j" and "-k" options disabled */
590  char *oname = NULL;         /* iname converted for display */
591  char *name = NULL;
592  char *iname = NULL;
593  char *zname = NULL;
594  char *zuname = NULL;
595  char *undosm = NULL;
596  struct flist far *f;        /* where in found, or new found entry */
597  struct zlist far *z;        /* where in zfiles (if found) */
598  int dosflag;
599
600  /* Scanning files ...
601   *
602   * After 5 seconds output Scanning files...
603   * then a dot every 2 seconds
604   */
605  if (noisy) {
606    /* If find files then output message after delay */
607    if (scan_count == 0) {
608      time_t current = time(NULL);
609      scan_start = current;
610    }
611    scan_count++;
612    if (scan_count % 100 == 0) {
613      time_t current = time(NULL);
614
615      if (current - scan_start > scan_delay) {
616        if (scan_last == 0) {
617          zipmessage_nl("Scanning files ", 0);
618          scan_last = current;
619        }
620        if (current - scan_last > scan_dot_time) {
621          scan_last = current;
622          fprintf(mesg, ".");
623          fflush(mesg);
624        }
625      }
626    }
627  }
628
629  /* Search for name in zip file.  If there, mark it, else add to
630     list of new names to do (or remove from that list). */
631  if ((inamew = ex2inw(namew, isdir, &dosflag)) == NULL)
632    return ZE_MEM;
633
634  /* Discard directory names with zip -rj */
635  if (*inamew == (wchar_t)'\0') {
636
637 /* If extensions needs to be swapped, we will have empty directory names
638    instead of the original directory. For example, zipping 'c.', 'c.main'
639    should zip only 'main.c' while 'c.' will be converted to '\0' by ex2in. */
640
641    if (pathput && !recurse) error("empty name without -j or -r");
642    free((zvoid *)inamew);
643    return ZE_OK;
644  }
645
646  if (dosflag || !pathput) {
647    int save_dosify = dosify, save_pathput = pathput;
648    dosify = 0;
649    pathput = 1;
650    /* zname is temporarly mis-used as "undosmode" iname pointer */
651    if ((znamew = ex2inw(namew, isdir, NULL)) != NULL) {
652      undosmw = in2exw(znamew);
653      free(znamew);
654    }
655    dosify = save_dosify;
656    pathput = save_pathput;
657  }
658  if ((znamew = in2exw(inamew)) == NULL)
659    return ZE_MEM;
660
661  /* Convert names from wchar_t to char */
662
663  name = wchar_to_local_string(namew);
664  iname = wchar_to_local_string(inamew);
665  zname = wchar_to_local_string(znamew);
666
667  oname = local_to_display_string(zname);
668
669  zuname = wchar_to_local_string(znamew);
670
671  if (undosmw == NULL)
672    undosmw = znamew;
673  undosm = wchar_to_local_string(undosmw);
674
675  if ((z = zsearch(zuname)) != NULL) {
676    if (pcount && !filter(undosm, casesensitive)) {
677      /* Do not clear z->mark if "exclude", because, when "dosify || !pathput"
678       * is in effect, two files with different filter options may hit the
679       * same z entry.
680       */
681      if (verbose)
682        fprintf(mesg, "excluding %s\n", oname);
683    } else {
684      z->mark = 1;
685      if ((z->name = malloc(strlen(name) + 1 + PAD)) == NULL) {
686        if (undosmw != znamew)
687          free(undosmw);
688        if (undosm) free(undosm);
689        if (inamew) free(inamew);
690        if (znamew) free(znamew);
691        if (name) free(name);
692        if (iname) free(iname);
693        if (zname) free(zname);
694        if (oname) free(oname);
695        if (zuname) free(zuname);
696        return ZE_MEM;
697      }
698      strcpy(z->name, name);
699      z->oname = oname;
700      oname = NULL;
701      z->dosflag = dosflag;
702
703#ifdef FORCE_NEWNAME
704      free((zvoid *)(z->iname));
705      z->iname = iname;
706      iname = NULL;
707#else
708      /* Better keep the old name. Useful when updating on MSDOS a zip file
709       * made on Unix.
710       */
711#endif /* ? FORCE_NEWNAME */
712    }
713
714    if ((z->namew = (wchar_t *)malloc((wcslen(namew) + 1) * sizeof(wchar_t))) == NULL) {
715      if (undosmw != znamew)
716        free(undosmw);
717      if (undosm) free(undosm);
718      if (inamew) free(inamew);
719      if (znamew) free(znamew);
720      if (name) free(name);
721      if (iname) free(iname);
722      if (zname) free(zname);
723      if (oname) free(oname);
724      if (zuname) free(zuname);
725      return ZE_MEM;
726    }
727    wcscpy(z->namew, namew);
728    z->inamew = inamew;
729    inamew = NULL;
730    z->znamew = znamew;
731    znamew = NULL;
732    z->uname = wchar_to_utf8_string(z->inamew);
733    if (name == label) {
734       label = z->name;
735    }
736  } else if (pcount == 0 || filter(undosm, casesensitive)) {
737
738    /* Check that we are not adding the zip file to itself. This
739     * catches cases like "zip -m foo ../dir/foo.zip".
740     */
741/* Version of stat() for CMS/MVS isn't complete enough to see if       */
742/* files match.  Just let ZIP.C compare the filenames.  That's good    */
743/* enough for CMS anyway since there aren't paths to worry about.      */
744    zw_stat statbw;     /* need for wide stat */
745    wchar_t *zipfilew = local_to_wchar_string(zipfile);
746
747    if (zipstate == -1)
748       zipstate = strcmp(zipfile, "-") != 0 &&
749                   zwstat(zipfilew, &zipstatbw) == 0;
750    free(zipfilew);
751
752    if (zipstate == 1 && (statbw = zipstatbw, zwstat(namew, &statbw) == 0
753      && zipstatbw.st_mode  == statbw.st_mode
754      && zipstatbw.st_ino   == statbw.st_ino
755      && zipstatbw.st_dev   == statbw.st_dev
756      && zipstatbw.st_uid   == statbw.st_uid
757      && zipstatbw.st_gid   == statbw.st_gid
758      && zipstatbw.st_size  == statbw.st_size
759      && zipstatbw.st_mtime == statbw.st_mtime
760      && zipstatbw.st_ctime == statbw.st_ctime)) {
761      /* Don't compare a_time since we are reading the file */
762        if (verbose)
763          fprintf(mesg, "file matches zip file -- skipping\n");
764        if (undosmw != znamew)
765          free(undosmw);
766        if (undosm) free(undosm);
767        if (inamew) free(inamew);
768        if (znamew) free(znamew);
769        if (name) free(name);
770        if (iname) free(iname);
771        if (zname) free(zname);
772        if (oname) free(oname);
773        if (zuname) free(zuname);
774        return ZE_OK;
775    }
776
777    /* allocate space and add to list */
778    if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
779        fcount + 1 < fcount ||
780        (f->name = malloc(strlen(name) + 1 + PAD)) == NULL)
781    {
782      if (f != NULL)
783        farfree((zvoid far *)f);
784      if (undosmw != znamew)
785        free(undosmw);
786      if (undosm) free(undosm);
787      if (inamew) free(inamew);
788      if (znamew) free(znamew);
789      if (name) free(name);
790      if (iname) free(iname);
791      if (zname) free(zname);
792      if (oname) free(oname);
793      if (zuname) free(zuname);
794      return ZE_MEM;
795    }
796    if (undosmw != znamew)
797      free((zvoid *)undosmw);
798    strcpy(f->name, name);
799    f->iname = iname;
800    iname = NULL;
801    f->zname = zname;
802    zname = NULL;
803    /* Unicode */
804    if ((f->namew = (wchar_t *)malloc((wcslen(namew) + 1) * sizeof(wchar_t))) == NULL) {
805      if (f != NULL)
806        farfree((zvoid far *)f);
807      if (undosmw != znamew)
808        free(undosmw);
809      if (undosm) free(undosm);
810      if (inamew) free(inamew);
811      if (znamew) free(znamew);
812      if (name) free(name);
813      if (iname) free(iname);
814      if (zname) free(zname);
815      if (oname) free(oname);
816      if (zuname) free(zuname);
817      return ZE_MEM;
818    }
819    wcscpy(f->namew, namew);
820    f->znamew = znamew;
821    znamew = NULL;
822    f->uname = wchar_to_utf8_string(inamew);
823    f->inamew = inamew;
824    inamew = NULL;
825    f->oname = oname;
826    oname = NULL;
827    f->dosflag = dosflag;
828    *fnxt = f;
829    f->lst = fnxt;
830    f->nxt = NULL;
831    fnxt = &f->nxt;
832    fcount++;
833    if (name == label) {
834      label = f->name;
835    }
836  }
837  if (undosm) free(undosm);
838  if (inamew) free(inamew);
839  if (znamew) free(znamew);
840  if (name) free(name);
841  if (iname) free(iname);
842  if (zname) free(zname);
843  if (oname) free(oname);
844  if (zuname) free(zuname);
845  return ZE_OK;
846}
847
848# endif
849#endif
850
851int newname(name, isdir, casesensitive)
852  char *name;           /* name to add (or exclude) */
853  int  isdir;           /* true for a directory */
854  int  casesensitive;   /* true for case-sensitive matching */
855/* Add (or exclude) the name of an existing disk file.  Return an error
856   code in the ZE_ class. */
857{
858  char *iname, *zname;  /* internal name, external version of iname */
859  char *undosm;         /* zname version with "-j" and "-k" options disabled */
860  char *oname;          /* iname converted for display */
861  struct flist far *f;  /* where in found, or new found entry */
862  struct zlist far *z;  /* where in zfiles (if found) */
863  int dosflag;
864
865  /* Scanning files ...
866   *
867   * After 5 seconds output Scanning files...
868   * then a dot every 2 seconds
869   */
870  if (noisy) {
871    /* If find files then output message after delay */
872    if (scan_count == 0) {
873      time_t current = time(NULL);
874      scan_start = current;
875    }
876    scan_count++;
877    if (scan_count % 100 == 0) {
878      time_t current = time(NULL);
879
880      if (current - scan_start > scan_delay) {
881        if (scan_last == 0) {
882          zipmessage_nl("Scanning files ", 0);
883          scan_last = current;
884        }
885        if (current - scan_last > scan_dot_time) {
886          scan_last = current;
887          fprintf(mesg, ".");
888          fflush(mesg);
889        }
890      }
891    }
892  }
893
894  /* Search for name in zip file.  If there, mark it, else add to
895     list of new names to do (or remove from that list). */
896  if ((iname = ex2in(name, isdir, &dosflag)) == NULL)
897    return ZE_MEM;
898
899  /* Discard directory names with zip -rj */
900  if (*iname == '\0') {
901#ifndef AMIGA
902/* A null string is a legitimate external directory name in AmigaDOS; also,
903 * a command like "zip -r zipfile FOO:" produces an empty internal name.
904 */
905# ifndef RISCOS
906 /* If extensions needs to be swapped, we will have empty directory names
907    instead of the original directory. For example, zipping 'c.', 'c.main'
908    should zip only 'main.c' while 'c.' will be converted to '\0' by ex2in. */
909
910    if (pathput && !recurse) error("empty name without -j or -r");
911
912# endif /* !RISCOS */
913#endif /* !AMIGA */
914    free((zvoid *)iname);
915    return ZE_OK;
916  }
917  undosm = NULL;
918  if (dosflag || !pathput) {
919    int save_dosify = dosify, save_pathput = pathput;
920    dosify = 0;
921    pathput = 1;
922    /* zname is temporarly mis-used as "undosmode" iname pointer */
923    if ((zname = ex2in(name, isdir, NULL)) != NULL) {
924      undosm = in2ex(zname);
925      free(zname);
926    }
927    dosify = save_dosify;
928    pathput = save_pathput;
929  }
930  if ((zname = in2ex(iname)) == NULL)
931    return ZE_MEM;
932#ifdef UNICODE_SUPPORT
933  /* Convert name to display or OEM name */
934  oname = local_to_display_string(iname);
935#else
936  if ((oname = malloc(strlen(zname) + 1)) == NULL)
937    return ZE_MEM;
938  strcpy(oname, zname);
939#endif
940  if (undosm == NULL)
941    undosm = zname;
942  if ((z = zsearch(zname)) != NULL) {
943    if (pcount && !filter(undosm, casesensitive)) {
944      /* Do not clear z->mark if "exclude", because, when "dosify || !pathput"
945       * is in effect, two files with different filter options may hit the
946       * same z entry.
947       */
948      if (verbose)
949        fprintf(mesg, "excluding %s\n", oname);
950      free((zvoid *)iname);
951      free((zvoid *)zname);
952    } else {
953      z->mark = 1;
954      if ((z->name = malloc(strlen(name) + 1 + PAD)) == NULL) {
955        if (undosm != zname)
956          free((zvoid *)undosm);
957        free((zvoid *)iname);
958        free((zvoid *)zname);
959        return ZE_MEM;
960      }
961      strcpy(z->name, name);
962      z->oname = oname;
963      z->dosflag = dosflag;
964
965#ifdef FORCE_NEWNAME
966      free((zvoid *)(z->iname));
967      z->iname = iname;
968#else
969      /* Better keep the old name. Useful when updating on MSDOS a zip file
970       * made on Unix.
971       */
972      free((zvoid *)iname);
973      free((zvoid *)zname);
974#endif /* ? FORCE_NEWNAME */
975    }
976#if defined(UNICODE_SUPPORT) && defined(WIN32)
977    z->namew = NULL;
978    z->inamew = NULL;
979    z->znamew = NULL;
980#endif
981    if (name == label) {
982       label = z->name;
983    }
984  } else if (pcount == 0 || filter(undosm, casesensitive)) {
985
986    /* Check that we are not adding the zip file to itself. This
987     * catches cases like "zip -m foo ../dir/foo.zip".
988     */
989#ifndef CMS_MVS
990/* Version of stat() for CMS/MVS isn't complete enough to see if       */
991/* files match.  Just let ZIP.C compare the filenames.  That's good    */
992/* enough for CMS anyway since there aren't paths to worry about.      */
993    z_stat statb;      /* now use structure z_stat and function zstat globally 7/24/04 EG */
994
995    if (zipstate == -1)
996       zipstate = strcmp(zipfile, "-") != 0 &&
997                   zstat(zipfile, &zipstatb) == 0;
998
999    if (zipstate == 1 && (statb = zipstatb, zstat(name, &statb) == 0
1000      && zipstatb.st_mode  == statb.st_mode
1001#ifdef VMS
1002      && memcmp(zipstatb.st_ino, statb.st_ino, sizeof(statb.st_ino)) == 0
1003      && strcmp(zipstatb.st_dev, statb.st_dev) == 0
1004      && zipstatb.st_uid   == statb.st_uid
1005#else /* !VMS */
1006      && zipstatb.st_ino   == statb.st_ino
1007      && zipstatb.st_dev   == statb.st_dev
1008      && zipstatb.st_uid   == statb.st_uid
1009      && zipstatb.st_gid   == statb.st_gid
1010#endif /* ?VMS */
1011      && zipstatb.st_size  == statb.st_size
1012      && zipstatb.st_mtime == statb.st_mtime
1013      && zipstatb.st_ctime == statb.st_ctime)) {
1014      /* Don't compare a_time since we are reading the file */
1015         if (verbose)
1016           fprintf(mesg, "file matches zip file -- skipping\n");
1017         if (undosm != zname)
1018           free((zvoid *)zname);
1019         if (undosm != iname)
1020           free((zvoid *)undosm);
1021         free((zvoid *)iname);
1022         free(oname);
1023         return ZE_OK;
1024    }
1025#endif  /* CMS_MVS */
1026
1027    /* allocate space and add to list */
1028    if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
1029        fcount + 1 < fcount ||
1030        (f->name = malloc(strlen(name) + 1 + PAD)) == NULL)
1031    {
1032      if (f != NULL)
1033        farfree((zvoid far *)f);
1034      if (undosm != zname)
1035        free((zvoid *)undosm);
1036      free((zvoid *)iname);
1037      free((zvoid *)zname);
1038      free(oname);
1039      return ZE_MEM;
1040    }
1041    strcpy(f->name, name);
1042    f->iname = iname;
1043    f->zname = zname;
1044#ifdef UNICODE_SUPPORT
1045    /* Unicode */
1046    f->uname = local_to_utf8_string(iname);
1047#ifdef WIN32
1048    f->namew = NULL;
1049    f->inamew = NULL;
1050    f->znamew = NULL;
1051    if (strcmp(f->name, "-") == 0) {
1052      f->namew = local_to_wchar_string(f->name);
1053    }
1054#endif
1055
1056#endif
1057    f->oname = oname;
1058    f->dosflag = dosflag;
1059
1060    *fnxt = f;
1061    f->lst = fnxt;
1062    f->nxt = NULL;
1063    fnxt = &f->nxt;
1064    fcount++;
1065    if (name == label) {
1066      label = f->name;
1067    }
1068  }
1069  if (undosm != zname)
1070    free((zvoid *)undosm);
1071  return ZE_OK;
1072}
1073
1074ulg dostime(y, n, d, h, m, s)
1075int y;                  /* year */
1076int n;                  /* month */
1077int d;                  /* day */
1078int h;                  /* hour */
1079int m;                  /* minute */
1080int s;                  /* second */
1081/* Convert the date y/n/d and time h:m:s to a four byte DOS date and
1082   time (date in high two bytes, time in low two bytes allowing magnitude
1083   comparison). */
1084{
1085  return y < 1980 ? DOSTIME_MINIMUM /* dostime(1980, 1, 1, 0, 0, 0) */ :
1086        (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
1087        ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
1088}
1089
1090
1091ulg unix2dostime(t)
1092time_t *t;              /* unix time to convert */
1093/* Return the Unix time t in DOS format, rounded up to the next two
1094   second boundary. */
1095{
1096  time_t t_even;
1097  struct tm *s;         /* result of localtime() */
1098
1099  t_even = (time_t)(((unsigned long)(*t) + 1) & (~1));
1100                                /* Round up to even seconds. */
1101  s = localtime(&t_even);       /* Use local time since MSDOS does. */
1102  if (s == (struct tm *)NULL) {
1103      /* time conversion error; use current time as emergency value
1104         (assuming that localtime() does at least accept this value!) */
1105      t_even = (time_t)(((unsigned long)time(NULL) + 1) & (~1));
1106      s = localtime(&t_even);
1107  }
1108  return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
1109                 s->tm_hour, s->tm_min, s->tm_sec);
1110}
1111
1112int issymlnk(a)
1113ulg a;                  /* Attributes returned by filetime() */
1114/* Return true if the attributes are those of a symbolic link */
1115{
1116#ifndef QDOS
1117#ifdef S_IFLNK
1118#ifdef __human68k__
1119  int *_dos_importlnenv(void);
1120
1121  if (_dos_importlnenv() == NULL)
1122    return 0;
1123#endif
1124  return ((a >> 16) & S_IFMT) == S_IFLNK;
1125#else /* !S_IFLNK */
1126  return (int)a & 0;    /* avoid warning on unused parameter */
1127#endif /* ?S_IFLNK */
1128#else
1129  return 0;
1130#endif
1131}
1132
1133#endif /* !UTIL */
1134
1135
1136#if (!defined(UTIL) && !defined(ZP_NEED_GEN_D2U_TIME))
1137   /* There is no need for dos2unixtime() in the ZipUtils' code. */
1138#  define ZP_NEED_GEN_D2U_TIME
1139#endif
1140#if ((defined(OS2) || defined(VMS)) && defined(ZP_NEED_GEN_D2U_TIME))
1141   /* OS/2 and VMS use a special solution to handle time-stams of files. */
1142#  undef ZP_NEED_GEN_D2U_TIME
1143#endif
1144#if (defined(W32_STATROOT_FIX) && !defined(ZP_NEED_GEN_D2U_TIME))
1145   /* The Win32 stat()-bandaid to fix stat'ing root directories needs
1146    * dos2unixtime() to calculate the time-stamps. */
1147#  define ZP_NEED_GEN_D2U_TIME
1148#endif
1149
1150#ifdef ZP_NEED_GEN_D2U_TIME
1151
1152time_t dos2unixtime(dostime)
1153ulg dostime;            /* DOS time to convert */
1154/* Return the Unix time_t value (GMT/UTC time) for the DOS format (local)
1155 * time dostime, where dostime is a four byte value (date in most significant
1156 * word, time in least significant word), see dostime() function.
1157 */
1158{
1159  struct tm *t;         /* argument for mktime() */
1160  ZCONST time_t clock = time(NULL);
1161
1162  t = localtime(&clock);
1163  t->tm_isdst = -1;     /* let mktime() determine if DST is in effect */
1164  /* Convert DOS time to UNIX time_t format */
1165  t->tm_sec  = (((int)dostime) <<  1) & 0x3e;
1166  t->tm_min  = (((int)dostime) >>  5) & 0x3f;
1167  t->tm_hour = (((int)dostime) >> 11) & 0x1f;
1168  t->tm_mday = (int)(dostime >> 16) & 0x1f;
1169  t->tm_mon  = ((int)(dostime >> 21) & 0x0f) - 1;
1170  t->tm_year = ((int)(dostime >> 25) & 0x7f) + 80;
1171
1172  return mktime(t);
1173}
1174
1175#undef ZP_NEED_GEN_D2U_TIME
1176#endif /* ZP_NEED_GEN_D2U_TIME */
1177
1178
1179#ifndef MACOS
1180int destroy(f)
1181  char *f;             /* file to delete */
1182/* Delete the file *f, returning non-zero on failure. */
1183{
1184  return unlink(f);
1185}
1186
1187
1188int replace(d, s)
1189char *d, *s;            /* destination and source file names */
1190/* Replace file *d by file *s, removing the old *s.  Return an error code
1191   in the ZE_ class. This function need not preserve the file attributes,
1192   this will be done by setfileattr() later.
1193 */
1194{
1195  z_stat t;         /* results of stat() */
1196#if defined(CMS_MVS)
1197  /* cmsmvs.h defines FOPW_TEMP as memory(hiperspace).  Since memory is
1198   * lost at end of run, always do copy instead of rename.
1199   */
1200  int copy = 1;
1201#else
1202  int copy = 0;
1203#endif
1204  int d_exists;
1205
1206#if defined(VMS) || defined(CMS_MVS)
1207  /* stat() is broken on VMS remote files (accessed through Decnet).
1208   * This patch allows creation of remote zip files, but is not sufficient
1209   * to update them or compress remote files */
1210  unlink(d);
1211#else /* !(VMS || CMS_MVS) */
1212  d_exists = (LSTAT(d, &t) == 0);
1213  if (d_exists)
1214  {
1215    /*
1216     * respect existing soft and hard links!
1217     */
1218    if (t.st_nlink > 1
1219# ifdef S_IFLNK
1220        || (t.st_mode & S_IFMT) == S_IFLNK
1221# endif
1222        )
1223       copy = 1;
1224    else if (unlink(d))
1225       return ZE_CREAT;                 /* Can't erase zip file--give up */
1226  }
1227#endif /* ?(VMS || CMS_MVS) */
1228#ifndef CMS_MVS
1229  if (!copy) {
1230      if (rename(s, d)) {               /* Just move s on top of d */
1231          copy = 1;                     /* failed ? */
1232#if !defined(VMS) && !defined(ATARI) && !defined(AZTEC_C)
1233#if !defined(CMS_MVS) && !defined(RISCOS) && !defined(QDOS)
1234    /* For VMS, ATARI, AMIGA Aztec, VM_CMS, MVS, RISCOS,
1235       always assume that failure is EXDEV */
1236          if (errno != EXDEV
1237#  ifdef THEOS
1238           && errno != EEXIST
1239#  else
1240#    ifdef ENOTSAM
1241           && errno != ENOTSAM /* Used at least on Turbo C */
1242#    endif
1243#  endif
1244              ) return ZE_CREAT;
1245#endif /* !CMS_MVS && !RISCOS */
1246#endif /* !VMS && !ATARI && !AZTEC_C */
1247      }
1248  }
1249#endif /* !CMS_MVS */
1250
1251  if (copy) {
1252    FILE *f, *g;        /* source and destination files */
1253    int r;              /* temporary variable */
1254
1255#ifdef RISCOS
1256    if (SWI_OS_FSControl_26(s,d,0xA1)!=NULL) {
1257#endif
1258
1259    /* Use zfopen for almost all opens where fopen is used.  For
1260       most OS that support large files we use the 64-bit file
1261       environment and zfopen maps to fopen, but this allows
1262       tweeking ports that don't do that.  7/24/04 */
1263    if ((f = zfopen(s, FOPR)) == NULL) {
1264      fprintf(mesg," replace: can't open %s\n", s);
1265      return ZE_TEMP;
1266    }
1267    if ((g = zfopen(d, FOPW)) == NULL)
1268    {
1269      fclose(f);
1270      return ZE_CREAT;
1271    }
1272
1273    r = fcopy(f, g, (ulg)-1L);
1274    fclose(f);
1275    if (fclose(g) || r != ZE_OK)
1276    {
1277      unlink(d);
1278      return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
1279    }
1280    unlink(s);
1281#ifdef RISCOS
1282    }
1283#endif
1284  }
1285  return ZE_OK;
1286}
1287#endif /* !MACOS */
1288
1289
1290int getfileattr(f)
1291char *f;                /* file path */
1292/* Return the file attributes for file f or 0 if failure */
1293{
1294#ifdef __human68k__
1295  struct _filbuf buf;
1296
1297  return _dos_files(&buf, f, 0xff) < 0 ? 0x20 : buf.atr;
1298#else
1299  z_stat s;
1300
1301  return SSTAT(f, &s) == 0 ? (int) s.st_mode : 0;
1302#endif
1303}
1304
1305
1306int setfileattr(f, a)
1307char *f;                /* file path */
1308int a;                  /* attributes returned by getfileattr() */
1309/* Give the file f the attributes a, return non-zero on failure */
1310{
1311#if defined(TOPS20) || defined (CMS_MVS)
1312  return 0;
1313#else
1314#ifdef __human68k__
1315  return _dos_chmod(f, a) < 0 ? -1 : 0;
1316#else
1317  return chmod(f, a);
1318#endif
1319#endif
1320}
1321
1322
1323/* tempname */
1324
1325#ifndef VMS /* VMS-specific function is in VMS.C. */
1326
1327char *tempname(zip)
1328  char *zip;              /* path name of zip file to generate temp name for */
1329
1330/* Return a temporary file name in its own malloc'ed space, using tempath. */
1331{
1332  char *t = zip;   /* malloc'ed space for name (use zip to avoid warning) */
1333
1334# ifdef CMS_MVS
1335  if ((t = malloc(strlen(tempath) + L_tmpnam + 2)) == NULL)
1336    return NULL;
1337
1338#  ifdef VM_CMS
1339  tmpnam(t);
1340  /* Remove filemode and replace with tempath, if any. */
1341  /* Otherwise A-disk is used by default */
1342  *(strrchr(t, ' ')+1) = '\0';
1343  if (tempath!=NULL)
1344     strcat(t, tempath);
1345  return t;
1346#  else   /* !VM_CMS */
1347  /* For MVS */
1348  tmpnam(t);
1349  if (tempath != NULL)
1350  {
1351    int l1 = strlen(t);
1352    char *dot;
1353    if (*t == '\'' && *(t+l1-1) == '\'' && (dot = strchr(t, '.')))
1354    {
1355      /* MVS and not OE.  tmpnam() returns quoted string of 5 qualifiers.
1356       * First is HLQ, rest are timestamps.  User can only replace HLQ.
1357       */
1358      int l2 = strlen(tempath);
1359      if (strchr(tempath, '.') || l2 < 1 || l2 > 8)
1360        ziperr(ZE_PARMS, "On MVS and not OE, tempath (-b) can only be HLQ");
1361      memmove(t+1+l2, dot, l1+1-(dot-t));  /* shift dot ready for new hlq */
1362      memcpy(t+1, tempath, l2);            /* insert new hlq */
1363    }
1364    else
1365    {
1366      /* MVS and probably OE.  tmpnam() returns filename based on TMPDIR,
1367       * no point in even attempting to change it.  User should modify TMPDIR
1368       * instead.
1369       */
1370      zipwarn("MVS, assumed to be OE, change TMPDIR instead of option -b: ",
1371              tempath);
1372    }
1373  }
1374  return t;
1375#  endif  /* !VM_CMS */
1376
1377# else /* !CMS_MVS */
1378
1379#  ifdef TANDEM
1380  char cur_subvol [FILENAME_MAX];
1381  char temp_subvol [FILENAME_MAX];
1382  char *zptr;
1383  char *ptr;
1384  char *cptr = &cur_subvol[0];
1385  char *tptr = &temp_subvol[0];
1386  short err;
1387  FILE *tempf;
1388  int attempts;
1389
1390  t = (char *)malloc(NAMELEN); /* malloc here as you cannot free */
1391                               /* tmpnam allocated storage later */
1392
1393  zptr = strrchr(zip, TANDEM_DELIMITER);
1394
1395  if (zptr != NULL) {
1396    /* ZIP file specifies a Subvol so make temp file there so it can just
1397       be renamed at end */
1398
1399    *tptr = *cptr = '\0';
1400    strcat(cptr, getenv("DEFAULTS"));
1401
1402    strncat(tptr, zip, _min(FILENAME_MAX, (zptr - zip)) ); /* temp subvol */
1403    strncat(t, zip, _min(NAMELEN, ((zptr - zip) + 1)) );   /* temp stem   */
1404
1405    err = chvol(tptr);
1406    ptr = t + strlen(t);  /* point to end of stem */
1407  }
1408  else
1409    ptr = t;
1410
1411  /* If two zips are running in same subvol then we can get contention problems
1412     with the temporary filename.  As a work around we attempt to create
1413     the file here, and if it already exists we get a new temporary name */
1414
1415  attempts = 0;
1416  do {
1417    attempts++;
1418    tmpnam(ptr);  /* Add filename */
1419    tempf = zfopen(ptr, FOPW_TMP);    /* Attempt to create file */
1420  } while (tempf == NULL && attempts < 100);
1421
1422  if (attempts >= 100) {
1423    ziperr(ZE_TEMP, "Could not get unique temp file name");
1424  }
1425
1426  fclose(tempf);
1427
1428  if (zptr != NULL) {
1429    err = chvol(cptr);  /* Put ourself back to where we came in */
1430  }
1431
1432  return t;
1433
1434#  else /* !CMS_MVS && !TANDEM */
1435/*
1436 * Do something with TMPDIR, TMP, TEMP ????
1437 */
1438  if (tempath != NULL)
1439  {
1440    if ((t = malloc(strlen(tempath) + 12)) == NULL)
1441      return NULL;
1442    strcpy(t, tempath);
1443
1444#   if (!defined(VMS) && !defined(TOPS20))
1445#    ifdef MSDOS
1446    {
1447      char c = (char)lastchar(t);
1448      if (c != '/' && c != ':' && c != '\\')
1449        strcat(t, "/");
1450    }
1451#    else
1452
1453#     ifdef AMIGA
1454    {
1455      char c = (char)lastchar(t);
1456      if (c != '/' && c != ':')
1457        strcat(t, "/");
1458    }
1459#     else /* !AMIGA */
1460#      ifdef RISCOS
1461    if (lastchar(t) != '.')
1462      strcat(t, ".");
1463#      else /* !RISCOS */
1464
1465#       ifdef QDOS
1466    if (lastchar(t) != '_')
1467      strcat(t, "_");
1468#       else
1469    if (lastchar(t) != '/')
1470      strcat(t, "/");
1471#       endif /* ?QDOS */
1472#      endif /* ?RISCOS */
1473#     endif  /* ?AMIGA */
1474#    endif /* ?MSDOS */
1475#   endif /* !VMS && !TOPS20 */
1476  }
1477  else
1478  {
1479    if ((t = malloc(12)) == NULL)
1480      return NULL;
1481    *t = 0;
1482  }
1483#   ifdef NO_MKTEMP
1484  {
1485    char *p = t + strlen(t);
1486    sprintf(p, "%08lx", (ulg)time(NULL));
1487    return t;
1488  }
1489#   else
1490  strcat(t, "ziXXXXXX"); /* must use lowercase for Linux dos file system */
1491#     if defined(UNIX) && !defined(NO_MKSTEMP)
1492  /* tempname should not be called */
1493  return t;
1494#     else
1495  return mktemp(t);
1496#     endif
1497#   endif /* NO_MKTEMP */
1498#  endif /* TANDEM */
1499# endif /* CMS_MVS */
1500}
1501#endif /* !VMS */
1502
1503int fcopy(f, g, n)
1504  FILE *f, *g;            /* source and destination files */
1505  /* now use uzoff_t for all file sizes 5/14/05 CS */
1506  uzoff_t n;               /* number of bytes to copy or -1 for all */
1507/* Copy n bytes from file *f to file *g, or until EOF if (zoff_t)n == -1.
1508   Return an error code in the ZE_ class. */
1509{
1510  char *b;              /* malloc'ed buffer for copying */
1511  extent k;             /* result of fread() */
1512  uzoff_t m;            /* bytes copied so far */
1513
1514  if ((b = malloc(CBSZ)) == NULL)
1515    return ZE_MEM;
1516  m = 0;
1517  while (n == (uzoff_t)(-1L) || m < n)
1518  {
1519    if ((k = fread(b, 1, n == (uzoff_t)(-1) ?
1520                   CBSZ : (n - m < CBSZ ? (extent)(n - m) : CBSZ), f)) == 0)
1521    {
1522      if (ferror(f))
1523      {
1524        free((zvoid *)b);
1525        return ZE_READ;
1526      }
1527      else
1528        break;
1529    }
1530    if (fwrite(b, 1, k, g) != k)
1531    {
1532      free((zvoid *)b);
1533      fprintf(mesg," fcopy: write error\n");
1534      return ZE_TEMP;
1535    }
1536    m += k;
1537  }
1538  free((zvoid *)b);
1539  return ZE_OK;
1540}
1541
1542
1543/* from zipfile.c */
1544
1545#ifdef THEOS
1546 /* Macros cause stack overflow in compiler */
1547 ush SH(uch* p) { return ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)); }
1548 ulg LG(uch* p) { return ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)); }
1549#else /* !THEOS */
1550 /* Macros for converting integers in little-endian to machine format */
1551# define SH(a) ((ush)(((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8)))
1552# define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16))
1553# ifdef ZIP64_SUPPORT           /* zip64 support 08/31/2003 R.Nausedat */
1554#  define LLG(a) ((zoff_t)LG(a) | ((zoff_t)LG((a)+4) << 32))
1555# endif
1556#endif /* ?THEOS */
1557
1558
1559/* always copies from global in_file to global output file y */
1560int bfcopy(n)
1561  /* now use uzoff_t for all file sizes 5/14/05 CS */
1562  uzoff_t n;               /* number of bytes to copy or -1 for all */
1563/* Copy n bytes from in_file to out_file, or until EOF if (zoff_t)n == -1.
1564
1565   Normally we have the compressed size from either the central directory
1566   entry or the local header.
1567
1568   If n != -1 and EOF, close current split and open next and continue
1569   copying.
1570
1571   If n == -2, copy until find the extended header (data descriptor).  Only
1572   used for -FF when no size available.
1573
1574   If fix == 1 calculate CRC of input entry and verify matches.
1575
1576   If fix == 2 and this entry using data descriptor keep a sliding
1577   window in the buffer for looking for signature.
1578
1579   Return an error code in the ZE_ class. */
1580{
1581  char *b;              /* malloc'ed buffer for copying */
1582  extent k;             /* result of fread() */
1583  uzoff_t m;            /* bytes copied so far */
1584  extent brd;           /* bytes to read */
1585  zoff_t data_start = 0;
1586  zoff_t des_start = 0;
1587  char *split_path;
1588  extent kk;
1589  int i;
1590  char sbuf[4];         /* buffer for sliding signature window for fix = 2 */
1591  int des = 0;          /* this entry has data descriptor to find */
1592
1593  if ((b = malloc(CBSZ)) == NULL)
1594    return ZE_MEM;
1595
1596  if (copy_only && !display_globaldots) {
1597    /* initialize dot count */
1598    dot_count = -1;
1599  }
1600
1601  if (fix == 2 && n == (uzoff_t) -2) {
1602    data_start = zftello(in_file);
1603    for (kk = 0; kk < 4; kk++)
1604      sbuf[kk] = 0;
1605    des = 1;
1606  }
1607
1608  des_good = 0;
1609
1610  m = 0;
1611  while (des || n == (uzoff_t)(-1L) || m < n)
1612  {
1613    if (des || n == (uzoff_t)(-1))
1614      brd = CBSZ;
1615    else
1616      brd = (n - m < CBSZ ? (extent)(n - m) : CBSZ);
1617
1618    des_start = zftello(in_file);
1619
1620    if ((k = fread(b, 1, brd, in_file)) == 0)
1621    {
1622      if (fix == 2 && k < brd) {
1623        free((zvoid *)b);
1624        return ZE_READ;
1625      }
1626      else if (ferror(in_file))
1627      {
1628        free((zvoid *)b);
1629        return ZE_READ;
1630      }
1631      else {
1632        break;
1633      }
1634    }
1635
1636
1637    /* end at extended local header (data descriptor) signature */
1638    if (des) {
1639      des_crc = 0;
1640      des_csize = 0;
1641      des_usize = 0;
1642
1643      /* If first 4 bytes in buffer are data descriptor signature then
1644         try to read the data descriptor.
1645         If not, scan for signature and break if found, let bfwrite flush
1646         the data and then next read should put the data descriptor at
1647         the beginning of the buffer.
1648       */
1649
1650      if (
1651          (b[0] != 0x50 /*'P' except EBCDIC*/ ||
1652           b[1] != 0x4b /*'K' except EBCDIC*/ ||
1653           b[2] != '\07' ||
1654           b[3] != '\010')) {
1655        /* buffer is not start of data descriptor */
1656
1657        for (kk = 0; kk < k; kk++) {
1658          /* add byte to end of sbuf */
1659          for (i = 0; i < 3; i++)
1660            sbuf[i] = sbuf[i + 1];
1661          sbuf[3] = b[kk];
1662
1663          /* see if this is signature */
1664          if (
1665              (sbuf[0] == 0x50 /*'P' except EBCDIC*/ &&
1666               sbuf[1] == 0x4b /*'K' except EBCDIC*/ &&
1667               sbuf[2] == '\07' &&
1668               sbuf[3] == '\010')) {
1669            kk -= 3;
1670            if (zfseeko(in_file, bytes_this_split + kk, SEEK_SET) != 0) {
1671              /* seek error */
1672              ZIPERR(ZE_READ, "seek failed reading descriptor");
1673            }
1674            des_start = zftello(in_file);
1675            k = kk;
1676            break;
1677          }
1678        }
1679      }
1680      else
1681
1682      /* signature at start of buffer */
1683      {
1684        des_good = 0;
1685
1686#ifdef ZIP64_SUPPORT
1687        if (zip64_entry) {
1688
1689          /* read Zip64 data descriptor */
1690          if (k < 24) {
1691            /* not enough bytes, so can't be data descriptor
1692               as data descriptors can't be split across splits
1693             */
1694          }
1695          else
1696          {
1697            /* read the Zip64 descriptor */
1698
1699            des_crc = LG(b + 4);
1700            des_csize = LLG(b + 8);
1701            des_usize = LLG(b + 16);
1702
1703            /* if this is the right data descriptor then the sizes should match */
1704            if ((uzoff_t)des_start - (uzoff_t)data_start != des_csize) {
1705              /* apparently this signature does not go with this data so skip */
1706
1707              /* write out signature as data */
1708              k = 4;
1709              if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
1710                /* seek error */
1711                ZIPERR(ZE_READ, "seek failed reading descriptor");
1712              }
1713              if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
1714              {
1715                free((zvoid *)b);
1716                fprintf(mesg," fcopy: write error\n");
1717                return ZE_TEMP;
1718              }
1719              m += k;
1720              continue;
1721            }
1722            else
1723            {
1724              /* apparently this is the correct data descriptor */
1725
1726              /* we should check the CRC but would need to inflate
1727                 the data */
1728
1729              /* skip descriptor as will write out later */
1730              des_good = 1;
1731              k = 24;
1732              data_start = zftello(in_file);
1733              if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
1734                /* seek error */
1735                ZIPERR(ZE_READ, "seek failed reading descriptor");
1736              }
1737              data_start = zftello(in_file);
1738            }
1739          }
1740
1741        }
1742        else
1743#endif
1744        {
1745          /* read standard data descriptor */
1746
1747          if (k < 16) {
1748            /* not enough bytes, so can't be data descriptor
1749               as data descriptors can't be split across splits
1750             */
1751          }
1752          else
1753          {
1754            /* read the descriptor */
1755
1756            des_crc = LG(b + 4);
1757            des_csize = LG(b + 8);
1758            des_usize = LG(b + 12);
1759
1760            /* if this is the right data descriptor then the sizes should match */
1761            if ((uzoff_t)des_start - (uzoff_t)data_start != des_csize) {
1762              /* apparently this signature does not go with this data so skip */
1763
1764              /* write out signature as data */
1765              k = 4;
1766              if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
1767                /* seek error */
1768                ZIPERR(ZE_READ, "seek failed reading descriptor");
1769              }
1770              if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
1771              {
1772                free((zvoid *)b);
1773                fprintf(mesg," fcopy: write error\n");
1774                return ZE_TEMP;
1775              }
1776              m += k;
1777              continue;
1778            }
1779            else
1780            {
1781              /* apparently this is the correct data descriptor */
1782
1783              /* we should check the CRC but this does not work for
1784                 encrypted data */
1785
1786              /* skip descriptor as will write out later */
1787              des_good = 1;
1788              data_start = zftello(in_file);
1789              k = 16;
1790              if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
1791                /* seek error */
1792                ZIPERR(ZE_READ, "seek failed reading descriptor");
1793              }
1794              data_start = zftello(in_file);
1795            }
1796          }
1797
1798
1799        }
1800      }
1801    }
1802
1803
1804    if (des_good) {
1805      /* skip descriptor as will write out later */
1806    } else {
1807      /* write out apparently wrong descriptor as data */
1808      if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
1809      {
1810        free((zvoid *)b);
1811        fprintf(mesg," fcopy: write error\n");
1812        return ZE_TEMP;
1813      }
1814      m += k;
1815    }
1816
1817    if (copy_only && !display_globaldots) {
1818      if (dot_size > 0) {
1819        /* initial space */
1820        if (noisy && dot_count == -1) {
1821#ifndef WINDLL
1822          putc(' ', mesg);
1823          fflush(mesg);
1824#else
1825          fprintf(stdout,"%c",' ');
1826#endif
1827          dot_count++;
1828        }
1829        dot_count += k;
1830        if (dot_size <= dot_count) dot_count = 0;
1831      }
1832      if ((verbose || noisy) && dot_size && !dot_count) {
1833#ifndef WINDLL
1834        putc('.', mesg);
1835        fflush(mesg);
1836#else
1837        fprintf(stdout,"%c",'.');
1838#endif
1839        mesg_line_started = 1;
1840      }
1841    }
1842
1843    if (des_good)
1844      break;
1845
1846    if (des)
1847      continue;
1848
1849    if ((des || n != (uzoff_t)(-1L)) && m < n && feof(in_file)) {
1850      /* open next split */
1851      current_in_disk++;
1852
1853      if (current_in_disk >= total_disks) {
1854        /* done */
1855        break;
1856
1857      } else if (current_in_disk == total_disks - 1) {
1858        /* last disk is archive.zip */
1859        if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
1860          zipwarn("reading archive: ", in_path);
1861          return ZE_MEM;
1862        }
1863        strcpy(split_path, in_path);
1864      } else {
1865        /* other disks are archive.z01, archive.z02, ... */
1866        split_path = get_in_split_path(in_path, current_in_disk);
1867      }
1868
1869      fclose(in_file);
1870
1871      /* open the split */
1872      while ((in_file = zfopen(split_path, FOPR)) == NULL) {
1873        int r = 0;
1874
1875        /* could not open split */
1876
1877        if (fix == 1 && skip_this_disk) {
1878          free(split_path);
1879          free((zvoid *)b);
1880          return ZE_FORM;
1881        }
1882
1883        /* Ask for directory with split.  Updates in_path */
1884        r = ask_for_split_read_path(current_in_disk);
1885        if (r == ZE_ABORT) {
1886          zipwarn("could not find split: ", split_path);
1887          free(split_path);
1888          free((zvoid *)b);
1889          return ZE_ABORT;
1890        }
1891        if (r == ZE_EOF) {
1892          zipmessage_nl("", 1);
1893          zipwarn("user ended reading - closing archive", "");
1894          free(split_path);
1895          free((zvoid *)b);
1896          return ZE_EOF;
1897        }
1898        if (fix == 2 && skip_this_disk) {
1899          /* user asked to skip this disk */
1900          zipwarn("skipping split file: ", split_path);
1901          current_in_disk++;
1902        }
1903
1904        if (current_in_disk == total_disks - 1) {
1905          /* last disk is archive.zip */
1906          if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
1907            zipwarn("reading archive: ", in_path);
1908            return ZE_MEM;
1909          }
1910          strcpy(split_path, in_path);
1911        } else {
1912          /* other disks are archive.z01, archive.z02, ... */
1913          split_path = get_in_split_path(zipfile, current_in_disk);
1914        }
1915      }
1916      if (fix == 2 && skip_this_disk) {
1917        /* user asked to skip this disk */
1918        free(split_path);
1919        free((zvoid *)b);
1920        return ZE_FORM;
1921      }
1922      free(split_path);
1923    }
1924  }
1925  free((zvoid *)b);
1926  return ZE_OK;
1927}
1928
1929
1930
1931#ifdef NO_RENAME
1932int rename(from, to)
1933ZCONST char *from;
1934ZCONST char *to;
1935{
1936    unlink(to);
1937    if (link(from, to) == -1)
1938        return -1;
1939    if (unlink(from) == -1)
1940        return -1;
1941    return 0;
1942}
1943
1944#endif /* NO_RENAME */
1945
1946
1947#ifdef ZMEM
1948
1949/************************/
1950/*  Function memset()   */
1951/************************/
1952
1953/*
1954 * memset - for systems without it
1955 *  bill davidsen - March 1990
1956 */
1957
1958char *
1959memset(buf, init, len)
1960register char *buf;     /* buffer loc */
1961register int init;      /* initializer */
1962register unsigned int len;   /* length of the buffer */
1963{
1964    char *start;
1965
1966    start = buf;
1967    while (len--) *(buf++) = init;
1968    return(start);
1969}
1970
1971
1972/************************/
1973/*  Function memcpy()   */
1974/************************/
1975
1976char *
1977memcpy(dst,src,len)             /* v2.0f */
1978register char *dst, *src;
1979register unsigned int len;
1980{
1981    char *start;
1982
1983    start = dst;
1984    while (len--)
1985        *dst++ = *src++;
1986    return(start);
1987}
1988
1989
1990/************************/
1991/*  Function memcmp()   */
1992/************************/
1993
1994int
1995memcmp(b1,b2,len)                     /* jpd@usl.edu -- 11/16/90 */
1996register char *b1, *b2;
1997register unsigned int len;
1998{
1999
2000    if (len) do {       /* examine each byte (if any) */
2001      if (*b1++ != *b2++)
2002        return (*((uch *)b1-1) - *((uch *)b2-1));  /* exit when miscompare */
2003    } while (--len);
2004
2005    return(0);          /* no miscompares, yield 0 result */
2006}
2007
2008#endif  /* ZMEM */
2009
2010
2011/*------------------------------------------------------------------
2012 * Split archives
2013 */
2014
2015
2016/* ask_for_split_read_path
2017 *
2018 * If the next split file is not in the current directory, ask
2019 * the user where it is.
2020 *
2021 * in_path is the base path for reading splits and is usually
2022 * the same as zipfile.  The path in in_path must be the archive
2023 * file ending in .zip as this is assumed by get_in_split_path().
2024 *
2025 * Updates in_path if changed.  Returns ZE_OK if OK or ZE_ABORT if
2026 * user cancels reading archive.
2027 *
2028 * If fix = 1 then allow skipping disk (user may not have it).
2029 */
2030
2031#define SPLIT_MAXPATH (FNMAX + 4010)
2032
2033int ask_for_split_read_path(current_disk)
2034  ulg current_disk;
2035{
2036  FILE *f;
2037  int is_readable = 0;
2038  int i;
2039  char *split_dir = NULL;
2040  char *archive_name = NULL;
2041  char *split_name = NULL;
2042  char *split_path = NULL;
2043  char buf[SPLIT_MAXPATH + 100];
2044
2045  /* get split path */
2046  split_path = get_in_split_path(in_path, current_disk);
2047
2048  /* get the directory */
2049  if ((split_dir = malloc(strlen(in_path) + 40)) == NULL) {
2050    ZIPERR(ZE_MEM, "split path");
2051  }
2052  strcpy(split_dir, in_path);
2053
2054  /* remove any name at end */
2055  for (i = strlen(split_dir) - 1; i >= 0; i--) {
2056    if (split_dir[i] == '/' || split_dir[i] == '\\'
2057          || split_dir[i] == ':') {
2058      split_dir[i + 1] = '\0';
2059      break;
2060    }
2061  }
2062  if (i < 0)
2063    split_dir[0] = '\0';
2064
2065  /* get the name of the archive */
2066  if ((archive_name = malloc(strlen(in_path) + 1)) == NULL) {
2067    ZIPERR(ZE_MEM, "split path");
2068  }
2069  if (strlen(in_path) == strlen(split_dir)) {
2070    archive_name[0] = '\0';
2071  } else {
2072    strcpy(archive_name, in_path + strlen(split_dir));
2073  }
2074
2075  /* get the name of the split */
2076  if ((split_name = malloc(strlen(split_path) + 1)) == NULL) {
2077    ZIPERR(ZE_MEM, "split path");
2078  }
2079  if (strlen(in_path) == strlen(split_dir)) {
2080    split_name[0] = '\0';
2081  } else {
2082    strcpy(split_name, split_path + strlen(split_dir));
2083  }
2084  if (i < 0) {
2085    strcpy(split_dir, "(current directory)");
2086  }
2087
2088  fprintf(mesg, "\n\nCould not find:\n");
2089  fprintf(mesg, "  %s\n", split_path);
2090  /*
2091  fprintf(mesg, "Please enter the path directory (. for cur dir) where\n");
2092  fprintf(mesg, "  %s\n", split_name);
2093  fprintf(mesg, "is located\n");
2094  */
2095  for (;;) {
2096    if (is_readable) {
2097      fprintf(mesg, "\nHit c      (change path to where this split file is)");
2098      fprintf(mesg, "\n    q      (abort archive - quit)");
2099      fprintf(mesg, "\n or ENTER  (continue with this split): ");
2100    } else {
2101      if (fix == 1) {
2102        fprintf(mesg, "\nHit c      (change path to where this split file is)");
2103        fprintf(mesg, "\n    s      (skip this split)");
2104        fprintf(mesg, "\n    q      (abort archive - quit)");
2105        fprintf(mesg, "\n or ENTER  (try reading this split again): ");
2106      } else if (fix == 2) {
2107        fprintf(mesg, "\nHit c      (change path to where this split file is)");
2108        fprintf(mesg, "\n    s      (skip this split)");
2109        fprintf(mesg, "\n    q      (abort archive - quit)");
2110        fprintf(mesg, "\n    e      (end this archive - no more splits)");
2111        fprintf(mesg, "\n    z      (look for .zip split - the last split)");
2112        fprintf(mesg, "\n or ENTER  (try reading this split again): ");
2113      } else {
2114        fprintf(mesg, "\nHit c      (change path to where this split file is)");
2115        fprintf(mesg, "\n    q      (abort archive - quit)");
2116        fprintf(mesg, "\n or ENTER  (try reading this split again): ");
2117      }
2118    }
2119    fflush(mesg);
2120    fgets(buf, SPLIT_MAXPATH, stdin);
2121    /* remove any newline */
2122    for (i = 0; buf[i]; i++) {
2123      if (buf[i] == '\n') {
2124        buf[i] = '\0';
2125        break;
2126      }
2127    }
2128    if (toupper(buf[0]) == 'Q') {
2129      return ZE_ABORT;
2130    } else if ((fix == 1 || fix == 2) && toupper(buf[0]) == 'S') {
2131    /*
2132      fprintf(mesg, "\nSkip this split/disk?  (files in this split will not be recovered) [n/y] ");
2133      fflush(mesg);
2134      fgets(buf, SPLIT_MAXPATH, stdin);
2135      if (buf[0] == 'y' || buf[0] == 'Y') {
2136    */
2137      skip_this_disk = current_in_disk + 1;
2138      return ZE_FORM;
2139    } else if (toupper(buf[0]) == 'C') {
2140      fprintf(mesg, "\nEnter path where this split is (ENTER = same dir, . = current dir)");
2141      fprintf(mesg, "\n: ");
2142      fflush(mesg);
2143      fgets(buf, SPLIT_MAXPATH, stdin);
2144      is_readable = 0;
2145      /* remove any newline */
2146      for (i = 0; buf[i]; i++) {
2147        if (buf[i] == '\n') {
2148          buf[i] = '\0';
2149          break;
2150        }
2151      }
2152      if (buf[0] == '\0') {
2153        /* Hit ENTER so try old path again - could be removable media was changed */
2154        strcpy(buf, split_path);
2155      }
2156    } else if (fix == 2 && toupper(buf[0]) == 'E') {
2157      /* no more splits to read */
2158      return ZE_EOF;
2159    } else if (fix == 2 && toupper(buf[0]) == 'Z') {
2160      total_disks = current_disk + 1;
2161      free(split_path);
2162      split_path = get_in_split_path(in_path, current_disk);
2163      buf[0] = '\0';
2164      strncat(buf, split_path, SPLIT_MAXPATH);
2165    }
2166    if (strlen(buf) > 0) {
2167      /* changing path */
2168
2169      /* check if user wants current directory */
2170      if (buf[0] == '.' && buf[1] == '\0') {
2171        buf[0] = '\0';
2172      }
2173      /* remove any name at end */
2174      for (i = strlen(buf); i >= 0; i--) {
2175        if (buf[i] == '/' || buf[i] == '\\'
2176             || buf[i] == ':') {
2177          buf[i + 1] = '\0';
2178          break;
2179        }
2180      }
2181      /* update base_path to newdir/split_name - in_path is the .zip file path */
2182      free(in_path);
2183      if (i < 0) {
2184        /* just name so current directory */
2185        strcpy(buf, "(current directory)");
2186        if (archive_name == NULL) {
2187          i = 0;
2188        } else {
2189          i = strlen(archive_name);
2190        }
2191        if ((in_path = malloc(strlen(archive_name) + 40)) == NULL) {
2192          ZIPERR(ZE_MEM, "split path");
2193        }
2194        strcpy(in_path, archive_name);
2195      } else {
2196        /* not the current directory */
2197        /* remove any name at end */
2198        for (i = strlen(buf); i >= 0; i--) {
2199          if (buf[i] == '/') {
2200            buf[i + 1] = '\0';
2201            break;
2202          }
2203        }
2204        if (i < 0) {
2205          buf[0] = '\0';
2206        }
2207        if ((in_path = malloc(strlen(buf) + strlen(archive_name) + 40)) == NULL) {
2208          ZIPERR(ZE_MEM, "split path");
2209        }
2210        strcpy(in_path, buf);
2211        strcat(in_path, archive_name);
2212      }
2213
2214      free(split_path);
2215
2216      /* get split path */
2217      split_path = get_in_split_path(in_path, current_disk);
2218
2219      free(split_dir);
2220      if ((split_dir = malloc(strlen(in_path) + 40)) == NULL) {
2221        ZIPERR(ZE_MEM, "split path");
2222      }
2223      strcpy(split_dir, in_path);
2224      /* remove any name at end */
2225      for (i = strlen(split_dir); i >= 0; i--) {
2226        if (split_dir[i] == '/') {
2227          split_dir[i + 1] = '\0';
2228          break;
2229        }
2230      }
2231
2232      /* try to open it */
2233      if ((f = fopen(split_path, "r")) == NULL) {
2234        fprintf(mesg, "\nCould not find or open\n");
2235        fprintf(mesg, "  %s\n", split_path);
2236        /*
2237        fprintf(mesg, "Please enter the path (. for cur dir) where\n");
2238        fprintf(mesg, "  %s\n", split_name);
2239        fprintf(mesg, "is located\n");
2240        */
2241        continue;
2242      }
2243      fclose(f);
2244      is_readable = 1;
2245      fprintf(mesg, "Found:  %s\n", split_path);
2246    } else {
2247      /* try to open it */
2248      if ((f = fopen(split_path, "r")) == NULL) {
2249        fprintf(mesg, "\nCould not find or open\n");
2250        fprintf(mesg, "  %s\n", split_path);
2251        /*
2252        fprintf(mesg, "Please enter the path (. for cur dir) where\n");
2253        fprintf(mesg, "  %s\n", split_name);
2254        fprintf(mesg, "is located\n");
2255        */
2256        continue;
2257      }
2258      fclose(f);
2259      is_readable = 1;
2260      fprintf(mesg, "\nFound:  %s\n", split_path);
2261      break;
2262    }
2263  }
2264  free(archive_name);
2265  free(split_dir);
2266  free(split_name);
2267
2268  return ZE_OK;
2269}
2270
2271
2272/* ask_for_split_write_path
2273 *
2274 * Verify the directory for the next split.  Called
2275 * when -sp is used to pause between writing splits.
2276 *
2277 * Updates out_path and return 1 if OK or 0 if cancel
2278 */
2279int ask_for_split_write_path(current_disk)
2280  ulg current_disk;
2281{
2282  unsigned int num = (unsigned int)current_disk + 1;
2283  int i;
2284  char *split_dir = NULL;
2285  char *split_name = NULL;
2286  char buf[FNMAX + 40];
2287
2288  /* get the directory */
2289  if ((split_dir = malloc(strlen(out_path) + 40)) == NULL) {
2290    ZIPERR(ZE_MEM, "split path");
2291  }
2292  strcpy(split_dir, out_path);
2293
2294  /* remove any name at end */
2295  for (i = strlen(split_dir); i >= 0; i--) {
2296    if (split_dir[i] == '/' || split_dir[i] == '\\'
2297          || split_dir[i] == ':') {
2298      split_dir[i + 1] = '\0';
2299      break;
2300    }
2301  }
2302
2303  /* get the name of the split */
2304  if ((split_name = malloc(strlen(out_path) + 1)) == NULL) {
2305    ZIPERR(ZE_MEM, "split path");
2306  }
2307  if (strlen(out_path) == strlen(split_dir)) {
2308    split_name[0] = '\0';
2309  } else {
2310    strcpy(split_name, out_path + strlen(split_dir));
2311  }
2312  if (i < 0) {
2313    strcpy(split_dir, "(current directory)");
2314  }
2315  if (mesg_line_started)
2316    fprintf(mesg, "\n");
2317  fprintf(mesg, "\nOpening disk %d\n", num);
2318  fprintf(mesg, "Hit ENTER to write to default path of\n");
2319  fprintf(mesg, "  %s\n", split_dir);
2320  fprintf(mesg, "or enter a new directory path (. for cur dir) and hit ENTER\n");
2321  for (;;) {
2322    fprintf(mesg, "\nPath (or hit ENTER to continue): ");
2323    fflush(mesg);
2324    fgets(buf, FNMAX, stdin);
2325    /* remove any newline */
2326    for (i = 0; buf[i]; i++) {
2327      if (buf[i] == '\n') {
2328        buf[i] = '\0';
2329        break;
2330      }
2331    }
2332    if (strlen(buf) > 0) {
2333      /* changing path */
2334
2335      /* current directory */
2336      if (buf[0] == '.' && buf[1] == '\0') {
2337        buf[0] = '\0';
2338      }
2339      /* remove any name at end */
2340      for (i = strlen(buf); i >= 0; i--) {
2341        if (buf[i] == '/' || buf[i] == '\\'
2342             || buf[i] == ':') {
2343          buf[i + 1] = '\0';
2344          break;
2345        }
2346      }
2347      /* update out_path to newdir/split_name */
2348      free(out_path);
2349      if (i < 0) {
2350        /* just name so current directory */
2351        strcpy(buf, "(current directory)");
2352        if (split_name == NULL) {
2353          i = 0;
2354        } else {
2355          i = strlen(split_name);
2356        }
2357        if ((out_path = malloc(strlen(split_name) + 40)) == NULL) {
2358          ZIPERR(ZE_MEM, "split path");
2359        }
2360        strcpy(out_path, split_name);
2361      } else {
2362        /* not the current directory */
2363        /* remove any name at end */
2364        for (i = strlen(buf); i >= 0; i--) {
2365          if (buf[i] == '/') {
2366            buf[i + 1] = '\0';
2367            break;
2368          }
2369        }
2370        if (i < 0) {
2371          buf[0] = '\0';
2372        }
2373        if ((out_path = malloc(strlen(buf) + strlen(split_name) + 40)) == NULL) {
2374          ZIPERR(ZE_MEM, "split path");
2375        }
2376        strcpy(out_path, buf);
2377        strcat(out_path, split_name);
2378      }
2379      fprintf(mesg, "Writing to:\n  %s\n", buf);
2380      free(split_name);
2381      free(split_dir);
2382      if ((split_dir = malloc(strlen(out_path) + 40)) == NULL) {
2383        ZIPERR(ZE_MEM, "split path");
2384      }
2385      strcpy(split_dir, out_path);
2386      /* remove any name at end */
2387      for (i = strlen(split_dir); i >= 0; i--) {
2388        if (split_dir[i] == '/') {
2389          split_dir[i + 1] = '\0';
2390          break;
2391        }
2392      }
2393      if ((split_name = malloc(strlen(out_path) + 1)) == NULL) {
2394        ZIPERR(ZE_MEM, "split path");
2395      }
2396      strcpy(split_name, out_path + strlen(split_dir));
2397    } else {
2398      break;
2399    }
2400  }
2401  free(split_dir);
2402  free(split_name);
2403
2404  /* for now no way out except Ctrl C */
2405  return 1;
2406}
2407
2408
2409/* split_name
2410 *
2411 * get name of split being read
2412 */
2413char *get_in_split_path(base_path, disk_number)
2414  char *base_path;
2415  ulg disk_number;
2416{
2417  char *split_path = NULL;
2418  int base_len = 0;
2419  int path_len = 0;
2420  ulg num = disk_number + 1;
2421  char ext[6];
2422#ifdef VMS
2423  int vers_len;                         /* File version length. */
2424  char *vers_ptr;                       /* File version string. */
2425#endif /* def VMS */
2426
2427  /*
2428   * A split has extension z01, z02, ..., z99, z100, z101, ... z999
2429   * We currently support up to .z99999
2430   * WinZip will also read .100, .101, ... but AppNote 6.2.2 uses above
2431   * so use that.  Means on DOS can only have 100 splits.
2432   */
2433
2434  if (num == total_disks) {
2435    /* last disk is base path */
2436    if ((split_path = malloc(strlen(base_path) + 1)) == NULL) {
2437      ZIPERR(ZE_MEM, "base path");
2438    }
2439    strcpy(split_path, base_path);
2440
2441    return split_path;
2442  } else {
2443    if (num > 99999) {
2444      ZIPERR(ZE_BIG, "More than 99999 splits needed");
2445    }
2446    sprintf(ext, "z%02lu", num);
2447  }
2448
2449  /* create path for this split - zip.c checked for .zip extension */
2450  base_len = strlen(base_path) - 3;
2451  path_len = base_len + strlen(ext);
2452
2453#ifdef VMS
2454  /* On VMS, locate the file version, and adjust base_len accordingly.
2455     Note that path_len is correct, as-is.
2456  */
2457  vers_ptr = vms_file_version( base_path);
2458  vers_len = strlen( vers_ptr);
2459  base_len -= vers_len;
2460#endif /* def VMS */
2461
2462  if ((split_path = malloc(path_len + 1)) == NULL) {
2463    ZIPERR(ZE_MEM, "split path");
2464  }
2465  /* copy base_path except for end zip */
2466  strcpy(split_path, base_path);
2467  split_path[base_len] = '\0';
2468  /* add extension */
2469  strcat(split_path, ext);
2470
2471#ifdef VMS
2472  /* On VMS, append (preserve) the file version. */
2473  strcat(split_path, vers_ptr);
2474#endif /* def VMS */
2475
2476  return split_path;
2477}
2478
2479
2480/* split_name
2481 *
2482 * get name of split being written
2483 */
2484char *get_out_split_path(base_path, disk_number)
2485  char *base_path;
2486  ulg disk_number;
2487{
2488  char *split_path = NULL;
2489  int base_len = 0;
2490  int path_len = 0;
2491  ulg num = disk_number + 1;
2492  char ext[6];
2493#ifdef VMS
2494  int vers_len;                         /* File version length. */
2495  char *vers_ptr;                       /* File version string. */
2496#endif /* def VMS */
2497
2498  /*
2499   * A split has extension z01, z02, ..., z99, z100, z101, ... z999
2500   * We currently support up to .z99999
2501   * WinZip will also read .100, .101, ... but AppNote 6.2.2 uses above
2502   * so use that.  Means on DOS can only have 100 splits.
2503   */
2504
2505  if (num > 99999) {
2506    ZIPERR(ZE_BIG, "More than 99999 splits needed");
2507  }
2508  sprintf(ext, "z%02lu", num);
2509
2510  /* create path for this split - zip.c checked for .zip extension */
2511  base_len = strlen(base_path) - 3;
2512  path_len = base_len + strlen(ext);
2513
2514#ifdef VMS
2515  /* On VMS, locate the file version, and adjust base_len accordingly.
2516     Note that path_len is correct, as-is.
2517  */
2518  vers_ptr = vms_file_version( base_path);
2519  vers_len = strlen( vers_ptr);
2520  base_len -= vers_len;
2521#endif /* def VMS */
2522
2523  if ((split_path = malloc(path_len + 1)) == NULL) {
2524    ZIPERR(ZE_MEM, "split path");
2525  }
2526  /* copy base_path except for end zip */
2527  strcpy(split_path, base_path);
2528  split_path[base_len] = '\0';
2529  /* add extension */
2530  strcat(split_path, ext);
2531
2532#ifdef VMS
2533  /* On VMS, append (preserve) the file version. */
2534  strcat(split_path, vers_ptr);
2535#endif /* def VMS */
2536
2537  return split_path;
2538}
2539
2540/* close_split
2541 *
2542 * close a split - assume that the paths needed for the splits are
2543 * available.
2544 */
2545int close_split(disk_number, tempfile, temp_name)
2546  ulg disk_number;
2547  FILE *tempfile;
2548  char *temp_name;
2549{
2550  char *split_path = NULL;
2551
2552  split_path = get_out_split_path(out_path, disk_number);
2553
2554  if (noisy_splits) {
2555    zipmessage("\tClosing split ", split_path);
2556  }
2557
2558  fclose(tempfile);
2559
2560  rename_split(temp_name, split_path);
2561  set_filetype(split_path);
2562
2563  return ZE_OK;
2564}
2565
2566/* bfwrite
2567   Does the fwrite but also counts bytes and does splits */
2568size_t bfwrite(buffer, size, count, mode)
2569  ZCONST void *buffer;
2570  size_t size;
2571  size_t count;
2572  int mode;
2573{
2574  size_t bytes_written = 0;
2575  size_t r;
2576  size_t b = size * count;
2577  uzoff_t bytes_left_in_split = 0;
2578  size_t bytes_to_write = b;
2579
2580
2581  /* -------------------------------- */
2582  /* local header */
2583  if (mode == BFWRITE_LOCALHEADER) {
2584    /* writing local header - reset entry data count */
2585    bytes_this_entry = 0;
2586    /* save start of local header so we can rewrite later */
2587    current_local_file = y;
2588    current_local_disk = current_disk;
2589    current_local_offset = bytes_this_split;
2590  }
2591
2592  if (split_size == 0)
2593    bytes_left_in_split = bytes_to_write;
2594  else
2595    bytes_left_in_split = split_size - bytes_this_split;
2596
2597  if (bytes_to_write > bytes_left_in_split) {
2598    if (mode == BFWRITE_HEADER ||
2599        mode == BFWRITE_LOCALHEADER ||
2600        mode == BFWRITE_CENTRALHEADER) {
2601      /* if can't write entire header save for next split */
2602      bytes_to_write = 0;
2603    } else {
2604      /* normal data so fill the split */
2605      bytes_to_write = (size_t)bytes_left_in_split;
2606    }
2607  }
2608
2609  /* -------------------------------- */
2610  /* central header */
2611  if (mode == BFWRITE_CENTRALHEADER) {
2612    /* set start disk for CD */
2613    if (cd_start_disk == (ulg)-1) {
2614      cd_start_disk = current_disk;
2615      cd_start_offset = bytes_this_split;
2616    }
2617    cd_entries_this_disk++;
2618    total_cd_entries++;
2619  }
2620
2621  /* -------------------------------- */
2622  if (bytes_to_write > 0) {
2623    /* write out the bytes for this split */
2624    r = fwrite(buffer, size, bytes_to_write, y);
2625    bytes_written += r;
2626    bytes_to_write = b - r;
2627    bytes_this_split += r;
2628    if (mode == BFWRITE_DATA)
2629      /* if data descriptor do not include in count */
2630      bytes_this_entry += r;
2631  } else {
2632    bytes_to_write = b;
2633  }
2634
2635  if (bytes_to_write > 0) {
2636    if (split_method) {
2637      /* still bytes to write so close split and open next split */
2638      bytes_prev_splits += bytes_this_split;
2639
2640      if (split_method == 1 && ferror(y)) {
2641        /* if writing all splits to same place and have problem then bad */
2642        ZIPERR(ZE_WRITE, "Could not write split");
2643      }
2644
2645      if (split_method == 2 && ferror(y)) {
2646        /* A split must be at least 64K except last .zip split */
2647        if (bytes_this_split < 64 * (uzoff_t)0x400) {
2648          ZIPERR(ZE_WRITE, "Not enough space to write split");
2649        }
2650      }
2651
2652      /* close this split */
2653      if (split_method == 1 && current_local_disk == current_disk) {
2654        /* keep split open so can update it */
2655        current_local_tempname = tempzip;
2656      } else {
2657        /* close split */
2658        close_split(current_disk, y, tempzip);
2659        y = NULL;
2660        free(tempzip);
2661        tempzip = NULL;
2662      }
2663      cd_entries_this_disk = 0;
2664      bytes_this_split = 0;
2665
2666      /* increment disk - disks are numbered 0, 1, 2, ... and
2667         splits are 01, 02, ... */
2668      current_disk++;
2669
2670      if (split_method == 2 && split_bell) {
2671        /* bell when pause to ask for next split */
2672        putc('\007', mesg);
2673        fflush(mesg);
2674      }
2675
2676      for (;;) {
2677        /* if method 2 pause and allow changing path */
2678        if (split_method == 2) {
2679          if (ask_for_split_write_path(current_disk) == 0) {
2680            ZIPERR(ZE_ABORT, "could not write split");
2681          }
2682        }
2683
2684        /* open next split */
2685#if defined(UNIX) && !defined(NO_MKSTEMP)
2686        {
2687          int yd;
2688          int i;
2689
2690          /* use mkstemp to avoid race condition and compiler warning */
2691
2692          if (tempath != NULL)
2693          {
2694            /* if -b used to set temp file dir use that for split temp */
2695            if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
2696              ZIPERR(ZE_MEM, "allocating temp filename");
2697            }
2698            strcpy(tempzip, tempath);
2699            if (lastchar(tempzip) != '/')
2700              strcat(tempzip, "/");
2701          }
2702          else
2703          {
2704            /* create path by stripping name and appending template */
2705            if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
2706            ZIPERR(ZE_MEM, "allocating temp filename");
2707            }
2708            strcpy(tempzip, zipfile);
2709            for(i = strlen(tempzip); i > 0; i--) {
2710              if (tempzip[i - 1] == '/')
2711                break;
2712            }
2713            tempzip[i] = '\0';
2714          }
2715          strcat(tempzip, "ziXXXXXX");
2716
2717          if ((yd = mkstemp(tempzip)) == EOF) {
2718            ZIPERR(ZE_TEMP, tempzip);
2719          }
2720          if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
2721            ZIPERR(ZE_TEMP, tempzip);
2722          }
2723        }
2724#else
2725        if ((tempzip = tempname(zipfile)) == NULL) {
2726          ZIPERR(ZE_MEM, "allocating temp filename");
2727        }
2728        if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
2729          ZIPERR(ZE_TEMP, tempzip);
2730        }
2731#endif
2732
2733        r = fwrite((char *)buffer + bytes_written, 1, bytes_to_write, y);
2734        bytes_written += r;
2735        bytes_this_split += r;
2736        if (!(mode == BFWRITE_HEADER ||
2737              mode == BFWRITE_LOCALHEADER ||
2738              mode == BFWRITE_CENTRALHEADER)) {
2739          bytes_this_entry += r;
2740        }
2741        if (bytes_to_write > r) {
2742          /* buffer bigger than split */
2743          if (split_method == 2) {
2744            /* let user choose another disk */
2745            zipwarn("Not enough room on disk", "");
2746            continue;
2747          } else {
2748            ZIPERR(ZE_WRITE, "Not enough room on disk");
2749          }
2750        }
2751        if (mode == BFWRITE_LOCALHEADER ||
2752            mode == BFWRITE_HEADER ||
2753            mode == BFWRITE_CENTRALHEADER) {
2754          if (split_method == 1 && current_local_file &&
2755              current_local_disk != current_disk) {
2756            /* We're opening a new split because the next header
2757               did not fit on the last split.  We need to now close
2758               the last split and update the pointers for
2759               the current split. */
2760            close_split(current_local_disk, current_local_file,
2761                        current_local_tempname);
2762            free(current_local_tempname);
2763          }
2764          current_local_tempname = tempzip;
2765          current_local_file = y;
2766          current_local_offset = 0;
2767          current_local_disk = current_disk;
2768        }
2769        break;
2770      }
2771    }
2772    else
2773    {
2774      /* likely have more than fits but no splits */
2775
2776      /* probably already have error "no space left on device" */
2777      /* could let flush_outbuf() handle error but bfwrite() is called for
2778         headers also */
2779      if (ferror(y))
2780        ziperr(ZE_WRITE, "write error on zip file");
2781    }
2782  }
2783
2784
2785  /* display dots for archive instead of for each file */
2786  if (display_globaldots) {
2787    if (dot_size > 0) {
2788      /* initial space */
2789      if (dot_count == -1) {
2790#ifndef WINDLL
2791        putc(' ', mesg);
2792        fflush(mesg);
2793#else
2794        fprintf(stdout,"%c",' ');
2795#endif
2796        /* assume a header will be written first, so avoid 0 */
2797        dot_count = 1;
2798      }
2799      /* skip incrementing dot count for small buffers like for headers */
2800      if (size * count > 1000) {
2801        dot_count++;
2802        if (dot_size <= dot_count * (zoff_t)size * (zoff_t)count) dot_count = 0;
2803      }
2804    }
2805    if (dot_size && !dot_count) {
2806      dot_count++;
2807#ifndef WINDLL
2808      putc('.', mesg);
2809      fflush(mesg);
2810#else
2811      fprintf(stdout,"%c",'.');
2812#endif
2813      mesg_line_started = 1;
2814    }
2815  }
2816
2817
2818  return bytes_written;
2819}
2820
2821
2822#ifdef UNICODE_SUPPORT
2823
2824/*---------------------------------------------
2825 * Unicode conversion functions
2826 *
2827 * Provided by Paul Kienitz
2828 *
2829 * Some modifications to work with Zip
2830 *
2831 *---------------------------------------------
2832 */
2833
2834/*
2835   NOTES APPLICABLE TO ALL STRING FUNCTIONS:
2836
2837   All of the x_to_y functions take parameters for an output buffer and
2838   its available length, and return an int.  The value returned is the
2839   length of the string that the input produces, which may be larger than
2840   the provided buffer length.  If the returned value is less than the
2841   buffer length, then the contents of the buffer will be null-terminated;
2842   otherwise, it will not be terminated and may be invalid, possibly
2843   stopping in the middle of a multibyte sequence.
2844
2845   In all cases you may pass NULL as the buffer and/or 0 as the length, if
2846   you just want to learn how much space the string is going to require.
2847
2848   The functions will return -1 if the input is invalid UTF-8 or cannot be
2849   encoded as UTF-8.
2850*/
2851
2852/* utility functions for managing UTF-8 and UCS-4 strings */
2853
2854
2855/* utf8_char_bytes
2856 *
2857 * Returns the number of bytes used by the first character in a UTF-8
2858 * string, or -1 if the UTF-8 is invalid or null.
2859 */
2860local int utf8_char_bytes(utf8)
2861  ZCONST char *utf8;
2862{
2863  int      t, r;
2864  unsigned lead;
2865
2866  if (!utf8)
2867    return -1;          /* no input */
2868  lead = (unsigned char) *utf8;
2869  if (lead < 0x80)
2870    r = 1;              /* an ascii-7 character */
2871  else if (lead < 0xC0)
2872    return -1;          /* error: trailing byte without lead byte */
2873  else if (lead < 0xE0)
2874    r = 2;              /* an 11 bit character */
2875  else if (lead < 0xF0)
2876    r = 3;              /* a 16 bit character */
2877  else if (lead < 0xF8)
2878    r = 4;              /* a 21 bit character (the most currently used) */
2879  else if (lead < 0xFC)
2880    r = 5;              /* a 26 bit character (shouldn't happen) */
2881  else if (lead < 0xFE)
2882    r = 6;              /* a 31 bit character (shouldn't happen) */
2883  else
2884    return -1;          /* error: invalid lead byte */
2885  for (t = 1; t < r; t++)
2886    if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0)
2887      return -1;        /* error: not enough valid trailing bytes */
2888  return r;
2889}
2890
2891
2892/* ucs4_char_from_utf8
2893 *
2894 * Given a reference to a pointer into a UTF-8 string, returns the next
2895 * UCS-4 character and advances the pointer to the next character sequence.
2896 * Returns ~0 and does not advance the pointer when input is ill-formed.
2897 *
2898 * Since the Unicode standard says 32-bit values won't be used (just
2899 * up to the current 21-bit mappings) changed this to signed to allow -1 to
2900 * be returned.
2901 */
2902long ucs4_char_from_utf8(utf8)
2903  ZCONST char **utf8;
2904{
2905  ulg  ret;
2906  int  t, bytes;
2907
2908  if (!utf8)
2909    return -1;                          /* no input */
2910  bytes = utf8_char_bytes(*utf8);
2911  if (bytes <= 0)
2912    return -1;                          /* invalid input */
2913  if (bytes == 1)
2914    ret = **utf8;                       /* ascii-7 */
2915  else
2916    ret = **utf8 & (0x7F >> bytes);     /* lead byte of a multibyte sequence */
2917  (*utf8)++;
2918  for (t = 1; t < bytes; t++)           /* consume trailing bytes */
2919    ret = (ret << 6) | (*((*utf8)++) & 0x3F);
2920  return (long) ret;
2921}
2922
2923
2924/* utf8_from_ucs4_char - Convert UCS char to UTF-8
2925 *
2926 * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6,
2927 * or -1 if ch is too large to represent.  utf8buf must have room for 6 bytes.
2928 */
2929local int utf8_from_ucs4_char(utf8buf, ch)
2930  char *utf8buf;
2931  ulg ch;
2932{
2933  int trailing = 0;
2934  int leadmask = 0x80;
2935  int leadbits = 0x3F;
2936  ulg tch = ch;
2937  int ret;
2938
2939  if (ch > 0x7FFFFFFF)
2940    return -1;                /* UTF-8 can represent 31 bits */
2941  if (ch < 0x7F)
2942  {
2943    *utf8buf++ = (char) ch;   /* ascii-7 */
2944    return 1;
2945  }
2946  do {
2947    trailing++;
2948    leadmask = (leadmask >> 1) | 0x80;
2949    leadbits >>= 1;
2950    tch >>= 6;
2951  } while (tch & ~leadbits);
2952  ret = trailing + 1;
2953  /* produce lead byte */
2954  *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing)));
2955  /* produce trailing bytes */
2956  while (--trailing >= 0)
2957    *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F));
2958  return ret;
2959}
2960
2961
2962/*===================================================================*/
2963
2964/* utf8_to_ucs4_string - convert UTF-8 string to UCS string
2965 *
2966 * Return UCS count.  Now returns int so can return -1.
2967 */
2968local int utf8_to_ucs4_string(utf8, ucs4buf, buflen)
2969  ZCONST char *utf8;
2970  ulg *ucs4buf;
2971  int buflen;
2972{
2973  int count = 0;
2974
2975  for (;;)
2976  {
2977    long ch = ucs4_char_from_utf8(&utf8);
2978    if (ch == -1)
2979      return -1;
2980    else
2981    {
2982      if (ucs4buf && count < buflen)
2983        ucs4buf[count] = ch;
2984      if (ch == 0)
2985        return count;
2986      count++;
2987    }
2988  }
2989}
2990
2991
2992/* ucs4_string_to_utf8
2993 *
2994 *
2995 */
2996local int ucs4_string_to_utf8(ucs4, utf8buf, buflen)
2997  ZCONST ulg *ucs4;
2998  char *utf8buf;
2999  int buflen;
3000{
3001  char mb[6];
3002  int  count = 0;
3003
3004  if (!ucs4)
3005    return -1;
3006  for (;;)
3007  {
3008    int mbl = utf8_from_ucs4_char(mb, *ucs4++);
3009    int c;
3010    if (mbl <= 0)
3011      return -1;
3012    /* We could optimize this a bit by passing utf8buf + count */
3013    /* directly to utf8_from_ucs4_char when buflen >= count + 6... */
3014    c = buflen - count;
3015    if (mbl < c)
3016      c = mbl;
3017    if (utf8buf && count < buflen)
3018      strncpy(utf8buf + count, mb, c);
3019    if (mbl == 1 && !mb[0])
3020      return count;           /* terminating nul */
3021    count += mbl;
3022  }
3023}
3024
3025
3026#if 0  /* currently unused */
3027/* utf8_chars
3028 *
3029 * Wrapper: counts the actual unicode characters in a UTF-8 string.
3030 */
3031local int utf8_chars(utf8)
3032  ZCONST char *utf8;
3033{
3034  return utf8_to_ucs4_string(utf8, NULL, 0);
3035}
3036#endif
3037
3038
3039/* --------------------------------------------------- */
3040/* Unicode Support
3041 *
3042 * These functions common for all Unicode ports.
3043 *
3044 * These functions should allocate and return strings that can be
3045 * freed with free().
3046 *
3047 * 8/27/05 EG
3048 *
3049 * Use zwchar for wide char which is unsigned long
3050 * in zip.h and 32 bits.  This avoids problems with
3051 * different sizes of wchar_t.
3052 */
3053
3054#ifdef WIN32
3055
3056zwchar *wchar_to_wide_string(wchar_string)
3057  wchar_t *wchar_string;
3058{
3059  int i;
3060  int wchar_len;
3061  zwchar *wide_string;
3062
3063  wchar_len = wcslen(wchar_string);
3064
3065  if ((wide_string = malloc((wchar_len + 1) * sizeof(zwchar))) == NULL) {
3066    ZIPERR(ZE_MEM, "wchar to wide conversion");
3067  }
3068  for (i = 0; i <= wchar_len; i++) {
3069    wide_string[i] = wchar_string[i];
3070  }
3071
3072  return wide_string;
3073}
3074
3075/* is_ascii_stringw
3076 * Checks if a wide string is all ascii
3077 */
3078int is_ascii_stringw(wstring)
3079  wchar_t *wstring;
3080{
3081  wchar_t *pw;
3082  wchar_t cw;
3083
3084  if (wstring == NULL)
3085    return 0;
3086
3087  for (pw = wstring; (cw = *pw) != '\0'; pw++) {
3088    if (cw > 0x7F) {
3089      return 0;
3090    }
3091  }
3092  return 1;
3093}
3094
3095#endif
3096
3097/* is_ascii_string
3098 * Checks if a string is all ascii
3099 */
3100int is_ascii_string(mbstring)
3101  char *mbstring;
3102{
3103  char *p;
3104  uch c;
3105
3106  if (mbstring == NULL)
3107    return 0;
3108
3109  for (p = mbstring; (c = (uch)*p) != '\0'; p++) {
3110    if (c > 0x7F) {
3111      return 0;
3112    }
3113  }
3114  return 1;
3115}
3116
3117/* local to UTF-8 */
3118char *local_to_utf8_string(local_string)
3119  char *local_string;
3120{
3121  zwchar *wide_string = local_to_wide_string(local_string);
3122  char *utf8_string = wide_to_utf8_string(wide_string);
3123
3124  free(wide_string);
3125  return utf8_string;
3126}
3127
3128/* wide_char_to_escape_string
3129   provides a string that represents a wide char not in local char set
3130
3131   An initial try at an algorithm.  Suggestions welcome.
3132
3133   If not an ASCII char, probably need 2 bytes at least.  So if
3134   a 2-byte wide encode it as 4 hex digits with a leading #U.
3135   Since the Unicode standard has been frozen, it looks like 3 bytes
3136   should be enough for any large Unicode character.  In these cases
3137   prefix the string with #L.
3138   So
3139   #U1234
3140   is a 2-byte wide character with bytes 0x12 and 0x34 while
3141   #L123456
3142   is a 3-byte wide with bytes 0x12, 0x34, and 0x56.
3143   On Windows, wide that need two wide characters as a surrogate pair
3144   to represent them need to be converted to a single number.
3145  */
3146
3147 /* set this to the max bytes an escape can be */
3148#define MAX_ESCAPE_BYTES 8
3149
3150char *wide_char_to_escape_string(wide_char)
3151  zwchar wide_char;
3152{
3153  int i;
3154  zwchar w = wide_char;
3155  uch b[9];
3156  char e[7];
3157  int len;
3158  char *r;
3159
3160  /* fill byte array with zeros */
3161  for (len = 0; len < sizeof(zwchar); len++) {
3162    b[len] = 0;
3163  }
3164  /* get bytes in right to left order */
3165  for (len = 0; w; len++) {
3166    b[len] = (char)(w % 0x100);
3167    w /= 0x100;
3168  }
3169
3170  if ((r = malloc(MAX_ESCAPE_BYTES + 8)) == NULL) {
3171    ZIPERR(ZE_MEM, "wide_char_to_escape_string");
3172  }
3173  strcpy(r, "#");
3174  /* either 2 bytes or 4 bytes */
3175  if (len < 3) {
3176    len = 2;
3177    strcat(r, "U");
3178  } else {
3179    len = 3;
3180    strcat(r, "L");
3181  }
3182  for (i = len - 1; i >= 0; i--) {
3183    sprintf(e, "%02x", b[i]);
3184    strcat(r, e);
3185  }
3186  return r;
3187}
3188
3189#if 0
3190/* returns the wide character represented by the escape string */
3191zwchar escape_string_to_wide(escape_string)
3192  char *escape_string;
3193{
3194  int i;
3195  zwchar w;
3196  char c;
3197  char u;
3198  int len;
3199  char *e = escape_string;
3200
3201  if (e == NULL) {
3202    return 0;
3203  }
3204  if (e[0] != '#') {
3205    /* no leading # */
3206    return 0;
3207  }
3208  len = strlen(e);
3209  /* either #U1234 or #L123456 format */
3210  if (len != 6 && len != 8) {
3211    return 0;
3212  }
3213  w = 0;
3214  if (e[1] == 'L') {
3215    if (len != 8) {
3216      return 0;
3217    }
3218    /* 3 bytes */
3219    for (i = 2; i < 8; i++) {
3220      c = e[i];
3221      u = toupper(c);
3222      if (u >= 'A' && u <= 'F') {
3223        w = w * 0x10 + (zwchar)(u + 10 - 'A');
3224      } else if (c >= '0' && c <= '9') {
3225        w = w * 0x10 + (zwchar)(c - '0');
3226      } else {
3227        return 0;
3228      }
3229    }
3230  } else if (e[1] == 'U') {
3231    /* 2 bytes */
3232    for (i = 2; i < 6; i++) {
3233      c = e[i];
3234      u = toupper(c);
3235      if (u >= 'A' && u <= 'F') {
3236        w = w * 0x10 + (zwchar)(u + 10 - 'A');
3237      } else if (c >= '0' && c <= '9') {
3238        w = w * 0x10 + (zwchar)(c - '0');
3239      } else {
3240        return 0;
3241      }
3242    }
3243  }
3244  return w;
3245}
3246#endif
3247
3248
3249char *local_to_escape_string(local_string)
3250  char *local_string;
3251{
3252  zwchar *wide_string = local_to_wide_string(local_string);
3253  char *escape_string = wide_to_escape_string(wide_string);
3254
3255  free(wide_string);
3256  return escape_string;
3257}
3258
3259#ifdef WIN32
3260char *wchar_to_local_string(wstring)
3261  wchar_t *wstring;
3262{
3263  zwchar *wide_string = wchar_to_wide_string(wstring);
3264  char *local_string = wide_to_local_string(wide_string);
3265
3266  free(wide_string);
3267
3268  return local_string;
3269}
3270#endif
3271
3272
3273#ifndef WIN32   /* The Win32 port uses a system-specific variant. */
3274/* convert wide character string to multi-byte character string */
3275char *wide_to_local_string(wide_string)
3276  zwchar *wide_string;
3277{
3278  int i;
3279  wchar_t wc;
3280  int b;
3281  int state_dependent;
3282  int wsize = 0;
3283  int max_bytes = MB_CUR_MAX;
3284  char buf[9];
3285  char *buffer = NULL;
3286  char *local_string = NULL;
3287
3288  for (wsize = 0; wide_string[wsize]; wsize++) ;
3289
3290  if (MAX_ESCAPE_BYTES > max_bytes)
3291    max_bytes = MAX_ESCAPE_BYTES;
3292
3293  if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
3294    ZIPERR(ZE_MEM, "wide_to_local_string");
3295  }
3296
3297  /* convert it */
3298  buffer[0] = '\0';
3299  /* set initial state if state-dependent encoding */
3300  wc = (wchar_t)'a';
3301  b = wctomb(NULL, wc);
3302  if (b == 0)
3303    state_dependent = 0;
3304  else
3305    state_dependent = 1;
3306  for (i = 0; i < wsize; i++) {
3307    if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
3308      /* wchar_t probably 2 bytes */
3309      /* could do surrogates if state_dependent and wctomb can do */
3310      wc = zwchar_to_wchar_t_default_char;
3311    } else {
3312      wc = (wchar_t)wide_string[i];
3313    }
3314    b = wctomb(buf, wc);
3315    if (unicode_escape_all) {
3316      if (b == 1 && (uch)buf[0] <= 0x7f) {
3317        /* ASCII */
3318        strncat(buffer, buf, b);
3319      } else {
3320        /* use escape for wide character */
3321        char *e = wide_char_to_escape_string(wide_string[i]);
3322        strcat(buffer, e);
3323        free(e);
3324      }
3325    } else if (b > 0) {
3326      /* multi-byte char */
3327      strncat(buffer, buf, b);
3328    } else {
3329      /* no MB for this wide */
3330      if (use_wide_to_mb_default) {
3331        /* default character */
3332        strcat(buffer, wide_to_mb_default_string);
3333      } else {
3334        /* use escape for wide character */
3335        char *e = wide_char_to_escape_string(wide_string[i]);
3336        strcat(buffer, e);
3337        free(e);
3338      }
3339    }
3340  }
3341  if ((local_string = (char *)malloc(strlen(buffer) + 1)) == NULL) {
3342    free(buffer);
3343    ZIPERR(ZE_MEM, "wide_to_local_string");
3344  }
3345  strcpy(local_string, buffer);
3346  free(buffer);
3347
3348  return local_string;
3349}
3350#endif /* !WIN32 */
3351
3352
3353/* convert wide character string to escaped string */
3354char *wide_to_escape_string(wide_string)
3355  zwchar *wide_string;
3356{
3357  int i;
3358  int wsize = 0;
3359  char buf[9];
3360  char *buffer = NULL;
3361  char *escape_string = NULL;
3362
3363  for (wsize = 0; wide_string[wsize]; wsize++) ;
3364
3365  if ((buffer = (char *)malloc(wsize * MAX_ESCAPE_BYTES + 1)) == NULL) {
3366    ZIPERR(ZE_MEM, "wide_to_escape_string");
3367  }
3368
3369  /* convert it */
3370  buffer[0] = '\0';
3371  for (i = 0; i < wsize; i++) {
3372    if (wide_string[i] <= 0x7f && isprint((char)wide_string[i])) {
3373      /* ASCII */
3374      buf[0] = (char)wide_string[i];
3375      buf[1] = '\0';
3376      strcat(buffer, buf);
3377    } else {
3378      /* use escape for wide character */
3379      char *e = wide_char_to_escape_string(wide_string[i]);
3380      strcat(buffer, e);
3381      free(e);
3382    }
3383  }
3384  if ((escape_string = (char *)malloc(strlen(buffer) + 1)) == NULL) {
3385    ZIPERR(ZE_MEM, "wide_to_escape_string");
3386  }
3387  strcpy(escape_string, buffer);
3388  free(buffer);
3389
3390  return escape_string;
3391}
3392
3393
3394/* convert local string to display character set string */
3395char *local_to_display_string(local_string)
3396  char *local_string;
3397{
3398  char *temp_string;
3399  char *display_string;
3400
3401  /* For Windows, OEM string should never be bigger than ANSI string, says
3402     CharToOem description.
3403     On UNIX, non-printable characters (0x00 - 0xFF) will be replaced by
3404     "^x", so more space may be needed.  Note that "^" itself is a valid
3405     name character, so this leaves an ambiguity, but UnZip displays
3406     names this way, too.  (0x00 is not possible, I hope.)
3407     For all other ports, just make a copy of local_string.
3408  */
3409
3410#ifdef UNIX
3411  char *cp_dst;                 /* Character pointers used in the */
3412  char *cp_src;                 /*  copying/changing procedure.   */
3413#endif
3414
3415  if ((temp_string = (char *)malloc(2 * strlen(local_string) + 1)) == NULL) {
3416    ZIPERR(ZE_MEM, "local_to_display_string");
3417  }
3418
3419#ifdef WIN32
3420  /* convert to OEM display character set */
3421  local_to_oem_string(temp_string, local_string);
3422#else
3423# ifdef UNIX
3424  /* Copy source string, expanding non-printable characters to "^x". */
3425  cp_dst = temp_string;
3426  cp_src = local_string;
3427  while (*cp_src != '\0') {
3428    if ((unsigned char)*cp_src < ' ') {
3429      *cp_dst++ = '^';
3430      *cp_dst++ = '@'+ *cp_src++;
3431    }
3432    else {
3433      *cp_dst++ = *cp_src++;
3434    }
3435  }
3436  *cp_dst = '\0';
3437# else /* not UNIX */
3438  strcpy(temp_string, local_string);
3439# endif /* UNIX */
3440#endif
3441
3442#ifdef EBCDIC
3443  {
3444    char *ebc;
3445
3446    if ((ebc = malloc(strlen(display_string) + 1)) ==  NULL) {
3447      ZIPERR(ZE_MEM, "local_to_display_string");
3448    }
3449    strtoebc(ebc, display_string);
3450    free(display_string);
3451    display_string = ebc;
3452  }
3453#endif
3454
3455  if ((display_string = (char *)malloc(strlen(temp_string) + 1)) == NULL) {
3456    ZIPERR(ZE_MEM, "local_to_display_string");
3457  }
3458  strcpy(display_string, temp_string);
3459  free(temp_string);
3460
3461  return display_string;
3462}
3463
3464/* UTF-8 to local */
3465char *utf8_to_local_string(utf8_string)
3466  char *utf8_string;
3467{
3468  zwchar *wide_string = utf8_to_wide_string(utf8_string);
3469  char *loc = wide_to_local_string(wide_string);
3470  if (wide_string)
3471    free(wide_string);
3472  return loc;
3473}
3474
3475/* UTF-8 to local */
3476char *utf8_to_escape_string(utf8_string)
3477  char *utf8_string;
3478{
3479  zwchar *wide_string = utf8_to_wide_string(utf8_string);
3480  char *escape_string = wide_to_escape_string(wide_string);
3481  free(wide_string);
3482  return escape_string;
3483}
3484
3485#ifndef WIN32   /* The Win32 port uses a system-specific variant. */
3486/* convert multi-byte character string to wide character string */
3487zwchar *local_to_wide_string(local_string)
3488  char *local_string;
3489{
3490  int wsize;
3491  wchar_t *wc_string;
3492  zwchar *wide_string;
3493
3494  /* for now try to convert as string - fails if a bad char in string */
3495  wsize = mbstowcs(NULL, local_string, MB_CUR_MAX );
3496  if (wsize == (size_t)-1) {
3497    /* could not convert */
3498    return NULL;
3499  }
3500
3501  /* convert it */
3502  if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) {
3503    ZIPERR(ZE_MEM, "local_to_wide_string");
3504  }
3505  wsize = mbstowcs(wc_string, local_string, strlen(local_string) + 1);
3506  wc_string[wsize] = (wchar_t) 0;
3507
3508  /* in case wchar_t is not zwchar */
3509  if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) {
3510    ZIPERR(ZE_MEM, "local_to_wide_string");
3511  }
3512  for (wsize = 0; (wide_string[wsize] = (zwchar)wc_string[wsize]); wsize++) ;
3513  wide_string[wsize] = (zwchar)0;
3514  free(wc_string);
3515
3516  return wide_string;
3517}
3518#endif /* !WIN32 */
3519
3520
3521#if 0
3522/* All wchar functions are only used by Windows and are
3523   now in win32zip.c so that the Windows functions can
3524   be used and multiple character wide characters can
3525   be handled easily. */
3526# ifndef WIN32
3527char *wchar_to_utf8_string(wstring)
3528  wchar_t *wstring;
3529{
3530  zwchar *wide_string = wchar_to_wide_string(wstring);
3531  char *local_string = wide_to_utf8_string(wide_string);
3532
3533  free(wide_string);
3534
3535  return local_string;
3536}
3537# endif
3538#endif
3539
3540
3541/* convert wide string to UTF-8 */
3542char *wide_to_utf8_string(wide_string)
3543  zwchar *wide_string;
3544{
3545  int mbcount;
3546  char *utf8_string;
3547
3548  /* get size of utf8 string */
3549  mbcount = ucs4_string_to_utf8(wide_string, NULL, 0);
3550  if (mbcount == -1)
3551    return NULL;
3552  if ((utf8_string = (char *) malloc(mbcount + 1)) == NULL) {
3553    ZIPERR(ZE_MEM, "wide_to_utf8_string");
3554  }
3555  mbcount = ucs4_string_to_utf8(wide_string, utf8_string, mbcount + 1);
3556  if (mbcount == -1)
3557    return NULL;
3558
3559  return utf8_string;
3560}
3561
3562/* convert UTF-8 string to wide string */
3563zwchar *utf8_to_wide_string(utf8_string)
3564  char *utf8_string;
3565{
3566  int wcount;
3567  zwchar *wide_string;
3568
3569  wcount = utf8_to_ucs4_string(utf8_string, NULL, 0);
3570  if (wcount == -1)
3571    return NULL;
3572  if ((wide_string = (zwchar *) malloc((wcount + 2) * sizeof(zwchar))) == NULL) {
3573    ZIPERR(ZE_MEM, "utf8_to_wide_string");
3574  }
3575  wcount = utf8_to_ucs4_string(utf8_string, wide_string, wcount + 1);
3576
3577  return wide_string;
3578}
3579
3580
3581#endif /* UNICODE_SUPPORT */
3582
3583
3584/*---------------------------------------------------------------
3585 *  Long option support
3586 *  8/23/2003
3587 *
3588 *  Defines function get_option() to get and process the command
3589 *  line options and arguments from argv[].  The caller calls
3590 *  get_option() in a loop to get either one option and possible
3591 *  value or a non-option argument each loop.
3592 *
3593 *  This version does not include argument file support and can
3594 *  work directly on argv.  The argument file code complicates things and
3595 *  it seemed best to leave it out for now.  If argument file support (reading
3596 *  in command line arguments stored in a file and inserting into
3597 *  command line where @filename is found) is added later the arguments
3598 *  can change and a freeable copy of argv will be needed and can be
3599 *  created using copy_args in the left out code.
3600 *
3601 *  Supports short and long options as defined in the array options[]
3602 *  in zip.c, multiple short options in an argument (like -jlv), long
3603 *  option abbreviation (like --te for --temp-file if --te unique),
3604 *  short and long option values (like -b filename or --temp-file filename
3605 *  or --temp-file=filename), optional and required values, option negation
3606 *  by trailing - (like -S- to not include hidden and system files in MSDOS),
3607 *  value lists (like -x a b c), argument permuting (returning all options
3608 *  and values before any non-option arguments), and argument files (where any
3609 *  non-option non-value argument in form @path gets substituted with the
3610 *  white space separated arguments in the text file at path).  In this
3611 *  version argument file support has been removed to simplify development but
3612 *  may be added later.
3613 *
3614 *  E. Gordon
3615 */
3616
3617
3618/* message output - char casts are needed to handle constants */
3619#define oWARN(message) zipwarn((char *) message, "")
3620#define oERR(err,message) ZIPERR(err, (char *) message)
3621
3622
3623/* Although the below provides some support for multibyte characters
3624   the proper thing to do may be to use wide characters and support
3625   Unicode.  May get to it soon.  EG
3626 */
3627
3628/* For now stay with muti-byte characters.  May support wide characters
3629   in Zip 3.1.
3630 */
3631
3632/* multibyte character set support
3633   Multibyte characters use typically two or more sequential bytes
3634   to represent additional characters than can fit in a single byte
3635   character set.  The code used here is based on the ANSI mblen function. */
3636#ifdef MULTIBYTE_GETOPTNS
3637  int mb_clen(ptr)
3638    ZCONST char *ptr;
3639  {
3640    /* return the number of bytes that the char pointed to is.  Return 1 if
3641       null character or error like not start of valid multibyte character. */
3642    int cl;
3643
3644    cl = mblen(ptr, MB_CUR_MAX);
3645    return (cl > 0) ? cl : 1;
3646  }
3647#endif
3648
3649
3650  /* moved to zip.h */
3651#if 0
3652#ifdef UNICODE_SUPPORT
3653# define MB_CLEN(ptr) (1)
3654# define MB_NEXTCHAR(ptr) ((ptr)++)
3655# ifdef MULTIBYTE_GETOPTNS
3656#    undef MULTIBYTE_GETOPTNS
3657# endif
3658#else
3659# ifdef _MBCS
3660#  ifndef MULTIBYTE_GETOPTNS
3661#    define MULTIBYTE_GETOPTNS
3662#  endif
3663# endif
3664/* multibyte character set support
3665   Multibyte characters use typically two or more sequential bytes
3666   to represent additional characters than can fit in a single byte
3667   character set.  The code used here is based on the ANSI mblen function. */
3668#  ifdef MULTIBYTE_GETOPTNS
3669  local int mb_clen OF((ZCONST char *));  /* declare proto first */
3670  local int mb_clen(ptr)
3671    ZCONST char *ptr;
3672  {
3673    /* return the number of bytes that the char pointed to is.  Return 1 if
3674       null character or error like not start of valid multibyte character. */
3675    int cl;
3676
3677    cl = mblen(ptr, MB_CUR_MAX);
3678    return (cl > 0) ? cl : 1;
3679  }
3680#  define MB_CLEN(ptr) mb_clen(ptr)
3681#  define MB_NEXTCHAR(ptr) ((ptr) += MB_CLEN(ptr))
3682# else
3683#  define MB_CLEN(ptr) (1)
3684#  define MB_NEXTCHAR(ptr) ((ptr)++)
3685# endif
3686#endif
3687#endif
3688
3689
3690/* constants */
3691
3692/* function get_args_from_arg_file() can return this in depth parameter */
3693#define ARG_FILE_ERR -1
3694
3695/* internal settings for optchar */
3696#define SKIP_VALUE_ARG   -1
3697#define THIS_ARG_DONE    -2
3698#define START_VALUE_LIST -3
3699#define IN_VALUE_LIST    -4
3700#define NON_OPTION_ARG   -5
3701#define STOP_VALUE_LIST  -6
3702/* 7/25/04 EG */
3703#define READ_REST_ARGS_VERBATIM -7
3704
3705
3706/* global veriables */
3707
3708int enable_permute = 1;                     /* yes - return options first */
3709/* 7/25/04 EG */
3710int doubledash_ends_options = 1;            /* when -- what follows are not options */
3711
3712/* buffer for error messages (this sizing is a guess but must hold 2 paths) */
3713#define OPTIONERR_BUF_SIZE (FNMAX * 2 + 4000)
3714local char Far optionerrbuf[OPTIONERR_BUF_SIZE + 1];
3715
3716/* error messages */
3717static ZCONST char Far op_not_neg_err[] = "option %s not negatable";
3718static ZCONST char Far op_req_val_err[] = "option %s requires a value";
3719static ZCONST char Far op_no_allow_val_err[] = "option %s does not allow a value";
3720static ZCONST char Far sh_op_not_sup_err[] = "short option '%c' not supported";
3721static ZCONST char Far oco_req_val_err[] = "option %s requires one character value";
3722static ZCONST char Far oco_no_mbc_err[] = "option %s does not support multibyte values";
3723static ZCONST char Far num_req_val_err[] = "option %s requires number value";
3724static ZCONST char Far long_op_ambig_err[] = "long option '%s' ambiguous";
3725static ZCONST char Far long_op_not_sup_err[] = "long option '%s' not supported";
3726
3727static ZCONST char Far no_arg_files_err[] = "argument files not enabled\n";
3728
3729
3730/* below removed as only used for processing argument files */
3731
3732/* get_nextarg */
3733/* get_args_from_string */
3734/* insert_args */
3735/* get_args_from_arg_file */
3736
3737
3738/* copy error, option name, and option description if any to buf */
3739local int optionerr(buf, err, optind, islong)
3740  char *buf;
3741  ZCONST char *err;
3742  int optind;
3743  int islong;
3744{
3745  char optname[50];
3746
3747  if (options[optind].name && options[optind].name[0] != '\0') {
3748    if (islong)
3749      sprintf(optname, "'%s' (%s)", options[optind].longopt, options[optind].name);
3750    else
3751      sprintf(optname, "'%s' (%s)", options[optind].shortopt, options[optind].name);
3752  } else {
3753    if (islong)
3754      sprintf(optname, "'%s'", options[optind].longopt);
3755    else
3756      sprintf(optname, "'%s'", options[optind].shortopt);
3757  }
3758  sprintf(buf, err, optname);
3759  return 0;
3760}
3761
3762
3763/* copy_args
3764 *
3765 * Copy arguments in args, allocating storage with malloc.
3766 * Copies until a NULL argument is found or until max_args args
3767 * including args[0] are copied.  Set max_args to 0 to copy
3768 * until NULL.  Always terminates returned args[] with NULL arg.
3769 *
3770 * Any argument in the returned args can be freed with free().  Any
3771 * freed argument should be replaced with either another string
3772 * allocated with malloc or by NULL if last argument so that free_args
3773 * will properly work.
3774 */
3775char **copy_args(args, max_args)
3776  char **args;
3777  int max_args;
3778{
3779  int j;
3780  char **new_args;
3781
3782  if (args == NULL) {
3783    return NULL;
3784  }
3785
3786  /* count args */
3787  for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) ;
3788
3789  if ((new_args = (char **) malloc((j + 1) * sizeof(char *))) == NULL) {
3790    oERR(ZE_MEM, "ca");
3791  }
3792
3793  for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) {
3794    if (args[j] == NULL) {
3795      /* null argument is end of args */
3796      new_args[j] = NULL;
3797      break;
3798    }
3799    if ((new_args[j] = malloc(strlen(args[j]) + 1)) == NULL) {
3800      free_args(new_args);
3801      oERR(ZE_MEM, "ca");
3802    }
3803    strcpy(new_args[j], args[j]);
3804  }
3805  new_args[j] = NULL;
3806
3807  return new_args;
3808}
3809
3810
3811/* free args - free args created with one of these functions */
3812int free_args(args)
3813  char **args;
3814{
3815  int i;
3816
3817  if (args == NULL) {
3818    return 0;
3819  }
3820
3821  for (i = 0; args[i]; i++) {
3822    free(args[i]);
3823  }
3824  free(args);
3825  return i;
3826}
3827
3828
3829/* insert_arg
3830 *
3831 * Insert the argument arg into the array args before argument at_arg.
3832 * Return the new count of arguments (argc).
3833 *
3834 * If free_args is true, this function frees the old args array
3835 * (but not the component strings).  DO NOT set free_args on original
3836 * argv but only on args allocated with malloc.
3837 */
3838
3839int insert_arg(pargs, arg, at_arg, free_args)
3840   char ***pargs;
3841   ZCONST char *arg;
3842   int at_arg;
3843   int free_args;
3844{
3845   char *newarg = NULL;
3846   char **args;
3847   char **newargs = NULL;
3848   int argnum;
3849   int newargnum;
3850   int argcnt;
3851   int newargcnt;
3852
3853   if (pargs == NULL) {
3854     return 0;
3855   }
3856   args = *pargs;
3857
3858   /* count args */
3859   if (args == NULL) {
3860     argcnt = 0;
3861   } else {
3862     for (argcnt = 0; args[argcnt]; argcnt++) ;
3863   }
3864   if (arg == NULL) {
3865     /* done */
3866     return argcnt;
3867   }
3868   newargcnt = argcnt + 1;
3869
3870   /* get storage for new args */
3871   if ((newargs = (char **) malloc((newargcnt + 1) * sizeof(char *))) == NULL) {
3872     oERR(ZE_MEM, "ia");
3873   }
3874
3875   /* copy argument pointers from args to position at_arg, copy arg, then rest args */
3876   argnum = 0;
3877   newargnum = 0;
3878   if (args) {
3879     for (; args[argnum] && argnum < at_arg; argnum++) {
3880       newargs[newargnum++] = args[argnum];
3881     }
3882   }
3883   /* copy new arg */
3884   if ((newarg = (char *) malloc(strlen(arg) + 1)) == NULL) {
3885     oERR(ZE_MEM, "ia");
3886   }
3887   strcpy(newarg, arg);
3888
3889   newargs[newargnum++] = newarg;
3890   if (args) {
3891     for ( ; args[argnum]; argnum++) {
3892       newargs[newargnum++] = args[argnum];
3893     }
3894   }
3895   newargs[newargnum] = NULL;
3896
3897   /* free old args array but not component strings - this assumes that
3898      args was allocated with malloc as copy_args does.  DO NOT DO THIS
3899      on the original argv.
3900    */
3901   if (free_args)
3902     free(args);
3903
3904   *pargs = newargs;
3905
3906   return newargnum;
3907}
3908
3909/* ------------------------------------- */
3910
3911
3912
3913
3914/* get_shortopt
3915 *
3916 * Get next short option from arg.  The state is stored in argnum, optchar, and
3917 * option_num so no static storage is used.  Returns the option_ID.
3918 *
3919 * parameters:
3920 *    args        - argv array of arguments
3921 *    argnum      - index of current arg in args
3922 *    optchar     - pointer to index of next char to process.  Can be 0 or
3923 *                  const defined at top of this file like THIS_ARG_DONE
3924 *    negated     - on return pointer to int set to 1 if option negated or 0 otherwise
3925 *    value       - on return pointer to string set to value of option if any or NULL
3926 *                  if none.  If value is returned then the caller should free()
3927 *                  it when not needed anymore.
3928 *    option_num  - pointer to index in options[] of returned option or
3929 *                  o_NO_OPTION_MATCH if none.  Do not change as used by
3930 *                  value lists.
3931 *    depth       - recursion depth (0 at top level, 1 or more in arg files)
3932 */
3933local unsigned long get_shortopt(args, argnum, optchar, negated, value,
3934                                 option_num, depth)
3935  char **args;
3936  int argnum;
3937  int *optchar;
3938  int *negated;
3939  char **value;
3940  int *option_num;
3941  int depth;
3942{
3943  char *shortopt;
3944  int clen;
3945  char *nextchar;
3946  char *s;
3947  char *start;
3948  int op;
3949  char *arg;
3950  int match = -1;
3951
3952
3953  /* get arg */
3954  arg = args[argnum];
3955  /* current char in arg */
3956  nextchar = arg + (*optchar);
3957  clen = MB_CLEN(nextchar);
3958  /* next char in arg */
3959  (*optchar) +=  clen;
3960  /* get first char of short option */
3961  shortopt = arg + (*optchar);
3962  /* no value */
3963  *value = NULL;
3964
3965  if (*shortopt == '\0') {
3966    /* no more options in arg */
3967    *optchar = 0;
3968    *option_num = o_NO_OPTION_MATCH;
3969    return 0;
3970  }
3971
3972  /* look for match in options */
3973  clen = MB_CLEN(shortopt);
3974  for (op = 0; options[op].option_ID; op++) {
3975    s = options[op].shortopt;
3976    if (s && s[0] == shortopt[0]) {
3977      if (s[1] == '\0' && clen == 1) {
3978        /* single char match */
3979        match = op;
3980      } else {
3981        /* 2 wide short opt.  Could support more chars but should use long opts instead */
3982        if (s[1] == shortopt[1]) {
3983          /* match 2 char short opt or 2 byte char */
3984          match = op;
3985          if (clen == 1) (*optchar)++;
3986          break;
3987        }
3988      }
3989    }
3990  }
3991
3992  if (match > -1) {
3993    /* match */
3994    clen = MB_CLEN(shortopt);
3995    nextchar = arg + (*optchar) + clen;
3996    /* check for trailing dash negating option */
3997    if (*nextchar == '-') {
3998      /* negated */
3999      if (options[match].negatable == o_NOT_NEGATABLE) {
4000        if (options[match].value_type == o_NO_VALUE) {
4001          optionerr(optionerrbuf, op_not_neg_err, match, 0);
4002          if (depth > 0) {
4003            /* unwind */
4004            oWARN(optionerrbuf);
4005            return o_ARG_FILE_ERR;
4006          } else {
4007            oERR(ZE_PARMS, optionerrbuf);
4008          }
4009        }
4010      } else {
4011        *negated = 1;
4012        /* set up to skip negating dash */
4013        (*optchar) += clen;
4014        clen = 1;
4015      }
4016    }
4017
4018    /* value */
4019    clen = MB_CLEN(arg + (*optchar));
4020    /* optional value, one char value, and number value must follow option */
4021    if (options[match].value_type == o_ONE_CHAR_VALUE) {
4022      /* one char value */
4023      if (arg[(*optchar) + clen]) {
4024        /* has value */
4025        if (MB_CLEN(arg + (*optchar) + clen) > 1) {
4026          /* multibyte value not allowed for now */
4027          optionerr(optionerrbuf, oco_no_mbc_err, match, 0);
4028          if (depth > 0) {
4029            /* unwind */
4030            oWARN(optionerrbuf);
4031            return o_ARG_FILE_ERR;
4032          } else {
4033            oERR(ZE_PARMS, optionerrbuf);
4034          }
4035        }
4036        if ((*value = (char *) malloc(2)) == NULL) {
4037          oERR(ZE_MEM, "gso");
4038        }
4039        (*value)[0] = *(arg + (*optchar) + clen);
4040        (*value)[1] = '\0';
4041        *optchar += clen;
4042        clen = 1;
4043      } else {
4044        /* one char values require a value */
4045        optionerr(optionerrbuf, oco_req_val_err, match, 0);
4046        if (depth > 0) {
4047          oWARN(optionerrbuf);
4048          return o_ARG_FILE_ERR;
4049        } else {
4050          oERR(ZE_PARMS, optionerrbuf);
4051        }
4052      }
4053    } else if (options[match].value_type == o_NUMBER_VALUE) {
4054      /* read chars until end of number */
4055      start = arg + (*optchar) + clen;
4056      if (*start == '+' || *start == '-') {
4057        start++;
4058      }
4059      s = start;
4060      for (; isdigit(*s); MB_NEXTCHAR(s)) ;
4061      if (s == start) {
4062        /* no digits */
4063        optionerr(optionerrbuf, num_req_val_err, match, 0);
4064        if (depth > 0) {
4065          oWARN(optionerrbuf);
4066          return o_ARG_FILE_ERR;
4067        } else {
4068          oERR(ZE_PARMS, optionerrbuf);
4069        }
4070      }
4071      start = arg + (*optchar) + clen;
4072      if ((*value = (char *) malloc((int)(s - start) + 1)) == NULL) {
4073        oERR(ZE_MEM, "gso");
4074      }
4075      *optchar += (int)(s - start);
4076      strncpy(*value, start, (int)(s - start));
4077      (*value)[(int)(s - start)] = '\0';
4078      clen = MB_CLEN(s);
4079    } else if (options[match].value_type == o_OPTIONAL_VALUE) {
4080      /* optional value */
4081      /* This seemed inconsistent so now if no value attached to argument look
4082         to the next argument if that argument is not an option for option
4083         value - 11/12/04 EG */
4084      if (arg[(*optchar) + clen]) {
4085        /* has value */
4086        /* add support for optional = - 2/6/05 EG */
4087        if (arg[(*optchar) + clen] == '=') {
4088          /* skip = */
4089          clen++;
4090        }
4091        if (arg[(*optchar) + clen]) {
4092          if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
4093              == NULL) {
4094            oERR(ZE_MEM, "gso");
4095          }
4096          strcpy(*value, arg + (*optchar) + clen);
4097        }
4098        *optchar = THIS_ARG_DONE;
4099      } else if (args[argnum + 1] && args[argnum + 1][0] != '-') {
4100        /* use next arg for value */
4101        if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
4102          oERR(ZE_MEM, "gso");
4103        }
4104        /* using next arg as value */
4105        strcpy(*value, args[argnum + 1]);
4106        *optchar = SKIP_VALUE_ARG;
4107      }
4108    } else if (options[match].value_type == o_REQUIRED_VALUE ||
4109               options[match].value_type == o_VALUE_LIST) {
4110      /* see if follows option */
4111      if (arg[(*optchar) + clen]) {
4112        /* has value following option as -ovalue */
4113        /* add support for optional = - 6/5/05 EG */
4114        if (arg[(*optchar) + clen] == '=') {
4115          /* skip = */
4116          clen++;
4117        }
4118          if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
4119              == NULL) {
4120          oERR(ZE_MEM, "gso");
4121        }
4122        strcpy(*value, arg + (*optchar) + clen);
4123        *optchar = THIS_ARG_DONE;
4124      } else {
4125        /* use next arg for value */
4126        if (args[argnum + 1]) {
4127          if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
4128            oERR(ZE_MEM, "gso");
4129          }
4130          strcpy(*value, args[argnum + 1]);
4131          if (options[match].value_type == o_VALUE_LIST) {
4132            *optchar = START_VALUE_LIST;
4133          } else {
4134            *optchar = SKIP_VALUE_ARG;
4135          }
4136        } else {
4137          /* no value found */
4138          optionerr(optionerrbuf, op_req_val_err, match, 0);
4139          if (depth > 0) {
4140            oWARN(optionerrbuf);
4141            return o_ARG_FILE_ERR;
4142          } else {
4143            oERR(ZE_PARMS, optionerrbuf);
4144          }
4145        }
4146      }
4147    }
4148
4149    *option_num = match;
4150    return options[match].option_ID;
4151  }
4152  sprintf(optionerrbuf, sh_op_not_sup_err, *shortopt);
4153  if (depth > 0) {
4154    /* unwind */
4155    oWARN(optionerrbuf);
4156    return o_ARG_FILE_ERR;
4157  } else {
4158    oERR(ZE_PARMS, optionerrbuf);
4159  }
4160  return 0;
4161}
4162
4163
4164/* get_longopt
4165 *
4166 * Get the long option in args array at argnum.
4167 * Parameters same as for get_shortopt.
4168 */
4169
4170local unsigned long get_longopt(args, argnum, optchar, negated, value,
4171                                option_num, depth)
4172  char **args;
4173  int argnum;
4174  int *optchar;
4175  int *negated;
4176  char **value;
4177  int *option_num;
4178  int depth;
4179{
4180  char *longopt;
4181  char *lastchr;
4182  char *valuestart;
4183  int op;
4184  char *arg;
4185  int match = -1;
4186  *value = NULL;
4187
4188  if (args == NULL) {
4189    *option_num = o_NO_OPTION_MATCH;
4190    return 0;
4191  }
4192  if (args[argnum] == NULL) {
4193    *option_num = o_NO_OPTION_MATCH;
4194    return 0;
4195  }
4196  /* copy arg so can chop end if value */
4197  if ((arg = (char *)malloc(strlen(args[argnum]) + 1)) == NULL) {
4198    oERR(ZE_MEM, "glo");
4199  }
4200  strcpy(arg, args[argnum]);
4201
4202  /* get option */
4203  longopt = arg + 2;
4204  /* no value */
4205  *value = NULL;
4206
4207  /* find = */
4208  for (lastchr = longopt, valuestart = longopt;
4209       *valuestart && *valuestart != '=';
4210       lastchr = valuestart, MB_NEXTCHAR(valuestart)) ;
4211  if (*valuestart) {
4212    /* found =value */
4213    *valuestart = '\0';
4214    valuestart++;
4215  } else {
4216    valuestart = NULL;
4217  }
4218
4219  if (*lastchr == '-') {
4220    /* option negated */
4221    *negated = 1;
4222    *lastchr = '\0';
4223  } else {
4224    *negated = 0;
4225  }
4226
4227  /* look for long option match */
4228  for (op = 0; options[op].option_ID; op++) {
4229    if (options[op].longopt && strcmp(options[op].longopt, longopt) == 0) {
4230      /* exact match */
4231      match = op;
4232      break;
4233    }
4234    if (options[op].longopt && strncmp(options[op].longopt, longopt, strlen(longopt)) == 0) {
4235      if (match > -1) {
4236        sprintf(optionerrbuf, long_op_ambig_err, longopt);
4237        free(arg);
4238        if (depth > 0) {
4239          /* unwind */
4240          oWARN(optionerrbuf);
4241          return o_ARG_FILE_ERR;
4242        } else {
4243          oERR(ZE_PARMS, optionerrbuf);
4244        }
4245      }
4246      match = op;
4247    }
4248  }
4249
4250  if (match == -1) {
4251    sprintf(optionerrbuf, long_op_not_sup_err, longopt);
4252    free(arg);
4253    if (depth > 0) {
4254      oWARN(optionerrbuf);
4255      return o_ARG_FILE_ERR;
4256    } else {
4257      oERR(ZE_PARMS, optionerrbuf);
4258    }
4259  }
4260
4261  /* one long option an arg */
4262  *optchar = THIS_ARG_DONE;
4263
4264  /* if negated then see if allowed */
4265  if (*negated && options[match].negatable == o_NOT_NEGATABLE) {
4266    optionerr(optionerrbuf, op_not_neg_err, match, 1);
4267    free(arg);
4268    if (depth > 0) {
4269      /* unwind */
4270      oWARN(optionerrbuf);
4271      return o_ARG_FILE_ERR;
4272    } else {
4273      oERR(ZE_PARMS, optionerrbuf);
4274    }
4275  }
4276  /* get value */
4277  if (options[match].value_type == o_OPTIONAL_VALUE) {
4278    /* optional value in form option=value */
4279    if (valuestart) {
4280      /* option=value */
4281      if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
4282        free(arg);
4283        oERR(ZE_MEM, "glo");
4284      }
4285      strcpy(*value, valuestart);
4286    }
4287  } else if (options[match].value_type == o_REQUIRED_VALUE ||
4288             options[match].value_type == o_NUMBER_VALUE ||
4289             options[match].value_type == o_ONE_CHAR_VALUE ||
4290             options[match].value_type == o_VALUE_LIST) {
4291    /* handle long option one char and number value as required value */
4292    if (valuestart) {
4293      /* option=value */
4294      if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
4295        free(arg);
4296        oERR(ZE_MEM, "glo");
4297      }
4298      strcpy(*value, valuestart);
4299    } else {
4300      /* use next arg */
4301      if (args[argnum + 1]) {
4302        if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
4303          free(arg);
4304          oERR(ZE_MEM, "glo");
4305        }
4306        /* using next arg as value */
4307        strcpy(*value, args[argnum + 1]);
4308        if (options[match].value_type == o_VALUE_LIST) {
4309          *optchar = START_VALUE_LIST;
4310        } else {
4311          *optchar = SKIP_VALUE_ARG;
4312        }
4313      } else {
4314        /* no value found */
4315        optionerr(optionerrbuf, op_req_val_err, match, 1);
4316        free(arg);
4317        if (depth > 0) {
4318          /* unwind */
4319          oWARN(optionerrbuf);
4320          return o_ARG_FILE_ERR;
4321        } else {
4322          oERR(ZE_PARMS, optionerrbuf);
4323        }
4324      }
4325    }
4326  } else if (options[match].value_type == o_NO_VALUE) {
4327    /* this option does not accept a value */
4328    if (valuestart) {
4329      /* --option=value */
4330      optionerr(optionerrbuf, op_no_allow_val_err, match, 1);
4331      free(arg);
4332      if (depth > 0) {
4333        oWARN(optionerrbuf);
4334        return o_ARG_FILE_ERR;
4335      } else {
4336        oERR(ZE_PARMS, optionerrbuf);
4337      }
4338    }
4339  }
4340  free(arg);
4341
4342  *option_num = match;
4343  return options[match].option_ID;
4344}
4345
4346
4347
4348/* get_option
4349 *
4350 * Main interface for user.  Use this function to get options, values and
4351 * non-option arguments from a command line provided in argv form.
4352 *
4353 * To use get_option() first define valid options by setting
4354 * the global variable options[] to an array of option_struct.  Also
4355 * either change defaults below or make variables global and set elsewhere.
4356 * Zip uses below defaults.
4357 *
4358 * Call get_option() to get an option (like -b or --temp-file) and any
4359 * value for that option (like filename for -b) or a non-option argument
4360 * (like archive name) each call.  If *value* is not NULL after calling
4361 * get_option() it is a returned value and the caller should either store
4362 * the char pointer or free() it before calling get_option() again to avoid
4363 * leaking memory.  If a non-option non-value argument is returned get_option()
4364 * returns o_NON_OPTION_ARG and value is set to the entire argument.
4365 * When there are no more arguments get_option() returns 0.
4366 *
4367 * The parameters argnum (after set to 0 on initial call),
4368 * optchar, first_nonopt_arg, option_num, and depth (after initial
4369 * call) are set and maintained by get_option() and should not be
4370 * changed.  The parameters argc, negated, and value are outputs and
4371 * can be used by the calling program.  get_option() returns either the
4372 * option_ID for the current option, a special value defined in
4373 * zip.h, or 0 when no more arguments.
4374 *
4375 * The value returned by get_option() is the ID value in the options
4376 * table.  This value can be duplicated in the table if different
4377 * options are really the same option.  The index into the options[]
4378 * table is given by option_num, though the ID should be used as
4379 * option numbers change when the table is changed.  The ID must
4380 * not be 0 for any option as this ends the table.  If get_option()
4381 * finds an option not in the table it calls oERR to post an
4382 * error and exit.  Errors also result if the option requires a
4383 * value that is missing, a value is present but the option does
4384 * not take one, and an option is negated but is not
4385 * negatable.  Non-option arguments return o_NON_OPTION_ARG
4386 * with the entire argument in value.
4387 *
4388 * For Zip, permuting is on and all options and their values are
4389 * returned before any non-option arguments like archive name.
4390 *
4391 * The arguments "-" alone and "--" alone return as non-option arguments.
4392 * Note that "-" should not be used as part of a short option
4393 * entry in the table but can be used in the middle of long
4394 * options such as in the long option "a-long-option".  Now "--" alone
4395 * stops option processing, returning any arguments following "--" as
4396 * non-option arguments instead of options.
4397 *
4398 * Argument file support is removed from this version. It may be added later.
4399 *
4400 * After each call:
4401 *   argc       is set to the current size of args[] but should not change
4402 *                with argument file support removed,
4403 *   argnum     is the index of the current arg,
4404 *   value      is either the value of the returned option or non-option
4405 *                argument or NULL if option with no value,
4406 *   negated    is set if the option was negated by a trailing dash (-)
4407 *   option_num is set to either the index in options[] for the option or
4408 *                o_NO_OPTION_MATCH if no match.
4409 * Negation is checked before the value is read if the option is negatable so
4410 * that the - is not included in the value.  If the option is not negatable
4411 * but takes a value then the - will start the value.  If permuting then
4412 * argnum and first_nonopt_arg are unreliable and should not be used.
4413 *
4414 * Command line is read from left to right.  As get_option() finds non-option
4415 * arguments (arguments not starting with - and that are not values to options)
4416 * it moves later options and values in front of the non-option arguments.
4417 * This permuting is turned off by setting enable_permute to 0.  Then
4418 * get_option() will return options and non-option arguments in the order
4419 * found.  Currently permuting is only done after an argument is completely
4420 * processed so that any value can be moved with options they go with.  All
4421 * state information is stored in the parameters argnum, optchar,
4422 * first_nonopt_arg and option_num.  You should not change these after the
4423 * first call to get_option().  If you need to back up to a previous arg then
4424 * set argnum to that arg (remembering that args may have been permuted) and
4425 * set optchar = 0 and first_nonopt_arg to the first non-option argument if
4426 * permuting.  After all arguments are returned the next call to get_option()
4427 * returns 0.  The caller can then call free_args(args) if appropriate.
4428 *
4429 * get_option() accepts arguments in the following forms:
4430 *  short options
4431 *       of 1 and 2 characters, e.g. a, b, cc, d, and ba, after a single
4432 *       leading -, as in -abccdba.  In this example if 'b' is followed by 'a'
4433 *       it matches short option 'ba' else it is interpreted as short option
4434 *       b followed by another option.  The character - is not legal as a
4435 *       short option or as part of a 2 character short option.
4436 *
4437 *       If a short option has a value it immediately follows the option or
4438 *       if that option is the end of the arg then the next arg is used as
4439 *       the value.  So if short option e has a value, it can be given as
4440 *             -evalue
4441 *       or
4442 *             -e value
4443 *       and now
4444 *             -e=value
4445 *       but now that = is optional a leading = is stripped for the first.
4446 *       This change allows optional short option values to be defaulted as
4447 *             -e=
4448 *       Either optional or required values can be specified.  Optional values
4449 *       now use both forms as ignoring the later got confusing.  Any
4450 *       non-value short options can preceed a valued short option as in
4451 *             -abevalue
4452 *       Some value types (one_char and number) allow options after the value
4453 *       so if oc is an option that takes a character and n takes a number
4454 *       then
4455 *             -abocVccn42evalue
4456 *       returns value V for oc and value 42 for n.  All values are strings
4457 *       so programs may have to convert the "42" to a number.  See long
4458 *       options below for how value lists are handled.
4459 *
4460 *       Any short option can be negated by following it with -.  Any - is
4461 *       handled and skipped over before any value is read unless the option
4462 *       is not negatable but takes a value and then - starts the value.
4463 *
4464 *       If the value for an optional value is just =, then treated as no
4465 *       value.
4466 *
4467 *  long options
4468 *       of arbitrary length are assumed if an arg starts with -- but is not
4469 *       exactly --.  Long options are given one per arg and can be abbreviated
4470 *       if the abbreviation uniquely matches one of the long options.
4471 *       Exact matches always match before partial matches.  If ambiguous an
4472 *       error is generated.
4473 *
4474 *       Values are specified either in the form
4475 *             --longoption=value
4476 *       or can be the following arg if the value is required as in
4477 *             --longoption value
4478 *       Optional values to long options must be in the first form.
4479 *
4480 *       Value lists are specified by o_VALUE_LIST and consist of an option
4481 *       that takes a value followed by one or more value arguments.
4482 *       The two forms are
4483 *             --option=value
4484 *       or
4485 *             -ovalue
4486 *       for a single value or
4487 *             --option value1 value2 value3 ... --option2
4488 *       or
4489 *             -o value1 value2 value3 ...
4490 *       for a list of values.  The list ends at the next option, the
4491 *       end of the command line, or at a single "@" argument.
4492 *       Each value is treated as if it was preceeded by the option, so
4493 *             --option1 val1 val2
4494 *       with option1 value_type set to o_VALUE_LIST is the same as
4495 *             --option1=val1 --option1=val2
4496 *
4497 *       Long options can be negated by following the option with - as in
4498 *             --longoption-
4499 *       Long options with values can also be negated if this makes sense for
4500 *       the caller as:
4501 *             --longoption-=value
4502 *       If = is not followed by anything it is treated as no value.
4503 *
4504 *  @path
4505 *       When an argument in the form @path is encountered, the file at path
4506 *       is opened and white space separated arguments read from the file
4507 *       and inserted into the command line at that point as if the contents
4508 *       of the file were directly typed at that location.  The file can
4509 *       have options, files to zip, or anything appropriate at that location
4510 *       in the command line.  Since Zip has permuting enabled, options and
4511 *       files will propagate to the appropriate locations in the command
4512 *       line.
4513 *
4514 *       Argument files support has been removed from this version.  It may
4515 *       be added back later.
4516 *
4517 *  non-option argument
4518 *       is any argument not given above.  If enable_permute is 1 then
4519 *       these are returned after all options, otherwise all options and
4520 *       args are returned in order.  Returns option ID o_NON_OPTION_ARG
4521 *       and sets value to the argument.
4522 *
4523 *
4524 * Arguments to get_option:
4525 *  char ***pargs          - pointer to arg array in the argv form
4526 *  int *argc              - returns the current argc for args incl. args[0]
4527 *  int *argnum            - the index of the current argument (caller
4528 *                            should set = 0 on first call and not change
4529 *                            after that)
4530 *  int *optchar           - index of next short opt in arg or special
4531 *  int *first_nonopt_arg  - used by get_option to permute args
4532 *  int *negated           - option was negated (had trailing -)
4533 *  char *value            - value of option if any (free when done with it) or NULL
4534 *  int *option_num        - the index in options of the last option returned
4535 *                            (can be o_NO_OPTION_MATCH)
4536 *  int recursion_depth    - current depth of recursion
4537 *                            (always set to 0 by caller)
4538 *                            (always 0 with argument files support removed)
4539 *
4540 *  Caller should only read the returned option ID and the value, negated,
4541 *  and option_num (if required) parameters after each call.
4542 *
4543 *  Ed Gordon
4544 *  24 August 2003 (last updated 2 April 2008 EG)
4545 *
4546 */
4547
4548unsigned long get_option(pargs, argc, argnum, optchar, value,
4549                         negated, first_nonopt_arg, option_num, recursion_depth)
4550  char ***pargs;
4551  int *argc;
4552  int *argnum;
4553  int *optchar;
4554  char **value;
4555  int *negated;
4556  int *first_nonopt_arg;
4557  int *option_num;
4558  int recursion_depth;
4559{
4560  char **args;
4561  unsigned long option_ID;
4562
4563  int argcnt;
4564  int first_nonoption_arg;
4565  char *arg = NULL;
4566  int h;
4567  int optc;
4568  int argn;
4569  int j;
4570  int v;
4571  int read_rest_args_verbatim = 0;  /* 7/25/04 - ignore options and arg files for rest args */
4572
4573  /* value is outdated.  The caller should free value before
4574     calling get_option again. */
4575  *value = NULL;
4576
4577  /* if args is NULL then done */
4578  if (pargs == NULL) {
4579    *argc = 0;
4580    return 0;
4581  }
4582  args = *pargs;
4583  if (args == NULL) {
4584    *argc = 0;
4585    return 0;
4586  }
4587
4588  /* count args */
4589  for (argcnt = 0; args[argcnt]; argcnt++) ;
4590
4591  /* if no provided args then nothing to do */
4592  if (argcnt < 1 || (recursion_depth == 0 && argcnt < 2)) {
4593    *argc = argcnt;
4594    /* return 0 to note that no args are left */
4595    return 0;
4596  }
4597
4598  *negated = 0;
4599  first_nonoption_arg = *first_nonopt_arg;
4600  argn = *argnum;
4601  optc = *optchar;
4602
4603  if (optc == READ_REST_ARGS_VERBATIM) {
4604    read_rest_args_verbatim = 1;
4605  }
4606
4607  if (argn == -1 || (recursion_depth == 0 && argn == 0)) {
4608    /* first call */
4609    /* if depth = 0 then args[0] is argv[0] so skip */
4610    *option_num = o_NO_OPTION_MATCH;
4611    optc = THIS_ARG_DONE;
4612    first_nonoption_arg = -1;
4613  }
4614
4615  /* if option_num is set then restore last option_ID in case continuing value list */
4616  option_ID = 0;
4617  if (*option_num != o_NO_OPTION_MATCH) {
4618    option_ID = options[*option_num].option_ID;
4619  }
4620
4621  /* get next option if any */
4622  for (;;)  {
4623    if (read_rest_args_verbatim) {
4624      /* rest of args after "--" are non-option args if doubledash_ends_options set */
4625      argn++;
4626      if (argn > argcnt || args[argn] == NULL) {
4627        /* done */
4628        option_ID = 0;
4629        break;
4630      }
4631      arg = args[argn];
4632      if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
4633        oERR(ZE_MEM, "go");
4634      }
4635      strcpy(*value, arg);
4636      *option_num = o_NO_OPTION_MATCH;
4637      option_ID = o_NON_OPTION_ARG;
4638      break;
4639
4640    /* permute non-option args after option args so options are returned first */
4641    } else if (enable_permute) {
4642      if (optc == SKIP_VALUE_ARG || optc == THIS_ARG_DONE ||
4643          optc == START_VALUE_LIST || optc == IN_VALUE_LIST ||
4644          optc == STOP_VALUE_LIST) {
4645        /* moved to new arg */
4646        if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
4647          /* do the permuting - move non-options after this option */
4648          /* if option and value separate args or starting list skip option */
4649          if (optc == SKIP_VALUE_ARG || optc == START_VALUE_LIST) {
4650            v = 1;
4651          } else {
4652            v = 0;
4653          }
4654          for (h = first_nonoption_arg; h < argn; h++) {
4655            arg = args[first_nonoption_arg];
4656            for (j = first_nonoption_arg; j < argn + v; j++) {
4657              args[j] = args[j + 1];
4658            }
4659            args[j] = arg;
4660          }
4661          first_nonoption_arg += 1 + v;
4662        }
4663      }
4664    } else if (optc == NON_OPTION_ARG) {
4665      /* if not permuting then already returned arg */
4666      optc = THIS_ARG_DONE;
4667    }
4668
4669    /* value lists */
4670    if (optc == STOP_VALUE_LIST) {
4671      optc = THIS_ARG_DONE;
4672    }
4673
4674    if (optc == START_VALUE_LIST || optc == IN_VALUE_LIST) {
4675      if (optc == START_VALUE_LIST) {
4676        /* already returned first value */
4677        argn++;
4678        optc = IN_VALUE_LIST;
4679      }
4680      argn++;
4681      arg = args[argn];
4682      /* if end of args and still in list and there are non-option args then
4683         terminate list */
4684      if (arg == NULL && (optc == START_VALUE_LIST || optc == IN_VALUE_LIST)
4685          && first_nonoption_arg > -1) {
4686        /* terminate value list with @ */
4687        /* this is only needed for argument files */
4688        /* but is also good for show command line so command lines with lists
4689           can always be read back in */
4690        argcnt = insert_arg(&args, "@", first_nonoption_arg, 1);
4691        argn++;
4692        if (first_nonoption_arg > -1) {
4693          first_nonoption_arg++;
4694        }
4695      }
4696
4697      arg = args[argn];
4698      if (arg && arg[0] == '@' && arg[1] == '\0') {
4699          /* inserted arguments terminator */
4700          optc = STOP_VALUE_LIST;
4701          continue;
4702      } else if (arg && arg[0] != '-') {  /* not option */
4703        /* - and -- are not allowed in value lists unless escaped */
4704        /* another value in value list */
4705        if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
4706          oERR(ZE_MEM, "go");
4707        }
4708        strcpy(*value, args[argn]);
4709        break;
4710
4711      } else {
4712        argn--;
4713        optc = THIS_ARG_DONE;
4714      }
4715    }
4716
4717    /* move to next arg */
4718    if (optc == SKIP_VALUE_ARG) {
4719      argn += 2;
4720      optc = 0;
4721    } else if (optc == THIS_ARG_DONE) {
4722      argn++;
4723      optc = 0;
4724    }
4725    if (argn > argcnt) {
4726      break;
4727    }
4728    if (args[argn] == NULL) {
4729      /* done unless permuting and non-option args */
4730      if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
4731        /* return non-option arguments at end */
4732        if (optc == NON_OPTION_ARG) {
4733          first_nonoption_arg++;
4734        }
4735        /* after first pass args are permuted but skipped over non-option args */
4736        /* swap so argn points to first non-option arg */
4737        j = argn;
4738        argn = first_nonoption_arg;
4739        first_nonoption_arg = j;
4740      }
4741      if (argn > argcnt || args[argn] == NULL) {
4742        /* done */
4743        option_ID = 0;
4744        break;
4745      }
4746    }
4747
4748    /* after swap first_nonoption_arg points to end which is NULL */
4749    if (first_nonoption_arg > -1 && (args[first_nonoption_arg] == NULL)) {
4750      /* only non-option args left */
4751      if (optc == NON_OPTION_ARG) {
4752        argn++;
4753      }
4754      if (argn > argcnt || args[argn] == NULL) {
4755        /* done */
4756        option_ID = 0;
4757        break;
4758      }
4759      if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
4760        oERR(ZE_MEM, "go");
4761      }
4762      strcpy(*value, args[argn]);
4763      optc = NON_OPTION_ARG;
4764      option_ID = o_NON_OPTION_ARG;
4765      break;
4766    }
4767
4768    arg = args[argn];
4769
4770    /* is it an option */
4771    if (arg[0] == '-') {
4772      /* option */
4773      if (arg[1] == '\0') {
4774        /* arg = - */
4775        /* treat like non-option arg */
4776        *option_num = o_NO_OPTION_MATCH;
4777        if (enable_permute) {
4778          /* permute args to move all non-option args to end */
4779          if (first_nonoption_arg < 0) {
4780            first_nonoption_arg = argn;
4781          }
4782          argn++;
4783        } else {
4784          /* not permute args so return non-option args when found */
4785          if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
4786            oERR(ZE_MEM, "go");
4787          }
4788          strcpy(*value, arg);
4789          optc = NON_OPTION_ARG;
4790          option_ID = o_NON_OPTION_ARG;
4791          break;
4792        }
4793
4794      } else if (arg[1] == '-') {
4795        /* long option */
4796        if (arg[2] == '\0') {
4797          /* arg = -- */
4798          if (doubledash_ends_options) {
4799            /* Now -- stops permuting and forces the rest of
4800               the command line to be read verbatim - 7/25/04 EG */
4801
4802            /* never permute args after -- and return as non-option args */
4803            if (first_nonoption_arg < 1) {
4804              /* -- is first non-option argument - 8/7/04 EG */
4805              argn--;
4806            } else {
4807              /* go back to start of non-option args - 8/7/04 EG */
4808              argn = first_nonoption_arg - 1;
4809            }
4810
4811            /* disable permuting and treat remaining arguments as not
4812               options */
4813            read_rest_args_verbatim = 1;
4814            optc = READ_REST_ARGS_VERBATIM;
4815
4816          } else {
4817            /* treat like non-option arg */
4818            *option_num = o_NO_OPTION_MATCH;
4819            if (enable_permute) {
4820              /* permute args to move all non-option args to end */
4821              if (first_nonoption_arg < 0) {
4822                first_nonoption_arg = argn;
4823              }
4824              argn++;
4825            } else {
4826              /* not permute args so return non-option args when found */
4827              if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
4828                oERR(ZE_MEM, "go");
4829              }
4830              strcpy(*value, arg);
4831              optc = NON_OPTION_ARG;
4832              option_ID = o_NON_OPTION_ARG;
4833              break;
4834            }
4835          }
4836
4837        } else {
4838          option_ID = get_longopt(args, argn, &optc, negated, value, option_num, recursion_depth);
4839          if (option_ID == o_ARG_FILE_ERR) {
4840            /* unwind as only get this if recursion_depth > 0 */
4841            return option_ID;
4842          }
4843          break;
4844        }
4845
4846      } else {
4847        /* short option */
4848        option_ID = get_shortopt(args, argn, &optc, negated, value, option_num, recursion_depth);
4849
4850        if (option_ID == o_ARG_FILE_ERR) {
4851          /* unwind as only get this if recursion_depth > 0 */
4852          return option_ID;
4853        }
4854
4855        if (optc == 0) {
4856          /* if optc = 0 then ran out of short opts this arg */
4857          optc = THIS_ARG_DONE;
4858        } else {
4859          break;
4860        }
4861      }
4862
4863#if 0
4864    /* argument file code left out
4865       so for now let filenames start with @
4866    */
4867
4868    } else if (allow_arg_files && arg[0] == '@') {
4869      /* arg file */
4870      oERR(ZE_PARMS, no_arg_files_err);
4871#endif
4872
4873    } else {
4874      /* non-option */
4875      if (enable_permute) {
4876        /* permute args to move all non-option args to end */
4877        if (first_nonoption_arg < 0) {
4878          first_nonoption_arg = argn;
4879        }
4880        argn++;
4881      } else {
4882        /* no permute args so return non-option args when found */
4883        if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
4884          oERR(ZE_MEM, "go");
4885        }
4886        strcpy(*value, arg);
4887        *option_num = o_NO_OPTION_MATCH;
4888        optc = NON_OPTION_ARG;
4889        option_ID = o_NON_OPTION_ARG;
4890        break;
4891      }
4892
4893    }
4894  }
4895
4896  *pargs = args;
4897  *argc = argcnt;
4898  *first_nonopt_arg = first_nonoption_arg;
4899  *argnum = argn;
4900  *optchar = optc;
4901
4902  return option_ID;
4903}
4904