changeset 12473:81590e0c5feb

test-getopt: enhance test Add coverage of optind==0 for getopt_long, since coreutils depends on it. Also test an optstring containing "W;", since that tends to expose corner-case bugs (even in glibc, so the test is weaker than it could be). * m4/getopt.m4 (gl_GETOPT_CHECK_HEADERS): Require that getopt_long supports optind=0. * tests/test-getopt.c (OPTIND_MIN): Move... * tests/test-getopt.h (OPTIND_MIN): ...here. * tests/test-getopt_long.h (test_getopt_long): Add more coverage. Require that optind=0 works, since modern BSD supports it in addition to optreset, and since coreutils expects it. (test_getopt_long_only): New test. * doc/glibc-functions/getopt_long.texi (getopt_long): Document glibc shortcomings with 'W;', and enforcement of optind=0. * doc/glibc-functions/getopt_long_only.texi (getopt_long_only): Likewise.
author Eric Blake <ebb9@byu.net>
date Tue, 01 Dec 2009 17:21:34 -0700
parents b48b6eb9e594
children 266f24fed73e
files ChangeLog doc/glibc-functions/getopt_long.texi doc/glibc-functions/getopt_long_only.texi m4/getopt.m4 tests/test-getopt.c tests/test-getopt.h tests/test-getopt_long.h
diffstat 7 files changed, 1144 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2009-12-22  Eric Blake  <ebb9@byu.net>
+
+	test-getopt: enhance test
+	* m4/getopt.m4 (gl_GETOPT_CHECK_HEADERS): Require that getopt_long
+	supports optind=0.
+	* tests/test-getopt.c (OPTIND_MIN): Move...
+	* tests/test-getopt.h (OPTIND_MIN): ...here.
+	* tests/test-getopt_long.h (test_getopt_long): Add more coverage.
+	Require that optind=0 works, since modern BSD supports it in
+	addition to optreset, and since coreutils expects it.
+	(test_getopt_long_only): New test.
+	* doc/glibc-functions/getopt_long.texi (getopt_long): Document
+	glibc shortcomings with 'W;', and enforcement of optind=0.
+	* doc/glibc-functions/getopt_long_only.texi (getopt_long_only):
+	Likewise.
+
 2009-12-21  Bruno Haible  <bruno@clisp.org>
 
 	localename: Improvements for MacOS X and Cygwin.
--- a/doc/glibc-functions/getopt_long.texi
+++ b/doc/glibc-functions/getopt_long.texi
@@ -15,6 +15,10 @@
 options string when @env{POSIXLY_CORRECT} is set on some platforms:
 Cygwin 1.7.0.
 @item
+Some implementations fail to reset state, including re-checking
+@env{POSIXLY_CORRECT}, when @code{optind} is set to @samp{0}:
+NetBSD, Cygwin 1.7.0.
+@item
 The function @code{getopt_long} does not support options with optional
 arguments on some platforms:
 MacOS X 10.5, OpenBSD 4.0, AIX 5.2, IRIX 6.5, Solaris 10, Cygwin 1.5.x.
@@ -26,9 +30,7 @@
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-The glibc implementation allows a complete reset of the environment,
-including re-checking for @env{POSIXLY_CORRECT}, by setting
-@code{optind} to 0.  Other implementations provide @code{optreset},
-causing a reset by setting it non-zero, although it does not
-necessarily re-read @env{POSIXLY_CORRECT}.
+The glibc extension of using @samp{W;} in the optstring argument to
+allow @code{-W foo} to behave synonymously with @code{--foo} is not
+very reliable, even in glibc.
 @end itemize
--- a/doc/glibc-functions/getopt_long_only.texi
+++ b/doc/glibc-functions/getopt_long_only.texi
@@ -15,6 +15,10 @@
 in the options string when @env{POSIXLY_CORRECT} is set on some platforms:
 Cygwin 1.7.0.
 @item
+Some implementations fail to reset state, including re-checking
+@env{POSIXLY_CORRECT}, when @code{optind} is set to @samp{0}:
+NetBSD, Cygwin 1.7.0.
+@item
 The function @code{getopt_long_only} does not support options with
 optional arguments on some platforms:
 MacOS X 10.5, OpenBSD 4.0, AIX 5.2, Solaris 10, Cygwin 1.5.x.
