diff -ru2 unz60e03/unzip.c u6e3_np/unzip.c
--- unz60e03/unzip.c	Wed Mar 19 13:08:38 2008
+++ u6e3_np/unzip.c	Mon Mar 24 14:16:58 2008
@@ -128,4 +128,6 @@
     "error:  command line parameter #%d exceeds internal size limit\n";
 #endif /* !SFX */
+static ZCONST char Far NoMemArgsList[] =
+  "error:  no memory for arguments list";
 
 #if (defined(REENTRANT) && !defined(NO_EXCEPT_SIGNALS))
@@ -245,5 +247,5 @@
    static ZCONST char Far local3[] = "\
   -Y  treat \".nnn\" as \";nnn\" version         -2  force ODS2 names\n\
-  --D restore dir (-D: no) timestamps        -M  pipe through \"more\" pager\n\
+  -D- restore dir (-D: no) timestamps        -M  pipe through \"more\" pager\n\
   (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)\
 \n\n";
@@ -251,5 +253,5 @@
    static ZCONST char Far local3[] = "\n\
   -Y  treat \".nnn\" as \";nnn\" version         -2  force ODS2 names\n\
-  --D restore dir (-D: no) timestamps\n\
+  -D- restore dir (-D: no) timestamps\n\
   (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND.)\
 \n\n";
@@ -694,5 +696,5 @@
     char *p;
 #endif
-#if (defined(DOS_FLX_H68_NLM_OS2_W32) || !defined(SFX))
+#if ((defined(WIN32) && defined(__RSXNT__)) || !defined(SFX))
     int i;
 #endif
@@ -1053,4 +1055,45 @@
      * 'forward slashes' for user's convenience (include zipfile name itself)
      */
+    {
+        /* pfnames */
+
+        char **names;
+
+        for (names = G.pfnames; *names; names++) {
+#ifdef __human68k__
+            extern char *_toslash(char *);
+            _toslash(*names);
+#else /* !__human68k__ */
+            char *q = *names;
+
+            while (*q != '\0') {
+                if (*q == '\\')
+                    *q = '/';
+                INCSTR(q);
+            }
+#endif /* ?__human68k__ */
+        }
+    }
+    {
+        /* G.wildzipfn */
+
+#ifdef __human68k__
+        extern char *_toslash(char *);
+        _toslash(*G.wildzipfn);
+#else /* !__human68k__ */
+        char *q = G.wildzipfn;
+
+        while (*q != '\0') {
+            if (*q == '\\')
+                *q = '/';
+            INCSTR(q);
+        }
+#endif /* ?__human68k__ */
+    }
+#endif /* DOS_FLX_H68_NLM_OS2_W32 */
+
+
+#if 0
+#ifdef DOS_FLX_H68_NLM_OS2_W32
 #ifdef SFX
     for (G.pfnames = argv, i = argc;  i > 0;  --i) {
@@ -1074,11 +1117,18 @@
     }
 #endif /* DOS_FLX_H68_NLM_OS2_W32 */
+#endif /* 0 */
 
+/*
 #ifndef SFX
     G.wildzipfn = *argv++;
 #endif
+*/
 
 #if (defined(SFX) && !defined(SFX_EXDIR)) /* only check for -x */
 
+# if 0
+    /* all this should be done in the options call now */
+
+
     G.filespecs = argc;
     G.xfilespecs = 0;
@@ -1104,7 +1154,10 @@
     } else
         G.process_all_files = TRUE;      /* for speed */
+# endif
 
 #else /* !SFX || SFX_EXDIR */             /* check for -x or -d */
 
+# if 0
+
     G.filespecs = argc;
     G.xfilespecs = 0;
