1diff -ru2 unz60e03/unzip.c u6e3_np/unzip.c
2--- unz60e03/unzip.c	Wed Mar 19 13:08:38 2008
3+++ u6e3_np/unzip.c	Mon Mar 24 14:16:58 2008
4@@ -128,4 +128,6 @@
5     "error:  command line parameter #%d exceeds internal size limit\n";
6 #endif /* !SFX */
7+static ZCONST char Far NoMemArgsList[] =
8+  "error:  no memory for arguments list";
9
10 #if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS))
11@@ -245,5 +247,5 @@
12    static ZCONST char Far local3[] = "\
13   -Y  treat \".nnn\" as \";nnn\" version         -2  force ODS2 names\n\
14-  --D restore dir (-D: no) timestamps        -M  pipe through \"more\" pager\n\
15+  -D- restore dir (-D: no) timestamps        -M  pipe through \"more\" pager\n\
16   (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)\
17 \n\n";
18@@ -251,5 +253,5 @@
19    static ZCONST char Far local3[] = "\n\
20   -Y  treat \".nnn\" as \";nnn\" version         -2  force ODS2 names\n\
21-  --D restore dir (-D: no) timestamps\n\
22+  -D- restore dir (-D: no) timestamps\n\
23   (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)\
24 \n\n";
25@@ -694,5 +696,5 @@
26     char *p;
27 #endif
28-#if (defined(DOS_FLX_H68_NLM_OS2_W32) || !defined(SFX))
29+#if ((defined(WIN32) && defined(__RSXNT__)) || !defined(SFX))
30     int i;
31 #endif
32@@ -1053,4 +1055,45 @@
33      * 'forward slashes' for user's convenience (include zipfile name itself)
34      */
35+    {
36+        /* pfnames */
37+
38+        char **names;
39+
40+        for (names = G.pfnames; *names; names++) {
41+#ifdef __human68k__
42+            extern char *_toslash(char *);
43+            _toslash(*names);
44+#else /* !__human68k__ */
45+            char *q = *names;
46+
47+            while (*q != '\0') {
48+                if (*q == '\\')
49+                    *q = '/';
50+                INCSTR(q);
51+            }
52+#endif /* ?__human68k__ */
53+        }
54+    }
55+    {
56+        /* G.wildzipfn */
57+
58+#ifdef __human68k__
59+        extern char *_toslash(char *);
60+        _toslash(*G.wildzipfn);
61+#else /* !__human68k__ */
62+        char *q = G.wildzipfn;
63+
64+        while (*q != '\0') {
65+            if (*q == '\\')
66+                *q = '/';
67+            INCSTR(q);
68+        }
69+#endif /* ?__human68k__ */
70+    }
71+#endif /* DOS_FLX_H68_NLM_OS2_W32 */
72+
73+
74+#if 0
75+#ifdef DOS_FLX_H68_NLM_OS2_W32
76 #ifdef SFX
77     for (G.pfnames = argv, i = argc;  i > 0;  --i) {
78@@ -1074,11 +1117,18 @@
79     }
80 #endif /* DOS_FLX_H68_NLM_OS2_W32 */
81+#endif /* 0 */
82
83+/*
84 #ifndef SFX
85     G.wildzipfn = *argv++;
86 #endif
87+*/
88
89 #if (defined(SFX) && !defined(SFX_EXDIR)) /* only check for -x */
90
91+# if 0
92+    /* all this should be done in the options call now */
93+
94+
95     G.filespecs = argc;
96     G.xfilespecs = 0;
97@@ -1104,7 +1154,10 @@
98     } else
99         G.process_all_files = TRUE;      /* for speed */
100+# endif
101
102 #else /* !SFX || SFX_EXDIR */             /* check for -x or -d */
103
104+# if 0
105+
106     G.filespecs = argc;
107     G.xfilespecs = 0;
108@@ -1118,9 +1171,9 @@
109         while (*++pp) {
110             Trace((stderr, "pp - argv = %d\n", pp-argv));
111-#ifdef CMS_MVS
112+# ifdef CMS_MVS
113             if (!uO.exdir && STRNICMP(*pp, "-d", 2) == 0) {
114-#else
115+# else
116             if (!uO.exdir && strncmp(*pp, "-d", 2) == 0) {
117-#endif
118+# endif
119                 int firstarg = (pp == argv);
120
121@@ -1177,4 +1230,5 @@
122     } else
123         G.process_all_files = TRUE;      /* for speed */
124+# endif
125
126     if (uO.exdir != (char *)NULL && !G.extract_flag)    /* -d ignored */
127@@ -1260,4 +1314,269 @@
128
129
130+/*
131+  -------------------------------------------------------
132+  Command Line Options
133+  -------------------------------------------------------
134+
135+  Valid command line options.
136+
137+  The function get_option() uses this table to check if an
138+  option is valid and if it takes a value (also called an
139+  option parameter).  To add an option to unzip just add it
140+  to this table and add a case in the main switch to handle
141+  it.  If either shortopt or longopt not used set to "".
142+
143+   The fields:
144+       option_group - UZO for UnZip option, ZIO for ZipInfo option
145+       shortopt     - short option name (1 or 2 chars)
146+       longopt      - long option name
147+       value_type   - see zip.h for constants
148+       negatable    - option is negatable with trailing -
149+       ID           - unsigned long int returned for option
150+       name         - short description of option which is
151+                        returned on some errors and when options
152+                        are listed with -so option, can be NULL
153+*/
154+
155+/* Most option IDs are set to the shortopt char.  For
156+   multichar short options set to arbitrary unused constant. */
157+#define o_so            0x101
158+
159+
160+/* The below is from the old main command line code with a few changes.
161+   Note that UnZip and ZipInfo filter out their own options based on the
162+   option_group value, so the same option letter can be used for both. */
163+
164+static struct option_struct far options[] = {
165+
166+  /* UnZip options */
167+
168+  /* short longopt                      value_type        negatable
169+       ID    name */
170+#ifdef RISCOS
171+    {UZO, "/",  "",                     o_REQUIRED_VALUE, o_NEGATABLE,
172+       '/',  "override Unzip$Exts"},
173+#endif
174+    {UZO, "a",  "",                     o_NO_VALUE,       o_NEGATABLE,
175+       'a',  "text conv (EOL char, ASCII->EBCDIC"},
176+#if (defined(DLL) && defined(API_DOC))
177+    {UZO, "A",  "",                     o_NO_VALUE,       o_NEGATABLE,
178+       'A',  "extended help for API"},
179+#endif
180+    {UZO, "b",  "",                     o_NO_VALUE,       o_NEGATABLE,
181+       'b',  "binary, no ASCII conversions"},
182+#ifdef UNIXBACKUP
183+    {UZO, "B",  "",                     o_NO_VALUE,       o_NEGATABLE,
184+       'B',  "back up existing files"},
185+#endif
186+#ifdef CMS_MVS
187+    {UZO, "B",  "",                     o_NO_VALUE,       o_NEGATABLE,
188+       'b',  "CMS/MVS binary"},
189+#endif
190+    {UZO, "c",  "",                     o_NO_VALUE,       o_NEGATABLE,
191+       'c',  "output to stdout"},
192+#ifdef CMS_MVS
193+    /* for CMS_MVS map to lower case */
194+    {UZO, "C",  "",                     o_NO_VALUE,       o_NEGATABLE,
195+       'C',  "CMS/MVS lower case"},
196+#endif
197+#if (!defined(SFX) || defined(SFX_EXDIR))
198+    {UZO, "d",  "",                     o_REQUIRED_VALUE, o_NEGATABLE,
199+       'd',  "extraction root directory"},
200+#endif
201+#if (!defined(NO_TIMESTAMPS))
202+    {UZO, "D",  "",                     o_NO_VALUE,       o_NEGATABLE,
203+       'D',  "don't restore dir (-DD: any) timestamps"},
204+#endif
205+    {UZO, "e",  "",                     o_NO_VALUE,       o_NEGATABLE,
206+       'e',  "extract (not used?)"},
207+#ifdef MACOS
208+    {UZO, "E",  "",                     o_NO_VALUE,       o_NEGATABLE,
209+       'E',  "display Mac e.f. when restoring"},
210+#endif
211+    {UZO, "f",  "",                     o_NO_VALUE,       o_NEGATABLE,
212+       'f',  "freshen (extract only newer files)"},
213+#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
214+    {UZO, "F",  "",                     o_NO_VALUE,       o_NEGATABLE,
215+       'F',  "Acorn filetype & NFS extension handling"},
216+#endif
217+    {UZO, "h",  "",                     o_NO_VALUE,       o_NOT_NEGATABLE,
218+       'h',  "help"},
219+#ifdef MACOS
220+    {UZO, "i",  "",                     o_NO_VALUE,       o_NEGATABLE,
221+       'i',  "ignore filenames stored in Mac ef"},
222+#endif
223+    {UZO, "j",  "",                     o_NO_VALUE,       o_NEGATABLE,
224+       'j',  "junk directories, extract names only"},
225+#if (defined(ATH_BEO) || defined(MACOS))
226+    {UZO, "J",  "",                     o_NO_VALUE,       o_NEGATABLE,
227+       'J',  "Junk AtheOS, BeOS or MacOS file attrs"},
228+#endif
229+#ifdef ATH_BEO_UNX
230+    {UZO, "K",  "",                     o_NO_VALUE,       o_NEGATABLE,
231+       'K',  "retain SUID/SGID/Tacky attrs"},
232+#endif
233+#ifndef SFX
234+    {UZO, "l",  "",                     o_NO_VALUE,       o_NEGATABLE,
235+        'l',  "listing verbosity"},
236+#endif
237+#ifndef CMS_MVS
238+    {UZO, "L",  "",                     o_NO_VALUE,       o_NEGATABLE,
239+       'L',  "convert (some) names to lower"},
240+#endif
241+#ifdef MORE
242+# ifdef CMS_MVS
243+    {UZO, "m",  "",                     o_NO_VALUE,       o_NEGATABLE,
244+       'm',  "pipe output through more"},
245+# endif
246+    {UZO, "M",  "",                     o_NO_VALUE,       o_NEGATABLE,
247+       'M',  "pipe output through more"},
248+#endif /* MORE */
249+    {UZO, "n",  "",                     o_NO_VALUE,       o_NEGATABLE,
250+       'n',  "never overwrite files (no prompting)"},
251+#ifdef AMIGA
252+    {UZO, "N",  "",                     o_NO_VALUE,       o_NEGATABLE,
253+       'N',  "restore comments as filenotes"},
254+#endif
255+    {UZO, "o",  "",                     o_NO_VALUE,       o_NEGATABLE,
256+       'o',  "overwrite files without prompting"},
257+    {UZO, "p",  "",                     o_NO_VALUE,       o_NEGATABLE,
258+       'p',  "pipe extraction to stdout, no messages"},
259+#if CRYPT
260+    {UZO, "P",  "",                     o_REQUIRED_VALUE, o_NEGATABLE,
261+       'P',  "password"},
262+#endif
263+    {UZO, "q",  "",                     o_NO_VALUE,       o_NEGATABLE,
264+       'q',  "quiet"},
265+#ifdef QDOS
266+    {UZO, "Q",  "",                     o_NO_VALUE,       o_NEGATABLE,
267+       'Q',  "QDOS flags"},
268+#endif
269+#ifdef TANDEM
270+    {UZO, "r",  "",                     o_NO_VALUE,       o_NEGATABLE,
271+       'r',  "remove file extensions"},
272+#endif
273+#ifdef DOS_FLX_NLM_OS2_W32
274+    {UZO, "s",  "",                     o_NO_VALUE,       o_NEGATABLE,
275+       's',  "spaces to underscores"},
276+#endif
277+#ifdef VMS
278+    {UZO, "S",  "",                     o_NO_VALUE,       o_NEGATABLE,
279+       'S',  "VMS extract text as Stream LF"},
280+#endif
281+    {UZO, "t",  "",                     o_NO_VALUE,       o_NEGATABLE,
282+       't',  "test"},
283+#ifdef TIMESTAMP
284+    {UZO, "T",  "",                     o_NO_VALUE,       o_NEGATABLE,
285+       'T',  "timestamps"},
286+#endif
287+    {UZO, "u",  "",                     o_NO_VALUE,       o_NEGATABLE,
288+       'u',  "update (extract only new/newer files)"},
289+#ifdef UNICODE_SUPPORT
290+    {UZO, "U",  "",                     o_NO_VALUE,       o_NEGATABLE,
291+       'U',  "escape non-ASCII Unicode, disable Unicode"},
292+#else /* !UNICODE_SUPPORT */
293+# ifndef CMS_MVS
294+    {UZO, "U",  "",                     o_NO_VALUE,       o_NEGATABLE,
295+       'U',  "names to lower case"},
296+# endif /* !CMS_MVS */
297+#endif /* ?UNICODE_SUPPORT */
298+#ifndef SFX
299+    {UZO, "v",  "",                     o_NO_VALUE,       o_NEGATABLE,
300+       'v',  "verbose"},
301+#endif
302+#ifndef CMS_MVS
303+    {UZO, "V",  "",                     o_NO_VALUE,       o_NEGATABLE,
304+       'V',  "don't strip VMS version numbers"},
305+#endif
306+#ifdef WILD_STOP_AT_DIR
307+    {UZO, "W",  "",                     o_NO_VALUE,       o_NEGATABLE,
308+       'W',  "wildcard * doesn't span /"},
309+#endif
310+    {UZO, "x",  "",                     o_VALUE_LIST,     o_NOT_NEGATABLE,
311+       'x',  "exclude this list of files"},
312+#if (defined(RESTORE_UIDGID) || defined(RESTORE_ACL))
313+    {UZO, "X",  "",                     o_NO_VALUE,       o_NEGATABLE,
314+       'X',  "restore owner/prot or UID/GID or ACLs"},
315+#endif
316+#ifdef VMS
317+    {UZO, "Y",  "",                     o_NO_VALUE,       o_NEGATABLE,
318+       'Y',  "VMS treat .nnn as ;nnn version"},
319+#endif
320+    {UZO, "z",  "",                     o_NO_VALUE,       o_NEGATABLE,
321+       'z',  "display zipfile comment"},
322+#ifndef SFX
323+    {UZO, "Z",  "",                     o_NO_VALUE,       o_NOT_NEGATABLE,
324+       'Z',  "ZipInfo mode"},
325+#endif
326+#ifdef VMS
327+    {UZO, "2",  "",                     o_NO_VALUE,       o_NEGATABLE,
328+       '2',  "Force ODS2-compliant names."},
329+#endif
330+#ifdef DOS_H68_OS2_W32
331+    {UZO, "$",  "",                     o_NO_VALUE,       o_NEGATABLE,
332+       '$',  "extract volume labels"},
333+#endif
334+#if (!defined(RISCOS) && !defined(CMS_MVS) && !defined(TANDEM))
335+    {UZO, ":",  "",                     o_NO_VALUE,       o_NEGATABLE,
336+       ':',  "don't skip ../ path elements"},
337+#endif
338+#ifdef UNIX
339+    {UZO, "^",  "",                     o_NO_VALUE,       o_NEGATABLE,
340+       '^',  "allow control chars in filenames"},
341+#endif
342+
343+#ifndef NO_ZIPINFO
344+  /* ZipInfo options */
345+
346+  /* short longopt                      value_type        negatable
347+       ID    name (help text) */
348+    {ZIO, "1",  "",                     o_NO_VALUE,       o_NEGATABLE,
349+       '1',  "shortest list"},
350+    {ZIO, "2",  "",                     o_NO_VALUE,       o_NEGATABLE,
351+       '2',  "names and headers"},
352+#ifndef CMS_MVS
353+    {ZIO, "C",  "",                     o_NO_VALUE,       o_NEGATABLE,
354+       'C',  "ignore case"},
355+#endif
356+    {ZIO, "h",  "",                     o_NO_VALUE,       o_NEGATABLE,
357+       'h',  "header line"},
358+    {ZIO, "l",  "",                     o_NO_VALUE,       o_NEGATABLE,
359+       'l',  "longer listing"},
360+    {ZIO, "m",  "",                     o_NO_VALUE,       o_NEGATABLE,
361+       'm',  "medium listing"},
362+#ifdef MORE
363+    {ZIO, "M",  "",                     o_NO_VALUE,       o_NEGATABLE,
364+       'M',  "output like more"},
365+#endif
366+    {ZIO, "s",  "",                     o_NO_VALUE,       o_NEGATABLE,
367+       's',  "shorter list"},
368+    {ZIO, "t",  "",                     o_NO_VALUE,       o_NEGATABLE,
369+       't',  "totals line"},
370+    {ZIO, "T",  "",                     o_NO_VALUE,       o_NEGATABLE,
371+       'T',  "decimal time format"},
372+#ifdef UNICODE_SUPPORT
373+    {ZIO, "U",  "",                     o_NO_VALUE,       o_NEGATABLE,
374+       'U',  "escape non-ASCII Unicode, disable Unicode"},
375+#endif
376+    {ZIO, "v",  "",                     o_NO_VALUE,       o_NEGATABLE,
377+       'v',  "turbo-verbose listing"},
378+#ifdef WILD_STOP_AT_DIR
379+    {ZIO, "W",  "",                     o_NO_VALUE,       o_NEGATABLE,
380+       'W',  "wild stop at /"},
381+#endif
382+    {ZIO, "x",  "",                     o_VALUE_LIST,     o_NOT_NEGATABLE,
383+       'x',  "exclude this list of files"},
384+    {ZIO, "z",  "",                     o_NO_VALUE,       o_NEGATABLE,
385+       'z',  "print zipfile comment"},
386+    {ZIO, "Z",  "",                     o_NO_VALUE,       o_NEGATABLE,
387+       'Z',  "ZipInfo mode"},
388+#endif /* !NO_ZIPINFO */
389+
390+    /* the end of the list */
391+    {0,   NULL, NULL,                   o_NO_VALUE,       o_NOT_NEGATABLE,
392+       0,    NULL} /* end has option_ID = 0 */
393+  };
394+
395
396
397@@ -1271,502 +1590,649 @@
398     char ***pargv;
399 {
400-    char **argv, *s;
401-    int argc, c, error=FALSE, negative=0;
402+    char **args;
403+    int argc, error=FALSE;
404
405+    /* used by get_option */
406+    unsigned long option; /* option ID returned by get_option */
407+    int argcnt = 0;       /* current argcnt in args */
408+    int argnum = 0;       /* arg number */
409+    int optchar = 0;      /* option state */
410+    char *value = NULL;   /* non-option arg, option value or NULL */
411+    int negative = 0;     /* 1 = option negated */
412+    int fna = 0;          /* current first non-opt arg */
413+    int optnum = 0;       /* index in table */
414
415-    argc = *pargc;
416-    argv = *pargv;
417
418-    while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) {
419-        s = *argv + 1;
420-        while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
421-#ifdef CMS_MVS
422-            switch (tolower(c))
423-#else
424-            switch (c)
425-#endif
426-            {
427-                case ('-'):
428-                    ++negative;
429-                    break;
430+    /* since get_option() returns xfiles and files one at a time, store them
431+       in linked lists until have them all */
432+
433+    int file_count = 0;
434+    struct file_list *next_file;
435+
436+    /* files to extract */
437+    int in_files_count = 0;
438+    struct file_list *in_files = NULL;
439+    struct file_list *next_in_files = NULL;
440+
441+    /* files to exclude in -x list */
442+    int in_xfiles_count = 0;
443+    struct file_list *in_xfiles = NULL;
444+    struct file_list *next_in_xfiles = NULL;
445+
446+    G.wildzipfn = NULL;
447+
448+    /* make copy of args that can use with insert_arg() used by get_option() */
449+    args = copy_args(*pargv, 0);
450+
451+
452+    /* Initialize lists */
453+    G.filespecs = 0;
454+    G.xfilespecs = 0;
455+
456+
457+    /*
458+    -------------------------------------------
459+    Process command line using get_option
460+    -------------------------------------------
461+
462+    Each call to get_option() returns either a command
463+    line option and possible value or a non-option argument.
464+    Arguments are permuted so that all options (-r, -b temp)
465+    are returned before non-option arguments (zipfile).
466+    Returns 0 when nothing left to read.
467+    */
468+
469+    /* set argnum = 0 on first call to init get_option */
470+    argnum = 0;
471+
472+    /* get_option returns the option ID and updates parameters:
473+           args    - usually same as argv if no argument file support
474+           argcnt  - current argc for args
475+           value   - char* to value (free() when done with it) or NULL if none
476+           negated - option was negated with trailing -
477+    */
478+
479+    while ((option = get_option(UZO, &args, &argcnt, &argnum,
480+                                &optchar, &value, &negative,
481+                                &fna, &optnum, 0)))
482+    {
483+        if(option == o_BAD_ERR) {
484+          return(PK_PARAM);
485+        }
486+
487+        switch (option)
488+        {
489 #ifdef RISCOS
490-                case ('/'):
491-                    if (negative) {   /* negative not allowed with -/ swap */
492-                        Info(slide, 0x401, ((char *)slide,
493-                          "error:  must give extensions list"));
494-                        return(PK_PARAM);  /* don't extract here by accident */
495-                    }
496-                    exts2swap = s; /* override Unzip$Exts */
497-                    s += strlen(s);
498-                    break;
499-#endif
500-                case ('a'):
501-                    if (negative) {
502-                        uO.aflag = MAX(uO.aflag-negative,0);
503-                        negative = 0;
504-                    } else
505-                        ++uO.aflag;
506-                    break;
507+            case ('/'):
508+                if (negative) {   /* negative not allowed with -/ swap */
509+                    Info(slide, 0x401, ((char *)slide,
510+                      "error:  must give extensions list"));
511+                    return(PK_PARAM);  /* don't extract here by accident */
512+                }
513+                exts2swap = value; /* override Unzip$Exts */
514+                break;
515+#endif
516+            case ('a'):
517+                if (negative) {
518+                    uO.aflag = MAX(uO.aflag-negative,0);
519+                    negative = 0;
520+                } else
521+                    ++uO.aflag;
522+                break;
523 #if (defined(DLL) && defined(API_DOC))
524-                case ('A'):    /* extended help for API */
525-                    APIhelp(__G__ argc, argv);
526-                    *pargc = -1;  /* signal to exit successfully */
527-                    return 0;
528+            case ('A'):    /* extended help for API */
529+                APIhelp(__G__ argc, args);
530+                *pargc = -1;  /* signal to exit successfully */
531+                return 0;
532 #endif
533-                case ('b'):
534-                    if (negative) {
535+            case ('b'):
536+                if (negative) {
537 #if (defined(TANDEM) || defined(VMS))
538-                        uO.bflag = MAX(uO.bflag-negative,0);
539+                    uO.bflag = MAX(uO.bflag-negative,0);
540 #endif
541-                        negative = 0;   /* do nothing:  "-b" is default */
542-                    } else {
543+                    negative = 0;   /* do nothing:  "-b" is default */
544+                } else {
545 #ifdef VMS
546-                        if (uO.aflag == 0)
547-                           ++uO.bflag;
548+                    if (uO.aflag == 0)
549+                       ++uO.bflag;
550 #endif
551 #ifdef TANDEM
552-                        ++uO.bflag;
553+                    ++uO.bflag;
554 #endif
555-                        uO.aflag = 0;
556-                    }
557-                    break;
558+                    uO.aflag = 0;
559+                }
560+                break;
561 #ifdef UNIXBACKUP
562-                case ('B'): /* -B: back up existing files */
563-                    if (negative)
564-                        uO.B_flag = FALSE, negative = 0;
565-                    else
566-                        uO.B_flag = TRUE;
567-                    break;
568-#endif
569-                case ('c'):
570-                    if (negative) {
571-                        uO.cflag = FALSE, negative = 0;
572+            case ('B'): /* -B: back up existing files */
573+                if (negative)
574+                    uO.B_flag = FALSE, negative = 0;
575+                else
576+                    uO.B_flag = TRUE;
577+                break;
578+#endif
579+            case ('c'):
580+                if (negative) {
581+                    uO.cflag = FALSE, negative = 0;
582 #ifdef NATIVE
583-                        uO.aflag = 0;
584+                    uO.aflag = 0;
585 #endif
586-                    } else {
587-                        uO.cflag = TRUE;
588+                } else {
589+                    uO.cflag = TRUE;
590 #ifdef NATIVE
591-                        uO.aflag = 2;   /* so you can read it on the screen */
592+                    uO.aflag = 2;   /* so you can read it on the screen */
593 #endif
594 #ifdef DLL
595-                        if (G.redirect_text)
596-                            G.redirect_data = 2;
597+                    if (G.redirect_text)
598+                        G.redirect_data = 2;
599 #endif
600-                    }
601-                    break;
602+                }
603+                break;
604 #ifndef CMS_MVS
605-                case ('C'):    /* -C:  match filenames case-insensitively */
606-                    if (negative)
607-                        uO.C_flag = FALSE, negative = 0;
608-                    else
609-                        uO.C_flag = TRUE;
610-                    break;
611+            case ('C'):    /* -C:  match filenames case-insensitively */
612+                if (negative)
613+                    uO.C_flag = FALSE, negative = 0;
614+                else
615+                    uO.C_flag = TRUE;
616+                break;
617 #endif /* !CMS_MVS */
618 #if (!defined(SFX) || defined(SFX_EXDIR))
619-                case ('d'):
620-                    if (negative) {   /* negative not allowed with -d exdir */
621+            case ('d'):
622+                if (negative) {   /* negative not allowed with -d exdir */
623+                    Info(slide, 0x401, ((char *)slide,
624+                      LoadFarString(MustGiveExdir)));
625+                    return(PK_PARAM);  /* don't extract here by accident */
626+                }
627+                if (uO.exdir != (char *)NULL) {
628+                    Info(slide, 0x401, ((char *)slide,
629+                      LoadFarString(OnlyOneExdir)));
630+                    return(PK_PARAM);    /* GRR:  stupid restriction? */
631+                } else {
632+                    /* first check for "-dexdir", then for "-d exdir" */
633+                    uO.exdir = value;
634+                    if (uO.exdir == NULL || *uO.exdir == '\0') {
635                         Info(slide, 0x401, ((char *)slide,
636                           LoadFarString(MustGiveExdir)));
637-                        return(PK_PARAM);  /* don't extract here by accident */
638-                    }
639-                    if (uO.exdir != (char *)NULL) {
640-                        Info(slide, 0x401, ((char *)slide,
641-                          LoadFarString(OnlyOneExdir)));
642-                        return(PK_PARAM);    /* GRR:  stupid restriction? */
643-                    } else {
644-                        /* first check for "-dexdir", then for "-d exdir" */
645-                        uO.exdir = s;
646-                        if (*uO.exdir == '\0') {
647-                            if (argc > 1) {
648-                                --argc;
649-                                uO.exdir = *++argv;
650-                                if (*uO.exdir == '-') {
651-                                    Info(slide, 0x401, ((char *)slide,
652-                                      LoadFarString(MustGiveExdir)));
653-                                    return(PK_PARAM);
654-                                }
655-                                /* else uO.exdir points at extraction dir */
656-                            } else {
657-                                Info(slide, 0x401, ((char *)slide,
658-                                  LoadFarString(MustGiveExdir)));
659-                                return(PK_PARAM);
660-                            }
661-                        }
662-                        /* uO.exdir now points at extraction dir (-dexdir or
663-                         *  -d exdir); point s at end of exdir to avoid mis-
664-                         *  interpretation of exdir characters as more options
665-                         */
666-                        if (*s != 0)
667-                            while (*++s != 0)
668-                                ;
669+                        return(PK_PARAM);
670                     }
671-                    break;
672+                    /* else uO.exdir points at extraction dir */
673+                }
674+                break;
675 #endif /* !SFX || SFX_EXDIR */
676 #if (!defined(NO_TIMESTAMPS))
677-                case ('D'):    /* -D: Skip restoring dir (or any) timestamp. */
678-                    if (negative) {
679-                        uO.D_flag = MAX(uO.D_flag-negative,0);
680-                        negative = 0;
681-                    } else
682-                        uO.D_flag++;
683-                    break;
684+            case ('D'):    /* -D: Skip restoring dir (or any) timestamp. */
685+                if (negative) {
686+                    uO.D_flag = MAX(uO.D_flag-negative,0);
687+                    negative = 0;
688+                } else
689+                    uO.D_flag++;
690+                break;
691 #endif /* (!NO_TIMESTAMPS) */
692-                case ('e'):    /* just ignore -e, -x options (extract) */
693-                    break;
694+            case ('e'):    /* just ignore -e, -x options (extract) */
695+                break;
696 #ifdef MACOS
697-                case ('E'): /* -E [MacOS] display Mac e.f. when restoring */
698-                    if( negative ) {
699-                        uO.E_flag = FALSE, negative = 0;
700-                    } else {
701-                        uO.E_flag = TRUE;
702-                    }
703-                    break;
704+            case ('E'): /* -E [MacOS] display Mac e.f. when restoring */
705+                if( negative ) {
706+                    uO.E_flag = FALSE, negative = 0;
707+                } else {
708+                    uO.E_flag = TRUE;
709+                }
710+                break;
711 #endif /* MACOS */
712-                case ('f'):    /* "freshen" (extract only newer files) */
713-                    if (negative)
714-                        uO.fflag = uO.uflag = FALSE, negative = 0;
715-                    else
716-                        uO.fflag = uO.uflag = TRUE;
717-                    break;
718+            case ('f'):    /* "freshen" (extract only newer files) */
719+                if (negative)
720+                    uO.fflag = uO.uflag = FALSE, negative = 0;
721+                else
722+                    uO.fflag = uO.uflag = TRUE;
723+                break;
724 #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
725-                case ('F'):    /* Acorn filetype & NFS extension handling */
726-                    if (negative)
727-                        uO.acorn_nfs_ext = FALSE, negative = 0;
728-                    else
729-                        uO.acorn_nfs_ext = TRUE;
730-                    break;
731+            case ('F'):    /* Acorn filetype & NFS extension handling */
732+                if (negative)
733+                    uO.acorn_nfs_ext = FALSE, negative = 0;
734+                else
735+                    uO.acorn_nfs_ext = TRUE;
736+                break;
737 #endif /* RISCOS || ACORN_FTYPE_NFS */
738-                case ('h'):    /* just print help message and quit */
739-                    *pargc = -1;
740-                    return USAGE(PK_OK);
741+            case ('h'):    /* just print help message and quit */
742+                *pargc = -1;
743+                return USAGE(PK_OK);
744 #ifdef MACOS
745-                case ('i'): /* -i [MacOS] ignore filenames stored in Mac ef */
746-                    if( negative ) {
747-                        uO.i_flag = FALSE, negative = 0;
748-                    } else {
749-                        uO.i_flag = TRUE;
750-                    }
751-                    break;
752+            case ('i'): /* -i [MacOS] ignore filenames stored in Mac ef */
753+                if( negative ) {
754+                    uO.i_flag = FALSE, negative = 0;
755+                } else {
756+                    uO.i_flag = TRUE;
757+                }
758+                break;
759 #endif  /* MACOS */
760-                case ('j'):    /* junk pathnames/directory structure */
761-                    if (negative)
762-                        uO.jflag = FALSE, negative = 0;
763-                    else
764-                        uO.jflag = TRUE;
765-                    break;
766+            case ('j'):    /* junk pathnames/directory structure */
767+                if (negative)
768+                    uO.jflag = FALSE, negative = 0;
769+                else
770+                    uO.jflag = TRUE;
771+                break;
772 #if (defined(ATH_BEO) || defined(MACOS))
773-                case ('J'):    /* Junk AtheOS, BeOS or MacOS file attributes */
774-                    if( negative ) {
775-                        uO.J_flag = FALSE, negative = 0;
776-                    } else {
777-                        uO.J_flag = TRUE;
778-                    }
779-                    break;
780+            case ('J'):    /* Junk AtheOS, BeOS or MacOS file attributes */
781+                if( negative ) {
782+                    uO.J_flag = FALSE, negative = 0;
783+                } else {
784+                    uO.J_flag = TRUE;
785+                }
786+                break;
787 #endif /* ATH_BEO || MACOS */
788 #ifdef ATH_BEO_UNX
789-                case ('K'):
790-                    if (negative) {
791-                        uO.K_flag = FALSE, negative = 0;
792-                    } else {
793-                        uO.K_flag = TRUE;
794-                    }
795-                    break;
796+            case ('K'):
797+                if (negative) {
798+                    uO.K_flag = FALSE, negative = 0;
799+                } else {
800+                    uO.K_flag = TRUE;
801+                }
802+                break;
803 #endif /* ATH_BEO_UNX */
804 #ifndef SFX
805-                case ('l'):
806-                    if (negative) {
807-                        uO.vflag = MAX(uO.vflag-negative,0);
808-                        negative = 0;
809-                    } else
810-                        ++uO.vflag;
811-                    break;
812+            case ('l'):
813+                if (negative) {
814+                    uO.vflag = MAX(uO.vflag-negative,0);
815+                    negative = 0;
816+                } else
817+                    ++uO.vflag;
818+                break;
819 #endif /* !SFX */
820 #ifndef CMS_MVS
821-                case ('L'):    /* convert (some) filenames to lowercase */
822-                    if (negative) {
823-                        uO.L_flag = MAX(uO.L_flag-negative,0);
824-                        negative = 0;
825-                    } else
826-                        ++uO.L_flag;
827-                    break;
828+            case ('L'):    /* convert (some) filenames to lowercase */
829+                if (negative) {
830+                    uO.L_flag = MAX(uO.L_flag-negative,0);
831+                    negative = 0;
832+                } else
833+                    ++uO.L_flag;
834+                break;
835 #endif /* !CMS_MVS */
836 #ifdef MORE
837 #ifdef CMS_MVS
838-                case ('m'):
839+            case ('m'):
840 #endif
841-                case ('M'):    /* send all screen output through "more" fn. */
842+            case ('M'):    /* send all screen output through "more" fn. */
843 /* GRR:  eventually check for numerical argument => height */
844-                    if (negative)
845-                        G.M_flag = FALSE, negative = 0;
846-                    else
847-                        G.M_flag = TRUE;
848-                    break;
849+                if (negative)
850+                    G.M_flag = FALSE, negative = 0;
851+                else
852+                    G.M_flag = TRUE;
853+                break;
854 #endif /* MORE */
855-                case ('n'):    /* don't overwrite any files */
856-                    if (negative)
857-                        uO.overwrite_none = FALSE, negative = 0;
858-                    else
859-                        uO.overwrite_none = TRUE;
860-                    break;
861+            case ('n'):    /* don't overwrite any files */
862+                if (negative)
863+                    uO.overwrite_none = FALSE, negative = 0;
864+                else
865+                    uO.overwrite_none = TRUE;
866+                break;
867 #ifdef AMIGA
868-                case ('N'):    /* restore comments as filenotes */
869-                    if (negative)
870-                        uO.N_flag = FALSE, negative = 0;
871-                    else
872-                        uO.N_flag = TRUE;
873-                    break;
874+            case ('N'):    /* restore comments as filenotes */
875+                if (negative)
876+                    uO.N_flag = FALSE, negative = 0;
877+                else
878+                    uO.N_flag = TRUE;
879+                break;
880 #endif /* AMIGA */
881-                case ('o'):    /* OK to overwrite files without prompting */
882-                    if (negative) {
883-                        uO.overwrite_all = MAX(uO.overwrite_all-negative,0);
884-                        negative = 0;
885-                    } else
886-                        ++uO.overwrite_all;
887-                    break;
888-                case ('p'):    /* pipes:  extract to stdout, no messages */
889-                    if (negative) {
890-                        uO.cflag = FALSE;
891-                        uO.qflag = MAX(uO.qflag-999,0);
892-                        negative = 0;
893-                    } else {
894-                        uO.cflag = TRUE;
895-                        uO.qflag += 999;
896-                    }
897-                    break;
898+            case ('o'):    /* OK to overwrite files without prompting */
899+                if (negative) {
900+                    uO.overwrite_all = MAX(uO.overwrite_all-negative,0);
901+                    negative = 0;
902+                } else
903+                    ++uO.overwrite_all;
904+                break;
905+            case ('p'):    /* pipes:  extract to stdout, no messages */
906+                if (negative) {
907+                    uO.cflag = FALSE;
908+                    uO.qflag = MAX(uO.qflag-999,0);
909+                    negative = 0;
910+                } else {
911+                    uO.cflag = TRUE;
912+                    uO.qflag += 999;
913+                }
914+                break;
915 #if CRYPT
916-                /* GRR:  yes, this is highly insecure, but dozens of people
917-                 * have pestered us for this, so here we go... */
918-                case ('P'):
919-                    if (negative) {   /* negative not allowed with -P passwd */
920-                        Info(slide, 0x401, ((char *)slide,
921-                          LoadFarString(MustGivePasswd)));
922-                        return(PK_PARAM);  /* don't extract here by accident */
923-                    }
924-                    if (uO.pwdarg != (char *)NULL) {
925+            /* GRR:  yes, this is highly insecure, but dozens of people
926+             * have pestered us for this, so here we go... */
927+            case ('P'):
928+                if (negative) {   /* negative not allowed with -P passwd */
929+                    Info(slide, 0x401, ((char *)slide,
930+                      LoadFarString(MustGivePasswd)));
931+                    return(PK_PARAM);  /* don't extract here by accident */
932+                }
933+                if (uO.pwdarg != (char *)NULL) {
934 /*
935-                        GRR:  eventually support multiple passwords?
936+                    GRR:  eventually support multiple passwords?
937+                    Info(slide, 0x401, ((char *)slide,
938+                      LoadFarString(OnlyOnePasswd)));
939+                    return(PK_PARAM);
940+*/
941+                } else {
942+                    /* first check for "-Ppasswd", then for "-P passwd" */
943+                    uO.pwdarg = value;
944+                    if (uO.pwdarg == NULL || *uO.pwdarg == '\0') {
945                         Info(slide, 0x401, ((char *)slide,
946-                          LoadFarString(OnlyOnePasswd)));
947+                          LoadFarString(MustGivePasswd)));
948                         return(PK_PARAM);
949- */
950-                    } else {
951-                        /* first check for "-Ppasswd", then for "-P passwd" */
952-                        uO.pwdarg = s;
953-                        if (*uO.pwdarg == '\0') {
954-                            if (argc > 1) {
955-                                --argc;
956-                                uO.pwdarg = *++argv;
957-                                if (*uO.pwdarg == '-') {
958-                                    Info(slide, 0x401, ((char *)slide,
959-                                      LoadFarString(MustGivePasswd)));
960-                                    return(PK_PARAM);
961-                                }
962-                                /* else pwdarg points at decryption password */
963-                            } else {
964-                                Info(slide, 0x401, ((char *)slide,
965-                                  LoadFarString(MustGivePasswd)));
966-                                return(PK_PARAM);
967-                            }
968-                        }
969-                        /* pwdarg now points at decryption password (-Ppasswd or
970-                         *  -P passwd); point s at end of passwd to avoid mis-
971-                         *  interpretation of passwd characters as more options
972-                         */
973-                        if (*s != 0)
974-                            while (*++s != 0)
975-                                ;
976+                        /* else pwdarg points at decryption password */
977                     }
978-                    break;
979+                }
980+                break;
981 #endif /* CRYPT */
982-                case ('q'):    /* quiet:  fewer comments/messages */
983-                    if (negative) {
984-                        uO.qflag = MAX(uO.qflag-negative,0);
985-                        negative = 0;
986-                    } else
987-                        ++uO.qflag;
988-                    break;
989+            case ('q'):    /* quiet:  fewer comments/messages */
990+                if (negative) {
991+                    uO.qflag = MAX(uO.qflag-negative,0);
992+                    negative = 0;
993+                } else
994+                    ++uO.qflag;
995+                break;
996 #ifdef QDOS
997-                case ('Q'):   /* QDOS flags */
998-                    qlflag ^= strtol(s, &s, 10);
999-                    break;    /* we XOR this as we can config qlflags */
1000+            case ('Q'):   /* QDOS flags */
1001+                qlflag ^= strtol(value, &value, 10);
1002+                break;    /* we XOR this as we can config qlflags */
1003 #endif
1004 #ifdef TANDEM
1005-                case ('r'):    /* remove file extensions */
1006-                    if (negative)
1007-                        uO.rflag = FALSE, negative = 0;
1008-                    else
1009-                        uO.rflag = TRUE;
1010-                    break;
1011+            case ('r'):    /* remove file extensions */
1012+                if (negative)
1013+                    uO.rflag = FALSE, negative = 0;
1014+                else
1015+                    uO.rflag = TRUE;
1016+                break;
1017 #endif /* TANDEM */
1018 #ifdef DOS_FLX_NLM_OS2_W32
1019-                case ('s'):    /* spaces in filenames:  allow by default */
1020-                    if (negative)
1021-                        uO.sflag = FALSE, negative = 0;
1022-                    else
1023-                        uO.sflag = TRUE;
1024-                    break;
1025+            case ('s'):    /* spaces in filenames:  allow by default */
1026+                if (negative)
1027+                    uO.sflag = FALSE, negative = 0;
1028+                else
1029+                    uO.sflag = TRUE;
1030+                break;
1031 #endif /* DOS_FLX_NLM_OS2_W32 */
1032 #ifdef VMS
1033-                /* VMS:  extract "text" files in Stream_LF format (-a[a]) */
1034-                case ('S'):
1035-                    if (negative)
1036-                        uO.S_flag = FALSE, negative = 0;
1037-                    else
1038-                        uO.S_flag = TRUE;
1039-                    break;
1040+            /* VMS:  extract "text" files in Stream_LF format (-a[a]) */
1041+            case ('S'):
1042+                if (negative)
1043+                    uO.S_flag = FALSE, negative = 0;
1044+                else
1045+                    uO.S_flag = TRUE;
1046+                break;
1047 #endif /* VMS */
1048-                case ('t'):
1049-                    if (negative)
1050-                        uO.tflag = FALSE, negative = 0;
1051-                    else
1052-                        uO.tflag = TRUE;
1053-                    break;
1054+            case ('t'):
1055+                if (negative)
1056+                    uO.tflag = FALSE, negative = 0;
1057+                else
1058+                    uO.tflag = TRUE;
1059+                break;
1060 #ifdef TIMESTAMP
1061-                case ('T'):
1062-                    if (negative)
1063-                        uO.T_flag = FALSE, negative = 0;
1064-                    else
1065-                        uO.T_flag = TRUE;
1066-                    break;
1067-#endif
1068-                case ('u'):    /* update (extract only new and newer files) */
1069-                    if (negative)
1070-                        uO.uflag = FALSE, negative = 0;
1071-                    else
1072-                        uO.uflag = TRUE;
1073-                    break;
1074+            case ('T'):
1075+                if (negative)
1076+                    uO.T_flag = FALSE, negative = 0;
1077+                else
1078+                    uO.T_flag = TRUE;
1079+                break;
1080+#endif
1081+            case ('u'):    /* update (extract only new and newer files) */
1082+                if (negative)
1083+                    uO.uflag = FALSE, negative = 0;
1084+                else
1085+                    uO.uflag = TRUE;
1086+                break;
1087 #ifdef UNICODE_SUPPORT
1088-                case ('U'):    /* escape UTF-8, or disable UTF-8 support */
1089-                    if (negative) {
1090-                        uO.U_flag = MAX(uO.U_flag-negative,0);
1091-                        negative = 0;
1092-                    } else
1093-                        uO.U_flag++;
1094-                    break;
1095+            case ('U'):    /* escape UTF-8, or disable UTF-8 support */
1096+                if (negative)
1097+                    uO.U_flag = MAX(uO.U_flag - 1, 0);
1098+                else
1099+                    uO.U_flag++;
1100+                break;
1101 #else /* !UNICODE_SUPPORT */
1102 #ifndef CMS_MVS
1103-                case ('U'):    /* obsolete; to be removed in version 6.0 */
1104-                    if (negative)
1105-                        uO.L_flag = TRUE, negative = 0;
1106-                    else
1107-                        uO.L_flag = FALSE;
1108-                    break;
1109+            case ('U'):    /* obsolete; to be removed in version 6.0 */
1110+                if (negative)
1111+                    uO.L_flag = TRUE, negative = 0;
1112+                else
1113+                    uO.L_flag = FALSE;
1114+                break;
1115 #endif /* !CMS_MVS */
1116 #endif /* ?UNICODE_SUPPORT */
1117 #ifndef SFX
1118-                case ('v'):    /* verbose */
1119-                    if (negative) {
1120-                        uO.vflag = MAX(uO.vflag-negative,0);
1121-                        negative = 0;
1122-                    } else if (uO.vflag)
1123-                        ++uO.vflag;
1124-                    else
1125-                        uO.vflag = 2;
1126-                    break;
1127+            case ('v'):    /* verbose */
1128+                if (negative) {
1129+                    uO.vflag = MAX(uO.vflag-negative,0);
1130+                    negative = 0;
1131+                } else if (uO.vflag)
1132+                    ++uO.vflag;
1133+                else
1134+                    uO.vflag = 2;
1135+                break;
1136 #endif /* !SFX */
1137 #ifndef CMS_MVS
1138-                case ('V'):    /* Version (retain VMS/DEC-20 file versions) */
1139-                    if (negative)
1140-                        uO.V_flag = FALSE, negative = 0;
1141-                    else
1142-                        uO.V_flag = TRUE;
1143-                    break;
1144+            case ('V'):    /* Version (retain VMS/DEC-20 file versions) */
1145+                if (negative)
1146+                    uO.V_flag = FALSE, negative = 0;
1147+                else
1148+                    uO.V_flag = TRUE;
1149+                break;
1150 #endif /* !CMS_MVS */
1151 #ifdef WILD_STOP_AT_DIR
1152-                case ('W'):    /* Wildcard interpretation (stop at '/'?) */
1153-                    if (negative)
1154-                        uO.W_flag = FALSE, negative = 0;
1155-                    else
1156-                        uO.W_flag = TRUE;
1157-                    break;
1158+            case ('W'):    /* Wildcard interpretation (stop at '/'?) */
1159+                if (negative)
1160+                    uO.W_flag = FALSE, negative = 0;
1161+                else
1162+                    uO.W_flag = TRUE;
1163+                break;
1164 #endif /* WILD_STOP_AT_DIR */
1165-                case ('x'):    /* extract:  default */
1166-#ifdef SFX
1167-                    /* when 'x' is the only option in this argument, and the
1168-                     * next arg is not an option, assume this initiates an
1169-                     * exclusion list (-x xlist):  terminate option-scanning
1170-                     * and leave uz_opts with argv still pointing to "-x";
1171-                     * the xlist is processed later
1172-                     */
1173-                    if (s - argv[0] == 2 && *s == '\0' &&
1174-                        argc > 1 && argv[1][0] != '-') {
1175-                        /* break out of nested loops without "++argv;--argc" */
1176-                        goto opts_done;
1177+            case ('x'):    /* extract:  default */
1178+                /* add -x file to linked list */
1179+
1180+                if (in_xfiles_count == 0) {
1181+                    /* first entry */
1182+                    if ((in_xfiles = (struct file_list *)
1183+                                     malloc(sizeof(struct file_list))
1184+                        ) == NULL) {
1185+                        Info(slide, 0x401, ((char *)slide,
1186+                          LoadFarString(NoMemArgsList)));
1187+                        return PK_MEM;
1188+                    }
1189+                    in_xfiles->name = value;
1190+                    in_xfiles->next = NULL;
1191+                    next_in_xfiles = in_xfiles;
1192+                } else {
1193+                    /* add next entry */
1194+                    if ((next_file = (struct file_list *)
1195+                                     malloc(sizeof(struct file_list))
1196+                        ) == NULL) {
1197+                        Info(slide, 0x401, ((char *)slide,
1198+                          LoadFarString(NoMemArgsList)));
1199+                        return PK_MEM;
1200                     }
1201+                    next_in_xfiles->next = next_file;
1202+                    next_file->name = value;
1203+                    next_file->next = NULL;
1204+                    next_in_xfiles = next_file;
1205+                }
1206+                in_xfiles_count++;
1207+
1208+#if 0
1209+#ifdef SFX
1210+                /* now get -x list one entry at a time */
1211+
1212+
1213+
1214+                /* when 'x' is the only option in this argument, and the
1215+                 * next arg is not an option, assume this initiates an
1216+                 * exclusion list (-x xlist):  terminate option-scanning
1217+                 * and leave uz_opts with argv still pointing to "-x";
1218+                 * the xlist is processed later
1219+                 */
1220+                if (s - argv[0] == 2 && *s == '\0' &&
1221+                    argc > 1 && argv[1][0] != '-') {
1222+                    /* break out of nested loops without "++argv;--argc" */
1223+                    goto opts_done;
1224+                }
1225 #endif /* SFX */
1226-                    break;
1227+#endif
1228+                break;
1229 #if (defined(RESTORE_UIDGID) || defined(RESTORE_ACL))
1230-                case ('X'):   /* restore owner/protection info (need privs?) */
1231-                    if (negative) {
1232-                        uO.X_flag = MAX(uO.X_flag-negative,0);
1233-                        negative = 0;
1234-                    } else
1235-                        ++uO.X_flag;
1236-                    break;
1237+            case ('X'):   /* restore owner/protection info (need privs?) */
1238+                if (negative) {
1239+                    uO.X_flag = MAX(uO.X_flag-negative,0);
1240+                    negative = 0;
1241+                } else
1242+                    ++uO.X_flag;
1243+                break;
1244 #endif /* RESTORE_UIDGID || RESTORE_ACL */
1245 #ifdef VMS
1246-                case ('Y'):    /* Treat ".nnn" as ";nnn" version. */
1247-                    if (negative)
1248-                        uO.Y_flag = FALSE, negative = 0;
1249-                    else
1250-                        uO.Y_flag = TRUE;
1251-                    break;
1252+            case ('Y'):    /* Treat ".nnn" as ";nnn" version. */
1253+                if (negative)
1254+                    uO.Y_flag = FALSE, negative = 0;
1255+                else
1256+                    uO.Y_flag = TRUE;
1257+                break;
1258 #endif /* VMS */
1259-                case ('z'):    /* display only the archive comment */
1260-                    if (negative) {
1261-                        uO.zflag = MAX(uO.zflag-negative,0);
1262-                        negative = 0;
1263-                    } else
1264-                        ++uO.zflag;
1265-                    break;
1266+            case ('z'):    /* display only the archive comment */
1267+                if (negative) {
1268+                    uO.zflag = MAX(uO.zflag-negative,0);
1269+                    negative = 0;
1270+                } else
1271+                    ++uO.zflag;
1272+                break;
1273 #ifndef SFX
1274-                case ('Z'):    /* should have been first option (ZipInfo) */
1275-                    Info(slide, 0x401, ((char *)slide, LoadFarString(Zfirst)));
1276-                    error = TRUE;
1277-                    break;
1278+            case ('Z'):    /* should have been first option (ZipInfo) */
1279+                Info(slide, 0x401, ((char *)slide, LoadFarString(Zfirst)));
1280+                error = TRUE;
1281+                break;
1282 #endif /* !SFX */
1283 #ifdef VMS
1284-                case ('2'):    /* Force ODS2-compliant names. */
1285-                    if (negative)
1286-                        uO.ods2_flag = FALSE, negative = 0;
1287-                    else
1288-                        uO.ods2_flag = TRUE;
1289-                    break;
1290+            case ('2'):    /* Force ODS2-compliant names. */
1291+                if (negative)
1292+                    uO.ods2_flag = FALSE, negative = 0;
1293+                else
1294+                    uO.ods2_flag = TRUE;
1295+                break;
1296 #endif /* VMS */
1297 #ifdef DOS_H68_OS2_W32
1298-                case ('$'):
1299-                    if (negative) {
1300-                        uO.volflag = MAX(uO.volflag-negative,0);
1301-                        negative = 0;
1302-                    } else
1303-                        ++uO.volflag;
1304-                    break;
1305+            case ('$'):
1306+                if (negative) {
1307+                    uO.volflag = MAX(uO.volflag-negative,0);
1308+                    negative = 0;
1309+                } else
1310+                    ++uO.volflag;
1311+                break;
1312 #endif /* DOS_H68_OS2_W32 */
1313 #if (!defined(RISCOS) && !defined(CMS_MVS) && !defined(TANDEM))
1314-                case (':'):    /* allow "parent dir" path components */
1315-                    if (negative) {
1316-                        uO.ddotflag = MAX(uO.ddotflag-negative,0);
1317-                        negative = 0;
1318-                    } else
1319-                        ++uO.ddotflag;
1320-                    break;
1321+            case (':'):    /* allow "parent dir" path components */
1322+                if (negative) {
1323+                    uO.ddotflag = MAX(uO.ddotflag-negative,0);
1324+                    negative = 0;
1325+                } else
1326+                    ++uO.ddotflag;
1327+                break;
1328 #endif /* !RISCOS && !CMS_MVS && !TANDEM */
1329 #ifdef UNIX
1330-                case ('^'):    /* allow control chars in filenames */
1331-                    if (negative) {
1332-                        uO.cflxflag = MAX(uO.cflxflag-negative,0);
1333-                        negative = 0;
1334-                    } else
1335-                        ++uO.cflxflag;
1336-                    break;
1337+            case ('^'):    /* allow control chars in filenames */
1338+                if (negative) {
1339+                    uO.cflxflag = MAX(uO.cflxflag-negative,0);
1340+                    negative = 0;
1341+                } else
1342+                    ++uO.cflxflag;
1343+                break;
1344 #endif /* UNIX */
1345-                default:
1346-                    error = TRUE;
1347-                    break;
1348-
1349-            } /* end switch */
1350-        } /* end while (not end of argument string) */
1351-    } /* end while (not done with switches) */
1352+            case o_NON_OPTION_ARG:
1353+                /* not an option */
1354+                /* no more options as permuting */
1355+
1356+
1357+                if (G.wildzipfn == NULL) {
1358+                    /* first non-option argument is zip file */
1359+                    G.wildzipfn = value;
1360+
1361+                } else {
1362+                    /* add include file to list */
1363+                    if (in_files_count == 0) {
1364+                        /* first entry */
1365+                        if ((next_file = (struct file_list *)
1366+                                         malloc(sizeof(struct file_list))
1367+                            ) == NULL) {
1368+                            Info(slide, 0x401, ((char *)slide,
1369+                              LoadFarString(NoMemArgsList)));
1370+                            return PK_MEM;
1371+                        }
1372+                        next_file->name = value;
1373+                        next_file->next = NULL;
1374+                        in_files = next_file;
1375+                        next_in_files = next_file;
1376+                    } else {
1377+                        /* add next entry */
1378+                        if ((next_file = (struct file_list *)
1379+                                         malloc(sizeof(struct file_list))
1380+                            ) == NULL) {
1381+                            Info(slide, 0x401, ((char *)slide,
1382+                              LoadFarString(NoMemArgsList)));
1383+                            return PK_MEM;
1384+                        }
1385+                        next_in_files->next = next_file;
1386+                        next_file->name = value;
1387+                        next_file->next = NULL;
1388+                        next_in_files = next_file;
1389+                    }
1390+                    in_files_count++;
1391+                }
1392+                break;
1393+            default:
1394+                error = TRUE;
1395+                break;
1396+
1397+        } /* end switch */
1398+    } /* get_option() */
1399+
1400+
1401+    /* convert files and xfiles lists to arrays */
1402+
1403+    /* convert files list to array */
1404+    if (in_files_count) {
1405+      if ((G.pfnames = (char **) malloc((in_files_count + 1) * sizeof(char *))
1406+          ) == NULL) {
1407+          Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArgsList)));
1408+          return PK_MEM;
1409+      }
1410+      file_count = 0;
1411+      for (next_file = in_files; next_file;) {
1412+          G.pfnames[file_count] = next_file->name;
1413+          in_files = next_file;
1414+          next_file = next_file->next;
1415+          free(in_files);
1416+          file_count++;
1417+      }
1418+      G.pfnames[file_count] = NULL;
1419+      G.filespecs = in_files_count;
1420+    }
1421+
1422+    /* convert xfiles list to array */
1423+    if (in_xfiles_count) {
1424+      if ((G.pxnames = (char **) malloc((in_xfiles_count + 1) * sizeof(char *))
1425+          ) == NULL) {
1426+          Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArgsList)));
1427+          return PK_MEM;
1428+      }
1429+      file_count = 0;
1430+      for (next_file = in_xfiles; next_file;) {
1431+          G.pxnames[file_count] = next_file->name;
1432+          in_xfiles = next_file;
1433+          next_file = next_file->next;
1434+          free(in_xfiles);
1435+          file_count++;
1436+      }
1437+      G.pxnames[file_count] = NULL;
1438+      G.xfilespecs = in_xfiles_count;
1439+    }
1440+
1441+    if (in_files_count || in_xfiles_count) {
1442+        G.process_all_files = FALSE;
1443+    } else {
1444+        G.process_all_files = TRUE;      /* for speed */
1445+    }
1446+
1447+
1448+    /* it's possible the arg count could have been changed by get_option() */
1449+    argc = arg_count(args);
1450+
1451+
1452
1453 /*---------------------------------------------------------------------------
1454@@ -1774,7 +2240,77 @@
1455   ---------------------------------------------------------------------------*/
1456
1457+    if ((uO.cflag && (uO.tflag || uO.uflag)) ||
1458+        (uO.tflag && uO.uflag) || (uO.fflag && uO.overwrite_none))
1459+    {
1460+        Info(slide, 0x401, ((char *)slide, LoadFarString(InvalidOptionsMsg)));
1461+        error = TRUE;
1462+    }
1463+    if (uO.aflag > 2)
1464+        uO.aflag = 2;
1465+#ifdef VMS
1466+    if (uO.bflag > 2)
1467+        uO.bflag = 2;
1468+    /* Clear -s flag when converting text files. */
1469+    if (uO.aflag <= 0)
1470+        uO.S_flag = 0;
1471+#endif /* VMS */
1472+    if (uO.overwrite_all && uO.overwrite_none) {
1473+        Info(slide, 0x401, ((char *)slide, LoadFarString(IgnoreOOptionMsg)));
1474+        uO.overwrite_all = FALSE;
1475+    }
1476+#ifdef MORE
1477+    if (G.M_flag && !isatty(1))  /* stdout redirected: "more" func. useless */
1478+        G.M_flag = 0;
1479+#endif
1480+
1481+#ifdef SFX
1482+    if (error)
1483+#else
1484+    if ((G.wildzipfn == NULL) || error)
1485+#endif
1486+    {
1487+        /* tell caller to exit */
1488+        if (argc <= 2)
1489+            argc = -1;
1490+
1491+        *pargc = argc;
1492+        *pargv = args;
1493+#ifndef SFX
1494+        if (uO.vflag >= 2 && argc == -1) {              /* "unzip -v" */
1495+            show_version_info(__G);
1496+            return PK_OK;
1497+        }
1498+        if (!G.noargs && !error)
1499+            error = TRUE;       /* had options (not -h or -v) but no zipfile */
1500+#endif /* !SFX */
1501+        return USAGE(error);
1502+    }
1503+
1504 #ifdef SFX
1505-opts_done:  /* yes, very ugly...but only used by UnZipSFX with -x xlist */
1506+    /* print our banner unless we're being fairly quiet */
1507+    if (uO.qflag < 2)
1508+        Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner),
1509+          UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
1510+          LoadFarStringSmall(VersionDate)));
1511+#ifdef BETA
1512+    /* always print the beta warning:  no unauthorized distribution!! */
1513+    Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(BetaVersion), "\n",
1514+      "SFX"));
1515+#endif
1516+#endif /* SFX */
1517+
1518+    if (uO.cflag || uO.tflag || uO.vflag || uO.zflag
1519+#ifdef TIMESTAMP
1520+                                                     || uO.T_flag
1521 #endif
1522+                                                                 )
1523+        G.extract_flag = FALSE;
1524+    else
1525+        G.extract_flag = TRUE;
1526+
1527+#if 0
1528+# ifdef SFX
1529+opts_done:  /* yes, very ugly...but only used by UnZipSFX with -x xlist */
1530+# endif
1531
1532     if ((uO.cflag && (uO.tflag || uO.uflag)) ||
1533@@ -1786,5 +2322,5 @@
1534     if (uO.aflag > 2)
1535         uO.aflag = 2;
1536-#ifdef VMS
1537+# ifdef VMS
1538     if (uO.bflag > 2)
1539         uO.bflag = 2;
1540@@ -1792,23 +2328,23 @@
1541     if (uO.aflag <= 0)
1542         uO.S_flag = 0;
1543-#endif /* VMS */
1544+# endif /* VMS */
1545     if (uO.overwrite_all && uO.overwrite_none) {
1546         Info(slide, 0x401, ((char *)slide, LoadFarString(IgnoreOOptionMsg)));
1547         uO.overwrite_all = FALSE;
1548     }
1549-#ifdef MORE
1550+# ifdef MORE
1551     if (G.M_flag && !isatty(1))  /* stdout redirected: "more" func. useless */
1552         G.M_flag = 0;
1553-#endif
1554+# endif
1555
1556-#ifdef SFX
1557+# ifdef SFX
1558     if (error)
1559-#else
1560+# else
1561     if ((argc-- == 0) || error)
1562-#endif
1563+# endif
1564     {
1565         *pargc = argc;
1566-        *pargv = argv;
1567-#ifndef SFX
1568+        *pargv = args;
1569+# ifndef SFX
1570         if (uO.vflag >= 2 && argc == -1) {              /* "unzip -v" */
1571             show_version_info(__G);
1572@@ -1817,9 +2353,9 @@
1573         if (!G.noargs && !error)
1574             error = TRUE;       /* had options (not -h or -v) but no zipfile */
1575-#endif /* !SFX */
1576+# endif /* !SFX */
1577         return USAGE(error);
1578     }
1579
1580-#ifdef SFX
1581+# ifdef SFX
1582     /* print our banner unless we're being fairly quiet */
1583     if (uO.qflag < 2)
1584@@ -1827,22 +2363,23 @@
1585           UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
1586           LoadFarStringSmall(VersionDate)));
1587-#ifdef BETA
1588+# ifdef BETA
1589     /* always print the beta warning:  no unauthorized distribution!! */
1590     Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(BetaVersion), "\n",
1591       "SFX"));
1592-#endif
1593-#endif /* SFX */
1594+# endif
1595+# endif /* SFX */
1596
1597     if (uO.cflag || uO.tflag || uO.vflag || uO.zflag
1598-#ifdef TIMESTAMP
1599+# ifdef TIMESTAMP
1600                                                      || uO.T_flag
1601-#endif
1602+# endif
1603                                                                  )
1604         G.extract_flag = FALSE;
1605     else
1606         G.extract_flag = TRUE;
1607+#endif
1608
1609     *pargc = argc;
1610-    *pargv = argv;
1611+    *pargv = args;
1612     return PK_OK;
1613
1614@@ -2314,2 +2851,1366 @@
1615 #endif /* !SFX */
1616 #endif /* !WINDLL */
1617+
1618+
1619+
1620+
1621+
1622+
1623+/*---------------------------------------------------------------
1624+ *  Long option support
1625+ *  8/23/2003
1626+ *  Updated 3/1/2008 to support UnZip
1627+ *
1628+ *  Defines function get_option() to get and process the command
1629+ *  line options and arguments from argv[].  The caller calls
1630+ *  get_option() in a loop to get either one option and possible
1631+ *  value or a non-option argument each loop.
1632+ *
1633+ *  This version has been modified to work with UnZip and ZipInfo.
1634+ *  the major changes are removing the error returns, instead
1635+ *  passing back error codes for errors, and supporting separate
1636+ *  groups of options for UnZip and ZipInfo and selecting the option
1637+ *  group by an argument.
1638+ *
1639+ *  This version does not include argument file support and can
1640+ *  work directly on argv.  The argument file code complicates things and
1641+ *  it seemed best to leave it out for now.  If argument file support
1642+ *  (reading in command line arguments stored in a file and inserting into
1643+ *  command line where @filename is found) is added later the arguments
1644+ *  can change and a freeable copy of argv will be needed and can be
1645+ *  created using copy_args in the left out code.
1646+ *
1647+ *  Supports short and long options as defined in the array options[]
1648+ *  in zip.c, multiple short options in an argument (like -jlv), long
1649+ *  option abbreviation (like --te for --temp-file if --te unique),
1650+ *  short and long option values (like -b filename or --temp-file filename
1651+ *  or --temp-file=filename), optional and required values, option negation
1652+ *  by trailing - (like -S- to not include hidden and system files in MSDOS),
1653+ *  value lists (like -x a b c), argument permuting (returning all options
1654+ *  and values before any non-option arguments), and argument files (where
1655+ *  any non-option non-value argument in form @path gets substituted with
1656+ *  the white space separated arguments in the text file at path).  In this
1657+ *  version argument file support has been removed to simplify development
1658+ *  but may be added later.
1659+ *
1660+ *  E. Gordon
1661+ */
1662+
1663+
1664+/* message output - char casts are needed to handle constants */
1665+#define oWARN(message) Info(slide, 0x401, ((char *)slide, (char *)message))
1666+
1667+
1668+
1669+/* Although the below provides some support for multibyte characters
1670+   the proper thing to do may be to use wide characters and support
1671+   Unicode.  May get to it soon.  Wide support would likely require
1672+   the ability to convert the command line to wide strings, which most
1673+   modern OS should support now.  EG
1674+ */
1675+
1676+/* For now stay with multi-byte characters.  May support wide characters
1677+   in Zip 3.1 and UnZip 6.1.
1678+ */
1679+
1680+/* multibyte character set support
1681+   Multibyte characters use typically two or more sequential bytes
1682+   to represent additional characters than can fit in a single byte
1683+   character set.  The code used here is based on the ANSI mblen function. */
1684+#define MB_CLEN(ptr) CLEN(ptr)
1685+#define MB_NEXTCHAR(ptr) PREINCSTR(ptr)
1686+
1687+
1688+/* constants */
1689+
1690+/* function get_args_from_arg_file() can return this in depth parameter */
1691+#define ARG_FILE_ERR -1
1692+
1693+/* internal settings for optchar */
1694+#define SKIP_VALUE_ARG   -1
1695+#define THIS_ARG_DONE    -2
1696+#define START_VALUE_LIST -3
1697+#define IN_VALUE_LIST    -4
1698+#define NON_OPTION_ARG   -5
1699+#define STOP_VALUE_LIST  -6
1700+/* 7/25/04 EG */
1701+#define READ_REST_ARGS_VERBATIM -7
1702+
1703+
1704+/* global veriables */
1705+
1706+int enable_permute = 1;                     /* yes - return options first */
1707+/* 7/25/04 EG */
1708+int doubledash_ends_options = 1;            /* when -- what follows are not options */
1709+
1710+/* buffer for error messages (this sizing is a guess but must hold 2 paths) */
1711+#define OPTIONERR_BUF_SIZE (80+ 2*FILENAME_MAX)
1712+char optionerrbuf[OPTIONERR_BUF_SIZE + 1];
1713+
1714+/* error messages */
1715+static ZCONST char Far op_not_neg_err[] =
1716+   "option %s not negatable";
1717+static ZCONST char Far op_req_val_err[] =
1718+   "option %s requires a value";
1719+static ZCONST char Far op_no_allow_val_err[] =
1720+   "option %s does not allow a value";
1721+static ZCONST char Far sh_op_not_sup_err[] =
1722+   "short option '%c' not supported";
1723+static ZCONST char Far oco_req_val_err[] =
1724+   "option %s requires one character value";
1725+static ZCONST char Far oco_no_mbc_err[] =
1726+   "option %s does not support multibyte values";
1727+static ZCONST char Far num_req_val_err[] =
1728+   "option %s requires number value";
1729+static ZCONST char Far long_op_ambig_err[] =
1730+   "long option '%s' ambiguous";
1731+static ZCONST char Far long_op_not_sup_err[] =
1732+   "long option '%s' not supported";
1733+
1734+static ZCONST char Far no_arg_files_err[] = "argument files not enabled\n";
1735+
1736+
1737+/* below removed as only used for processing argument files */
1738+
1739+/* get_nextarg */
1740+/* get_args_from_string */
1741+/* get_args_from_arg_file */
1742+
1743+
1744+/* copy error, option name, and option description if any to buf */
1745+static int optionerr(options, buf, err, optind, islong)
1746+  struct option_struct *options;
1747+  char *buf;
1748+  ZCONST char Far *err;
1749+  int optind;
1750+  int islong;
1751+{
1752+  char optname[50];
1753+
1754+  if (options[optind].name && options[optind].name[0] != '\0') {
1755+    sprintf(optname, "'%s' (%s)",
1756+            LoadFarStringSmall2(islong ? options[optind].longopt
1757+                                       : options[optind].shortopt),
1758+            LoadFarStringSmall(options[optind].name));
1759+  } else {
1760+    sprintf(optname, "'%s'",
1761+            LoadFarStringSmall2(islong ? options[optind].longopt
1762+                                       : options[optind].shortopt));
1763+  }
1764+  sprintf(buf, LoadFarStringSmall(err), optname);
1765+  return 0;
1766+}
1767+
1768+
1769+/* copy_args
1770+ *
1771+ * Copy arguments in args, allocating storage with malloc.
1772+ * Copies until a NULL argument is found or until max_args args
1773+ * including args[0] are copied.  Set max_args to 0 to copy
1774+ * until NULL.  Always terminates returned args[] with NULL arg.
1775+ *
1776+ * Any argument in the returned args can be freed with free().  Any
1777+ * freed argument should be replaced with either another string
1778+ * allocated with malloc or by NULL if last argument so that free_args
1779+ * will properly work.
1780+ */
1781+char **copy_args(args, max_args)
1782+  char **args;
1783+  int max_args;
1784+{
1785+  int j;
1786+  char **new_args;
1787+
1788+  if (args == NULL) {
1789+    return NULL;
1790+  }
1791+
1792+  /* count args */
1793+  for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) ;
1794+
1795+  if ((new_args = (char **) malloc((j + 1) * sizeof(char *))) == NULL) {
1796+    oWARN("memory - ca");
1797+    return NULL;
1798+  }
1799+
1800+  for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) {
1801+    if (args[j] == NULL) {
1802+      /* null argument is end of args */
1803+      new_args[j] = NULL;
1804+      break;
1805+    }
1806+    if ((new_args[j] = malloc(strlen(args[j]) + 1)) == NULL) {
1807+      free_args(new_args);
1808+      oWARN("memory - ca");
1809+      return NULL;
1810+    }
1811+    strcpy(new_args[j], args[j]);
1812+  }
1813+  new_args[j] = NULL;
1814+
1815+  return new_args;
1816+}
1817+
1818+
1819+/* count args - count args in argv like array */
1820+int arg_count(args)
1821+  char **args;
1822+{
1823+  int i;
1824+
1825+  if (args == NULL) {
1826+    return 0;
1827+  }
1828+
1829+  for (i = 0; args[i]; i++) {
1830+  }
1831+  return i;
1832+}
1833+
1834+
1835+/* free args - free args created with one of these functions */
1836+int free_args(args)
1837+  char **args;
1838+{
1839+  int i;
1840+
1841+  if (args == NULL) {
1842+    return 0;
1843+  }
1844+
1845+  for (i = 0; args[i]; i++) {
1846+    free(args[i]);
1847+  }
1848+  free(args);
1849+  return i;
1850+}
1851+
1852+
1853+/* insert_arg
1854+ *
1855+ * Insert the argument arg into the array args before argument at_arg.
1856+ * If at_arg = -1 then append to end.
1857+ * Return the new count of arguments (argc).
1858+ *
1859+ * If free_args is true, this function frees the old args array
1860+ * (but not the component strings).  DO NOT set free_args on original
1861+ * argv but only on args allocated with malloc.
1862+ */
1863+
1864+int insert_arg(pargs, arg, at_arg, free_args)
1865+   char ***pargs;
1866+   ZCONST char *arg;
1867+   int at_arg;
1868+   int free_args;
1869+{
1870+   char *newarg = NULL;
1871+   char **args;
1872+   char **newargs = NULL;
1873+   int argnum;
1874+   int newargnum;
1875+   int argcnt;
1876+   int newargcnt;
1877+
1878+   if (pargs == NULL) {
1879+     return 0;
1880+   }
1881+   args = *pargs;
1882+
1883+   /* count args */
1884+   if (args == NULL) {
1885+     argcnt = 0;
1886+   } else {
1887+     for (argcnt = 0; args[argcnt]; argcnt++) ;
1888+   }
1889+   if (arg == NULL) {
1890+     /* done */
1891+     return argcnt;
1892+   }
1893+   if (at_arg == -1) {
1894+     at_arg = argcnt;
1895+   }
1896+   newargcnt = argcnt + 1;
1897+
1898+   /* get storage for new args */
1899+   if ((newargs = (char **) malloc((newargcnt + 1) * sizeof(char *))) == NULL)
1900+   {
1901+     oWARN("memory - ia");
1902+     return 0;
1903+   }
1904+
1905+   /* copy argument pointers from args to position at_arg, copy the new arg,
1906+      then copy the rest of the args */
1907+   argnum = 0;
1908+   newargnum = 0;
1909+   if (args) {
1910+     for (; args[argnum] && argnum < at_arg; argnum++) {
1911+       newargs[newargnum++] = args[argnum];
1912+     }
1913+   }
1914+   /* copy new arg */
1915+   if ((newarg = (char *) malloc(strlen(arg) + 1)) == NULL) {
1916+     oWARN("memory - ia");
1917+     return 0;
1918+   }
1919+   strcpy(newarg, arg);
1920+
1921+   newargs[newargnum++] = newarg;
1922+   if (args) {
1923+     for ( ; args[argnum]; argnum++) {
1924+       newargs[newargnum++] = args[argnum];
1925+     }
1926+   }
1927+   newargs[newargnum] = NULL;
1928+
1929+   /* free old args array but not component strings - this assumes that
1930+      args was allocated with malloc as copy_args does.  DO NOT DO THIS
1931+      on the original argv.
1932+    */
1933+   if (free_args)
1934+     free(args);
1935+
1936+   *pargs = newargs;
1937+
1938+   return newargnum;
1939+}
1940+
1941+/* ------------------------------------- */
1942+
1943+/* get_shortopt
1944+ *
1945+ * Get next short option from arg.  The state is stored in argnum, optchar, and
1946+ * option_num so no static storage is used.  Returns the option_ID.
1947+ *
1948+ * parameters:
1949+ *    option_group - either UZO for UnZip options or ZIO for ZipInfo options
1950+ *    args         - argv array of arguments
1951+ *    argnum       - index of current arg in args
1952+ *    optchar      - pointer to index of next char to process.  Can be 0 or
1953+ *                   const defined at top of this file like THIS_ARG_DONE
1954+ *    negated      - on return pointer to int set to 1 if option negated
1955+ *                   or 0 otherwise
1956+ *    value        - on return pointer to string set to value of option if any
1957+ *                   or NULL if none.  If value is returned then the caller
1958+ *                   should free() it when not needed anymore.
1959+ *    option_num   - pointer to index in options[] of returned option or
1960+ *                   o_NO_OPTION_MATCH if none.  Do not change as used by
1961+ *                   value lists.
1962+ *    depth        - recursion depth (0 at top level, 1 or more in arg files)
1963+ */
1964+static unsigned long get_shortopt(option_group, args, argnum, optchar, negated,
1965+                                  value, option_num, depth)
1966+  int option_group;
1967+  ZCONST char **args;
1968+  int argnum;
1969+  int *optchar;
1970+  int *negated;
1971+  char **value;
1972+  int *option_num;
1973+  int depth;
1974+{
1975+  ZCONST char *shortopt;
1976+  int clen;
1977+  ZCONST char *nextchar;
1978+  ZCONST char *s;
1979+  ZCONST char *start;
1980+  int op;
1981+  ZCONST char *arg;
1982+  int match = -1;
1983+
1984+
1985+  /* get arg */
1986+  arg = args[argnum];
1987+  /* current char in arg */
1988+  nextchar = arg + (*optchar);
1989+  clen = MB_CLEN(nextchar);
1990+  /* next char in arg */
1991+  (*optchar) +=  clen;
1992+  /* get first char of short option */
1993+  shortopt = arg + (*optchar);
1994+  /* no value */
1995+  *value = NULL;
1996+
1997+  if (*shortopt == '\0') {
1998+    /* no more options in arg */
1999+    *optchar = 0;
2000+    *option_num = o_NO_OPTION_MATCH;
2001+    return 0;
2002+  }
2003+
2004+  /* look for match in options */
2005+  clen = MB_CLEN(shortopt);
2006+  for (op = 0; options[op].option_ID; op++) {
2007+    /* Only look at options in this option group */
2008+    if (options[op].option_group == option_group) {
2009+      s = options[op].shortopt;
2010+      if (s && s[0] == shortopt[0]) {
2011+        if (s[1] == '\0' && clen == 1) {
2012+          /* single char match */
2013+          match = op;
2014+        } else {
2015+          /* 2 wide short opt.  Could support more chars but should use long opts instead */
2016+          if (s[1] == shortopt[1]) {
2017+            /* match 2 char short opt or 2 byte char */
2018+            match = op;
2019+            if (clen == 1) (*optchar)++;
2020+            break;
2021+          }
2022+        }
2023+      }
2024+    }
2025+  }
2026+
2027+  if (match > -1) {
2028+    /* match */
2029+    clen = MB_CLEN(shortopt);
2030+    nextchar = arg + (*optchar) + clen;
2031+    /* check for trailing dash negating option */
2032+    if (*nextchar == '-') {
2033+      /* negated */
2034+      if (options[match].negatable == o_NOT_NEGATABLE) {
2035+        if (options[match].value_type == o_NO_VALUE) {
2036+          optionerr(options, optionerrbuf, op_not_neg_err, match, 0);
2037+          if (depth > 0) {
2038+            /* unwind */
2039+            oWARN(optionerrbuf);
2040+            return o_ARG_FILE_ERR;
2041+          } else {
2042+            oWARN(optionerrbuf);
2043+            return o_BAD_ERR;
2044+          }
2045+        }
2046+      } else {
2047+        *negated = 1;
2048+        /* set up to skip negating dash */
2049+        (*optchar) += clen;
2050+        clen = 1;
2051+      }
2052+    }
2053+
2054+    /* value */
2055+    clen = MB_CLEN(arg + (*optchar));
2056+    /* optional value, one char value, and number value must follow option */
2057+    if (options[match].value_type == o_ONE_CHAR_VALUE) {
2058+      /* one char value */
2059+      if (arg[(*optchar) + clen]) {
2060+        /* has value */
2061+        if (MB_CLEN(arg + (*optchar) + clen) > 1) {
2062+          /* multibyte value not allowed for now */
2063+          optionerr(options, optionerrbuf, oco_no_mbc_err, match, 0);
2064+          if (depth > 0) {
2065+            /* unwind */
2066+            oWARN(optionerrbuf);
2067+            return o_ARG_FILE_ERR;
2068+          } else {
2069+            oWARN(optionerrbuf);
2070+            return o_BAD_ERR;
2071+          }
2072+        }
2073+        if ((*value = (char *) malloc(2)) == NULL) {
2074+          oWARN("memory - gso");
2075+          return o_BAD_ERR;
2076+        }
2077+        (*value)[0] = *(arg + (*optchar) + clen);
2078+        (*value)[1] = '\0';
2079+        *optchar += clen;
2080+        clen = 1;
2081+      } else {
2082+        /* one char values require a value */
2083+        optionerr(options, optionerrbuf, oco_req_val_err, match, 0);
2084+        if (depth > 0) {
2085+          oWARN(optionerrbuf);
2086+          return o_ARG_FILE_ERR;
2087+        } else {
2088+          oWARN(optionerrbuf);
2089+          return o_BAD_ERR;
2090+        }
2091+      }
2092+    } else if (options[match].value_type == o_NUMBER_VALUE) {
2093+      /* read chars until end of number */
2094+      start = arg + (*optchar) + clen;
2095+      if (*start == '+' || *start == '-') {
2096+        start++;
2097+      }
2098+      s = start;
2099+      for (; isdigit(*s); MB_NEXTCHAR(s)) ;
2100+      if (s == start) {
2101+        /* no digits */
2102+        optionerr(options, optionerrbuf, num_req_val_err, match, 0);
2103+        if (depth > 0) {
2104+          oWARN(optionerrbuf);
2105+          return o_ARG_FILE_ERR;
2106+        } else {
2107+          oWARN(optionerrbuf);
2108+          return o_BAD_ERR;
2109+        }
2110+      }
2111+      start = arg + (*optchar) + clen;
2112+      if ((*value = (char *) malloc((int)(s - start) + 1)) == NULL) {
2113+        oWARN("memory - gso");
2114+        return o_BAD_ERR;
2115+      }
2116+      *optchar += (int)(s - start);
2117+      strncpy(*value, start, (int)(s - start));
2118+      (*value)[(int)(s - start)] = '\0';
2119+      clen = MB_CLEN(s);
2120+    } else if (options[match].value_type == o_OPTIONAL_VALUE) {
2121+      /* optional value */
2122+      /* This seemed inconsistent so now if no value attached to argument look
2123+         to the next argument if that argument is not an option for option
2124+         value - 11/12/04 EG */
2125+      if (arg[(*optchar) + clen]) {
2126+        /* has value */
2127+        /* add support for optional = - 2/6/05 EG */
2128+        if (arg[(*optchar) + clen] == '=') {
2129+          /* skip = */
2130+          clen++;
2131+        }
2132+        if (arg[(*optchar) + clen]) {
2133+          if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
2134+              == NULL) {
2135+            oWARN("memory - gso");
2136+            return o_BAD_ERR;
2137+          }
2138+          strcpy(*value, arg + (*optchar) + clen);
2139+        }
2140+        *optchar = THIS_ARG_DONE;
2141+      } else if (args[argnum + 1] && args[argnum + 1][0] != '-') {
2142+        /* use next arg for value */
2143+        if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
2144+          oWARN("memory - gso");
2145+          return o_BAD_ERR;
2146+        }
2147+        /* using next arg as value */
2148+        strcpy(*value, args[argnum + 1]);
2149+        *optchar = SKIP_VALUE_ARG;
2150+      }
2151+    } else if (options[match].value_type == o_REQUIRED_VALUE ||
2152+               options[match].value_type == o_VALUE_LIST) {
2153+      /* see if follows option */
2154+      if (arg[(*optchar) + clen]) {
2155+        /* has value following option as -ovalue */
2156+        /* add support for optional = - 6/5/05 EG */
2157+        if (arg[(*optchar) + clen] == '=') {
2158+          /* skip = */
2159+          clen++;
2160+        }
2161+        if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
2162+            == NULL) {
2163+          oWARN("memory - gso");
2164+          return o_BAD_ERR;
2165+        }
2166+        strcpy(*value, arg + (*optchar) + clen);
2167+        *optchar = THIS_ARG_DONE;
2168+      } else {
2169+        /* use next arg for value */
2170+        if (args[argnum + 1]) {
2171+          if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1))
2172+              == NULL) {
2173+            oWARN("memory - gso");
2174+            return o_BAD_ERR;
2175+          }
2176+          strcpy(*value, args[argnum + 1]);
2177+          if (options[match].value_type == o_VALUE_LIST) {
2178+            *optchar = START_VALUE_LIST;
2179+          } else {
2180+            *optchar = SKIP_VALUE_ARG;
2181+          }
2182+        } else {
2183+          /* no value found */
2184+          optionerr(options, optionerrbuf, op_req_val_err, match, 0);
2185+          if (depth > 0) {
2186+            oWARN(optionerrbuf);
2187+            return o_ARG_FILE_ERR;
2188+          } else {
2189+            oWARN(optionerrbuf);
2190+            return o_BAD_ERR;
2191+          }
2192+        }
2193+      }
2194+    }
2195+
2196+    *option_num = match;
2197+    return options[match].option_ID;
2198+  }
2199+  sprintf(optionerrbuf, LoadFarStringSmall(sh_op_not_sup_err), *shortopt);
2200+  if (depth > 0) {
2201+    /* unwind */
2202+    oWARN(optionerrbuf);
2203+    return o_ARG_FILE_ERR;
2204+  } else {
2205+    oWARN(optionerrbuf);
2206+    return o_BAD_ERR;
2207+  }
2208+  return 0;
2209+}
2210+
2211+
2212+/* get_longopt
2213+ *
2214+ * Get the long option in args array at argnum.
2215+ * Parameters same as for get_shortopt.
2216+ */
2217+
2218+static unsigned long get_longopt(option_group, args, argnum, optchar, negated,
2219+                                 value, option_num, depth)
2220+  int option_group;
2221+  ZCONST char **args;
2222+  int argnum;
2223+  int *optchar;
2224+  int *negated;
2225+  char **value;
2226+  int *option_num;
2227+  int depth;
2228+{
2229+  char *longopt;
2230+  char *lastchr;
2231+  char *valuestart;
2232+  int op;
2233+  char *arg;
2234+  int match = -1;
2235+  *value = NULL;
2236+
2237+  if (args == NULL) {
2238+    *option_num = o_NO_OPTION_MATCH;
2239+    return 0;
2240+  }
2241+  if (args[argnum] == NULL) {
2242+    *option_num = o_NO_OPTION_MATCH;
2243+    return 0;
2244+  }
2245+  /* copy arg so can chop end if value */
2246+  if ((arg = (char *)malloc(strlen(args[argnum]) + 1)) == NULL) {
2247+    oWARN("memory - glo");
2248+    return o_BAD_ERR;
2249+  }
2250+  strcpy(arg, args[argnum]);
2251+
2252+  /* get option */
2253+  longopt = arg + 2;
2254+  /* no value */
2255+  *value = NULL;
2256+
2257+  /* find = */
2258+  for (lastchr = longopt, valuestart = longopt;
2259+       *valuestart && *valuestart != '=';
2260+       lastchr = valuestart, MB_NEXTCHAR(valuestart)) ;
2261+  if (*valuestart) {
2262+    /* found =value */
2263+    *valuestart = '\0';
2264+    valuestart++;
2265+  } else {
2266+    valuestart = NULL;
2267+  }
2268+
2269+  if (*lastchr == '-') {
2270+    /* option negated */
2271+    *negated = 1;
2272+    *lastchr = '\0';
2273+  } else {
2274+    *negated = 0;
2275+  }
2276+
2277+  /* look for long option match */
2278+  for (op = 0; options[op].option_ID; op++) {
2279+    /* Only look at options in the option group */
2280+    if (options[op].option_group == option_group) {
2281+      if (options[op].longopt &&
2282+          strcmp(LoadFarStringSmall(options[op].longopt), longopt) == 0) {
2283+        /* exact match */
2284+        match = op;
2285+        break;
2286+      }
2287+      if (options[op].longopt &&
2288+          strncmp(LoadFarStringSmall(options[op].longopt),
2289+                  longopt, strlen(longopt)) == 0) {
2290+        if (match > -1) {
2291+          sprintf(optionerrbuf, LoadFarStringSmall(long_op_ambig_err),
2292+                  longopt);
2293+          free(arg);
2294+          if (depth > 0) {
2295+            /* unwind */
2296+            oWARN(optionerrbuf);
2297+            return o_ARG_FILE_ERR;
2298+          } else {
2299+            oWARN(optionerrbuf);
2300+            return o_BAD_ERR;
2301+          }
2302+        }
2303+        match = op;
2304+      }
2305+    }
2306+  }
2307+
2308+  if (match == -1) {
2309+    sprintf(optionerrbuf, LoadFarStringSmall(long_op_not_sup_err), longopt);
2310+    free(arg);
2311+    if (depth > 0) {
2312+      oWARN(optionerrbuf);
2313+      return o_ARG_FILE_ERR;
2314+    } else {
2315+      oWARN(optionerrbuf);
2316+      return o_BAD_ERR;
2317+    }
2318+  }
2319+
2320+  /* one long option an arg */
2321+  *optchar = THIS_ARG_DONE;
2322+
2323+  /* if negated then see if allowed */
2324+  if (*negated && options[match].negatable == o_NOT_NEGATABLE) {
2325+    optionerr(options, optionerrbuf, op_not_neg_err, match, 1);
2326+    free(arg);
2327+    if (depth > 0) {
2328+      /* unwind */
2329+      oWARN(optionerrbuf);
2330+      return o_ARG_FILE_ERR;
2331+    } else {
2332+      oWARN(optionerrbuf);
2333+      return o_BAD_ERR;
2334+    }
2335+  }
2336+  /* get value */
2337+  if (options[match].value_type == o_OPTIONAL_VALUE) {
2338+    /* optional value in form option=value */
2339+    if (valuestart) {
2340+      /* option=value */
2341+      if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
2342+        free(arg);
2343+        oWARN("memory - glo");
2344+        return o_BAD_ERR;
2345+      }
2346+      strcpy(*value, valuestart);
2347+    }
2348+  } else if (options[match].value_type == o_REQUIRED_VALUE ||
2349+             options[match].value_type == o_NUMBER_VALUE ||
2350+             options[match].value_type == o_ONE_CHAR_VALUE ||
2351+             options[match].value_type == o_VALUE_LIST) {
2352+    /* handle long option one char and number value as required value */
2353+    if (valuestart) {
2354+      /* option=value */
2355+      if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
2356+        free(arg);
2357+        oWARN("memory - glo");
2358+        return o_BAD_ERR;
2359+      }
2360+      strcpy(*value, valuestart);
2361+    } else {
2362+      /* use next arg */
2363+      if (args[argnum + 1]) {
2364+        if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
2365+          free(arg);
2366+          oWARN("memory - glo");
2367+          return o_BAD_ERR;
2368+        }
2369+        /* using next arg as value */
2370+        strcpy(*value, args[argnum + 1]);
2371+        if (options[match].value_type == o_VALUE_LIST) {
2372+          *optchar = START_VALUE_LIST;
2373+        } else {
2374+          *optchar = SKIP_VALUE_ARG;
2375+        }
2376+      } else {
2377+        /* no value found */
2378+        optionerr(options, optionerrbuf, op_req_val_err, match, 1);
2379+        free(arg);
2380+        if (depth > 0) {
2381+          /* unwind */
2382+          oWARN(optionerrbuf);
2383+          return o_ARG_FILE_ERR;
2384+        } else {
2385+          oWARN(optionerrbuf);
2386+          return o_BAD_ERR;
2387+        }
2388+      }
2389+    }
2390+  } else if (options[match].value_type == o_NO_VALUE) {
2391+    /* this option does not accept a value */
2392+    if (valuestart) {
2393+      /* --option=value */
2394+      optionerr(options, optionerrbuf, op_no_allow_val_err, match, 1);
2395+      free(arg);
2396+      if (depth > 0) {
2397+        oWARN(optionerrbuf);
2398+        return o_ARG_FILE_ERR;
2399+      } else {
2400+        oWARN(optionerrbuf);
2401+        return o_BAD_ERR;
2402+      }
2403+    }
2404+  }
2405+  free(arg);
2406+
2407+  *option_num = match;
2408+  return options[match].option_ID;
2409+}
2410+
2411+
2412+
2413+/* get_option
2414+ *
2415+ * Main interface for user.  Use this function to get options, values and
2416+ * non-option arguments from a command line provided in argv form.
2417+ *
2418+ * To use get_option() first define valid options by setting
2419+ * the global variable options[] to an array of option_struct.  Also
2420+ * either change defaults below or make variables global and set elsewhere.
2421+ * Zip uses below defaults.
2422+ *
2423+ * Call get_option() to get an option (like -b or --temp-file) and any
2424+ * value for that option (like filename for -b) or a non-option argument
2425+ * (like archive name) each call.  If *value* is not NULL after calling
2426+ * get_option() it is a returned value and the caller should either store
2427+ * the char pointer or free() it before calling get_option() again to avoid
2428+ * leaking memory.  If a non-option non-value argument is returned get_option()
2429+ * returns o_NON_OPTION_ARG and value is set to the entire argument.
2430+ * When there are no more arguments get_option() returns 0.
2431+ *
2432+ * The parameters argnum (after set to 0 on initial call),
2433+ * optchar, first_nonopt_arg, option_num, and depth (after initial
2434+ * call) are set and maintained by get_option() and should not be
2435+ * changed.  The parameters argc, negated, and value are outputs and
2436+ * can be used by the calling program.  get_option() returns either the
2437+ * option_ID for the current option, a special value defined in
2438+ * zip.h, or 0 when no more arguments.
2439+ *
2440+ * The value returned by get_option() is the ID value in the options
2441+ * table.  This value can be duplicated in the table if different
2442+ * options are really the same option.  The index into the options[]
2443+ * table is given by option_num, though the ID should be used as
2444+ * option numbers change when the table is changed.  The ID must
2445+ * not be 0 for any option as this ends the table.  If get_option()
2446+ * finds an option not in the table it calls oERR to post an
2447+ * error and exit.  Errors also result if the option requires a
2448+ * value that is missing, a value is present but the option does
2449+ * not take one, and an option is negated but is not
2450+ * negatable.  Non-option arguments return o_NON_OPTION_ARG
2451+ * with the entire argument in value.
2452+ *
2453+ * For Zip and UnZip, permuting is on and all options and their values
2454+ * are returned before any non-option arguments like archive name.
2455+ *
2456+ * The arguments "-" alone and "--" alone return as non-option arguments.
2457+ * Note that "-" should not be used as part of a short option
2458+ * entry in the table but can be used in the middle of long
2459+ * options such as in the long option "a-long-option".  Now "--" alone
2460+ * stops option processing, returning any arguments following "--" as
2461+ * non-option arguments instead of options.
2462+ *
2463+ * Argument file support is removed from this version. It may be added later.
2464+ *
2465+ * After each call:
2466+ *   argc       is set to the current size of args[] but should not change
2467+ *                with argument file support removed,
2468+ *   argnum     is the index of the current arg,
2469+ *   value      is either the value of the returned option or non-option
2470+ *                argument or NULL if option with no value,
2471+ *   negated    is set if the option was negated by a trailing dash (-)
2472+ *   option_num is set to either the index in options[] for the option or
2473+ *                o_NO_OPTION_MATCH if no match.
2474+ * Negation is checked before the value is read if the option is negatable so
2475+ * that the - is not included in the value.  If the option is not negatable
2476+ * but takes a value then the - will start the value.  If permuting then
2477+ * argnum and first_nonopt_arg are unreliable and should not be used.
2478+ *
2479+ * Command line is read from left to right.  As get_option() finds non-option
2480+ * arguments (arguments not starting with - and that are not values to options)
2481+ * it moves later options and values in front of the non-option arguments.
2482+ * This permuting is turned off by setting enable_permute to 0.  Then
2483+ * get_option() will return options and non-option arguments in the order
2484+ * found.  Currently permuting is only done after an argument is completely
2485+ * processed so that any value can be moved with options they go with.  All
2486+ * state information is stored in the parameters argnum, optchar,
2487+ * first_nonopt_arg and option_num.  You should not change these after the
2488+ * first call to get_option().  If you need to back up to a previous arg then
2489+ * set argnum to that arg (remembering that args may have been permuted) and
2490+ * set optchar = 0 and first_nonopt_arg to the first non-option argument if
2491+ * permuting.  After all arguments are returned the next call to get_option()
2492+ * returns 0.  The caller can then call free_args(args) if appropriate.
2493+ *
2494+ * get_option() accepts arguments in the following forms:
2495+ *  short options
2496+ *       of 1 and 2 characters, e.g. a, b, cc, d, and ba, after a single
2497+ *       leading -, as in -abccdba.  In this example if 'b' is followed by 'a'
2498+ *       it matches short option 'ba' else it is interpreted as short option
2499+ *       b followed by another option.  The character - is not legal as a
2500+ *       short option or as part of a 2 character short option.
2501+ *
2502+ *       If a short option has a value it immediately follows the option or
2503+ *       if that option is the end of the arg then the next arg is used as
2504+ *       the value.  So if short option e has a value, it can be given as
2505+ *             -evalue
2506+ *       or
2507+ *             -e value
2508+ *       and now
2509+ *             -e=value
2510+ *       but now that = is optional a leading = is stripped for the first.
2511+ *       This change allows optional short option values to be defaulted as
2512+ *             -e=
2513+ *       Either optional or required values can be specified.  Optional values
2514+ *       now use both forms as ignoring the later got confusing.  Any
2515+ *       non-value short options can preceed a valued short option as in
2516+ *             -abevalue
2517+ *       Some value types (one_char and number) allow options after the value
2518+ *       so if oc is an option that takes a character and n takes a number
2519+ *       then
2520+ *             -abocVccn42evalue
2521+ *       returns value V for oc and value 42 for n.  All values are strings
2522+ *       so programs may have to convert the "42" to a number.  See long
2523+ *       options below for how value lists are handled.
2524+ *
2525+ *       Any short option can be negated by following it with -.  Any - is
2526+ *       handled and skipped over before any value is read unless the option
2527+ *       is not negatable but takes a value and then - starts the value.
2528+ *
2529+ *       If the value for an optional value is just =, then treated as no
2530+ *       value.
2531+ *
2532+ *  long options
2533+ *       of arbitrary length are assumed if an arg starts with -- but is not
2534+ *       exactly --.  Long options are given one per arg and can be abbreviated
2535+ *       if the abbreviation uniquely matches one of the long options.
2536+ *       Exact matches always match before partial matches.  If ambiguous an
2537+ *       error is generated.
2538+ *
2539+ *       Values are specified either in the form
2540+ *             --longoption=value
2541+ *       or can be the following arg if the value is required as in
2542+ *             --longoption value
2543+ *       Optional values to long options must be in the first form.
2544+ *
2545+ *       Value lists are specified by o_VALUE_LIST and consist of an option
2546+ *       that takes a value followed by one or more value arguments.
2547+ *       The two forms are
2548+ *             --option=value
2549+ *       or
2550+ *             -ovalue
2551+ *       for a single value or
2552+ *             --option value1 value2 value3 ... --option2
2553+ *       or
2554+ *             -o value1 value2 value3 ...
2555+ *       for a list of values.  The list ends at the next option, the
2556+ *       end of the command line, or at a single "@" argument.
2557+ *       Each value is treated as if it was preceeded by the option, so
2558+ *             --option1 val1 val2
2559+ *       with option1 value_type set to o_VALUE_LIST is the same as
2560+ *             --option1=val1 --option1=val2
2561+ *
2562+ *       Long options can be negated by following the option with - as in
2563+ *             --longoption-
2564+ *       Long options with values can also be negated if this makes sense for
2565+ *       the caller as:
2566+ *             --longoption-=value
2567+ *       If = is not followed by anything it is treated as no value.
2568+ *
2569+ *  @path
2570+ *       Argument files support removed from this version.  It may be added
2571+ *       back later.
2572+ *
2573+ *  non-option argument
2574+ *       is any argument not given above.  If enable_permute is 1 then
2575+ *       these are returned after all options, otherwise all options and
2576+ *       args are returned in order.  Returns option ID o_NON_OPTION_ARG
2577+ *       and sets value to the argument.
2578+ *
2579+ *
2580+ * Arguments to get_option:
2581+ *  int option_group       - either UZO for UnZip or ZIO for ZipInfo
2582+ *  char ***pargs          - pointer to arg array in the argv form
2583+ *  int *argc              - returns the current argc for args incl. args[0]
2584+ *  int *argnum            - the index of the current argument (caller
2585+ *                            should set = 0 on first call and not change
2586+ *                            after that)
2587+ *  int *optchar           - index of next short opt in arg or special
2588+ *  int *first_nonopt_arg  - used by get_option to permute args
2589+ *  int *negated           - option was negated (had trailing -)
2590+ *  char *value            - value of option if any (free when done with it)
2591+ *                            or NULL
2592+ *  int *option_num        - the index in options of the last option returned
2593+ *                            (can be o_NO_OPTION_MATCH)
2594+ *  int recursion_depth    - current depth of recursion
2595+ *                            (always set to 0 by caller)
2596+ *                            (always 0 with argument files support removed)
2597+ *
2598+ *  Caller should only read the returned option ID and the value, negated,
2599+ *  and option_num (if required) parameters after each call.
2600+ *
2601+ *  Ed Gordon
2602+ *  8/24/2003 (last updated 3/1/2008 EG)
2603+ *
2604+ */
2605+
2606+unsigned long get_option(option_group, pargs, argc, argnum, optchar, value,
2607+                         negated, first_nonopt_arg, option_num, recursion_depth)
2608+  int option_group;
2609+  char ***pargs;
2610+  int *argc;
2611+  int *argnum;
2612+  int *optchar;
2613+  char **value;
2614+  int *negated;
2615+  int *first_nonopt_arg;
2616+  int *option_num;
2617+  int recursion_depth;
2618+{
2619+  char **args;
2620+  unsigned long option_ID;
2621+
2622+  int argcnt;
2623+  int first_nonoption_arg;
2624+  char *arg = NULL;
2625+  int h;
2626+  int optc;
2627+  int argn;
2628+  int j;
2629+  int v;
2630+  int read_rest_args_verbatim = 0;  /* 7/25/04 - ignore options and arg files for rest args */
2631+
2632+  /* caller should free value or assign it to another
2633+     variable before calling get_option again. */
2634+  *value = NULL;
2635+
2636+  /* if args is NULL then done */
2637+  if (pargs == NULL) {
2638+    *argc = 0;
2639+    return 0;
2640+  }
2641+  args = *pargs;
2642+  if (args == NULL) {
2643+    *argc = 0;
2644+    return 0;
2645+  }
2646+
2647+  /* count args */
2648+  for (argcnt = 0; args[argcnt]; argcnt++) ;
2649+
2650+  /* if no provided args then nothing to do */
2651+  if (argcnt < 1 || (recursion_depth == 0 && argcnt < 2)) {
2652+    *argc = argcnt;
2653+    /* return 0 to note that no args are left */
2654+    return 0;
2655+  }
2656+
2657+  *negated = 0;
2658+  first_nonoption_arg = *first_nonopt_arg;
2659+  argn = *argnum;
2660+  optc = *optchar;
2661+
2662+  if (optc == READ_REST_ARGS_VERBATIM) {
2663+    read_rest_args_verbatim = 1;
2664+  }
2665+
2666+  if (argn == -1 || (recursion_depth == 0 && argn == 0)) {
2667+    /* first call */
2668+    /* if depth = 0 then args[0] is argv[0] so skip */
2669+    *option_num = o_NO_OPTION_MATCH;
2670+    optc = THIS_ARG_DONE;
2671+    first_nonoption_arg = -1;
2672+  }
2673+
2674+  /* if option_num is set then restore last option_ID in case continuing
2675+     value list */
2676+  option_ID = 0;
2677+  if (*option_num != o_NO_OPTION_MATCH) {
2678+    option_ID = options[*option_num].option_ID;
2679+  }
2680+
2681+  /* get next option if any */
2682+  for (;;)  {
2683+    if (read_rest_args_verbatim) {
2684+      /* rest of args after "--" are non-option args if doubledash_ends_options
2685+         set */
2686+      argn++;
2687+      if (argn > argcnt || args[argn] == NULL) {
2688+        /* done */
2689+        option_ID = 0;
2690+        break;
2691+      }
2692+      arg = args[argn];
2693+      if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
2694+        oWARN("memory - go");
2695+        return o_BAD_ERR;
2696+      }
2697+      strcpy(*value, arg);
2698+      *option_num = o_NO_OPTION_MATCH;
2699+      option_ID = o_NON_OPTION_ARG;
2700+      break;
2701+
2702+    /* permute non-option args after option args so options are returned
2703+       first */
2704+    } else if (enable_permute) {
2705+      if (optc == SKIP_VALUE_ARG || optc == THIS_ARG_DONE ||
2706+          optc == START_VALUE_LIST || optc == IN_VALUE_LIST ||
2707+          optc == STOP_VALUE_LIST) {
2708+        /* moved to new arg */
2709+        if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
2710+          /* do the permuting - move non-options after this option */
2711+          /* if option and value separate args or starting list skip option */
2712+          if (optc == SKIP_VALUE_ARG || optc == START_VALUE_LIST) {
2713+            v = 1;
2714+          } else {
2715+            v = 0;
2716+          }
2717+          for (h = first_nonoption_arg; h < argn; h++) {
2718+            arg = args[first_nonoption_arg];
2719+            for (j = first_nonoption_arg; j < argn + v; j++) {
2720+              args[j] = args[j + 1];
2721+            }
2722+            args[j] = arg;
2723+          }
2724+          first_nonoption_arg += 1 + v;
2725+        }
2726+      }
2727+    } else if (optc == NON_OPTION_ARG) {
2728+      /* if not permuting then already returned arg */
2729+      optc = THIS_ARG_DONE;
2730+    }
2731+
2732+    /* value lists */
2733+    if (optc == STOP_VALUE_LIST) {
2734+      optc = THIS_ARG_DONE;
2735+    }
2736+
2737+    if (optc == START_VALUE_LIST || optc == IN_VALUE_LIST) {
2738+      if (optc == START_VALUE_LIST) {
2739+        /* already returned first value */
2740+        argn++;
2741+        optc = IN_VALUE_LIST;
2742+      }
2743+      argn++;
2744+      arg = args[argn];
2745+      /* if end of args and still in list and there are non-option args then
2746+         terminate list */
2747+      if (arg == NULL && (optc == START_VALUE_LIST || optc == IN_VALUE_LIST)
2748+          && first_nonoption_arg > -1) {
2749+        /* terminate value list with @ */
2750+        /* this is only needed for argument files */
2751+        /* but is also good for show command line so command lines with lists
2752+           can always be read back in */
2753+        argcnt = insert_arg(&args, "@", first_nonoption_arg, 1);
2754+        argn++;
2755+        if (first_nonoption_arg > -1) {
2756+          first_nonoption_arg++;
2757+        }
2758+      }
2759+
2760+      arg = args[argn];
2761+      if (arg && arg[0] == '@' && arg[1] == '\0') {
2762+          /* inserted arguments terminator */
2763+          optc = STOP_VALUE_LIST;
2764+          continue;
2765+      } else if (arg && arg[0] != '-') {  /* not option */
2766+        /* - and -- are not allowed in value lists unless escaped */
2767+        /* another value in value list */
2768+        if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
2769+          oWARN("memory - go");
2770+          return o_BAD_ERR;
2771+        }
2772+        strcpy(*value, args[argn]);
2773+        break;
2774+
2775+      } else {
2776+        argn--;
2777+        optc = THIS_ARG_DONE;
2778+      }
2779+    }
2780+
2781+    /* move to next arg */
2782+    if (optc == SKIP_VALUE_ARG) {
2783+      argn += 2;
2784+      optc = 0;
2785+    } else if (optc == THIS_ARG_DONE) {
2786+      argn++;
2787+      optc = 0;
2788+    }
2789+    if (argn > argcnt) {
2790+      break;
2791+    }
2792+    if (args[argn] == NULL) {
2793+      /* done unless permuting and non-option args */
2794+      if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
2795+        /* return non-option arguments at end */
2796+        if (optc == NON_OPTION_ARG) {
2797+          first_nonoption_arg++;
2798+        }
2799+        /* after first pass args are permuted but skipped over non-option
2800+           args */
2801+        /* swap so argn points to first non-option arg */
2802+        j = argn;
2803+        argn = first_nonoption_arg;
2804+        first_nonoption_arg = j;
2805+      }
2806+      if (argn > argcnt || args[argn] == NULL) {
2807+        /* done */
2808+        option_ID = 0;
2809+        break;
2810+      }
2811+    }
2812+
2813+    /* after swap first_nonoption_arg points to end which is NULL */
2814+    if (first_nonoption_arg > -1 && (args[first_nonoption_arg] == NULL)) {
2815+      /* only non-option args left */
2816+      if (optc == NON_OPTION_ARG) {
2817+        argn++;
2818+      }
2819+      if (argn > argcnt || args[argn] == NULL) {
2820+        /* done */
2821+        option_ID = 0;
2822+        break;
2823+      }
2824+      if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
2825+        oWARN("memory - go");
2826+        return o_BAD_ERR;
2827+      }
2828+      strcpy(*value, args[argn]);
2829+      optc = NON_OPTION_ARG;
2830+      option_ID = o_NON_OPTION_ARG;
2831+      break;
2832+    }
2833+
2834+    arg = args[argn];
2835+
2836+    /* is it an option */
2837+    if (arg[0] == '-') {
2838+      /* option */
2839+      if (arg[1] == '\0') {
2840+        /* arg = - */
2841+        /* treat like non-option arg */
2842+        *option_num = o_NO_OPTION_MATCH;
2843+        if (enable_permute) {
2844+          /* permute args to move all non-option args to end */
2845+          if (first_nonoption_arg < 0) {
2846+            first_nonoption_arg = argn;
2847+          }
2848+          argn++;
2849+        } else {
2850+          /* not permute args so return non-option args when found */
2851+          if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
2852+            oWARN("memory - go");
2853+            return o_BAD_ERR;
2854+          }
2855+          strcpy(*value, arg);
2856+          optc = NON_OPTION_ARG;
2857+          option_ID = o_NON_OPTION_ARG;
2858+          break;
2859+        }
2860+
2861+      } else if (arg[1] == '-') {
2862+        /* long option */
2863+        if (arg[2] == '\0') {
2864+          /* arg = -- */
2865+          if (doubledash_ends_options) {
2866+            /* Now -- stops permuting and forces the rest of
2867+               the command line to be read verbatim - 7/25/04 EG */
2868+
2869+            /* never permute args after -- and return as non-option args */
2870+            if (first_nonoption_arg < 1) {
2871+              /* -- is first non-option argument - 8/7/04 EG */
2872+              argn--;
2873+            } else {
2874+              /* go back to start of non-option args - 8/7/04 EG */
2875+              argn = first_nonoption_arg - 1;
2876+            }
2877+
2878+            /* disable permuting and treat remaining arguments as not
2879+               options */
2880+            read_rest_args_verbatim = 1;
2881+            optc = READ_REST_ARGS_VERBATIM;
2882+
2883+          } else {
2884+            /* treat like non-option arg */
2885+            *option_num = o_NO_OPTION_MATCH;
2886+            if (enable_permute) {
2887+              /* permute args to move all non-option args to end */
2888+              if (first_nonoption_arg < 0) {
2889+                first_nonoption_arg = argn;
2890+              }
2891+              argn++;
2892+            } else {
2893+              /* not permute args so return non-option args when found */
2894+              if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
2895+                oWARN("memory - go");
2896+                return o_BAD_ERR;
2897+              }
2898+              strcpy(*value, arg);
2899+              optc = NON_OPTION_ARG;
2900+              option_ID = o_NON_OPTION_ARG;
2901+              break;
2902+            }
2903+          }
2904+
2905+        } else {
2906+          option_ID = get_longopt(option_group, (ZCONST char **)args, argn,
2907+                                  &optc, negated,
2908+                                  value, option_num, recursion_depth);
2909+          if (option_ID == o_BAD_ERR) {
2910+            return o_BAD_ERR;
2911+          } else if (option_ID == o_ARG_FILE_ERR) {
2912+            /* unwind as only get this if recursion_depth > 0 */
2913+            return option_ID;
2914+          }
2915+          break;
2916+        }
2917+
2918+      } else {
2919+        /* short option */
2920+        option_ID = get_shortopt(option_group, (ZCONST char **)args, argn,
2921+                                 &optc, negated,
2922+                                 value, option_num, recursion_depth);
2923+
2924+        if (option_ID == o_BAD_ERR) {
2925+          return o_BAD_ERR;
2926+        } else if (option_ID == o_ARG_FILE_ERR) {
2927+          /* unwind as only get this if recursion_depth > 0 */
2928+          return option_ID;
2929+        }
2930+
2931+        if (optc == 0) {
2932+          /* if optc = 0 then ran out of short opts this arg */
2933+          optc = THIS_ARG_DONE;
2934+        } else {
2935+          break;
2936+        }
2937+      }
2938+
2939+#if 0
2940+    /* argument file code left out
2941+       so for now let filenames start with @
2942+    */
2943+
2944+    } else if (allow_arg_files && arg[0] == '@') {
2945+      /* arg file */
2946+      oERR(PK_PARMS, no_arg_files_err);
2947+#endif
2948+
2949+    } else {
2950+      /* non-option */
2951+      if (enable_permute) {
2952+        /* permute args to move all non-option args to end */
2953+        if (first_nonoption_arg < 0) {
2954+          first_nonoption_arg = argn;
2955+        }
2956+        argn++;
2957+      } else {
2958+        /* no permute args so return non-option args when found */
2959+        if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
2960+          oWARN("memory - go");
2961+          return o_BAD_ERR;
2962+        }
2963+        strcpy(*value, arg);
2964+        *option_num = o_NO_OPTION_MATCH;
2965+        optc = NON_OPTION_ARG;
2966+        option_ID = o_NON_OPTION_ARG;
2967+        break;
2968+      }
2969+
2970+    }
2971+  }
2972+
2973+  *pargs = args;
2974+  *argc = argcnt;
2975+  *first_nonopt_arg = first_nonoption_arg;
2976+  *argnum = argn;
2977+  *optchar = optc;
2978+
2979+  return option_ID;
2980+}
2981diff -ru2 unz60e03/unzpriv.h u6e3_np/unzpriv.h
2982--- unz60e03/unzpriv.h	Mon Mar 24 11:53:24 2008
2983+++ u6e3_np/unzpriv.h	Mon Mar 24 14:13:02 2008
2984@@ -1271,4 +1271,89 @@
2985 #endif
2986
2987+
2988+/*--------------------------------------------------------------------
2989+    Long option support
2990+    23 August 2003
2991+    Updated for UnZip 1 March 2008
2992+    See unzip.c
2993+  --------------------------------------------------------------------*/
2994+
2995+/* The below is for use in the caller-provided options table */
2996+
2997+/* option groups */
2998+#define UZO 1   /* UnZip option */
2999+#define ZIO 2   /* ZipInfo option */
3000+
3001+
3002+/* value_type - value is always returned as a string. */
3003+#define o_NO_VALUE        0   /* this option does not take a value */
3004+#define o_REQUIRED_VALUE  1   /* this option requires a value */
3005+#define o_OPTIONAL_VALUE  2   /* value is optional (see get_option() for details) */
3006+#define o_VALUE_LIST      3   /* this option takes a list of values */
3007+#define o_ONE_CHAR_VALUE  4   /* next char is value (does not end short opt string) */
3008+#define o_NUMBER_VALUE    5   /* value is integer (does not end short opt string) */
3009+
3010+
3011+/* negatable - a dash following the option (but before any value) sets negated. */
3012+#define o_NOT_NEGATABLE   0   /* trailing '-' to negate either starts value or generates error */
3013+#define o_NEGATABLE       1   /* trailing '-' sets negated to TRUE */
3014+
3015+
3016+/* option_num can be this when option not in options table */
3017+#define o_NO_OPTION_MATCH     -1
3018+
3019+/* special values returned by get_option - do not use these as option IDs */
3020+#define o_NON_OPTION_ARG      ((unsigned long) 0xFFFF)    /* returned for non-option
3021+                                                             args */
3022+#define o_ARG_FILE_ERR        ((unsigned long) 0xFFFE)    /* internal recursion
3023+                                                             return (user never sees) */
3024+#define o_BAD_ERR             ((unsigned long) 0xFFFD)    /* bad error */
3025+
3026+/* options array is set in unzip.c */
3027+struct option_struct {
3028+  int option_group;         /* either UZO for UnZip or ZIO for ZipInfo syntax */
3029+  char Far *shortopt;       /* pointer to short option string */
3030+  char Far *longopt;        /* pointer to long option string */
3031+  int  value_type;          /* from above */
3032+  int  negatable;           /* from above */
3033+  unsigned long option_ID;  /* value returned by get_option when this option
3034+                               is found */
3035+  char Far *name;           /* optional string for option returned on some
3036+                               errors */
3037+};
3038+
3039+/* structure used to create -x and include file lists */
3040+struct file_list {
3041+  char *name;
3042+  struct file_list *next;
3043+};
3044+
3045+
3046+/* function prototypes */
3047+
3048+/* get the next option from args */
3049+unsigned long get_option OF((int option_group,
3050+                             char ***pargs, int *argc, int *argnum,
3051+                             int *optchar,
3052+                             char **value, int *negated, int *first_nonopt_arg,
3053+                             int *option_num, int recursion_depth));
3054+
3055+/* copy args - copy an args array, allocating space as needed */
3056+char **copy_args OF((char **args, int max_args));
3057+
3058+/* arg count - count args in argv like array */
3059+int arg_count OF((char **args));
3060+
3061+/* free args - free args created with one of these functions */
3062+int free_args OF((char **args));
3063+
3064+/* insert arg - copy an arg into args */
3065+int insert_arg OF((char ***args, ZCONST char *arg, int insert_at,
3066+                   int free_args));
3067+
3068+/*--------------------------------------------------------------------
3069+    End of Long option support
3070+  --------------------------------------------------------------------*/
3071+
3072 /***********************************/
3073 /*  LARGE_FILE_SUPPORT             */
3074diff -ru2 unz60e03/vms/cmdline.c u6e3_np/vms/cmdline.c
3075--- unz60e03/vms/cmdline.c	Tue Feb 12 01:37:42 2008
3076+++ u6e3_np/vms/cmdline.c	Mon Mar 24 14:13:10 2008
3077@@ -34,4 +34,6 @@
3078 **  Modified by:
3079 **
3080+**      02-014          E. Gordon               10-Mar-2008 03:12
3081+**              Modified to work with get_options().
3082 **      02-013          S. Schweda, C. Spieler  29-Dec-2007 03:34
3083 **              Extended /RESTORE qualifier to support timestamp restoration
3084@@ -172,10 +174,10 @@
3085 $DESCRIPTOR(cli_text_auto,      "TEXT.AUTO");           /* -a */
3086 $DESCRIPTOR(cli_text_all,       "TEXT.ALL");            /* -aa */
3087-$DESCRIPTOR(cli_text_none,      "TEXT.NONE");           /* ---a */
3088+$DESCRIPTOR(cli_text_none,      "TEXT.NONE");           /* -a- */
3089 $DESCRIPTOR(cli_text_stmlf,     "TEXT.STMLF");          /* -S */
3090 $DESCRIPTOR(cli_binary,         "BINARY");              /* -b[b] */
3091 $DESCRIPTOR(cli_binary_auto,    "BINARY.AUTO");         /* -b */
3092 $DESCRIPTOR(cli_binary_all,     "BINARY.ALL");          /* -bb */
3093-$DESCRIPTOR(cli_binary_none,    "BINARY.NONE");         /* ---b */
3094+$DESCRIPTOR(cli_binary_none,    "BINARY.NONE");         /* -b- */
3095 $DESCRIPTOR(cli_case_insensitive,"CASE_INSENSITIVE");   /* -C */
3096 $DESCRIPTOR(cli_screen,         "SCREEN");              /* -c */
3097@@ -202,5 +204,5 @@
3098 $DESCRIPTOR(cli_restore_own,    "RESTORE.OWNER_PROT");  /* -X */
3099 $DESCRIPTOR(cli_restore_date,   "RESTORE.DATE");        /* -DD */
3100-$DESCRIPTOR(cli_restore_date_all, "RESTORE.DATE.ALL");  /* --D */
3101+$DESCRIPTOR(cli_restore_date_all, "RESTORE.DATE.ALL");  /* -D- */
3102 $DESCRIPTOR(cli_restore_date_files, "RESTORE.DATE.FILES"); /* -D */
3103 $DESCRIPTOR(cli_dot_version,    "DOT_VERSION");         /* -Y */
3104@@ -299,4 +301,6 @@
3105 **      SS$_ABORT       - Bad time value
3106 **
3107+**  Modified to work with the get_option() command line parser.  10 March 2008
3108+**
3109 */
3110     register unsigned long status;
3111@@ -419,5 +423,4 @@
3112         if (status != CLI$_ABSENT) {
3113             *ptr++ = '-';
3114-            *ptr++ = '-';
3115             *ptr++ = 'b';
3116             if ((status & 1) &&
3117@@ -427,4 +430,5 @@
3118                     *ptr++ = 'b';
3119             }
3120+            *ptr++ = '-';
3121         }
3122
3123@@ -436,5 +440,4 @@
3124         if (status != CLI$_ABSENT) {
3125             *ptr++ = '-';
3126-            *ptr++ = '-';
3127             *ptr++ = 'a';
3128             if ((status & 1) &&
3129@@ -446,4 +449,5 @@
3130                     *ptr++ = 'S';
3131             }
3132+            *ptr++ = '-';
3133         }
3134
3135diff -ru2 unz60e03/zipinfo.c u6e3_np/zipinfo.c
3136--- unz60e03/zipinfo.c	Mon Mar 24 14:23:54 2008
3137+++ u6e3_np/zipinfo.c	Mon Mar 24 14:25:24 2008
3138@@ -171,4 +171,6 @@
3139 static ZCONST char Far ZipfileCommTruncMsg[] =
3140   "\ncaution:  zipfile comment truncated\n";
3141+static ZCONST char Far NoMemArguments[] =
3142+  "envargs:  cannot get memory for arguments";
3143
3144 static ZCONST char Far CentralDirEntry[] =
3145@@ -459,10 +461,48 @@
3146     __GDEF
3147 {
3148-    char   **argv, *s;
3149-    int    argc, c, error=FALSE, negative=0;
3150+    int    argc, error=FALSE;
3151     int    hflag_slmv=TRUE, hflag_2=FALSE;  /* diff options => diff defaults */
3152     int    tflag_slm=TRUE, tflag_2v=FALSE;
3153     int    explicit_h=FALSE, explicit_t=FALSE;
3154
3155+    char **args;
3156+
3157+
3158+    /* used by get_option */
3159+    unsigned long option; /* option ID returned by get_option */
3160+    int argcnt = 0;       /* current argcnt in args */
3161+    int argnum = 0;       /* arg number */
3162+    int optchar = 0;      /* option state */
3163+    char *value = NULL;   /* non-option arg, option value or NULL */
3164+    int negative = 0;     /* 1 = option negated */
3165+    int fna = 0;          /* current first non-opt arg */
3166+    int optnum = 0;       /* index in table */
3167+
3168+
3169+    /* since get_option() returns xfiles and files one at a time, store them in
3170+       linked lists until have them all */
3171+
3172+    int file_count;
3173+    struct file_list *next_file;
3174+
3175+    /* files to extract */
3176+    int in_files_count = 0;
3177+    struct file_list *in_files = NULL;
3178+    struct file_list *next_in_files = NULL;
3179+
3180+    /* files to exclude in -x list */
3181+    int in_xfiles_count = 0;
3182+    struct file_list *in_xfiles = NULL;
3183+    struct file_list *next_in_xfiles = NULL;
3184+
3185+    G.wildzipfn = NULL;
3186+
3187+    /* make copy of args that can use with insert_arg() used by get_option() */
3188+    args = copy_args(*pargv, 0);
3189+
3190+
3191+    /* Initialize lists */
3192+    G.filespecs = 0;
3193+    G.xfilespecs = 0;
3194
3195 #ifdef MACOS
3196@@ -470,17 +510,41 @@
3197 #endif
3198     G.extract_flag = FALSE;   /* zipinfo does not extract to disk */
3199-    argc = *pargc;
3200-    argv = *pargv;
3201
3202-    while (--argc > 0 && (*++argv)[0] == '-') {
3203-        s = argv[0] + 1;
3204-        while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
3205-            switch (c) {
3206-                case '-':
3207-                    ++negative;
3208-                    break;
3209+
3210+    /*
3211+    -------------------------------------------
3212+    Process command line using get_option
3213+    -------------------------------------------
3214+
3215+    Each call to get_option() returns either a command
3216+    line option and possible value or a non-option argument.
3217+    Arguments are permuted so that all options (-r, -b temp)
3218+    are returned before non-option arguments (zipfile).
3219+    Returns 0 when nothing left to read.
3220+    */
3221+
3222+    /* set argnum = 0 on first call to init get_option */
3223+    argnum = 0;
3224+
3225+    /* get_option returns the option ID and updates parameters:
3226+           args    - usually same as argv if no argument file support
3227+           argcnt  - current argc for args
3228+           value   - char* to value (free() when done with it) or NULL if no value
3229+           negated - option was negated with trailing -
3230+    */
3231+
3232+    while ((option = get_option(ZIO, &args, &argcnt, &argnum,
3233+                                &optchar, &value, &negative,
3234+                                &fna, &optnum, 0)))
3235+    {
3236+        if(option == o_BAD_ERR) {
3237+          return(PK_PARAM);
3238+        }
3239+
3240+        switch (option)
3241+        {
3242                 case '1':      /* shortest listing:  JUST filenames */
3243                     if (negative)
3244-                        uO.lflag = -2, negative = 0;
3245+                        uO.lflag = -2;
3246                     else
3247                         uO.lflag = 1;
3248@@ -488,5 +552,5 @@
3249                 case '2':      /* just filenames, plus headers if specified */
3250                     if (negative)
3251-                        uO.lflag = -2, negative = 0;
3252+                        uO.lflag = -2;
3253                     else
3254                         uO.lflag = 2;
3255@@ -495,5 +559,5 @@
3256                 case ('C'):    /* -C:  match filenames case-insensitively */
3257                     if (negative)
3258-                        uO.C_flag = FALSE, negative = 0;
3259+                        uO.C_flag = FALSE;
3260                     else
3261                         uO.C_flag = TRUE;
3262@@ -502,5 +566,5 @@
3263                 case 'h':      /* header line */
3264                     if (negative)
3265-                        hflag_2 = hflag_slmv = FALSE, negative = 0;
3266+                        hflag_2 = hflag_slmv = FALSE;
3267                     else {
3268                         hflag_2 = hflag_slmv = explicit_h = TRUE;
3269@@ -511,5 +575,5 @@
3270                 case 'l':      /* longer form of "ls -l" type listing */
3271                     if (negative)
3272-                        uO.lflag = -2, negative = 0;
3273+                        uO.lflag = -2;
3274                     else
3275                         uO.lflag = 5;
3276@@ -517,5 +581,5 @@
3277                 case 'm':      /* medium form of "ls -l" type listing */
3278                     if (negative)
3279-                        uO.lflag = -2, negative = 0;
3280+                        uO.lflag = -2;
3281                     else
3282                         uO.lflag = 4;
3283@@ -524,5 +588,5 @@
3284                 case 'M':      /* send output through built-in "more" */
3285                     if (negative)
3286-                        G.M_flag = FALSE, negative = 0;
3287+                        G.M_flag = FALSE;
3288                     else
3289                         G.M_flag = TRUE;
3290@@ -531,5 +595,5 @@
3291                 case 's':      /* default:  shorter "ls -l" type listing */
3292                     if (negative)
3293-                        uO.lflag = -2, negative = 0;
3294+                        uO.lflag = -2;
3295                     else
3296                         uO.lflag = 3;
3297@@ -537,5 +601,5 @@
3298                 case 't':      /* totals line */
3299                     if (negative)
3300-                        tflag_2v = tflag_slm = FALSE, negative = 0;
3301+                        tflag_2v = tflag_slm = FALSE;
3302                     else {
3303                         tflag_2v = tflag_slm = explicit_t = TRUE;
3304@@ -546,5 +610,5 @@
3305                 case ('T'):    /* use (sortable) decimal time format */
3306                     if (negative)
3307-                        uO.T_flag = FALSE, negative = 0;
3308+                        uO.T_flag = FALSE;
3309                     else
3310                         uO.T_flag = TRUE;
3311@@ -552,8 +616,7 @@
3312 #ifdef UNICODE_SUPPORT
3313                 case ('U'):    /* escape UTF-8, or disable UTF-8 support */
3314-                    if (negative) {
3315-                        uO.U_flag = MAX(uO.U_flag-negative,0);
3316-                        negative = 0;
3317-                    } else
3318+                    if (negative)
3319+                        uO.U_flag = MAX(uO.U_flag - 1, 0);
3320+                    else
3321                         uO.U_flag++;
3322                     break;
3323@@ -561,5 +624,5 @@
3324                 case 'v':      /* turbo-verbose listing */
3325                     if (negative)
3326-                        uO.lflag = -2, negative = 0;
3327+                        uO.lflag = -2;
3328                     else
3329                         uO.lflag = 10;
3330@@ -568,12 +631,36 @@
3331                 case ('W'):    /* Wildcard interpretation (stop at '/'?) */
3332                     if (negative)
3333-                        uO.W_flag = FALSE, negative = 0;
3334+                        uO.W_flag = FALSE;
3335                     else
3336                         uO.W_flag = TRUE;
3337                     break;
3338 #endif /* WILD_STOP_AT_DIR */
3339+                case ('x'):    /* extract:  default */
3340+                    /* add -x file to linked list */
3341+
3342+                    if (in_xfiles_count == 0) {
3343+                        /* first entry */
3344+                        if ((in_xfiles = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) {
3345+                            Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
3346+                            return PK_MEM;
3347+                        }
3348+                        in_xfiles->name = value;
3349+                        in_xfiles->next = NULL;
3350+                        next_in_xfiles = in_xfiles;
3351+                    } else {
3352+                        /* add next entry */
3353+                        if ((next_file = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) {
3354+                            Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
3355+                            return PK_MEM;
3356+                        }
3357+                        next_in_xfiles->next = next_file;
3358+                        next_file->name = value;
3359+                        next_file->next = NULL;
3360+                        next_in_xfiles = next_file;
3361+                    }
3362+                    in_xfiles_count++;
3363                 case 'z':      /* print zipfile comment */
3364                     if (negative)
3365-                        uO.zflag = negative = 0;
3366+                        uO.zflag = 0;
3367                     else
3368                         uO.zflag = 1;
3369@@ -581,13 +668,96 @@
3370                 case 'Z':      /* ZipInfo mode:  ignore */
3371                     break;
3372+                case o_NON_OPTION_ARG:
3373+                    /* not an option */
3374+                    /* no more options as permuting */
3375+
3376+
3377+                    if (G.wildzipfn == NULL) {
3378+                        /* first non-option argument is zip file */
3379+                        G.wildzipfn = value;
3380+
3381+                    } else {
3382+                        /* add include file to list */
3383+                        if (in_files_count == 0) {
3384+                            /* first entry */
3385+                            if ((next_file = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) {
3386+                                Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
3387+                                return PK_MEM;
3388+                            }
3389+                            next_file->name = value;
3390+                            next_file->next = NULL;
3391+                            in_files = next_file;
3392+                            next_in_files = next_file;
3393+                        } else {
3394+                            /* add next entry */
3395+                            if ((next_file = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) {
3396+                                Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
3397+                                return PK_MEM;
3398+                            }
3399+                            next_in_files->next = next_file;
3400+                            next_file->name = value;
3401+                            next_file->next = NULL;
3402+                            next_in_files = next_file;
3403+                        }
3404+                        in_files_count++;
3405+                    }
3406+                    break;
3407                 default:
3408                     error = TRUE;
3409                     break;
3410-            }
3411-        }
3412+        } /* switch */
3413+    } /* get_option() */
3414+
3415+    /* convert files and xfiles lists to arrays */
3416+
3417+    /* convert files list to array */
3418+    if (in_files_count) {
3419+      if ((G.pfnames = (char **) malloc((in_files_count + 1) * sizeof(char *))) == NULL) {
3420+          Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
3421+          return PK_MEM;
3422+      }
3423+      file_count = 0;
3424+      for (next_file = in_files; next_file;) {
3425+          G.pfnames[file_count] = next_file->name;
3426+          in_files = next_file;
3427+          next_file = next_file->next;
3428+          free(in_files);
3429+          file_count++;
3430+      }
3431+      G.pfnames[file_count] = NULL;
3432+      G.filespecs = in_files_count;
3433+    }
3434+
3435+    /* convert xfiles list to array */
3436+    if (in_xfiles_count) {
3437+      if ((G.pxnames = (char **) malloc((in_xfiles_count + 1) * sizeof(char *))) == NULL) {
3438+          Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
3439+          return PK_MEM;
3440+      }
3441+      file_count = 0;
3442+      for (next_file = in_xfiles; next_file;) {
3443+          G.pxnames[file_count] = next_file->name;
3444+          in_xfiles = next_file;
3445+          next_file = next_file->next;
3446+          free(in_xfiles);
3447+          file_count++;
3448+      }
3449+      G.pxnames[file_count] = NULL;
3450+      G.xfilespecs = in_xfiles_count;
3451     }
3452-    if ((argc-- == 0) || error) {
3453+
3454+    if (in_files_count || in_xfiles_count) {
3455+        G.process_all_files = FALSE;
3456+    } else {
3457+        G.process_all_files = TRUE;      /* for speed */
3458+    }
3459+
3460+    /* it's possible the arg count could have been changed by get_option() */
3461+    argc = arg_count(args);
3462+
3463+    if ((G.wildzipfn == NULL) || error) {
3464+        argc = -1;      /* tell the caller to stop processing */
3465         *pargc = argc;
3466-        *pargv = argv;
3467+        *pargv = args;
3468         return USAGE(error);
3469     }
3470@@ -628,5 +798,5 @@
3471
3472     *pargc = argc;
3473-    *pargv = argv;
3474+    *pargv = args;
3475     return 0;
3476
3477