@@ -27,9 +31,11 @@
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-The glibc implementation allows a complete reset of the environment,
-including re-checking for @env{POSIXLY_CORRECT}, by setting
-@code{optind} to 0.  Other implementations provide @code{optreset},
-causing a reset by setting it non-zero, although it does not
-necessarily re-read @env{POSIXLY_CORRECT}.
+The glibc extension of using @samp{W;} in the optstring argument to
+allow @code{-W foo} to behave synonymously with @code{--foo} is not
+very reliable.
+@item
+Some implementations return success instead of reporting an ambiguity
+if user's option is a prefix of two long options with the same flag:
+FreeBSD.
 @end itemize
--- a/m4/getopt.m4
+++ b/m4/getopt.m4
@@ -88,6 +88,7 @@
   dnl strings starts with '+' and it's not the first call.  Some internal state
   dnl is left over from earlier calls, and neither setting optind = 0 nor
   dnl setting optreset = 1 get rid of this internal state.
+  dnl POSIX is silent on optind vs. optreset, so we allow either behavior.
   if test -z "$gl_replace_getopt"; then
     AC_CACHE_CHECK([whether getopt is POSIX compatible],
       [gl_cv_func_getopt_posix],
@@ -187,6 +188,7 @@
       [# Even with POSIXLY_CORRECT, the GNU extension of leading '-' in the
        # optstring is necessary for programs like m4 that have POSIX-mandated
        # semantics for supporting options interspersed with files.
+       # Also, since getopt_long is a GNU extension, we require optind=0.
        gl_had_POSIXLY_CORRECT=${POSIXLY_CORRECT:+yes}
        POSIXLY_CORRECT=1
        export POSIXLY_CORRECT
@@ -194,11 +196,6 @@
         [AC_LANG_PROGRAM([[#include <getopt.h>
                            #include <stddef.h>
                            #include <string.h>
-#if !HAVE_DECL_OPTRESET
-# define OPTIND_MIN 0
-#else
-# define OPTIND_MIN (optreset = 1)
-#endif
            ]], [[
              /* This code succeeds on glibc 2.8, OpenBSD 4.0, Cygwin, mingw,
                 and fails on MacOS X 10.5, AIX 5.2, HP-UX 11, IRIX 6.5,
@@ -231,7 +228,7 @@
              /* This code succeeds on glibc 2.8 and fails on Cygwin 1.7.0.  */
              {
                char *argv[] = { "program", "foo", "-p", NULL };
-               optind = OPTIND_MIN;
+               optind = 0;
                if (getopt (3, argv, "-p") != 1)
                  return 6;
                if (getopt (3, argv, "-p") != 'p')
--- a/tests/test-getopt.c
+++ b/tests/test-getopt.c
@@ -39,14 +39,6 @@
     }                                                                        \
   while (0)
 
-/* The glibc/gnulib implementation of getopt supports setting optind = 0,
-   but other implementations don't.  */
-#if defined __GETOPT_PREFIX || (__GLIBC__ >= 2)
-# define OPTIND_MIN 0
-#else
-# define OPTIND_MIN 1
-#endif
-
 #include "test-getopt.h"
 #if GNULIB_GETOPT_GNU
 # include "test-getopt_long.h"
@@ -55,6 +47,10 @@
 int
 main (void)
 {
+  /* These default values are required by POSIX.  */
+  ASSERT (optind == 1);
+  ASSERT (opterr != 0);
+
   setenv ("POSIXLY_CORRECT", "1", 1);
   test_getopt ();
 
@@ -67,6 +63,7 @@
 
 #if GNULIB_GETOPT_GNU
   test_getopt_long ();
+  test_getopt_long_only ();
 #endif
 
   return 0;
--- a/tests/test-getopt.h
+++ b/tests/test-getopt.h
@@ -18,6 +18,17 @@
 
 #include <stdbool.h>
 
+/* The glibc/gnulib implementation of getopt supports setting optind =
+   0, but not all other implementations do.  This matters for getopt.
+   But for getopt_long, we require GNU compatibility.  */
+#if defined __GETOPT_PREFIX || (__GLIBC__ >= 2)
+# define OPTIND_MIN 0
+#elif HAVE_DECL_OPTRESET
+# define OPTIND_MIN (optreset = 1)
+#else
+# define OPTIND_MIN 1
+#endif
+
 static void
 getopt_loop (int argc, const char **argv,
              const char *options,
--- a/tests/test-getopt_long.h
+++ b/tests/test-getopt_long.h
@@ -18,13 +18,15 @@
 
 static int a_seen;
 static int b_seen;
+static int q_seen;
 
 static const struct option long_options_required[] =
   {
     { "alpha",    no_argument,       NULL, 'a' },
     { "beta",     no_argument,       &b_seen, 1 },
     { "prune",    required_argument, NULL, 'p' },
-    { "quetsche", required_argument, NULL, 'q' },
+    { "quetsche", required_argument, &q_seen, 1 },
+    { "xtremely-",no_argument,       NULL, 1003 },
     { "xtra",     no_argument,       NULL, 1001 },
     { "xtreme",   no_argument,       NULL, 1002 },
     { "xtremely", no_argument,       NULL, 1003 },
@@ -36,7 +38,7 @@
     { "alpha",    no_argument,       NULL, 'a' },
     { "beta",     no_argument,       &b_seen, 1 },
     { "prune",    optional_argument, NULL, 'p' },
-    { "quetsche", optional_argument, NULL, 'q' },
+    { "quetsche", optional_argument, &q_seen, 1 },
     { NULL,       0,                 NULL, 0 }
   };
 
@@ -47,10 +49,11 @@
                   int *non_options_count, const char **non_options,
                   int *unrecognized)
 {
-  int option_index;
+  int option_index = -1;
   int c;
 
   opterr = 0;
+  q_seen = 0;
   while ((c = getopt_long (argc, (char **) argv, options, long_options,
                            &option_index))
          != -1)
@@ -59,6 +62,8 @@
         {
         case 0:
           /* An option with a non-NULL flag pointer was processed.  */
+          if (q_seen)
+            *q_value = optarg;
           break;
         case 'a':
           a_seen++;
@@ -77,6 +82,12 @@
           ASSERT (options[0] == '-');
           non_options[(*non_options_count)++] = optarg;
           break;
+        case ':':
+          /* Must only happen with option ':' at the beginning.  */
+          ASSERT (options[0] == ':'
+                  || ((options[0] == '-' || options[0] == '+')
+                      && options[1] == ':'));
+          /* fall through */
         case '?':
           *unrecognized = optopt;
           break;
@@ -235,8 +246,76 @@
     ASSERT (c == 1003);
   }
 
-  /* Test processing of boolean options.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  /* Check that -W handles unknown options.  */
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-W";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long (argc, argv, "W;", long_options_required, &option_index);
+    ASSERT (c == '?');
+    ASSERT (optopt == 'W');
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-Wunknown";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long (argc, argv, "W;", long_options_required, &option_index);
+    /* glibc and BSD behave differently here, but for now, we allow
+       both behaviors since W support is not frequently used.  */
+    if (c == '?')
+      {
+        ASSERT (optopt == 0);
+        ASSERT (optarg == NULL);
+      }
+    else
+      {
+        ASSERT (c == 'W');
+        ASSERT (strcmp (optarg, "unknown") == 0);
+      }
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-W";
+    argv[argc++] = "unknown";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long (argc, argv, "W;", long_options_required, &option_index);
+    /* glibc and BSD behave differently here, but for now, we allow
+       both behaviors since W support is not frequently used.  */
+    if (c == '?')
+      {
+        ASSERT (optopt == 0);
+        ASSERT (optarg == NULL);
+      }
+    else
+      {
+        ASSERT (c == 'W');
+        ASSERT (strcmp (optarg, "unknown") == 0);
+      }
+  }
+
+  /* Test processing of boolean short options.  */
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -265,7 +344,7 @@
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
     }
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -295,7 +374,7 @@
       ASSERT (unrecognized == 0);
       ASSERT (optind == 3);
     }
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -324,7 +403,7 @@
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
     }
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -355,8 +434,196 @@
       ASSERT (optind == 3);
     }
 
-  /* Test processing of options with arguments.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  /* Test processing of boolean long options.  */
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "--alpha";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "ab", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "--beta";
+      argv[argc++] = "--alpha";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "ab", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 1);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 3);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "--alpha";
+      argv[argc++] = "--beta";
+      argv[argc++] = "--alpha";
+      argv[argc++] = "--beta";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "ab", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 2);
+      ASSERT (b_seen == 1);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 5);
+    }
+
+  /* Test processing of boolean long options via -W.  */
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-Walpha";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "abW;", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-W";
+      argv[argc++] = "beta";
+      argv[argc++] = "-W";
+      argv[argc++] = "alpha";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "aW;b", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 1);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 5);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-Walpha";
+      argv[argc++] = "-Wbeta";
+      argv[argc++] = "-Walpha";
+      argv[argc++] = "-Wbeta";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "W;ab", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 2);
+      ASSERT (b_seen == 1);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 5);
+    }
+
+  /* Test processing of short options with arguments.  */
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -384,7 +651,7 @@
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
     }
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -413,7 +680,7 @@
       ASSERT (unrecognized == 0);
       ASSERT (optind == 3);
     }
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -445,8 +712,190 @@
       ASSERT (optind == 5);
     }
 