@@ -1118,9 +1171,9 @@
         while (*++pp) {
             Trace((stderr, "pp - argv = %d\n", pp-argv));
-#ifdef CMS_MVS
+# ifdef CMS_MVS
             if (!uO.exdir && STRNICMP(*pp, "-d", 2) == 0) {
-#else
+# else
             if (!uO.exdir && strncmp(*pp, "-d", 2) == 0) {
-#endif
+# endif
                 int firstarg = (pp == argv);
 
@@ -1177,4 +1230,5 @@
     } else
         G.process_all_files = TRUE;      /* for speed */
+# endif
 
     if (uO.exdir != (char *)NULL && !G.extract_flag)    /* -d ignored */
@@ -1260,4 +1314,269 @@
 
 
+/*
+  -------------------------------------------------------
+  Command Line Options
+  -------------------------------------------------------
+
+  Valid command line options.
+
+  The function get_option() uses this table to check if an
+  option is valid and if it takes a value (also called an
+  option parameter).  To add an option to unzip just add it
+  to this table and add a case in the main switch to handle
+  it.  If either shortopt or longopt not used set to "".
+
+   The fields:
+       option_group - UZO for UnZip option, ZIO for ZipInfo option
+       shortopt     - short option name (1 or 2 chars)
+       longopt      - long option name
+       value_type   - see zip.h for constants
+       negatable    - option is negatable with trailing -
+       ID           - unsigned long int returned for option
+       name         - short description of option which is
+                        returned on some errors and when options
+                        are listed with -so option, can be NULL
+*/
+
+/* Most option IDs are set to the shortopt char.  For
+   multichar short options set to arbitrary unused constant. */
+#define o_so            0x101
+
+
+/* The below is from the old main command line code with a few changes.
+   Note that UnZip and ZipInfo filter out their own options based on the
+   option_group value, so the same option letter can be used for both. */
+
+static struct option_struct far options[] = {
+
+  /* UnZip options */
+
+  /* short longopt                      value_type        negatable
+       ID    name */
+#ifdef RISCOS
+    {UZO, "/",  "",                     o_REQUIRED_VALUE, o_NEGATABLE,
+       '/',  "override Unzip$Exts"},
+#endif
+    {UZO, "a",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'a',  "text conv (EOL char, ASCII->EBCDIC"},
+#if (defined(DLL) && defined(API_DOC))
+    {UZO, "A",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'A',  "extended help for API"},
+#endif
+    {UZO, "b",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'b',  "binary, no ASCII conversions"},
+#ifdef UNIXBACKUP
+    {UZO, "B",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'B',  "back up existing files"},
+#endif
+#ifdef CMS_MVS
+    {UZO, "B",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'b',  "CMS/MVS binary"},
+#endif
+    {UZO, "c",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'c',  "output to stdout"},
+#ifdef CMS_MVS
+    /* for CMS_MVS map to lower case */
+    {UZO, "C",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'C',  "CMS/MVS lower case"},
+#endif
+#if (!defined(SFX) || defined(SFX_EXDIR))
+    {UZO, "d",  "",                     o_REQUIRED_VALUE, o_NEGATABLE,
+       'd',  "extraction root directory"},
+#endif
+#if (!defined(NO_TIMESTAMPS))
+    {UZO, "D",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'D',  "don't restore dir (-DD: any) timestamps"},
+#endif
+    {UZO, "e",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'e',  "extract (not used?)"},
+#ifdef MACOS
+    {UZO, "E",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'E',  "display Mac e.f. when restoring"},
+#endif
+    {UZO, "f",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'f',  "freshen (extract only newer files)"},
+#if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
+    {UZO, "F",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'F',  "Acorn filetype & NFS extension handling"},
+#endif
+    {UZO, "h",  "",                     o_NO_VALUE,       o_NOT_NEGATABLE,
+       'h',  "help"},
+#ifdef MACOS
+    {UZO, "i",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'i',  "ignore filenames stored in Mac ef"},
+#endif
+    {UZO, "j",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'j',  "junk directories, extract names only"},
+#if (defined(ATH_BEO) || defined(MACOS))
+    {UZO, "J",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'J',  "Junk AtheOS, BeOS or MacOS file attrs"},
+#endif
+#ifdef ATH_BEO_UNX
+    {UZO, "K",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'K',  "retain SUID/SGID/Tacky attrs"},
+#endif
+#ifndef SFX
+    {UZO, "l",  "",                     o_NO_VALUE,       o_NEGATABLE,
+        'l',  "listing verbosity"},
+#endif
+#ifndef CMS_MVS
+    {UZO, "L",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'L',  "convert (some) names to lower"},
+#endif
+#ifdef MORE
+# ifdef CMS_MVS
+    {UZO, "m",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'm',  "pipe output through more"},
+# endif
+    {UZO, "M",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'M',  "pipe output through more"},
+#endif /* MORE */
+    {UZO, "n",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'n',  "never overwrite files (no prompting)"},
+#ifdef AMIGA
+    {UZO, "N",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'N',  "restore comments as filenotes"},
+#endif
+    {UZO, "o",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'o',  "overwrite files without prompting"},
+    {UZO, "p",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'p',  "pipe extraction to stdout, no messages"},
+#if CRYPT
+    {UZO, "P",  "",                     o_REQUIRED_VALUE, o_NEGATABLE,
+       'P',  "password"},
+#endif
+    {UZO, "q",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'q',  "quiet"},
+#ifdef QDOS
+    {UZO, "Q",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'Q',  "QDOS flags"},
+#endif
+#ifdef TANDEM
+    {UZO, "r",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'r',  "remove file extensions"},
+#endif
+#ifdef DOS_FLX_NLM_OS2_W32
+    {UZO, "s",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       's',  "spaces to underscores"},
+#endif
+#ifdef VMS
+    {UZO, "S",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'S',  "VMS extract text as Stream LF"},
+#endif
+    {UZO, "t",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       't',  "test"},
+#ifdef TIMESTAMP
+    {UZO, "T",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'T',  "timestamps"},
+#endif
+    {UZO, "u",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'u',  "update (extract only new/newer files)"},
+#ifdef UNICODE_SUPPORT
+    {UZO, "U",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'U',  "escape non-ASCII Unicode, disable Unicode"},
+#else /* !UNICODE_SUPPORT */
+# ifndef CMS_MVS
+    {UZO, "U",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'U',  "names to lower case"},
+# endif /* !CMS_MVS */
+#endif /* ?UNICODE_SUPPORT */
+#ifndef SFX
+    {UZO, "v",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'v',  "verbose"},
+#endif
+#ifndef CMS_MVS
+    {UZO, "V",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'V',  "don't strip VMS version numbers"},
+#endif
+#ifdef WILD_STOP_AT_DIR
+    {UZO, "W",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'W',  "wildcard * doesn't span /"},
+#endif
+    {UZO, "x",  "",                     o_VALUE_LIST,     o_NOT_NEGATABLE,
+       'x',  "exclude this list of files"},
+#if (defined(RESTORE_UIDGID) || defined(RESTORE_ACL))
+    {UZO, "X",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'X',  "restore owner/prot or UID/GID or ACLs"},
+#endif
+#ifdef VMS
+    {UZO, "Y",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'Y',  "VMS treat .nnn as ;nnn version"},
+#endif
+    {UZO, "z",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'z',  "display zipfile comment"},
+#ifndef SFX
+    {UZO, "Z",  "",                     o_NO_VALUE,       o_NOT_NEGATABLE,
+       'Z',  "ZipInfo mode"},
+#endif
+#ifdef VMS
+    {UZO, "2",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       '2',  "Force ODS2-compliant names."},
+#endif
+#ifdef DOS_H68_OS2_W32
+    {UZO, "$",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       '$',  "extract volume labels"},
+#endif
+#if (!defined(RISCOS) && !defined(CMS_MVS) && !defined(TANDEM))
+    {UZO, ":",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       ':',  "don't skip ../ path elements"},
+#endif
+#ifdef UNIX
+    {UZO, "^",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       '^',  "allow control chars in filenames"},
+#endif
+
+#ifndef NO_ZIPINFO
+  /* ZipInfo options */
+
+  /* short longopt                      value_type        negatable
+       ID    name (help text) */
+    {ZIO, "1",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       '1',  "shortest list"},
+    {ZIO, "2",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       '2',  "names and headers"},
+#ifndef CMS_MVS
+    {ZIO, "C",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'C',  "ignore case"},
+#endif
+    {ZIO, "h",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'h',  "header line"},
+    {ZIO, "l",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'l',  "longer listing"},
+    {ZIO, "m",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'm',  "medium listing"},
+#ifdef MORE
+    {ZIO, "M",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'M',  "output like more"},
+#endif
+    {ZIO, "s",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       's',  "shorter list"},
+    {ZIO, "t",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       't',  "totals line"},
+    {ZIO, "T",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'T',  "decimal time format"},
+#ifdef UNICODE_SUPPORT
+    {ZIO, "U",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'U',  "escape non-ASCII Unicode, disable Unicode"},
+#endif
+    {ZIO, "v",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'v',  "turbo-verbose listing"},
+#ifdef WILD_STOP_AT_DIR
+    {ZIO, "W",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'W',  "wild stop at /"},
+#endif
+    {ZIO, "x",  "",                     o_VALUE_LIST,     o_NOT_NEGATABLE,
+       'x',  "exclude this list of files"},
+    {ZIO, "z",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'z',  "print zipfile comment"},
+    {ZIO, "Z",  "",                     o_NO_VALUE,       o_NEGATABLE,
+       'Z',  "ZipInfo mode"},
+#endif /* !NO_ZIPINFO */
+
+    /* the end of the list */
+    {0,   NULL, NULL,                   o_NO_VALUE,       o_NOT_NEGATABLE,
+       0,    NULL} /* end has option_ID = 0 */
+  };
+
 
 
@@ -1271,502 +1590,649 @@
     char ***pargv;
 {
-    char **argv, *s;
-    int argc, c, error=FALSE, negative=0;
+    char **args;
+    int argc, error=FALSE;
 
+    /* used by get_option */
+    unsigned long option; /* option ID returned by get_option */
+    int argcnt = 0;       /* current argcnt in args */
+    int argnum = 0;       /* arg number */
+    int optchar = 0;      /* option state */
+    char *value = NULL;   /* non-option arg, option value or NULL */
+    int negative = 0;     /* 1 = option negated */
+    int fna = 0;          /* current first non-opt arg */
+    int optnum = 0;       /* index in table */
 
-    argc = *pargc;
-    argv = *pargv;
 
-    while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) {
-        s = *argv + 1;
-        while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
-#ifdef CMS_MVS
-            switch (tolower(c))
-#else
-            switch (c)
-#endif
-            {
-                case ('-'):
-                    ++negative;
-                    break;
+    /* since get_option() returns xfiles and files one at a time, store them
+       in linked lists until have them all */
+
+    int file_count = 0;
+    struct file_list *next_file;
+
+    /* files to extract */
+    int in_files_count = 0;
+    struct file_list *in_files = NULL;
+    struct file_list *next_in_files = NULL;
+
+    /* files to exclude in -x list */
+    int in_xfiles_count = 0;
+    struct file_list *in_xfiles = NULL;
+    struct file_list *next_in_xfiles = NULL;
+
+    G.wildzipfn = NULL;
+
+    /* make copy of args that can use with insert_arg() used by get_option() */
+    args = copy_args(*pargv, 0);
+
+
+    /* Initialize lists */
+    G.filespecs = 0;
+    G.xfilespecs = 0;
+
+
+    /*
+    -------------------------------------------
+    Process command line using get_option
+    -------------------------------------------
+
+    Each call to get_option() returns either a command
+    line option and possible value or a non-option argument.
+    Arguments are permuted so that all options (-r, -b temp)
+    are returned before non-option arguments (zipfile).
+    Returns 0 when nothing left to read.
+    */
+
+    /* set argnum = 0 on first call to init get_option */
+    argnum = 0;
+
+    /* get_option returns the option ID and updates parameters:
+           args    - usually same as argv if no argument file support
+           argcnt  - current argc for args
+           value   - char* to value (free() when done with it) or NULL if none
+           negated - option was negated with trailing -
+    */
+
+    while ((option = get_option(UZO, &args, &argcnt, &argnum,
+                                &optchar, &value, &negative,
+                                &fna, &optnum, 0)))
+    {
+        if(option == o_BAD_ERR) {
+          return(PK_PARAM);
+        }
+
+        switch (option)
+        {
 #ifdef RISCOS
-                case ('/'):
-                    if (negative) {   /* negative not allowed with -/ swap */
-                        Info(slide, 0x401, ((char *)slide,
-                          "error:  must give extensions list"));
-                        return(PK_PARAM);  /* don't extract here by accident */
-                    }
-                    exts2swap = s; /* override Unzip$Exts */
-                    s += strlen(s);
-                    break;
-#endif
-                case ('a'):
-                    if (negative) {
-                        uO.aflag = MAX(uO.aflag-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.aflag;
-                    break;
+            case ('/'):
+                if (negative) {   /* negative not allowed with -/ swap */
+                    Info(slide, 0x401, ((char *)slide,
+                      "error:  must give extensions list"));
+                    return(PK_PARAM);  /* don't extract here by accident */
+                }
+                exts2swap = value; /* override Unzip$Exts */
+                break;
+#endif
+            case ('a'):
+                if (negative) {
+                    uO.aflag = MAX(uO.aflag-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.aflag;
+                break;
 #if (defined(DLL) && defined(API_DOC))
-                case ('A'):    /* extended help for API */
-                    APIhelp(__G__ argc, argv);
-                    *pargc = -1;  /* signal to exit successfully */
-                    return 0;
+            case ('A'):    /* extended help for API */
+                APIhelp(__G__ argc, args);
+                *pargc = -1;  /* signal to exit successfully */
+                return 0;
 #endif
-                case ('b'):
-                    if (negative) {
+            case ('b'):
+                if (negative) {
 #if (defined(TANDEM) || defined(VMS))
-                        uO.bflag = MAX(uO.bflag-negative,0);
+                    uO.bflag = MAX(uO.bflag-negative,0);
 #endif
-                        negative = 0;   /* do nothing:  "-b" is default */
-                    } else {
+                    negative = 0;   /* do nothing:  "-b" is default */
+                } else {
 #ifdef VMS
-                        if (uO.aflag == 0)
-                           ++uO.bflag;
+                    if (uO.aflag == 0)
+                       ++uO.bflag;
 #endif
 #ifdef TANDEM
-                        ++uO.bflag;
+                    ++uO.bflag;
 #endif
-                        uO.aflag = 0;
-                    }
-                    break;
+                    uO.aflag = 0;
+                }
+                break;
 #ifdef UNIXBACKUP
-                case ('B'): /* -B: back up existing files */
-                    if (negative)
-                        uO.B_flag = FALSE, negative = 0;
-                    else
-                        uO.B_flag = TRUE;
-                    break;
-#endif
-                case ('c'):
-                    if (negative) {
-                        uO.cflag = FALSE, negative = 0;
+            case ('B'): /* -B: back up existing files */
+                if (negative)
+                    uO.B_flag = FALSE, negative = 0;
+                else
+                    uO.B_flag = TRUE;
+                break;
+#endif
+            case ('c'):
+                if (negative) {
+                    uO.cflag = FALSE, negative = 0;
 #ifdef NATIVE
-                        uO.aflag = 0;
+                    uO.aflag = 0;
 #endif
-                    } else {
-                        uO.cflag = TRUE;
+                } else {
+                    uO.cflag = TRUE;
 #ifdef NATIVE
-                        uO.aflag = 2;   /* so you can read it on the screen */
+                    uO.aflag = 2;   /* so you can read it on the screen */
 #endif
 #ifdef DLL
-                        if (G.redirect_text)
-                            G.redirect_data = 2;
+                    if (G.redirect_text)
+                        G.redirect_data = 2;
 #endif
-                    }
-                    break;
+                }
+                break;
 #ifndef CMS_MVS
-                case ('C'):    /* -C:  match filenames case-insensitively */
-                    if (negative)
-                        uO.C_flag = FALSE, negative = 0;
-                    else
-                        uO.C_flag = TRUE;
-                    break;
+            case ('C'):    /* -C:  match filenames case-insensitively */
+                if (negative)
+                    uO.C_flag = FALSE, negative = 0;
+                else
+                    uO.C_flag = TRUE;
+                break;
 #endif /* !CMS_MVS */
 #if (!defined(SFX) || defined(SFX_EXDIR))
-                case ('d'):
-                    if (negative) {   /* negative not allowed with -d exdir */
+            case ('d'):
+                if (negative) {   /* negative not allowed with -d exdir */
+                    Info(slide, 0x401, ((char *)slide,
+                      LoadFarString(MustGiveExdir)));
+                    return(PK_PARAM);  /* don't extract here by accident */
+                }
+                if (uO.exdir != (char *)NULL) {
+                    Info(slide, 0x401, ((char *)slide,
+                      LoadFarString(OnlyOneExdir)));
+                    return(PK_PARAM);    /* GRR:  stupid restriction? */
+                } else {
+                    /* first check for "-dexdir", then for "-d exdir" */
+                    uO.exdir = value;
+                    if (uO.exdir == NULL || *uO.exdir == '\0') {
                         Info(slide, 0x401, ((char *)slide,
                           LoadFarString(MustGiveExdir)));
-                        return(PK_PARAM);  /* don't extract here by accident */
-                    }
-                    if (uO.exdir != (char *)NULL) {
-                        Info(slide, 0x401, ((char *)slide,
-                          LoadFarString(OnlyOneExdir)));
-                        return(PK_PARAM);    /* GRR:  stupid restriction? */
-                    } else {
-                        /* first check for "-dexdir", then for "-d exdir" */
-                        uO.exdir = s;
-                        if (*uO.exdir == '\0') {
-                            if (argc > 1) {
-                                --argc;
-                                uO.exdir = *++argv;
-                                if (*uO.exdir == '-') {
-                                    Info(slide, 0x401, ((char *)slide,
-                                      LoadFarString(MustGiveExdir)));
-                                    return(PK_PARAM);
-                                }
-                                /* else uO.exdir points at extraction dir */
-                            } else {
-                                Info(slide, 0x401, ((char *)slide,
-                                  LoadFarString(MustGiveExdir)));
-                                return(PK_PARAM);
-                            }
-                        }
-                        /* uO.exdir now points at extraction dir (-dexdir or
-                         *  -d exdir); point s at end of exdir to avoid mis-
-                         *  interpretation of exdir characters as more options
-                         */
-                        if (*s != 0)
-                            while (*++s != 0)
-                                ;
+                        return(PK_PARAM);
                     }
-                    break;
+                    /* else uO.exdir points at extraction dir */
+                }
+                break;
 #endif /* !SFX || SFX_EXDIR */
 #if (!defined(NO_TIMESTAMPS))
-                case ('D'):    /* -D: Skip restoring dir (or any) timestamp. */
-                    if (negative) {
-                        uO.D_flag = MAX(uO.D_flag-negative,0);
-                        negative = 0;
-                    } else
-                        uO.D_flag++;
-                    break;
+            case ('D'):    /* -D: Skip restoring dir (or any) timestamp. */
+                if (negative) {
+                    uO.D_flag = MAX(uO.D_flag-negative,0);
+                    negative = 0;
+                } else
+                    uO.D_flag++;
+                break;
 #endif /* (!NO_TIMESTAMPS) */
-                case ('e'):    /* just ignore -e, -x options (extract) */
-                    break;
+            case ('e'):    /* just ignore -e, -x options (extract) */
+                break;
 #ifdef MACOS
-                case ('E'): /* -E [MacOS] display Mac e.f. when restoring */
-                    if( negative ) {
-                        uO.E_flag = FALSE, negative = 0;
-                    } else {
-                        uO.E_flag = TRUE;
-                    }
-                    break;
+            case ('E'): /* -E [MacOS] display Mac e.f. when restoring */
+                if( negative ) {
+                    uO.E_flag = FALSE, negative = 0;
+                } else {
+                    uO.E_flag = TRUE;
+                }
+                break;
 #endif /* MACOS */
-                case ('f'):    /* "freshen" (extract only newer files) */
-                    if (negative)
-                        uO.fflag = uO.uflag = FALSE, negative = 0;
-                    else
-                        uO.fflag = uO.uflag = TRUE;
-                    break;
+            case ('f'):    /* "freshen" (extract only newer files) */
+                if (negative)
+                    uO.fflag = uO.uflag = FALSE, negative = 0;
+                else
+                    uO.fflag = uO.uflag = TRUE;
+                break;
 #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS))
-                case ('F'):    /* Acorn filetype & NFS extension handling */
-                    if (negative)
-                        uO.acorn_nfs_ext = FALSE, negative = 0;
-                    else
-                        uO.acorn_nfs_ext = TRUE;
-                    break;
+            case ('F'):    /* Acorn filetype & NFS extension handling */
+                if (negative)
+                    uO.acorn_nfs_ext = FALSE, negative = 0;
+                else
+                    uO.acorn_nfs_ext = TRUE;
+                break;
 #endif /* RISCOS || ACORN_FTYPE_NFS */
-                case ('h'):    /* just print help message and quit */
-                    *pargc = -1;
-                    return USAGE(PK_OK);
+            case ('h'):    /* just print help message and quit */
+                *pargc = -1;
+                return USAGE(PK_OK);
 #ifdef MACOS
-                case ('i'): /* -i [MacOS] ignore filenames stored in Mac ef */
-                    if( negative ) {
-                        uO.i_flag = FALSE, negative = 0;
-                    } else {
-                        uO.i_flag = TRUE;
-                    }
-                    break;
+            case ('i'): /* -i [MacOS] ignore filenames stored in Mac ef */
+                if( negative ) {
+                    uO.i_flag = FALSE, negative = 0;
+                } else {
+                    uO.i_flag = TRUE;
+                }
+                break;
 #endif  /* MACOS */
-                case ('j'):    /* junk pathnames/directory structure */
-                    if (negative)
-                        uO.jflag = FALSE, negative = 0;
-                    else
-                        uO.jflag = TRUE;
-                    break;
+            case ('j'):    /* junk pathnames/directory structure */
+                if (negative)
+                    uO.jflag = FALSE, negative = 0;
+                else
+                    uO.jflag = TRUE;
+                break;
 #if (defined(ATH_BEO) || defined(MACOS))
-                case ('J'):    /* Junk AtheOS, BeOS or MacOS file attributes */
-                    if( negative ) {
-                        uO.J_flag = FALSE, negative = 0;
-                    } else {
-                        uO.J_flag = TRUE;
-                    }
-                    break;
+            case ('J'):    /* Junk AtheOS, BeOS or MacOS file attributes */
+                if( negative ) {
+                    uO.J_flag = FALSE, negative = 0;
+                } else {
+                    uO.J_flag = TRUE;
+                }
+                break;
 #endif /* ATH_BEO || MACOS */
 #ifdef ATH_BEO_UNX
-                case ('K'):
-                    if (negative) {
-                        uO.K_flag = FALSE, negative = 0;
-                    } else {
-                        uO.K_flag = TRUE;
-                    }
-                    break;
+            case ('K'):
+                if (negative) {
+                    uO.K_flag = FALSE, negative = 0;
+                } else {
+                    uO.K_flag = TRUE;
+                }
+                break;
 #endif /* ATH_BEO_UNX */
 #ifndef SFX
-                case ('l'):
-                    if (negative) {
-                        uO.vflag = MAX(uO.vflag-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.vflag;
-                    break;
+            case ('l'):
+                if (negative) {
+                    uO.vflag = MAX(uO.vflag-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.vflag;
+                break;
 #endif /* !SFX */
 #ifndef CMS_MVS
-                case ('L'):    /* convert (some) filenames to lowercase */
-                    if (negative) {
-                        uO.L_flag = MAX(uO.L_flag-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.L_flag;
-                    break;
+            case ('L'):    /* convert (some) filenames to lowercase */
+                if (negative) {
+                    uO.L_flag = MAX(uO.L_flag-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.L_flag;
+                break;
 #endif /* !CMS_MVS */
 #ifdef MORE
 #ifdef CMS_MVS
-                case ('m'):
+            case ('m'):
 #endif
-                case ('M'):    /* send all screen output through "more" fn. */
+            case ('M'):    /* send all screen output through "more" fn. */
 /* GRR:  eventually check for numerical argument => height */
-                    if (negative)
-                        G.M_flag = FALSE, negative = 0;
-                    else
-                        G.M_flag = TRUE;
-                    break;
+                if (negative)
+                    G.M_flag = FALSE, negative = 0;
+                else
+                    G.M_flag = TRUE;
+                break;
 #endif /* MORE */
-                case ('n'):    /* don't overwrite any files */
-                    if (negative)
-                        uO.overwrite_none = FALSE, negative = 0;
-                    else
-                        uO.overwrite_none = TRUE;
-                    break;
+            case ('n'):    /* don't overwrite any files */
+                if (negative)
+                    uO.overwrite_none = FALSE, negative = 0;
+                else
+                    uO.overwrite_none = TRUE;
+                break;
 #ifdef AMIGA
-                case ('N'):    /* restore comments as filenotes */
-                    if (negative)
-                        uO.N_flag = FALSE, negative = 0;
-                    else
-                        uO.N_flag = TRUE;
-                    break;
+            case ('N'):    /* restore comments as filenotes */
+                if (negative)
+                    uO.N_flag = FALSE, negative = 0;
+                else
+                    uO.N_flag = TRUE;
+                break;
 #endif /* AMIGA */
-                case ('o'):    /* OK to overwrite files without prompting */
-                    if (negative) {
-                        uO.overwrite_all = MAX(uO.overwrite_all-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.overwrite_all;
-                    break;
-                case ('p'):    /* pipes:  extract to stdout, no messages */
-                    if (negative) {
-                        uO.cflag = FALSE;
-                        uO.qflag = MAX(uO.qflag-999,0);
-                        negative = 0;
-                    } else {
-                        uO.cflag = TRUE;
-                        uO.qflag += 999;
-                    }
-                    break;
+            case ('o'):    /* OK to overwrite files without prompting */
+                if (negative) {
+                    uO.overwrite_all = MAX(uO.overwrite_all-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.overwrite_all;
+                break;
+            case ('p'):    /* pipes:  extract to stdout, no messages */
+                if (negative) {
+                    uO.cflag = FALSE;
+                    uO.qflag = MAX(uO.qflag-999,0);
+                    negative = 0;
+                } else {
+                    uO.cflag = TRUE;
+                    uO.qflag += 999;
+                }
+                break;
 #if CRYPT
-                /* GRR:  yes, this is highly insecure, but dozens of people
-                 * have pestered us for this, so here we go... */
-                case ('P'):
-                    if (negative) {   /* negative not allowed with -P passwd */
-                        Info(slide, 0x401, ((char *)slide,
-                          LoadFarString(MustGivePasswd)));
-                        return(PK_PARAM);  /* don't extract here by accident */
-                    }
-                    if (uO.pwdarg != (char *)NULL) {
+            /* GRR:  yes, this is highly insecure, but dozens of people
+             * have pestered us for this, so here we go... */
+            case ('P'):
+                if (negative) {   /* negative not allowed with -P passwd */
+                    Info(slide, 0x401, ((char *)slide,
+                      LoadFarString(MustGivePasswd)));
+                    return(PK_PARAM);  /* don't extract here by accident */
+                }
+                if (uO.pwdarg != (char *)NULL) {
 /*
-                        GRR:  eventually support multiple passwords?
+                    GRR:  eventually support multiple passwords?
+                    Info(slide, 0x401, ((char *)slide,
+                      LoadFarString(OnlyOnePasswd)));
+                    return(PK_PARAM);
+*/
+                } else {
+                    /* first check for "-Ppasswd", then for "-P passwd" */
+                    uO.pwdarg = value;
+                    if (uO.pwdarg == NULL || *uO.pwdarg == '\0') {
                         Info(slide, 0x401, ((char *)slide,
-                          LoadFarString(OnlyOnePasswd)));
+                          LoadFarString(MustGivePasswd)));
                         return(PK_PARAM);
- */
-                    } else {
-                        /* first check for "-Ppasswd", then for "-P passwd" */
-                        uO.pwdarg = s;
-                        if (*uO.pwdarg == '\0') {
-                            if (argc > 1) {
-                                --argc;
-                                uO.pwdarg = *++argv;
-                                if (*uO.pwdarg == '-') {
-                                    Info(slide, 0x401, ((char *)slide,
-                                      LoadFarString(MustGivePasswd)));
-                                    return(PK_PARAM);
-                                }
-                                /* else pwdarg points at decryption password */
-                            } else {
-                                Info(slide, 0x401, ((char *)slide,
-                                  LoadFarString(MustGivePasswd)));
-                                return(PK_PARAM);
-                            }
-                        }
-                        /* pwdarg now points at decryption password (-Ppasswd or
-                         *  -P passwd); point s at end of passwd to avoid mis-
-                         *  interpretation of passwd characters as more options
-                         */
-                        if (*s != 0)
-                            while (*++s != 0)
-                                ;
+                        /* else pwdarg points at decryption password */
                     }
-                    break;
+                }
+                break;
 #endif /* CRYPT */
-                case ('q'):    /* quiet:  fewer comments/messages */
-                    if (negative) {
-                        uO.qflag = MAX(uO.qflag-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.qflag;
-                    break;
+            case ('q'):    /* quiet:  fewer comments/messages */
+                if (negative) {
+                    uO.qflag = MAX(uO.qflag-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.qflag;
+                break;
 #ifdef QDOS
-                case ('Q'):   /* QDOS flags */
-                    qlflag ^= strtol(s, &s, 10);
-                    break;    /* we XOR this as we can config qlflags */
+            case ('Q'):   /* QDOS flags */
+                qlflag ^= strtol(value, &value, 10);
+                break;    /* we XOR this as we can config qlflags */
 #endif
 #ifdef TANDEM
-                case ('r'):    /* remove file extensions */
-                    if (negative)
-                        uO.rflag = FALSE, negative = 0;
-                    else
-                        uO.rflag = TRUE;
-                    break;
+            case ('r'):    /* remove file extensions */
+                if (negative)
+                    uO.rflag = FALSE, negative = 0;
+                else
+                    uO.rflag = TRUE;
+                break;
 #endif /* TANDEM */
 #ifdef DOS_FLX_NLM_OS2_W32
-                case ('s'):    /* spaces in filenames:  allow by default */
-                    if (negative)
-                        uO.sflag = FALSE, negative = 0;
-                    else
-                        uO.sflag = TRUE;
-                    break;
+            case ('s'):    /* spaces in filenames:  allow by default */
+                if (negative)
+                    uO.sflag = FALSE, negative = 0;
+                else
+                    uO.sflag = TRUE;
+                break;
 #endif /* DOS_FLX_NLM_OS2_W32 */
 #ifdef VMS
-                /* VMS:  extract "text" files in Stream_LF format (-a[a]) */
-                case ('S'):
-                    if (negative)
-                        uO.S_flag = FALSE, negative = 0;
-                    else
-                        uO.S_flag = TRUE;
-                    break;
+            /* VMS:  extract "text" files in Stream_LF format (-a[a]) */
+            case ('S'):
+                if (negative)
+                    uO.S_flag = FALSE, negative = 0;
+                else
+                    uO.S_flag = TRUE;
+                break;
 #endif /* VMS */
-                case ('t'):
-                    if (negative)
-                        uO.tflag = FALSE, negative = 0;
-                    else
-                        uO.tflag = TRUE;
-                    break;
+            case ('t'):
+                if (negative)
+                    uO.tflag = FALSE, negative = 0;
+                else
+                    uO.tflag = TRUE;
+                break;
 #ifdef TIMESTAMP
-                case ('T'):
-                    if (negative)
-                        uO.T_flag = FALSE, negative = 0;
-                    else
-                        uO.T_flag = TRUE;
-                    break;
-#endif
-                case ('u'):    /* update (extract only new and newer files) */
-                    if (negative)
-                        uO.uflag = FALSE, negative = 0;
-                    else
-                        uO.uflag = TRUE;
-                    break;
+            case ('T'):
+                if (negative)
+                    uO.T_flag = FALSE, negative = 0;
+                else
+                    uO.T_flag = TRUE;
+                break;
+#endif
+            case ('u'):    /* update (extract only new and newer files) */
+                if (negative)
+                    uO.uflag = FALSE, negative = 0;
+                else
+                    uO.uflag = TRUE;
+                break;
 #ifdef UNICODE_SUPPORT
-                case ('U'):    /* escape UTF-8, or disable UTF-8 support */
-                    if (negative) {
-                        uO.U_flag = MAX(uO.U_flag-negative,0);
-                        negative = 0;
-                    } else
-                        uO.U_flag++;
-                    break;
+            case ('U'):    /* escape UTF-8, or disable UTF-8 support */
+                if (negative)
+                    uO.U_flag = MAX(uO.U_flag - 1, 0);
+                else
+                    uO.U_flag++;
+                break;
 #else /* !UNICODE_SUPPORT */
 #ifndef CMS_MVS
-                case ('U'):    /* obsolete; to be removed in version 6.0 */
-                    if (negative)
-                        uO.L_flag = TRUE, negative = 0;
-                    else
-                        uO.L_flag = FALSE;
-                    break;
+            case ('U'):    /* obsolete; to be removed in version 6.0 */
+                if (negative)
+                    uO.L_flag = TRUE, negative = 0;
+                else
+                    uO.L_flag = FALSE;
+                break;
 #endif /* !CMS_MVS */
 #endif /* ?UNICODE_SUPPORT */
 #ifndef SFX
-                case ('v'):    /* verbose */
-                    if (negative) {
-                        uO.vflag = MAX(uO.vflag-negative,0);
-                        negative = 0;
-                    } else if (uO.vflag)
-                        ++uO.vflag;
-                    else
-                        uO.vflag = 2;
-                    break;
+            case ('v'):    /* verbose */
+                if (negative) {
+                    uO.vflag = MAX(uO.vflag-negative,0);
+                    negative = 0;
+                } else if (uO.vflag)
+                    ++uO.vflag;
+                else
+                    uO.vflag = 2;
+                break;
 #endif /* !SFX */
 #ifndef CMS_MVS
-                case ('V'):    /* Version (retain VMS/DEC-20 file versions) */
-                    if (negative)
-                        uO.V_flag = FALSE, negative = 0;
-                    else
-                        uO.V_flag = TRUE;
-                    break;
+            case ('V'):    /* Version (retain VMS/DEC-20 file versions) */
+                if (negative)
+                    uO.V_flag = FALSE, negative = 0;
+                else
+                    uO.V_flag = TRUE;
+                break;
 #endif /* !CMS_MVS */
 #ifdef WILD_STOP_AT_DIR
-                case ('W'):    /* Wildcard interpretation (stop at '/'?) */
-                    if (negative)
-                        uO.W_flag = FALSE, negative = 0;
-                    else
-                        uO.W_flag = TRUE;
-                    break;
+            case ('W'):    /* Wildcard interpretation (stop at '/'?) */
+                if (negative)
+                    uO.W_flag = FALSE, negative = 0;
+                else
+                    uO.W_flag = TRUE;
+                break;
 #endif /* WILD_STOP_AT_DIR */
-                case ('x'):    /* extract:  default */
-#ifdef SFX
-                    /* when 'x' is the only option in this argument, and the
-                     * next arg is not an option, assume this initiates an
-                     * exclusion list (-x xlist):  terminate option-scanning
-                     * and leave uz_opts with argv still pointing to "-x";
-                     * the xlist is processed later
-                     */
-                    if (s - argv[0] == 2 && *s == '\0' &&
-                        argc > 1 && argv[1][0] != '-') {
-                        /* break out of nested loops without "++argv;--argc" */
-                        goto opts_done;
+            case ('x'):    /* extract:  default */
+                /* add -x file to linked list */
+
+                if (in_xfiles_count == 0) {
+                    /* first entry */
+                    if ((in_xfiles = (struct file_list *)
+                                     malloc(sizeof(struct file_list))
+                        ) == NULL) {
+                        Info(slide, 0x401, ((char *)slide,
+                          LoadFarString(NoMemArgsList)));
+                        return PK_MEM;
+                    }
+                    in_xfiles->name = value;
+                    in_xfiles->next = NULL;
+                    next_in_xfiles = in_xfiles;
+                } else {
+                    /* add next entry */
+                    if ((next_file = (struct file_list *)
+                                     malloc(sizeof(struct file_list))
+                        ) == NULL) {
+                        Info(slide, 0x401, ((char *)slide,
+                          LoadFarString(NoMemArgsList)));
+                        return PK_MEM;
                     }
+                    next_in_xfiles->next = next_file;
+                    next_file->name = value;
+                    next_file->next = NULL;
+                    next_in_xfiles = next_file;
+                }
+                in_xfiles_count++;
+
+#if 0
+#ifdef SFX
+                /* now get -x list one entry at a time */
+
+
+
+                /* when 'x' is the only option in this argument, and the
+                 * next arg is not an option, assume this initiates an
+                 * exclusion list (-x xlist):  terminate option-scanning
+                 * and leave uz_opts with argv still pointing to "-x";
+                 * the xlist is processed later
+                 */
+                if (s - argv[0] == 2 && *s == '\0' &&
+                    argc > 1 && argv[1][0] != '-') {
+                    /* break out of nested loops without "++argv;--argc" */
+                    goto opts_done;
+                }
 #endif /* SFX */
-                    break;
+#endif
+                break;
 #if (defined(RESTORE_UIDGID) || defined(RESTORE_ACL))
-                case ('X'):   /* restore owner/protection info (need privs?) */
-                    if (negative) {
-                        uO.X_flag = MAX(uO.X_flag-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.X_flag;
-                    break;
+            case ('X'):   /* restore owner/protection info (need privs?) */
+                if (negative) {
+                    uO.X_flag = MAX(uO.X_flag-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.X_flag;
+                break;
 #endif /* RESTORE_UIDGID || RESTORE_ACL */
 #ifdef VMS
-                case ('Y'):    /* Treat ".nnn" as ";nnn" version. */
-                    if (negative)
-                        uO.Y_flag = FALSE, negative = 0;
-                    else
-                        uO.Y_flag = TRUE;
-                    break;
+            case ('Y'):    /* Treat ".nnn" as ";nnn" version. */
+                if (negative)
+                    uO.Y_flag = FALSE, negative = 0;
+                else
+                    uO.Y_flag = TRUE;
+                break;
 #endif /* VMS */
-                case ('z'):    /* display only the archive comment */
-                    if (negative) {
-                        uO.zflag = MAX(uO.zflag-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.zflag;
-                    break;
+            case ('z'):    /* display only the archive comment */
+                if (negative) {
+                    uO.zflag = MAX(uO.zflag-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.zflag;
+                break;
 #ifndef SFX
-                case ('Z'):    /* should have been first option (ZipInfo) */
-                    Info(slide, 0x401, ((char *)slide, LoadFarString(Zfirst)));
-                    error = TRUE;
-                    break;
+            case ('Z'):    /* should have been first option (ZipInfo) */
+                Info(slide, 0x401, ((char *)slide, LoadFarString(Zfirst)));
+                error = TRUE;
+                break;
 #endif /* !SFX */
 #ifdef VMS
-                case ('2'):    /* Force ODS2-compliant names. */
-                    if (negative)
-                        uO.ods2_flag = FALSE, negative = 0;
-                    else
-                        uO.ods2_flag = TRUE;
-                    break;
+            case ('2'):    /* Force ODS2-compliant names. */
+                if (negative)
+                    uO.ods2_flag = FALSE, negative = 0;
+                else
+                    uO.ods2_flag = TRUE;
+                break;
 #endif /* VMS */
 #ifdef DOS_H68_OS2_W32
-                case ('$'):
-                    if (negative) {
-                        uO.volflag = MAX(uO.volflag-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.volflag;
-                    break;
+            case ('$'):
+                if (negative) {
+                    uO.volflag = MAX(uO.volflag-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.volflag;
+                break;
 #endif /* DOS_H68_OS2_W32 */
 #if (!defined(RISCOS) && !defined(CMS_MVS) && !defined(TANDEM))
-                case (':'):    /* allow "parent dir" path components */
-                    if (negative) {
-                        uO.ddotflag = MAX(uO.ddotflag-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.ddotflag;
-                    break;
+            case (':'):    /* allow "parent dir" path components */
+                if (negative) {
+                    uO.ddotflag = MAX(uO.ddotflag-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.ddotflag;
+                break;
 #endif /* !RISCOS && !CMS_MVS && !TANDEM */
 #ifdef UNIX
-                case ('^'):    /* allow control chars in filenames */
-                    if (negative) {
-                        uO.cflxflag = MAX(uO.cflxflag-negative,0);
-                        negative = 0;
-                    } else
-                        ++uO.cflxflag;
-                    break;
+            case ('^'):    /* allow control chars in filenames */
+                if (negative) {
+                    uO.cflxflag = MAX(uO.cflxflag-negative,0);
+                    negative = 0;
+                } else
+                    ++uO.cflxflag;
+                break;
 #endif /* UNIX */
-                default:
-                    error = TRUE;
-                    break;
-
-            } /* end switch */
-        } /* end while (not end of argument string) */
-    } /* end while (not done with switches) */
+            case o_NON_OPTION_ARG:
+                /* not an option */
+                /* no more options as permuting */
+
+
+                if (G.wildzipfn == NULL) {
+                    /* first non-option argument is zip file */
+                    G.wildzipfn = value;
+
+                } else {
+                    /* add include file to list */
+                    if (in_files_count == 0) {
+                        /* first entry */
+                        if ((next_file = (struct file_list *)
+                                         malloc(sizeof(struct file_list))
+                            ) == NULL) {
+                            Info(slide, 0x401, ((char *)slide,
+                              LoadFarString(NoMemArgsList)));
+                            return PK_MEM;
+                        }
+                        next_file->name = value;
+                        next_file->next = NULL;
+                        in_files = next_file;
+                        next_in_files = next_file;
+                    } else {
+                        /* add next entry */
+                        if ((next_file = (struct file_list *)
+                                         malloc(sizeof(struct file_list))
+                            ) == NULL) {
+                            Info(slide, 0x401, ((char *)slide,
+                              LoadFarString(NoMemArgsList)));
+                            return PK_MEM;
+                        }
+                        next_in_files->next = next_file;
+                        next_file->name = value;
+                        next_file->next = NULL;
+                        next_in_files = next_file;
+                    }
+                    in_files_count++;
+                }
+                break;
+            default:
+                error = TRUE;
+                break;
+
+        } /* end switch */
+    } /* get_option() */
+
+
+    /* convert files and xfiles lists to arrays */
+
+    /* convert files list to array */
+    if (in_files_count) {
+      if ((G.pfnames = (char **) malloc((in_files_count + 1) * sizeof(char *))
+          ) == NULL) {
+          Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArgsList)));
+          return PK_MEM;
+      }
+      file_count = 0;
+      for (next_file = in_files; next_file;) {
+          G.pfnames[file_count] = next_file->name;
+          in_files = next_file;
+          next_file = next_file->next;
+          free(in_files);
+          file_count++;
+      }
+      G.pfnames[file_count] = NULL;
+      G.filespecs = in_files_count;
+    }
+
+    /* convert xfiles list to array */
+    if (in_xfiles_count) {
+      if ((G.pxnames = (char **) malloc((in_xfiles_count + 1) * sizeof(char *))
+          ) == NULL) {
+          Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArgsList)));
+          return PK_MEM;
+      }
+      file_count = 0;
+      for (next_file = in_xfiles; next_file;) {
+          G.pxnames[file_count] = next_file->name;
+          in_xfiles = next_file;
+          next_file = next_file->next;
+          free(in_xfiles);
+          file_count++;
+      }
+      G.pxnames[file_count] = NULL;
+      G.xfilespecs = in_xfiles_count;
+    }
+
+    if (in_files_count || in_xfiles_count) {
+        G.process_all_files = FALSE;
+    } else {
+        G.process_all_files = TRUE;      /* for speed */
+    }
+
+
+    /* it's possible the arg count could have been changed by get_option() */
+    argc = arg_count(args);
+
+
 
 /*---------------------------------------------------------------------------
@@ -1774,7 +2240,77 @@
   ---------------------------------------------------------------------------*/
 
+    if ((uO.cflag && (uO.tflag || uO.uflag)) ||
+        (uO.tflag && uO.uflag) || (uO.fflag && uO.overwrite_none))
+    {
+        Info(slide, 0x401, ((char *)slide, LoadFarString(InvalidOptionsMsg)));
+        error = TRUE;
+    }
+    if (uO.aflag > 2)
+        uO.aflag = 2;
+#ifdef VMS
+    if (uO.bflag > 2)
+        uO.bflag = 2;
+    /* Clear -s flag when converting text files. */
+    if (uO.aflag <= 0)
+        uO.S_flag = 0;
+#endif /* VMS */
+    if (uO.overwrite_all && uO.overwrite_none) {
+        Info(slide, 0x401, ((char *)slide, LoadFarString(IgnoreOOptionMsg)));
+        uO.overwrite_all = FALSE;
+    }
+#ifdef MORE
+    if (G.M_flag && !isatty(1))  /* stdout redirected: "more" func. useless */
+        G.M_flag = 0;
+#endif
+
+#ifdef SFX
+    if (error)
+#else
+    if ((G.wildzipfn == NULL) || error)
+#endif
+    {
+        /* tell caller to exit */
+        if (argc <= 2)
+            argc = -1;
+
+        *pargc = argc;
+        *pargv = args;
+#ifndef SFX
+        if (uO.vflag >= 2 && argc == -1) {              /* "unzip -v" */
+            show_version_info(__G);
+            return PK_OK;
+        }
+        if (!G.noargs && !error)
+            error = TRUE;       /* had options (not -h or -v) but no zipfile */
+#endif /* !SFX */
+        return USAGE(error);
+    }
+
 #ifdef SFX
-opts_done:  /* yes, very ugly...but only used by UnZipSFX with -x xlist */
+    /* print our banner unless we're being fairly quiet */
+    if (uO.qflag < 2)
+        Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner),
+          UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
+          LoadFarStringSmall(VersionDate)));
+#ifdef BETA
+    /* always print the beta warning:  no unauthorized distribution!! */
+    Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(BetaVersion), "\n",
+      "SFX"));
+#endif
+#endif /* SFX */
+
+    if (uO.cflag || uO.tflag || uO.vflag || uO.zflag
+#ifdef TIMESTAMP
+                                                     || uO.T_flag
 #endif
+                                                                 )
+        G.extract_flag = FALSE;
+    else
+        G.extract_flag = TRUE;
+
+#if 0
+# ifdef SFX
+opts_done:  /* yes, very ugly...but only used by UnZipSFX with -x xlist */
+# endif
 
     if ((uO.cflag && (uO.tflag || uO.uflag)) ||
@@ -1786,5 +2322,5 @@
     if (uO.aflag > 2)
         uO.aflag = 2;
-#ifdef VMS
+# ifdef VMS
     if (uO.bflag > 2)
         uO.bflag = 2;
@@ -1792,23 +2328,23 @@
     if (uO.aflag <= 0)
         uO.S_flag = 0;
-#endif /* VMS */
+# endif /* VMS */
     if (uO.overwrite_all && uO.overwrite_none) {
         Info(slide, 0x401, ((char *)slide, LoadFarString(IgnoreOOptionMsg)));
         uO.overwrite_all = FALSE;
     }
-#ifdef MORE
+# ifdef MORE
     if (G.M_flag && !isatty(1))  /* stdout redirected: "more" func. useless */
         G.M_flag = 0;
-#endif
+# endif
 
-#ifdef SFX
+# ifdef SFX
     if (error)
-#else
+# else
     if ((argc-- == 0) || error)
-#endif
+# endif
     {
         *pargc = argc;
-        *pargv = argv;
-#ifndef SFX
+        *pargv = args;
+# ifndef SFX
         if (uO.vflag >= 2 && argc == -1) {              /* "unzip -v" */
             show_version_info(__G);
@@ -1817,9 +2353,9 @@
         if (!G.noargs && !error)
             error = TRUE;       /* had options (not -h or -v) but no zipfile */
-#endif /* !SFX */
+# endif /* !SFX */
         return USAGE(error);
     }
 
-#ifdef SFX
+# ifdef SFX
     /* print our banner unless we're being fairly quiet */
     if (uO.qflag < 2)
@@ -1827,22 +2363,23 @@
           UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
           LoadFarStringSmall(VersionDate)));
-#ifdef BETA
+# ifdef BETA
     /* always print the beta warning:  no unauthorized distribution!! */
     Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(BetaVersion), "\n",
       "SFX"));
-#endif
-#endif /* SFX */
+# endif
+# endif /* SFX */
 
     if (uO.cflag || uO.tflag || uO.vflag || uO.zflag
-#ifdef TIMESTAMP
+# ifdef TIMESTAMP
                                                      || uO.T_flag
-#endif
+# endif
                                                                  )
         G.extract_flag = FALSE;
     else
         G.extract_flag = TRUE;
+#endif
 
     *pargc = argc;
-    *pargv = argv;
+    *pargv = args;
     return PK_OK;
 
@@ -2314,2 +2851,1366 @@
 #endif /* !SFX */
 #endif /* !WINDLL */
+
+
+
+
+
+
+/*---------------------------------------------------------------
+ *  Long option support
+ *  8/23/2003
+ *  Updated 3/1/2008 to support UnZip
+ *
+ *  Defines function get_option() to get and process the command
+ *  line options and arguments from argv[].  The caller calls
+ *  get_option() in a loop to get either one option and possible
+ *  value or a non-option argument each loop.
+ *
+ *  This version has been modified to work with UnZip and ZipInfo.
+ *  the major changes are removing the error returns, instead
+ *  passing back error codes for errors, and supporting separate
+ *  groups of options for UnZip and ZipInfo and selecting the option
+ *  group by an argument.
+ *
+ *  This version does not include argument file support and can
+ *  work directly on argv.  The argument file code complicates things and
+ *  it seemed best to leave it out for now.  If argument file support
+ *  (reading in command line arguments stored in a file and inserting into
+ *  command line where @filename is found) is added later the arguments
+ *  can change and a freeable copy of argv will be needed and can be
+ *  created using copy_args in the left out code.
+ *
+ *  Supports short and long options as defined in the array options[]
+ *  in zip.c, multiple short options in an argument (like -jlv), long
+ *  option abbreviation (like --te for --temp-file if --te unique),
+ *  short and long option values (like -b filename or --temp-file filename
+ *  or --temp-file=filename), optional and required values, option negation
+ *  by trailing - (like -S- to not include hidden and system files in MSDOS),
+ *  value lists (like -x a b c), argument permuting (returning all options
+ *  and values before any non-option arguments), and argument files (where
+ *  any non-option non-value argument in form @path gets substituted with
+ *  the white space separated arguments in the text file at path).  In this
+ *  version argument file support has been removed to simplify development
+ *  but may be added later.
+ *
+ *  E. Gordon
+ */
+
+
+/* message output - char casts are needed to handle constants */
+#define oWARN(message) Info(slide, 0x401, ((char *)slide, (char *)message))
+
+
+
+/* Although the below provides some support for multibyte characters
+   the proper thing to do may be to use wide characters and support
+   Unicode.  May get to it soon.  Wide support would likely require
+   the ability to convert the command line to wide strings, which most
+   modern OS should support now.  EG
+ */
+
+/* For now stay with multi-byte characters.  May support wide characters
+   in Zip 3.1 and UnZip 6.1.
+ */
+
+/* multibyte character set support
+   Multibyte characters use typically two or more sequential bytes
+   to represent additional characters than can fit in a single byte
+   character set.  The code used here is based on the ANSI mblen function. */
+#define MB_CLEN(ptr) CLEN(ptr)
+#define MB_NEXTCHAR(ptr) PREINCSTR(ptr)
+
+
+/* constants */
+
+/* function get_args_from_arg_file() can return this in depth parameter */
+#define ARG_FILE_ERR -1
+
+/* internal settings for optchar */
+#define SKIP_VALUE_ARG   -1
+#define THIS_ARG_DONE    -2
+#define START_VALUE_LIST -3
+#define IN_VALUE_LIST    -4
+#define NON_OPTION_ARG   -5
+#define STOP_VALUE_LIST  -6
+/* 7/25/04 EG */
+#define READ_REST_ARGS_VERBATIM -7
+
+
+/* global veriables */
+
+int enable_permute = 1;                     /* yes - return options first */
+/* 7/25/04 EG */
+int doubledash_ends_options = 1;            /* when -- what follows are not options */
+
+/* buffer for error messages (this sizing is a guess but must hold 2 paths) */
+#define OPTIONERR_BUF_SIZE (80+ 2*FILENAME_MAX)
+char optionerrbuf[OPTIONERR_BUF_SIZE + 1];
+
+/* error messages */
+static ZCONST char Far op_not_neg_err[] =
+   "option %s not negatable";
+static ZCONST char Far op_req_val_err[] =
+   "option %s requires a value";
+static ZCONST char Far op_no_allow_val_err[] =
+   "option %s does not allow a value";
+static ZCONST char Far sh_op_not_sup_err[] =
+   "short option '%c' not supported";
+static ZCONST char Far oco_req_val_err[] =
+   "option %s requires one character value";
+static ZCONST char Far oco_no_mbc_err[] =
+   "option %s does not support multibyte values";
+static ZCONST char Far num_req_val_err[] =
+   "option %s requires number value";
+static ZCONST char Far long_op_ambig_err[] =
+   "long option '%s' ambiguous";
+static ZCONST char Far long_op_not_sup_err[] =
+   "long option '%s' not supported";
+
+static ZCONST char Far no_arg_files_err[] = "argument files not enabled\n";
+
+
+/* below removed as only used for processing argument files */
+
+/* get_nextarg */
+/* get_args_from_string */
+/* get_args_from_arg_file */
+
+
+/* copy error, option name, and option description if any to buf */
+static int optionerr(options, buf, err, optind, islong)
+  struct option_struct *options;
+  char *buf;
+  ZCONST char Far *err;
+  int optind;
+  int islong;
+{
+  char optname[50];
+
+  if (options[optind].name && options[optind].name[0] != '\0') {
+    sprintf(optname, "'%s' (%s)",
+            LoadFarStringSmall2(islong ? options[optind].longopt
+                                       : options[optind].shortopt),
+            LoadFarStringSmall(options[optind].name));
+  } else {
+    sprintf(optname, "'%s'",
+            LoadFarStringSmall2(islong ? options[optind].longopt
+                                       : options[optind].shortopt));
+  }
+  sprintf(buf, LoadFarStringSmall(err), optname);
+  return 0;
+}
+
+
+/* copy_args
+ *
+ * Copy arguments in args, allocating storage with malloc.
+ * Copies until a NULL argument is found or until max_args args
+ * including args[0] are copied.  Set max_args to 0 to copy
+ * until NULL.  Always terminates returned args[] with NULL arg.
+ *
+ * Any argument in the returned args can be freed with free().  Any
+ * freed argument should be replaced with either another string
+ * allocated with malloc or by NULL if last argument so that free_args
+ * will properly work.
+ */
+char **copy_args(args, max_args)
+  char **args;
+  int max_args;
+{
+  int j;
+  char **new_args;
+
+  if (args == NULL) {
+    return NULL;
+  }
+
+  /* count args */
+  for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) ;
+
+  if ((new_args = (char **) malloc((j + 1) * sizeof(char *))) == NULL) {
+    oWARN("memory - ca");
+    return NULL;
+  }
+
+  for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) {
+    if (args[j] == NULL) {
+      /* null argument is end of args */
+      new_args[j] = NULL;
+      break;
+    }
+    if ((new_args[j] = malloc(strlen(args[j]) + 1)) == NULL) {
+      free_args(new_args);
+      oWARN("memory - ca");
+      return NULL;
+    }
+    strcpy(new_args[j], args[j]);
+  }
+  new_args[j] = NULL;
+
+  return new_args;
+}
+
+
+/* count args - count args in argv like array */
+int arg_count(args)
+  char **args;
+{
+  int i;
+
+  if (args == NULL) {
+    return 0;
+  }
+
+  for (i = 0; args[i]; i++) {
+  }
+  return i;
+}
+
+
+/* free args - free args created with one of these functions */
+int free_args(args)
+  char **args;
+{
+  int i;
+
+  if (args == NULL) {
+    return 0;
+  }
+
+  for (i = 0; args[i]; i++) {
+    free(args[i]);
+  }
+  free(args);
+  return i;
+}
+
+
+/* insert_arg
+ *
+ * Insert the argument arg into the array args before argument at_arg.
+ * If at_arg = -1 then append to end.
+ * Return the new count of arguments (argc).
+ *
+ * If free_args is true, this function frees the old args array
+ * (but not the component strings).  DO NOT set free_args on original
+ * argv but only on args allocated with malloc.
+ */
+
+int insert_arg(pargs, arg, at_arg, free_args)
+   char ***pargs;
+   ZCONST char *arg;
+   int at_arg;
+   int free_args;
+{
+   char *newarg = NULL;
+   char **args;
+   char **newargs = NULL;
+   int argnum;
+   int newargnum;
+   int argcnt;
+   int newargcnt;
+
+   if (pargs == NULL) {
+     return 0;
+   }
+   args = *pargs;
+
+   /* count args */
+   if (args == NULL) {
+     argcnt = 0;
+   } else {
+     for (argcnt = 0; args[argcnt]; argcnt++) ;
+   }
+   if (arg == NULL) {
+     /* done */
+     return argcnt;
+   }
+   if (at_arg == -1) {
+     at_arg = argcnt;
+   }
+   newargcnt = argcnt + 1;
+
+   /* get storage for new args */
+   if ((newargs = (char **) malloc((newargcnt + 1) * sizeof(char *))) == NULL)
+   {
+     oWARN("memory - ia");
+     return 0;
+   }
+
+   /* copy argument pointers from args to position at_arg, copy the new arg,
+      then copy the rest of the args */
+   argnum = 0;
+   newargnum = 0;
+   if (args) {
+     for (; args[argnum] && argnum < at_arg; argnum++) {
+       newargs[newargnum++] = args[argnum];
+     }
+   }
+   /* copy new arg */
+   if ((newarg = (char *) malloc(strlen(arg) + 1)) == NULL) {
+     oWARN("memory - ia");
+     return 0;
+   }
+   strcpy(newarg, arg);
+
+   newargs[newargnum++] = newarg;
+   if (args) {
+     for ( ; args[argnum]; argnum++) {
+       newargs[newargnum++] = args[argnum];
+     }
+   }
+   newargs[newargnum] = NULL;
+
+   /* free old args array but not component strings - this assumes that
+      args was allocated with malloc as copy_args does.  DO NOT DO THIS
+      on the original argv.
+    */
+   if (free_args)
+     free(args);
+
+   *pargs = newargs;
+
+   return newargnum;
+}
+
+/* ------------------------------------- */
+
+/* get_shortopt
+ *
+ * Get next short option from arg.  The state is stored in argnum, optchar, and
+ * option_num so no static storage is used.  Returns the option_ID.
+ *
+ * parameters:
+ *    option_group - either UZO for UnZip options or ZIO for ZipInfo options
+ *    args         - argv array of arguments
+ *    argnum       - index of current arg in args
+ *    optchar      - pointer to index of next char to process.  Can be 0 or
+ *                   const defined at top of this file like THIS_ARG_DONE
+ *    negated      - on return pointer to int set to 1 if option negated
+ *                   or 0 otherwise
+ *    value        - on return pointer to string set to value of option if any
+ *                   or NULL if none.  If value is returned then the caller
+ *                   should free() it when not needed anymore.
+ *    option_num   - pointer to index in options[] of returned option or
+ *                   o_NO_OPTION_MATCH if none.  Do not change as used by
+ *                   value lists.
+ *    depth        - recursion depth (0 at top level, 1 or more in arg files)
+ */
+static unsigned long get_shortopt(option_group, args, argnum, optchar, negated,
+                                  value, option_num, depth)
+  int option_group;
+  ZCONST char **args;
+  int argnum;
+  int *optchar;
+  int *negated;
+  char **value;
+  int *option_num;
+  int depth;
+{
+  ZCONST char *shortopt;
+  int clen;
+  ZCONST char *nextchar;
+  ZCONST char *s;
+  ZCONST char *start;
+  int op;
+  ZCONST char *arg;
+  int match = -1;
+
+
+  /* get arg */
+  arg = args[argnum];
+  /* current char in arg */
+  nextchar = arg + (*optchar);
+  clen = MB_CLEN(nextchar);
+  /* next char in arg */
+  (*optchar) +=  clen;
+  /* get first char of short option */
+  shortopt = arg + (*optchar);
+  /* no value */
+  *value = NULL;
+
+  if (*shortopt == '\0') {
+    /* no more options in arg */
+    *optchar = 0;
+    *option_num = o_NO_OPTION_MATCH;
+    return 0;
+  }
+
+  /* look for match in options */
+  clen = MB_CLEN(shortopt);
+  for (op = 0; options[op].option_ID; op++) {
+    /* Only look at options in this option group */
+    if (options[op].option_group == option_group) {
+      s = options[op].shortopt;
+      if (s && s[0] == shortopt[0]) {
+        if (s[1] == '\0' && clen == 1) {
+          /* single char match */
+          match = op;
+        } else {
+          /* 2 wide short opt.  Could support more chars but should use long opts instead */
+          if (s[1] == shortopt[1]) {
+            /* match 2 char short opt or 2 byte char */
+            match = op;
+            if (clen == 1) (*optchar)++;
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  if (match > -1) {
+    /* match */
+    clen = MB_CLEN(shortopt);
+    nextchar = arg + (*optchar) + clen;
+    /* check for trailing dash negating option */
+    if (*nextchar == '-') {
+      /* negated */
+      if (options[match].negatable == o_NOT_NEGATABLE) {
+        if (options[match].value_type == o_NO_VALUE) {
+          optionerr(options, optionerrbuf, op_not_neg_err, match, 0);
+          if (depth > 0) {
+            /* unwind */
+            oWARN(optionerrbuf);
+            return o_ARG_FILE_ERR;
+          } else {
+            oWARN(optionerrbuf);
+            return o_BAD_ERR;
+          }
+        }
+      } else {
+        *negated = 1;
+        /* set up to skip negating dash */
+        (*optchar) += clen;
+        clen = 1;
+      }
+    }
+
+    /* value */
+    clen = MB_CLEN(arg + (*optchar));
+    /* optional value, one char value, and number value must follow option */
+    if (options[match].value_type == o_ONE_CHAR_VALUE) {
+      /* one char value */
+      if (arg[(*optchar) + clen]) {
+        /* has value */
+        if (MB_CLEN(arg + (*optchar) + clen) > 1) {
+          /* multibyte value not allowed for now */
+          optionerr(options, optionerrbuf, oco_no_mbc_err, match, 0);
+          if (depth > 0) {
+            /* unwind */
+            oWARN(optionerrbuf);
+            return o_ARG_FILE_ERR;
+          } else {
+            oWARN(optionerrbuf);
+            return o_BAD_ERR;
+          }
+        }
+        if ((*value = (char *) malloc(2)) == NULL) {
+          oWARN("memory - gso");
+          return o_BAD_ERR;
+        }
+        (*value)[0] = *(arg + (*optchar) + clen);
+        (*value)[1] = '\0';
+        *optchar += clen;
+        clen = 1;
+      } else {
+        /* one char values require a value */
+        optionerr(options, optionerrbuf, oco_req_val_err, match, 0);
+        if (depth > 0) {
+          oWARN(optionerrbuf);
+          return o_ARG_FILE_ERR;
+        } else {
+          oWARN(optionerrbuf);
+          return o_BAD_ERR;
+        }
+      }
+    } else if (options[match].value_type == o_NUMBER_VALUE) {
+      /* read chars until end of number */
+      start = arg + (*optchar) + clen;
+      if (*start == '+' || *start == '-') {
+        start++;
+      }
+      s = start;
+      for (; isdigit(*s); MB_NEXTCHAR(s)) ;
+      if (s == start) {
+        /* no digits */
+        optionerr(options, optionerrbuf, num_req_val_err, match, 0);
+        if (depth > 0) {
+          oWARN(optionerrbuf);
+          return o_ARG_FILE_ERR;
+        } else {
+          oWARN(optionerrbuf);
+          return o_BAD_ERR;
+        }
+      }
+      start = arg + (*optchar) + clen;
+      if ((*value = (char *) malloc((int)(s - start) + 1)) == NULL) {
+        oWARN("memory - gso");
+        return o_BAD_ERR;
+      }
+      *optchar += (int)(s - start);
+      strncpy(*value, start, (int)(s - start));
+      (*value)[(int)(s - start)] = '\0';
+      clen = MB_CLEN(s);
+    } else if (options[match].value_type == o_OPTIONAL_VALUE) {
+      /* optional value */
+      /* This seemed inconsistent so now if no value attached to argument look
+         to the next argument if that argument is not an option for option
+         value - 11/12/04 EG */
+      if (arg[(*optchar) + clen]) {
+        /* has value */
+        /* add support for optional = - 2/6/05 EG */
+        if (arg[(*optchar) + clen] == '=') {
+          /* skip = */
+          clen++;
+        }
+        if (arg[(*optchar) + clen]) {
+          if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
+              == NULL) {
+            oWARN("memory - gso");
+            return o_BAD_ERR;
+          }
+          strcpy(*value, arg + (*optchar) + clen);
+        }
+        *optchar = THIS_ARG_DONE;
+      } else if (args[argnum + 1] && args[argnum + 1][0] != '-') {
+        /* use next arg for value */
+        if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
+          oWARN("memory - gso");
+          return o_BAD_ERR;
+        }
+        /* using next arg as value */
+        strcpy(*value, args[argnum + 1]);
+        *optchar = SKIP_VALUE_ARG;
+      }
+    } else if (options[match].value_type == o_REQUIRED_VALUE ||
+               options[match].value_type == o_VALUE_LIST) {
+      /* see if follows option */
+      if (arg[(*optchar) + clen]) {
+        /* has value following option as -ovalue */
+        /* add support for optional = - 6/5/05 EG */
+        if (arg[(*optchar) + clen] == '=') {
+          /* skip = */
+          clen++;
+        }
+        if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
+            == NULL) {
+          oWARN("memory - gso");
+          return o_BAD_ERR;
+        }
+        strcpy(*value, arg + (*optchar) + clen);
+        *optchar = THIS_ARG_DONE;
+      } else {
+        /* use next arg for value */
+        if (args[argnum + 1]) {
+          if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1))
+              == NULL) {
+            oWARN("memory - gso");
+            return o_BAD_ERR;
+          }
+          strcpy(*value, args[argnum + 1]);
+          if (options[match].value_type == o_VALUE_LIST) {
+            *optchar = START_VALUE_LIST;
+          } else {
+            *optchar = SKIP_VALUE_ARG;
+          }
+        } else {
+          /* no value found */
+          optionerr(options, optionerrbuf, op_req_val_err, match, 0);
+          if (depth > 0) {
+            oWARN(optionerrbuf);
+            return o_ARG_FILE_ERR;
+          } else {
+            oWARN(optionerrbuf);
+            return o_BAD_ERR;
+          }
+        }
+      }
+    }
+
+    *option_num = match;
+    return options[match].option_ID;
+  }
+  sprintf(optionerrbuf, LoadFarStringSmall(sh_op_not_sup_err), *shortopt);
+  if (depth > 0) {
+    /* unwind */
+    oWARN(optionerrbuf);
+    return o_ARG_FILE_ERR;
+  } else {
+    oWARN(optionerrbuf);
+    return o_BAD_ERR;
+  }
+  return 0;
+}
+
+
+/* get_longopt
+ *
+ * Get the long option in args array at argnum.
+ * Parameters same as for get_shortopt.
+ */
+
+static unsigned long get_longopt(option_group, args, argnum, optchar, negated,
+                                 value, option_num, depth)
+  int option_group;
+  ZCONST char **args;
+  int argnum;
+  int *optchar;
+  int *negated;
+  char **value;
+  int *option_num;
+  int depth;
+{
+  char *longopt;
+  char *lastchr;
+  char *valuestart;
+  int op;
+  char *arg;
+  int match = -1;
+  *value = NULL;
+
+  if (args == NULL) {
+    *option_num = o_NO_OPTION_MATCH;
+    return 0;
+  }
+  if (args[argnum] == NULL) {
+    *option_num = o_NO_OPTION_MATCH;
+    return 0;
+  }
+  /* copy arg so can chop end if value */
+  if ((arg = (char *)malloc(strlen(args[argnum]) + 1)) == NULL) {
+    oWARN("memory - glo");
+    return o_BAD_ERR;
+  }
+  strcpy(arg, args[argnum]);
+
+  /* get option */
+  longopt = arg + 2;
+  /* no value */
+  *value = NULL;
+
+  /* find = */
+  for (lastchr = longopt, valuestart = longopt;
+       *valuestart && *valuestart != '=';
+       lastchr = valuestart, MB_NEXTCHAR(valuestart)) ;
+  if (*valuestart) {
+    /* found =value */
+    *valuestart = '\0';
+    valuestart++;
+  } else {
+    valuestart = NULL;
+  }
+
+  if (*lastchr == '-') {
+    /* option negated */
+    *negated = 1;
+    *lastchr = '\0';
+  } else {
+    *negated = 0;
+  }
+
+  /* look for long option match */
+  for (op = 0; options[op].option_ID; op++) {
+    /* Only look at options in the option group */
+    if (options[op].option_group == option_group) {
+      if (options[op].longopt &&
+          strcmp(LoadFarStringSmall(options[op].longopt), longopt) == 0) {
+        /* exact match */
+        match = op;
+        break;
+      }
+      if (options[op].longopt &&
+          strncmp(LoadFarStringSmall(options[op].longopt),
+                  longopt, strlen(longopt)) == 0) {
+        if (match > -1) {
+          sprintf(optionerrbuf, LoadFarStringSmall(long_op_ambig_err),
+                  longopt);
+          free(arg);
+          if (depth > 0) {
+            /* unwind */
+            oWARN(optionerrbuf);
+            return o_ARG_FILE_ERR;
+          } else {
+            oWARN(optionerrbuf);
+            return o_BAD_ERR;
+          }
+        }
+        match = op;
+      }
+    }
+  }
+
+  if (match == -1) {
+    sprintf(optionerrbuf, LoadFarStringSmall(long_op_not_sup_err), longopt);
+    free(arg);
+    if (depth > 0) {
+      oWARN(optionerrbuf);
+      return o_ARG_FILE_ERR;
+    } else {
+      oWARN(optionerrbuf);
+      return o_BAD_ERR;
+    }
+  }
+
+  /* one long option an arg */
+  *optchar = THIS_ARG_DONE;
+
+  /* if negated then see if allowed */
+  if (*negated && options[match].negatable == o_NOT_NEGATABLE) {
+    optionerr(options, optionerrbuf, op_not_neg_err, match, 1);
+    free(arg);
+    if (depth > 0) {
+      /* unwind */
+      oWARN(optionerrbuf);
+      return o_ARG_FILE_ERR;
+    } else {
+      oWARN(optionerrbuf);
+      return o_BAD_ERR;
+    }
+  }
+  /* get value */
+  if (options[match].value_type == o_OPTIONAL_VALUE) {
+    /* optional value in form option=value */
+    if (valuestart) {
+      /* option=value */
+      if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
+        free(arg);
+        oWARN("memory - glo");
+        return o_BAD_ERR;
+      }
+      strcpy(*value, valuestart);
+    }
+  } else if (options[match].value_type == o_REQUIRED_VALUE ||
+             options[match].value_type == o_NUMBER_VALUE ||
+             options[match].value_type == o_ONE_CHAR_VALUE ||
+             options[match].value_type == o_VALUE_LIST) {
+    /* handle long option one char and number value as required value */
+    if (valuestart) {
+      /* option=value */
+      if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
+        free(arg);
+        oWARN("memory - glo");
+        return o_BAD_ERR;
+      }
+      strcpy(*value, valuestart);
+    } else {
+      /* use next arg */
+      if (args[argnum + 1]) {
+        if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
+          free(arg);
+          oWARN("memory - glo");
+          return o_BAD_ERR;
+        }
+        /* using next arg as value */
+        strcpy(*value, args[argnum + 1]);
+        if (options[match].value_type == o_VALUE_LIST) {
+          *optchar = START_VALUE_LIST;
+        } else {
+          *optchar = SKIP_VALUE_ARG;
+        }
+      } else {
+        /* no value found */
+        optionerr(options, optionerrbuf, op_req_val_err, match, 1);
+        free(arg);
+        if (depth > 0) {
+          /* unwind */
+          oWARN(optionerrbuf);
+          return o_ARG_FILE_ERR;
+        } else {
+          oWARN(optionerrbuf);
+          return o_BAD_ERR;
+        }
+      }
+    }
+  } else if (options[match].value_type == o_NO_VALUE) {
+    /* this option does not accept a value */
+    if (valuestart) {
+      /* --option=value */
+      optionerr(options, optionerrbuf, op_no_allow_val_err, match, 1);
+      free(arg);
+      if (depth > 0) {
+        oWARN(optionerrbuf);
+        return o_ARG_FILE_ERR;
+      } else {
+        oWARN(optionerrbuf);
+        return o_BAD_ERR;
+      }
+    }
+  }
+  free(arg);
+
+  *option_num = match;
+  return options[match].option_ID;
+}
+
+
+
+/* get_option
+ *
+ * Main interface for user.  Use this function to get options, values and
+ * non-option arguments from a command line provided in argv form.
+ *
+ * To use get_option() first define valid options by setting
+ * the global variable options[] to an array of option_struct.  Also
+ * either change defaults below or make variables global and set elsewhere.
+ * Zip uses below defaults.
+ *
+ * Call get_option() to get an option (like -b or --temp-file) and any
+ * value for that option (like filename for -b) or a non-option argument
+ * (like archive name) each call.  If *value* is not NULL after calling
+ * get_option() it is a returned value and the caller should either store
+ * the char pointer or free() it before calling get_option() again to avoid
+ * leaking memory.  If a non-option non-value argument is returned get_option()
+ * returns o_NON_OPTION_ARG and value is set to the entire argument.
+ * When there are no more arguments get_option() returns 0.
+ *
+ * The parameters argnum (after set to 0 on initial call),
+ * optchar, first_nonopt_arg, option_num, and depth (after initial
+ * call) are set and maintained by get_option() and should not be
+ * changed.  The parameters argc, negated, and value are outputs and
+ * can be used by the calling program.  get_option() returns either the
+ * option_ID for the current option, a special value defined in
+ * zip.h, or 0 when no more arguments.
+ *
+ * The value returned by get_option() is the ID value in the options
+ * table.  This value can be duplicated in the table if different
+ * options are really the same option.  The index into the options[]
+ * table is given by option_num, though the ID should be used as
+ * option numbers change when the table is changed.  The ID must
+ * not be 0 for any option as this ends the table.  If get_option()
+ * finds an option not in the table it calls oERR to post an
+ * error and exit.  Errors also result if the option requires a
+ * value that is missing, a value is present but the option does
+ * not take one, and an option is negated but is not
+ * negatable.  Non-option arguments return o_NON_OPTION_ARG
+ * with the entire argument in value.
+ *
+ * For Zip and UnZip, permuting is on and all options and their values
+ * are returned before any non-option arguments like archive name.
+ *
+ * The arguments "-" alone and "--" alone return as non-option arguments.
+ * Note that "-" should not be used as part of a short option
+ * entry in the table but can be used in the middle of long
+ * options such as in the long option "a-long-option".  Now "--" alone
+ * stops option processing, returning any arguments following "--" as
+ * non-option arguments instead of options.
+ *
+ * Argument file support is removed from this version. It may be added later.
+ *
+ * After each call:
+ *   argc       is set to the current size of args[] but should not change
+ *                with argument file support removed,
+ *   argnum     is the index of the current arg,
+ *   value      is either the value of the returned option or non-option
+ *                argument or NULL if option with no value,
+ *   negated    is set if the option was negated by a trailing dash (-)
+ *   option_num is set to either the index in options[] for the option or
+ *                o_NO_OPTION_MATCH if no match.
+ * Negation is checked before the value is read if the option is negatable so
+ * that the - is not included in the value.  If the option is not negatable
+ * but takes a value then the - will start the value.  If permuting then
+ * argnum and first_nonopt_arg are unreliable and should not be used.
+ *
+ * Command line is read from left to right.  As get_option() finds non-option
+ * arguments (arguments not starting with - and that are not values to options)
+ * it moves later options and values in front of the non-option arguments.
+ * This permuting is turned off by setting enable_permute to 0.  Then
+ * get_option() will return options and non-option arguments in the order
+ * found.  Currently permuting is only done after an argument is completely
+ * processed so that any value can be moved with options they go with.  All
+ * state information is stored in the parameters argnum, optchar,
+ * first_nonopt_arg and option_num.  You should not change these after the
+ * first call to get_option().  If you need to back up to a previous arg then
+ * set argnum to that arg (remembering that args may have been permuted) and
+ * set optchar = 0 and first_nonopt_arg to the first non-option argument if
+ * permuting.  After all arguments are returned the next call to get_option()
+ * returns 0.  The caller can then call free_args(args) if appropriate.
+ *
+ * get_option() accepts arguments in the following forms:
+ *  short options
+ *       of 1 and 2 characters, e.g. a, b, cc, d, and ba, after a single
+ *       leading -, as in -abccdba.  In this example if 'b' is followed by 'a'
+ *       it matches short option 'ba' else it is interpreted as short option
+ *       b followed by another option.  The character - is not legal as a
+ *       short option or as part of a 2 character short option.
+ *
+ *       If a short option has a value it immediately follows the option or
+ *       if that option is the end of the arg then the next arg is used as
+ *       the value.  So if short option e has a value, it can be given as
+ *             -evalue
+ *       or
+ *             -e value
+ *       and now
+ *             -e=value
+ *       but now that = is optional a leading = is stripped for the first.
+ *       This change allows optional short option values to be defaulted as
+ *             -e=
+ *       Either optional or required values can be specified.  Optional values
+ *       now use both forms as ignoring the later got confusing.  Any
+ *       non-value short options can preceed a valued short option as in
+ *             -abevalue
+ *       Some value types (one_char and number) allow options after the value
+ *       so if oc is an option that takes a character and n takes a number
+ *       then
+ *             -abocVccn42evalue
+ *       returns value V for oc and value 42 for n.  All values are strings
+ *       so programs may have to convert the "42" to a number.  See long
+ *       options below for how value lists are handled.
+ *
+ *       Any short option can be negated by following it with -.  Any - is
+ *       handled and skipped over before any value is read unless the option
+ *       is not negatable but takes a value and then - starts the value.
+ *
+ *       If the value for an optional value is just =, then treated as no
+ *       value.
+ *
+ *  long options
+ *       of arbitrary length are assumed if an arg starts with -- but is not
+ *       exactly --.  Long options are given one per arg and can be abbreviated
+ *       if the abbreviation uniquely matches one of the long options.
+ *       Exact matches always match before partial matches.  If ambiguous an
+ *       error is generated.
+ *
+ *       Values are specified either in the form
+ *             --longoption=value
+ *       or can be the following arg if the value is required as in
+ *             --longoption value
+ *       Optional values to long options must be in the first form.
+ *
+ *       Value lists are specified by o_VALUE_LIST and consist of an option
+ *       that takes a value followed by one or more value arguments.
+ *       The two forms are
+ *             --option=value
+ *       or
+ *             -ovalue
+ *       for a single value or
+ *             --option value1 value2 value3 ... --option2
+ *       or
+ *             -o value1 value2 value3 ...
+ *       for a list of values.  The list ends at the next option, the
+ *       end of the command line, or at a single "@" argument.
+ *       Each value is treated as if it was preceeded by the option, so
+ *             --option1 val1 val2
+ *       with option1 value_type set to o_VALUE_LIST is the same as
+ *             --option1=val1 --option1=val2
+ *
+ *       Long options can be negated by following the option with - as in
+ *             --longoption-
+ *       Long options with values can also be negated if this makes sense for
+ *       the caller as:
+ *             --longoption-=value
+ *       If = is not followed by anything it is treated as no value.
+ *
+ *  @path
+ *       Argument files support removed from this version.  It may be added
+ *       back later.
+ *
+ *  non-option argument
+ *       is any argument not given above.  If enable_permute is 1 then
+ *       these are returned after all options, otherwise all options and
+ *       args are returned in order.  Returns option ID o_NON_OPTION_ARG
+ *       and sets value to the argument.
+ *
+ *
+ * Arguments to get_option:
+ *  int option_group       - either UZO for UnZip or ZIO for ZipInfo
+ *  char ***pargs          - pointer to arg array in the argv form
+ *  int *argc              - returns the current argc for args incl. args[0]
+ *  int *argnum            - the index of the current argument (caller
+ *                            should set = 0 on first call and not change
+ *                            after that)
+ *  int *optchar           - index of next short opt in arg or special
+ *  int *first_nonopt_arg  - used by get_option to permute args
+ *  int *negated           - option was negated (had trailing -)
+ *  char *value            - value of option if any (free when done with it)
+ *                            or NULL
+ *  int *option_num        - the index in options of the last option returned
+ *                            (can be o_NO_OPTION_MATCH)
+ *  int recursion_depth    - current depth of recursion
+ *                            (always set to 0 by caller)
+ *                            (always 0 with argument files support removed)
+ *
+ *  Caller should only read the returned option ID and the value, negated,
+ *  and option_num (if required) parameters after each call.
+ *
+ *  Ed Gordon
+ *  8/24/2003 (last updated 3/1/2008 EG)
+ *
+ */
+
+unsigned long get_option(option_group, pargs, argc, argnum, optchar, value,
+                         negated, first_nonopt_arg, option_num, recursion_depth)
+  int option_group;
+  char ***pargs;
+  int *argc;
+  int *argnum;
+  int *optchar;
+  char **value;
+  int *negated;
+  int *first_nonopt_arg;
+  int *option_num;
+  int recursion_depth;
+{
+  char **args;
+  unsigned long option_ID;
+
+  int argcnt;
+  int first_nonoption_arg;
+  char *arg = NULL;
+  int h;
+  int optc;
+  int argn;
+  int j;
+  int v;
+  int read_rest_args_verbatim = 0;  /* 7/25/04 - ignore options and arg files for rest args */
+
+  /* caller should free value or assign it to another
+     variable before calling get_option again. */
+  *value = NULL;
+
+  /* if args is NULL then done */
+  if (pargs == NULL) {
+    *argc = 0;
+    return 0;
+  }
+  args = *pargs;
+  if (args == NULL) {
+    *argc = 0;
+    return 0;
+  }
+
+  /* count args */
+  for (argcnt = 0; args[argcnt]; argcnt++) ;
+
+  /* if no provided args then nothing to do */
+  if (argcnt < 1 || (recursion_depth == 0 && argcnt < 2)) {
+    *argc = argcnt;
+    /* return 0 to note that no args are left */
+    return 0;
+  }
+
+  *negated = 0;
+  first_nonoption_arg = *first_nonopt_arg;
+  argn = *argnum;
+  optc = *optchar;
+
+  if (optc == READ_REST_ARGS_VERBATIM) {
+    read_rest_args_verbatim = 1;
+  }
+
+  if (argn == -1 || (recursion_depth == 0 && argn == 0)) {
+    /* first call */
+    /* if depth = 0 then args[0] is argv[0] so skip */
+    *option_num = o_NO_OPTION_MATCH;
+    optc = THIS_ARG_DONE;
+    first_nonoption_arg = -1;
+  }
+
+  /* if option_num is set then restore last option_ID in case continuing
+     value list */
+  option_ID = 0;
+  if (*option_num != o_NO_OPTION_MATCH) {
+    option_ID = options[*option_num].option_ID;
+  }
+
+  /* get next option if any */
+  for (;;)  {
+    if (read_rest_args_verbatim) {
+      /* rest of args after "--" are non-option args if doubledash_ends_options
+         set */
+      argn++;
+      if (argn > argcnt || args[argn] == NULL) {
+        /* done */
+        option_ID = 0;
+        break;
+      }
+      arg = args[argn];
+      if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+        oWARN("memory - go");
+        return o_BAD_ERR;
+      }
+      strcpy(*value, arg);
+      *option_num = o_NO_OPTION_MATCH;
+      option_ID = o_NON_OPTION_ARG;
+      break;
+
+    /* permute non-option args after option args so options are returned
+       first */
+    } else if (enable_permute) {
+      if (optc == SKIP_VALUE_ARG || optc == THIS_ARG_DONE ||
+          optc == START_VALUE_LIST || optc == IN_VALUE_LIST ||
+          optc == STOP_VALUE_LIST) {
+        /* moved to new arg */
+        if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
+          /* do the permuting - move non-options after this option */
+          /* if option and value separate args or starting list skip option */
+          if (optc == SKIP_VALUE_ARG || optc == START_VALUE_LIST) {
+            v = 1;
+          } else {
+            v = 0;
+          }
+          for (h = first_nonoption_arg; h < argn; h++) {
+            arg = args[first_nonoption_arg];
+            for (j = first_nonoption_arg; j < argn + v; j++) {
+              args[j] = args[j + 1];
+            }
+            args[j] = arg;
+          }
+          first_nonoption_arg += 1 + v;
+        }
+      }
+    } else if (optc == NON_OPTION_ARG) {
+      /* if not permuting then already returned arg */
+      optc = THIS_ARG_DONE;
+    }
+
+    /* value lists */
+    if (optc == STOP_VALUE_LIST) {
+      optc = THIS_ARG_DONE;
+    }
+
+    if (optc == START_VALUE_LIST || optc == IN_VALUE_LIST) {
+      if (optc == START_VALUE_LIST) {
+        /* already returned first value */
+        argn++;
+        optc = IN_VALUE_LIST;
+      }
+      argn++;
+      arg = args[argn];
+      /* if end of args and still in list and there are non-option args then
+         terminate list */
+      if (arg == NULL && (optc == START_VALUE_LIST || optc == IN_VALUE_LIST)
+          && first_nonoption_arg > -1) {
+        /* terminate value list with @ */
+        /* this is only needed for argument files */
+        /* but is also good for show command line so command lines with lists
+           can always be read back in */
+        argcnt = insert_arg(&args, "@", first_nonoption_arg, 1);
+        argn++;
+        if (first_nonoption_arg > -1) {
+          first_nonoption_arg++;
+        }
+      }
+
+      arg = args[argn];
+      if (arg && arg[0] == '@' && arg[1] == '\0') {
+          /* inserted arguments terminator */
+          optc = STOP_VALUE_LIST;
+          continue;
+      } else if (arg && arg[0] != '-') {  /* not option */
+        /* - and -- are not allowed in value lists unless escaped */
+        /* another value in value list */
+        if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
+          oWARN("memory - go");
+          return o_BAD_ERR;
+        }
+        strcpy(*value, args[argn]);
+        break;
+
+      } else {
+        argn--;
+        optc = THIS_ARG_DONE;
+      }
+    }
+
+    /* move to next arg */
+    if (optc == SKIP_VALUE_ARG) {
+      argn += 2;
+      optc = 0;
+    } else if (optc == THIS_ARG_DONE) {
+      argn++;
+      optc = 0;
+    }
+    if (argn > argcnt) {
+      break;
+    }
+    if (args[argn] == NULL) {
+      /* done unless permuting and non-option args */
+      if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
+        /* return non-option arguments at end */
+        if (optc == NON_OPTION_ARG) {
+          first_nonoption_arg++;
+        }
+        /* after first pass args are permuted but skipped over non-option
+           args */
+        /* swap so argn points to first non-option arg */
+        j = argn;
+        argn = first_nonoption_arg;
+        first_nonoption_arg = j;
+      }
+      if (argn > argcnt || args[argn] == NULL) {
+        /* done */
+        option_ID = 0;
+        break;
+      }
+    }
+
+    /* after swap first_nonoption_arg points to end which is NULL */
+    if (first_nonoption_arg > -1 && (args[first_nonoption_arg] == NULL)) {
+      /* only non-option args left */
+      if (optc == NON_OPTION_ARG) {
+        argn++;
+      }
+      if (argn > argcnt || args[argn] == NULL) {
+        /* done */
+        option_ID = 0;
+        break;
+      }
+      if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
+        oWARN("memory - go");
+        return o_BAD_ERR;
+      }
+      strcpy(*value, args[argn]);
+      optc = NON_OPTION_ARG;
+      option_ID = o_NON_OPTION_ARG;
+      break;
+    }
+
+    arg = args[argn];
+
+    /* is it an option */
+    if (arg[0] == '-') {
+      /* option */
+      if (arg[1] == '\0') {
+        /* arg = - */
+        /* treat like non-option arg */
+        *option_num = o_NO_OPTION_MATCH;
+        if (enable_permute) {
+          /* permute args to move all non-option args to end */
+          if (first_nonoption_arg < 0) {
+            first_nonoption_arg = argn;
+          }
+          argn++;
+        } else {
+          /* not permute args so return non-option args when found */
+          if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+            oWARN("memory - go");
+            return o_BAD_ERR;
+          }
+          strcpy(*value, arg);
+          optc = NON_OPTION_ARG;
+          option_ID = o_NON_OPTION_ARG;
+          break;
+        }
+
+      } else if (arg[1] == '-') {
+        /* long option */
+        if (arg[2] == '\0') {
+          /* arg = -- */
+          if (doubledash_ends_options) {
+            /* Now -- stops permuting and forces the rest of
+               the command line to be read verbatim - 7/25/04 EG */
+
+            /* never permute args after -- and return as non-option args */
+            if (first_nonoption_arg < 1) {
+              /* -- is first non-option argument - 8/7/04 EG */
+              argn--;
+            } else {
+              /* go back to start of non-option args - 8/7/04 EG */
+              argn = first_nonoption_arg - 1;
+            }
+
+            /* disable permuting and treat remaining arguments as not
+               options */
+            read_rest_args_verbatim = 1;
+            optc = READ_REST_ARGS_VERBATIM;
+
+          } else {
+            /* treat like non-option arg */
+            *option_num = o_NO_OPTION_MATCH;
+            if (enable_permute) {
+              /* permute args to move all non-option args to end */
+              if (first_nonoption_arg < 0) {
+                first_nonoption_arg = argn;
+              }
+              argn++;
+            } else {
+              /* not permute args so return non-option args when found */
+              if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+                oWARN("memory - go");
+                return o_BAD_ERR;
+              }
+              strcpy(*value, arg);
+              optc = NON_OPTION_ARG;
+              option_ID = o_NON_OPTION_ARG;
+              break;
+            }
+          }
+
+        } else {
+          option_ID = get_longopt(option_group, (ZCONST char **)args, argn,
+                                  &optc, negated,
+                                  value, option_num, recursion_depth);
+          if (option_ID == o_BAD_ERR) {
+            return o_BAD_ERR;
+          } else if (option_ID == o_ARG_FILE_ERR) {
+            /* unwind as only get this if recursion_depth > 0 */
+            return option_ID;
+          }
+          break;
+        }
+
+      } else {
+        /* short option */
+        option_ID = get_shortopt(option_group, (ZCONST char **)args, argn,
+                                 &optc, negated,
+                                 value, option_num, recursion_depth);
+
+        if (option_ID == o_BAD_ERR) {
+          return o_BAD_ERR;
+        } else if (option_ID == o_ARG_FILE_ERR) {
+          /* unwind as only get this if recursion_depth > 0 */
+          return option_ID;
+        }
+
+        if (optc == 0) {
+          /* if optc = 0 then ran out of short opts this arg */
+          optc = THIS_ARG_DONE;
+        } else {
+          break;
+        }
+      }
+
+#if 0
+    /* argument file code left out
+       so for now let filenames start with @
+    */
+
+    } else if (allow_arg_files && arg[0] == '@') {
+      /* arg file */
+      oERR(PK_PARMS, no_arg_files_err);
+#endif
+
+    } else {
+      /* non-option */
+      if (enable_permute) {
+        /* permute args to move all non-option args to end */
+        if (first_nonoption_arg < 0) {
+          first_nonoption_arg = argn;
+        }
+        argn++;
+      } else {
+        /* no permute args so return non-option args when found */
+        if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+          oWARN("memory - go");
+          return o_BAD_ERR;
+        }
+        strcpy(*value, arg);
+        *option_num = o_NO_OPTION_MATCH;
+        optc = NON_OPTION_ARG;
+        option_ID = o_NON_OPTION_ARG;
+        break;
+      }
+
+    }
+  }
+
+  *pargs = args;
+  *argc = argcnt;
+  *first_nonopt_arg = first_nonoption_arg;
+  *argnum = argn;
+  *optchar = optc;
+
+  return option_ID;
+}
diff -ru2 unz60e03/unzpriv.h u6e3_np/unzpriv.h
--- unz60e03/unzpriv.h	Mon Mar 24 11:53:24 2008
+++ u6e3_np/unzpriv.h	Mon Mar 24 14:13:02 2008
@@ -1271,4 +1271,89 @@
 #endif
 
+
+/*--------------------------------------------------------------------
+    Long option support
+    23 August 2003
+    Updated for UnZip 1 March 2008
+    See unzip.c
+  --------------------------------------------------------------------*/
+
+/* The below is for use in the caller-provided options table */
+
+/* option groups */
+#define UZO 1   /* UnZip option */
+#define ZIO 2   /* ZipInfo option */
+
+
+/* value_type - value is always returned as a string. */
+#define o_NO_VALUE        0   /* this option does not take a value */
+#define o_REQUIRED_VALUE  1   /* this option requires a value */
+#define o_OPTIONAL_VALUE  2   /* value is optional (see get_option() for details) */
+#define o_VALUE_LIST      3   /* this option takes a list of values */
+#define o_ONE_CHAR_VALUE  4   /* next char is value (does not end short opt string) */
+#define o_NUMBER_VALUE    5   /* value is integer (does not end short opt string) */
+
+
+/* negatable - a dash following the option (but before any value) sets negated. */
+#define o_NOT_NEGATABLE   0   /* trailing '-' to negate either starts value or generates error */
+#define o_NEGATABLE       1   /* trailing '-' sets negated to TRUE */
+
+
+/* option_num can be this when option not in options table */
+#define o_NO_OPTION_MATCH     -1
+
+/* special values returned by get_option - do not use these as option IDs */
+#define o_NON_OPTION_ARG      ((unsigned long) 0xFFFF)    /* returned for non-option
+                                                             args */
+#define o_ARG_FILE_ERR        ((unsigned long) 0xFFFE)    /* internal recursion
+                                                             return (user never sees) */
+#define o_BAD_ERR             ((unsigned long) 0xFFFD)    /* bad error */
+
+/* options array is set in unzip.c */
+struct option_struct {
+  int option_group;         /* either UZO for UnZip or ZIO for ZipInfo syntax */
+  char Far *shortopt;       /* pointer to short option string */
+  char Far *longopt;        /* pointer to long option string */
+  int  value_type;          /* from above */
+  int  negatable;           /* from above */
+  unsigned long option_ID;  /* value returned by get_option when this option
+                               is found */
+  char Far *name;           /* optional string for option returned on some
+                               errors */
+};
+
+/* structure used to create -x and include file lists */
+struct file_list {
+  char *name;
+  struct file_list *next;
+};
+
+
+/* function prototypes */
+
+/* get the next option from args */
+unsigned long get_option OF((int option_group,
+                             char ***pargs, int *argc, int *argnum,
+                             int *optchar,
+                             char **value, int *negated, int *first_nonopt_arg,
+                             int *option_num, int recursion_depth));
+
+/* copy args - copy an args array, allocating space as needed */
+char **copy_args OF((char **args, int max_args));
+
+/* arg count - count args in argv like array */
+int arg_count OF((char **args));
+
+/* free args - free args created with one of these functions */
+int free_args OF((char **args));
+
+/* insert arg - copy an arg into args */
+int insert_arg OF((char ***args, ZCONST char *arg, int insert_at,
+                   int free_args));
+
+/*--------------------------------------------------------------------
+    End of Long option support
+  --------------------------------------------------------------------*/
+
 /***********************************/
 /*  LARGE_FILE_SUPPORT             */

HEREHERE





diff -ru2 unz60e03/vms/cmdline.c u6e3_np/vms/cmdline.c
--- unz60e03/vms/cmdline.c	Tue Feb 12 01:37:42 2008
+++ u6e3_np/vms/cmdline.c	Mon Mar 24 14:13:10 2008
@@ -34,4 +34,6 @@
 **  Modified by:
 **
+**      02-014          E. Gordon               10-Mar-2008 03:12
+**              Modified to work with get_options().
 **      02-013          S. Schweda, C. Spieler  29-Dec-2007 03:34
 **              Extended /RESTORE qualifier to support timestamp restoration
@@ -172,10 +174,10 @@
 $DESCRIPTOR(cli_text_auto,      "TEXT.AUTO");           /* -a */
 $DESCRIPTOR(cli_text_all,       "TEXT.ALL");            /* -aa */
-$DESCRIPTOR(cli_text_none,      "TEXT.NONE");           /* ---a */
+$DESCRIPTOR(cli_text_none,      "TEXT.NONE");           /* -a- */
 $DESCRIPTOR(cli_text_stmlf,     "TEXT.STMLF");          /* -S */
 $DESCRIPTOR(cli_binary,         "BINARY");              /* -b[b] */
 $DESCRIPTOR(cli_binary_auto,    "BINARY.AUTO");         /* -b */
 $DESCRIPTOR(cli_binary_all,     "BINARY.ALL");          /* -bb */
-$DESCRIPTOR(cli_binary_none,    "BINARY.NONE");         /* ---b */
+$DESCRIPTOR(cli_binary_none,    "BINARY.NONE");         /* -b- */
 $DESCRIPTOR(cli_case_insensitive,"CASE_INSENSITIVE");   /* -C */
 $DESCRIPTOR(cli_screen,         "SCREEN");              /* -c */
@@ -202,5 +204,5 @@
 $DESCRIPTOR(cli_restore_own,    "RESTORE.OWNER_PROT");  /* -X */
 $DESCRIPTOR(cli_restore_date,   "RESTORE.DATE");        /* -DD */
-$DESCRIPTOR(cli_restore_date_all, "RESTORE.DATE.ALL");  /* --D */
+$DESCRIPTOR(cli_restore_date_all, "RESTORE.DATE.ALL");  /* -D- */
 $DESCRIPTOR(cli_restore_date_files, "RESTORE.DATE.FILES"); /* -D */
 $DESCRIPTOR(cli_dot_version,    "DOT_VERSION");         /* -Y */
@@ -299,4 +301,6 @@
 **      SS$_ABORT       - Bad time value
 **
+**  Modified to work with the get_option() command line parser.  10 March 2008
+**
 */
     register unsigned long status;
@@ -419,5 +423,4 @@
         if (status != CLI$_ABSENT) {
             *ptr++ = '-';
-            *ptr++ = '-';
             *ptr++ = 'b';
             if ((status & 1) &&
@@ -427,4 +430,5 @@
                     *ptr++ = 'b';
             }
+            *ptr++ = '-';
         }
 
@@ -436,5 +440,4 @@
         if (status != CLI$_ABSENT) {
             *ptr++ = '-';
-            *ptr++ = '-';
             *ptr++ = 'a';
             if ((status & 1) &&
@@ -446,4 +449,5 @@
                     *ptr++ = 'S';
             }
+            *ptr++ = '-';
         }
 
diff -ru2 unz60e03/zipinfo.c u6e3_np/zipinfo.c
--- unz60e03/zipinfo.c	Mon Mar 24 14:23:54 2008
+++ u6e3_np/zipinfo.c	Mon Mar 24 14:25:24 2008
@@ -171,4 +171,6 @@
 static ZCONST char Far ZipfileCommTruncMsg[] =
   "\ncaution:  zipfile comment truncated\n";
+static ZCONST char Far NoMemArguments[] =
+  "envargs:  cannot get memory for arguments";
 
 static ZCONST char Far CentralDirEntry[] =
@@ -459,10 +461,48 @@
     __GDEF
 {
-    char   **argv, *s;
-    int    argc, c, error=FALSE, negative=0;
+    int    argc, error=FALSE;
     int    hflag_slmv=TRUE, hflag_2=FALSE;  /* diff options => diff defaults */
     int    tflag_slm=TRUE, tflag_2v=FALSE;
     int    explicit_h=FALSE, explicit_t=FALSE;
 
+    char **args;
+
+
+    /* used by get_option */
+    unsigned long option; /* option ID returned by get_option */
+    int argcnt = 0;       /* current argcnt in args */
+    int argnum = 0;       /* arg number */
+    int optchar = 0;      /* option state */
+    char *value = NULL;   /* non-option arg, option value or NULL */
+    int negative = 0;     /* 1 = option negated */
+    int fna = 0;          /* current first non-opt arg */
+    int optnum = 0;       /* index in table */
+
+
+    /* since get_option() returns xfiles and files one at a time, store them in
+       linked lists until have them all */
+
+    int file_count;
+    struct file_list *next_file;
+
+    /* files to extract */
+    int in_files_count = 0;
+    struct file_list *in_files = NULL;
+    struct file_list *next_in_files = NULL;
+
+    /* files to exclude in -x list */
+    int in_xfiles_count = 0;
+    struct file_list *in_xfiles = NULL;
+    struct file_list *next_in_xfiles = NULL;
+
+    G.wildzipfn = NULL;
+
+    /* make copy of args that can use with insert_arg() used by get_option() */
+    args = copy_args(*pargv, 0);
+
+
+    /* Initialize lists */
+    G.filespecs = 0;
+    G.xfilespecs = 0;
 
 #ifdef MACOS
@@ -470,17 +510,41 @@
 #endif
     G.extract_flag = FALSE;   /* zipinfo does not extract to disk */
-    argc = *pargc;
-    argv = *pargv;
 
-    while (--argc > 0 && (*++argv)[0] == '-') {
-        s = argv[0] + 1;
-        while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
-            switch (c) {
-                case '-':
-                    ++negative;
-                    break;
+
+    /*
+    -------------------------------------------
+    Process command line using get_option
+    -------------------------------------------
+
+    Each call to get_option() returns either a command
+    line option and possible value or a non-option argument.
+    Arguments are permuted so that all options (-r, -b temp)
+    are returned before non-option arguments (zipfile).
+    Returns 0 when nothing left to read.
+    */
+
+    /* set argnum = 0 on first call to init get_option */
+    argnum = 0;
+
+    /* get_option returns the option ID and updates parameters:
+           args    - usually same as argv if no argument file support
+           argcnt  - current argc for args
+           value   - char* to value (free() when done with it) or NULL if no value
+           negated - option was negated with trailing -
+    */
+
+    while ((option = get_option(ZIO, &args, &argcnt, &argnum,
+                                &optchar, &value, &negative,
+                                &fna, &optnum, 0)))
+    {
+        if(option == o_BAD_ERR) {
+          return(PK_PARAM);
+        }
+
+        switch (option)
+        {
                 case '1':      /* shortest listing:  JUST filenames */
                     if (negative)
-                        uO.lflag = -2, negative = 0;
+                        uO.lflag = -2;
                     else
                         uO.lflag = 1;
@@ -488,5 +552,5 @@
                 case '2':      /* just filenames, plus headers if specified */
                     if (negative)
-                        uO.lflag = -2, negative = 0;
+                        uO.lflag = -2;
                     else
                         uO.lflag = 2;
@@ -495,5 +559,5 @@
                 case ('C'):    /* -C:  match filenames case-insensitively */
                     if (negative)
-                        uO.C_flag = FALSE, negative = 0;
+                        uO.C_flag = FALSE;
                     else
                         uO.C_flag = TRUE;
@@ -502,5 +566,5 @@
                 case 'h':      /* header line */
                     if (negative)
-                        hflag_2 = hflag_slmv = FALSE, negative = 0;
+                        hflag_2 = hflag_slmv = FALSE;
                     else {
                         hflag_2 = hflag_slmv = explicit_h = TRUE;
@@ -511,5 +575,5 @@
                 case 'l':      /* longer form of "ls -l" type listing */
                     if (negative)
-                        uO.lflag = -2, negative = 0;
+                        uO.lflag = -2;
                     else
                         uO.lflag = 5;
@@ -517,5 +581,5 @@
                 case 'm':      /* medium form of "ls -l" type listing */
                     if (negative)
-                        uO.lflag = -2, negative = 0;
+                        uO.lflag = -2;
                     else
                         uO.lflag = 4;
@@ -524,5 +588,5 @@
                 case 'M':      /* send output through built-in "more" */
                     if (negative)
-                        G.M_flag = FALSE, negative = 0;
+                        G.M_flag = FALSE;
                     else
                         G.M_flag = TRUE;
@@ -531,5 +595,5 @@
                 case 's':      /* default:  shorter "ls -l" type listing */
                     if (negative)
-                        uO.lflag = -2, negative = 0;
+                        uO.lflag = -2;
                     else
                         uO.lflag = 3;
@@ -537,5 +601,5 @@
                 case 't':      /* totals line */
                     if (negative)
-                        tflag_2v = tflag_slm = FALSE, negative = 0;
+                        tflag_2v = tflag_slm = FALSE;
                     else {
                         tflag_2v = tflag_slm = explicit_t = TRUE;
@@ -546,5 +610,5 @@
                 case ('T'):    /* use (sortable) decimal time format */
                     if (negative)
-                        uO.T_flag = FALSE, negative = 0;
+                        uO.T_flag = FALSE;
                     else
                         uO.T_flag = TRUE;
@@ -552,8 +616,7 @@
 #ifdef UNICODE_SUPPORT
                 case ('U'):    /* escape UTF-8, or disable UTF-8 support */
-                    if (negative) {
-                        uO.U_flag = MAX(uO.U_flag-negative,0);
-                        negative = 0;
-                    } else
+                    if (negative)
+                        uO.U_flag = MAX(uO.U_flag - 1, 0);
+                    else
                         uO.U_flag++;
                     break;
@@ -561,5 +624,5 @@
                 case 'v':      /* turbo-verbose listing */
                     if (negative)
-                        uO.lflag = -2, negative = 0;
+                        uO.lflag = -2;
                     else
                         uO.lflag = 10;
@@ -568,12 +631,36 @@
                 case ('W'):    /* Wildcard interpretation (stop at '/'?) */
                     if (negative)
-                        uO.W_flag = FALSE, negative = 0;
+                        uO.W_flag = FALSE;
                     else
                         uO.W_flag = TRUE;
                     break;
 #endif /* WILD_STOP_AT_DIR */
+                case ('x'):    /* extract:  default */
+                    /* add -x file to linked list */
+
+                    if (in_xfiles_count == 0) {
+                        /* first entry */
+                        if ((in_xfiles = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) {
+                            Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
+                            return PK_MEM;
+                        }
+                        in_xfiles->name = value;
+                        in_xfiles->next = NULL;
+                        next_in_xfiles = in_xfiles;
+                    } else {
+                        /* add next entry */
+                        if ((next_file = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) {
+                            Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
+                            return PK_MEM;
+                        }
+                        next_in_xfiles->next = next_file;
+                        next_file->name = value;
+                        next_file->next = NULL;
+                        next_in_xfiles = next_file;
+                    }
+                    in_xfiles_count++;
                 case 'z':      /* print zipfile comment */
                     if (negative)
-                        uO.zflag = negative = 0;
+                        uO.zflag = 0;
                     else
                         uO.zflag = 1;
@@ -581,13 +668,96 @@
                 case 'Z':      /* ZipInfo mode:  ignore */
                     break;
+                case o_NON_OPTION_ARG:
+                    /* not an option */
+                    /* no more options as permuting */
+
+
+                    if (G.wildzipfn == NULL) {
+                        /* first non-option argument is zip file */
+                        G.wildzipfn = value;
+
+                    } else {
+                        /* add include file to list */
+                        if (in_files_count == 0) {
+                            /* first entry */
+                            if ((next_file = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) {
+                                Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
+                                return PK_MEM;
+                            }
+                            next_file->name = value;
+                            next_file->next = NULL;
+                            in_files = next_file;
+                            next_in_files = next_file;
+                        } else {
+                            /* add next entry */
+                            if ((next_file = (struct file_list *) malloc(sizeof(struct file_list))) == NULL) {
+                                Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
+                                return PK_MEM;
+                            }
+                            next_in_files->next = next_file;
+                            next_file->name = value;
+                            next_file->next = NULL;
+                            next_in_files = next_file;
+                        }
+                        in_files_count++;
+                    }
+                    break;
                 default:
                     error = TRUE;
                     break;
-            }
-        }
+        } /* switch */
+    } /* get_option() */
+
+    /* convert files and xfiles lists to arrays */
+
+    /* convert files list to array */
+    if (in_files_count) {
+      if ((G.pfnames = (char **) malloc((in_files_count + 1) * sizeof(char *))) == NULL) {
+          Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
+          return PK_MEM;
+      }
+      file_count = 0;
+      for (next_file = in_files; next_file;) {
+          G.pfnames[file_count] = next_file->name;
+          in_files = next_file;
+          next_file = next_file->next;
+          free(in_files);
+          file_count++;
+      }
+      G.pfnames[file_count] = NULL;
+      G.filespecs = in_files_count;
+    }
+
+    /* convert xfiles list to array */
+    if (in_xfiles_count) {
+      if ((G.pxnames = (char **) malloc((in_xfiles_count + 1) * sizeof(char *))) == NULL) {
+          Info(slide, 0x401, ((char *)slide, LoadFarString(NoMemArguments)));
+          return PK_MEM;
+      }
+      file_count = 0;
+      for (next_file = in_xfiles; next_file;) {
+          G.pxnames[file_count] = next_file->name;
+          in_xfiles = next_file;
+          next_file = next_file->next;
+          free(in_xfiles);
+          file_count++;
+      }
+      G.pxnames[file_count] = NULL;
+      G.xfilespecs = in_xfiles_count;
     }
-    if ((argc-- == 0) || error) {
+
+    if (in_files_count || in_xfiles_count) {
+        G.process_all_files = FALSE;
+    } else {
+        G.process_all_files = TRUE;      /* for speed */
+    }
+
+    /* it's possible the arg count could have been changed by get_option() */
+    argc = arg_count(args);
+
+    if ((G.wildzipfn == NULL) || error) {
+        argc = -1;      /* tell the caller to stop processing */
         *pargc = argc;
-        *pargv = argv;
+        *pargv = args;
         return USAGE(error);
     }
@@ -628,5 +798,5 @@
 
     *pargc = argc;
-    *pargv = argv;
+    *pargv = args;
     return 0;
 
