com32: update getopt() to the current version from klibc
authorH. Peter Anvin <hpa@zytor.com>
Sat, 3 Jul 2010 01:00:42 +0000 (18:00 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Sat, 3 Jul 2010 01:00:42 +0000 (18:00 -0700)
Update getopt() to the current klibc version.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
com32/lib/getopt.c

index 5e9b7c6..806735d 100644 (file)
@@ -9,64 +9,89 @@
 #include <string.h>
 
 char *optarg;
-int optind = 1;
-int opterr, optopt;
-static const char *__optptr;
+int optind, opterr, optopt;
+static struct getopt_private_state {
+       const char *optptr;
+       const char *last_optstring;
+       char *const *last_argv;
+} pvt;
 
 int getopt(int argc, char *const *argv, const char *optstring)
 {
-    const char *carg = argv[optind];
-    const char *osptr;
-    int opt;
+       const char *carg;
+       const char *osptr;
+       int opt;
 
-    /* We don't actually need argc */
-    (void)argc;
+       /* getopt() relies on a number of different global state
+          variables, which can make this really confusing if there is
+          more than one use of getopt() in the same program.  This
+          attempts to detect that situation by detecting if the
+          "optstring" or "argv" argument have changed since last time
+          we were called; if so, reinitialize the query state. */
 
-    /* First, eliminate all non-option cases */
-
-    if (!carg || carg[0] != '-' || !carg[1]) {
-       return -1;
-    }
+       if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
+           optind < 1 || optind > argc) {
+               /* optind doesn't match the current query */
+               pvt.last_optstring = optstring;
+               pvt.last_argv = argv;
+               optind = 1;
+               pvt.optptr = NULL;
+       }
 
-    if (carg[1] == '-' && !carg[2]) {
-       optind++;
-       return -1;
-    }
+       carg = argv[optind];
 
-    if ((uintptr_t) (__optptr - carg) > (uintptr_t) strlen(carg))
-       __optptr = carg + 1;    /* Someone frobbed optind, change to new opt. */
+       /* First, eliminate all non-option cases */
 
-    opt = *__optptr++;
+       if (!carg || carg[0] != '-' || !carg[1]) {
+               return -1;
+       }
 
-    if (opt != ':' && (osptr = strchr(optstring, opt))) {
-       if (osptr[1] == ':') {
-           if (*__optptr) {
-               /* Argument-taking option with attached argument */
-               optarg = (char *)__optptr;
+       if (carg[1] == '-' && !carg[2]) {
                optind++;
-           } else {
-               /* Argument-taking option with non-attached argument */
-               if (argv[optind + 1]) {
-                   optarg = (char *)argv[optind + 1];
-                   optind += 2;
+               return -1;
+       }
+
+       if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
+               /* Someone frobbed optind, change to new opt. */
+               pvt.optptr = carg + 1;
+       }
+
+       opt = *pvt.optptr++;
+
+       if (opt != ':' && (osptr = strchr(optstring, opt))) {
+               if (osptr[1] == ':') {
+                       if (*pvt.optptr) {
+                               /* Argument-taking option with attached
+                                  argument */
+                               optarg = (char *)pvt.optptr;
+                               optind++;
+                       } else {
+                               /* Argument-taking option with non-attached
+                                  argument */
+                               if (argv[optind + 1]) {
+                                       optarg = (char *)argv[optind+1];
+                                       optind += 2;
+                               } else {
+                                       /* Missing argument */
+                                       optind++;
+                                       return (optstring[0] == ':')
+                                               ? ':' : '?';
+                               }
+                       }
+                       return opt;
                } else {
-                   /* Missing argument */
-                   return (optstring[0] == ':') ? ':' : '?';
+                       /* Non-argument-taking option */
+                       /* pvt.optptr will remember the exact position to
+                          resume at */
+                       if (!*pvt.optptr)
+                               optind++;
+                       return opt;
                }
-           }
-           return opt;
        } else {
-           /* Non-argument-taking option */
-           /* __optptr will remember the exact position to resume at */
-           if (!*__optptr)
-               optind++;
-           return opt;
+               /* Unknown option */
+               optopt = opt;
+               if (!*pvt.optptr)
+                       optind++;
+               return '?';
        }
-    } else {
-       /* Unknown option */
-       optopt = opt;
-       if (!*__optptr)
-           optind++;
-       return '?';
-    }
 }