-  /* Test processing of options with optional arguments.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  /* Test processing of long options with arguments.  */
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "--p=foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "p:q:", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "--p";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "p:q:", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 3);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-ab";
+      argv[argc++] = "--q";
+      argv[argc++] = "baz";
+      argv[argc++] = "--p=foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 1);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value != NULL && strcmp (q_value, "baz") == 0);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 5);
+    }
+
+  /* Test processing of long options with arguments via -W.  */
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-Wp=foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "p:q:W;", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-W";
+      argv[argc++] = "p";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "p:W;q:", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 4);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-ab";
+      argv[argc++] = "-Wq";
+      argv[argc++] = "baz";
+      argv[argc++] = "-W";
+      argv[argc++] = "p=foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "W;abp:q:", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 1);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value != NULL && strcmp (q_value, "baz") == 0);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 6);
+    }
+
+  /* Test processing of short options with optional arguments.  */
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -474,7 +923,7 @@
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
     }
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -503,7 +952,7 @@
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
     }
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -533,8 +982,274 @@
       ASSERT (optind == 3);
     }
 
+  /* Test processing of long options with optional arguments.  */
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "--p=foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "p::q::", long_options_optional,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "--p";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "p::q::", long_options_optional,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "--p=";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "p::q::", long_options_optional,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && *p_value == '\0');
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "--p";
+      argv[argc++] = "-a";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "abp::q::", long_options_optional,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 3);
+    }
+
+  /* Test processing of long options with optional arguments via -W.  */
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-Wp=foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "p::q::W;", long_options_optional,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-Wp";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "p::q::W;", long_options_optional,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      /* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */
+      /* ASSERT (p_value == NULL); */
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-Wp=";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "W;p::q::", long_options_optional,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && *p_value == '\0');
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 2);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-W";
+      argv[argc++] = "p=";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "W;p::q::", long_options_optional,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && *p_value == '\0');
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 3);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-W";
+      argv[argc++] = "p";
+      argv[argc++] = "-a";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "W;abp::q::", long_options_optional,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 0);
+      /* ASSERT (p_value == NULL); */
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 4);
+    }
+
   /* Check that invalid options are recognized.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -565,9 +1280,104 @@
       ASSERT (unrecognized == 'x');
       ASSERT (optind == 5);
     }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "-:";
+      argv[argc++] = "-a";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == ':');
+      ASSERT (optind == 5);
+    }
+
+  /* Check that unexpected arguments are recognized.  */
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "--a=";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 'a');
+      ASSERT (optind == 4);
+    }
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "--b=";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      /* When flag is non-zero, glibc sets optopt anyway, but BSD
+         leaves optopt unchanged.  */
+      ASSERT (unrecognized == 1 || unrecognized == 0);
+      ASSERT (optind == 4);
+    }
 
   /* Check that by default, non-options arguments are moved to the end.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -609,7 +1419,7 @@
     }
 
   /* Check that '--' ends the argument processing.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -661,7 +1471,7 @@
     }
 
   /* Check that the '-' flag causes non-options to be returned in order.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -706,7 +1516,7 @@
     }
 
   /* Check that '--' ends the argument processing.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -778,7 +1588,7 @@
     }
 
   /* Check that the '-' flag has to come first.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -821,7 +1631,7 @@
 
   /* Check that the '+' flag causes the first non-option to terminate the
      loop.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -861,7 +1671,7 @@
       ASSERT (unrecognized == 0);
       ASSERT (optind == 1);
     }
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -890,7 +1700,7 @@
     }
 
   /* Check that '--' ends the argument processing.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -942,7 +1752,7 @@
     }
 
   /* Check that the '+' flag has to come first.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -993,8 +1803,50 @@
 {
   int start;
 
+  /* Check that POSIXLY_CORRECT stops parsing the same as leading '+'.  */
+  for (start = 0; start <= 1; start++)
+    {
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      int argc = 0;
+      const char *argv[10];
+      a_seen = 0;
+      b_seen = 0;
+
+      argv[argc++] = "program";
+      argv[argc++] = "donald";
+      argv[argc++] = "-p";
+      argv[argc++] = "billy";
+      argv[argc++] = "duck";
+      argv[argc++] = "-a";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+                        &p_value, &q_value,
+                        &non_options_count, non_options, &unrecognized);
+      ASSERT (strcmp (argv[0], "program") == 0);
+      ASSERT (strcmp (argv[1], "donald") == 0);
+      ASSERT (strcmp (argv[2], "-p") == 0);
+      ASSERT (strcmp (argv[3], "billy") == 0);
+      ASSERT (strcmp (argv[4], "duck") == 0);
+      ASSERT (strcmp (argv[5], "-a") == 0);
+      ASSERT (strcmp (argv[6], "bar") == 0);
+      ASSERT (argv[7] == NULL);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 0);
+      ASSERT (optind == 1);
+    }
+
   /* Check that POSIXLY_CORRECT doesn't change optional arguments.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -1024,7 +1876,7 @@
     }
 
   /* Check that leading - still sees options after non-options.  */
-  for (start = OPTIND_MIN; start <= 1; start++)
+  for (start = 0; start <= 1; start++)
     {
       const char *p_value = NULL;
       const char *q_value = NULL;
@@ -1055,3 +1907,214 @@
       ASSERT (optind == 4);
     }
 }
+
+/* Reduce casting, so we can use string literals elsewhere.
+   getopt_long_only takes an array of char*, but luckily does not
+   modify those elements, so we can pass const char*.  */
+static int
+do_getopt_long_only (int argc, const char **argv, const char *shortopts,
+                     const struct option *longopts, int *longind)
+{
+  return getopt_long_only (argc, (char **) argv, shortopts, longopts, longind);
+}
+
+static void
+test_getopt_long_only (void)
+{
+  /* Test disambiguation of options.  */
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-x";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "ab", long_options_required,
+                             &option_index);
+    ASSERT (c == '?');
+    ASSERT (optopt == 0);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-x";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+                             &option_index);
+    ASSERT (c == 'x');
+    ASSERT (optopt == 0);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "--x";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+                             &option_index);
+    ASSERT (c == '?');
+    ASSERT (optopt == 0);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-b";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    b_seen = 0;
+    c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+                             &option_index);
+    ASSERT (c == 'b');
+    ASSERT (b_seen == 0);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "--b";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    b_seen = 0;
+    c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+                             &option_index);
+    ASSERT (c == 0);
+    ASSERT (b_seen == 1);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-xt";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "ab", long_options_required,
+                             &option_index);
+    ASSERT (c == '?');
+    ASSERT (optopt == 0);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-xt";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+                             &option_index);
+    ASSERT (c == '?');
+    ASSERT (optopt == 0);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-xtra";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "ab", long_options_required,
+                             &option_index);
+    ASSERT (c == 1001);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-xtreme";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "abx:", long_options_required,
+                             &option_index);
+    ASSERT (c == 1002);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-xtremel";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "ab", long_options_required,
+                             &option_index);
+    /* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */
+    /* ASSERT (c == 1003); */
+    ASSERT (optind == 2);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-xtremel";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "abx::", long_options_required,
+                             &option_index);
+    /* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */
+    /* ASSERT (c == 1003); */
+    ASSERT (optind == 2);
+    ASSERT (optarg == NULL);
+  }
+  {
+    int argc = 0;
+    const char *argv[10];
+    int option_index;
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-xtras";
+    argv[argc] = NULL;
+    optind = 1;
+    opterr = 0;
+    c = do_getopt_long_only (argc, argv, "abx::", long_options_required,
+                             &option_index);
+    ASSERT (c == 'x');
+    ASSERT (strcmp (optarg, "tras") == 0);
+  }
+}