changeset 12474:266f24fed73e

test-getopt: test stderr behavior Portions of this commit are commented out because they tickle glibc bugs. For a real-life example of the bug: $ env -ua -: env: invalid option -- : Try `env --help' for more information. $ env -: env: invalid option -- : Try `env --help' for more information. $ env -+ env: invalid option -- + Try `env --help' for more information. $ env -ua -+ Try `env --help' for more information. Notice that when -+ is not given as the first argument, the error message is mistakenly suppressed. * modules/getopt-posix-tests (Depends-on): Add dup2. * tests/test-getopt.c (ASSERT): Avoid stderr. (main): Move stderr to a temporary file. * tests/test-getopt.h (getopt_loop): No longer manipulate opterr. Instead, add parameter to inform caller if output occurred. (test_getopt): Adjust all tests to expect silence, and add new tests of leading ":". * doc/glibc-functions/getopt_long.texi (getopt_long): Document glibc shortcomings with leading "-:" or "+:" in optstring. * doc/glibc-functions/getopt_long_only.texi (getopt_long_only): Likewise. * doc/posix-functions/getopt.texi (getopt): Likewise. Signed-off-by: Eric Blake <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Wed, 02 Dec 2009 15:48:08 -0700
parents 81590e0c5feb
children 93deb54acc5b
files ChangeLog doc/glibc-functions/getopt_long.texi doc/glibc-functions/getopt_long_only.texi doc/posix-functions/getopt.texi modules/getopt-posix-tests tests/test-getopt.c tests/test-getopt.h
diffstat 7 files changed, 427 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2009-12-22  Eric Blake  <ebb9@byu.net>
 
+	test-getopt: test stderr behavior
+	* modules/getopt-posix-tests (Depends-on): Add dup2.
+	* tests/test-getopt.c (ASSERT): Avoid stderr.
+	(main): Move stderr to a temporary file.
+	* tests/test-getopt.h (getopt_loop): No longer manipulate opterr.
+	Instead, add parameter to inform caller if output occurred.
+	(test_getopt): Adjust all existing tests to expect silence, and
+	add new tests of leading ":".
+	* doc/glibc-functions/getopt_long.texi (getopt_long): Document
+	glibc shortcomings with leading "-:" or "+:" in optstring.
+	* doc/glibc-functions/getopt_long_only.texi (getopt_long_only):
+	Likewise.
+	* doc/posix-functions/getopt.texi (getopt): Likewise.
+
 	test-getopt: enhance test
 	* m4/getopt.m4 (gl_GETOPT_CHECK_HEADERS): Require that getopt_long
 	supports optind=0.
--- a/doc/glibc-functions/getopt_long.texi
+++ b/doc/glibc-functions/getopt_long.texi
@@ -33,4 +33,7 @@
 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.
+@item
+Mixing a leading @samp{-} or @samp{+} with a leading @samp{:} in the
+optstring argument has inconsistent effects across platforms.
 @end itemize
--- a/doc/glibc-functions/getopt_long_only.texi
+++ b/doc/glibc-functions/getopt_long_only.texi
@@ -38,4 +38,7 @@
 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.
+@item
+Mixing a leading @samp{-} or @samp{+} with a leading @samp{:} in the
+optstring argument has inconsistent effects across platforms.
 @end itemize
--- a/doc/posix-functions/getopt.texi
+++ b/doc/posix-functions/getopt.texi
@@ -57,4 +57,7 @@
 @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}.
+@item
+Mixing a leading @samp{-} or @samp{+} with a leading @samp{:} in the
+optstring argument has inconsistent effects across platforms.
 @end itemize
--- a/modules/getopt-posix-tests
+++ b/modules/getopt-posix-tests
@@ -4,6 +4,7 @@
 tests/test-getopt_long.h
 
 Depends-on:
+dup2
 setenv
 stdbool
 unistd
--- a/tests/test-getopt.c
+++ b/tests/test-getopt.c
@@ -18,6 +18,13 @@
 
 #include <config.h>
 
+/* None of the files accessed by this test are large, so disable the
+   ftell link warning if we are not using the gnulib ftell module.  */
+#if !GNULIB_FTELL
+# undef GL_LINK_WARNING
+# define GL_LINK_WARNING(ignored) ((void) 0)
+#endif
+
 #if GNULIB_GETOPT_GNU
 # include <getopt.h>
 #endif
@@ -27,13 +34,20 @@
 #include <stdlib.h>
 #include <string.h>
 
+/* This test intentionally remaps stderr.  So, we arrange to have fd 10
+   (outside the range of interesting fd's during the test) set up to
+   duplicate the original stderr.  */
+
+#define BACKUP_STDERR_FILENO 10
+static FILE *myerr;
+
 #define ASSERT(expr) \
   do                                                                         \
     {                                                                        \
       if (!(expr))                                                           \
         {                                                                    \
-          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
-          fflush (stderr);                                                   \
+          fprintf (myerr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
+          fflush (myerr);                                                    \
           abort ();                                                          \
         }                                                                    \
     }                                                                        \
@@ -47,6 +61,14 @@
 int
 main (void)
 {
+   /* This test validates that stderr is used correctly, so move the
+      original into fd 10.  */
+  if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
+      || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
+    return 2;
+
+  ASSERT (freopen ("test-getopt.tmp", "w", stderr) == stderr);
+
   /* These default values are required by POSIX.  */
   ASSERT (optind == 1);
   ASSERT (opterr != 0);
@@ -66,5 +88,8 @@
   test_getopt_long_only ();
 #endif
 
+  ASSERT (fclose (stderr) == 0);
+  ASSERT (remove ("test-getopt.tmp") == 0);
+
   return 0;
 }
--- a/tests/test-getopt.h
+++ b/tests/test-getopt.h
@@ -35,11 +35,11 @@
              int *a_seen, int *b_seen,
              const char **p_value, const char **q_value,
              int *non_options_count, const char **non_options,
-             int *unrecognized)
+             int *unrecognized, bool *message_issued)
 {
   int c;
+  int pos = ftell (stderr);
 
-  opterr = 0;
   while ((c = getopt (argc, (char **) argv, options)) != -1)
     {
       switch (c)
@@ -61,6 +61,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;
@@ -69,6 +75,8 @@
           break;
         }
     }
+
+  *message_issued = pos < ftell (stderr);
 }
 
 static void
@@ -94,6 +102,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -103,9 +112,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "ab",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 1);
       ASSERT (b_seen == 0);
       ASSERT (p_value == NULL);
@@ -113,6 +123,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -123,6 +134,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -133,9 +145,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "ab",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 1);
       ASSERT (b_seen == 1);
       ASSERT (p_value == NULL);
@@ -143,6 +156,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 3);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -153,6 +167,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -162,9 +177,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "ab",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 1);
       ASSERT (b_seen == 1);
       ASSERT (p_value == NULL);
@@ -172,6 +188,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -182,6 +199,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -192,9 +210,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "ab",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 2);
       ASSERT (b_seen == 1);
       ASSERT (p_value == NULL);
@@ -202,6 +221,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 3);
+      ASSERT (!output);
     }
 
   /* Test processing of options with arguments.  */
@@ -214,6 +234,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -222,9 +243,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "p:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 0);
       ASSERT (b_seen == 0);
       ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -232,6 +254,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -242,6 +265,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -251,9 +275,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "p:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 0);
       ASSERT (b_seen == 0);
       ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -261,6 +286,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 3);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -271,6 +297,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -282,9 +309,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 1);
       ASSERT (b_seen == 1);
       ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -292,6 +320,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 5);
+      ASSERT (!output);
     }
 
 #if GNULIB_GETOPT_GNU
@@ -305,6 +334,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -313,9 +343,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "p::q::",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 0);
       ASSERT (b_seen == 0);
       ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -323,6 +354,39 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
+      ASSERT (!output);
+    }
+  for (start = OPTIND_MIN; start <= 1; start++)
+    {
+      int a_seen = 0;
+      int b_seen = 0;
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      bool output;
+      int argc = 0;
+      const char *argv[10];
+
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      opterr = 1;
+      getopt_loop (argc, argv, "p::q::",
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      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);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -333,25 +397,66 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
+      int argc = 0;
+      const char *argv[10];
+
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "-a";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      opterr = 1;
+      getopt_loop (argc, argv, "abp::q::",
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      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);
+      ASSERT (!output);
+    }
+#endif
+
+  /* Check that invalid options are recognized; and that both opterr
+     and leading ':' can silence output.  */
+  for (start = OPTIND_MIN; start <= 1; start++)
+    {
+      int a_seen = 0;
+      int b_seen = 0;
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-p";
       argv[argc++] = "foo";
+      argv[argc++] = "-x";
+      argv[argc++] = "-a";
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
-      getopt_loop (argc, argv, "p::q::",
+      opterr = 42;
+      getopt_loop (argc, argv, "abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
-      ASSERT (a_seen == 0);
+                   &non_options_count, non_options, &unrecognized, &output);
+      ASSERT (a_seen == 1);
       ASSERT (b_seen == 0);
-      ASSERT (p_value == NULL);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
       ASSERT (q_value == NULL);
       ASSERT (non_options_count == 0);
-      ASSERT (unrecognized == 0);
-      ASSERT (optind == 2);
+      ASSERT (unrecognized == 'x');
+      ASSERT (optind == 5);
+      ASSERT (output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -362,29 +467,31 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "-x";
       argv[argc++] = "-a";
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
-      getopt_loop (argc, argv, "abp::q::",
+      opterr = 0;
+      getopt_loop (argc, argv, "abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 1);
       ASSERT (b_seen == 0);
-      ASSERT (p_value == NULL);
+      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
       ASSERT (q_value == NULL);
       ASSERT (non_options_count == 0);
-      ASSERT (unrecognized == 0);
-      ASSERT (optind == 3);
+      ASSERT (unrecognized == 'x');
+      ASSERT (optind == 5);
+      ASSERT (!output);
     }
-#endif
-
-  /* Check that invalid options are recognized.  */
   for (start = OPTIND_MIN; start <= 1; start++)
     {
       int a_seen = 0;
@@ -394,6 +501,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -405,9 +513,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
-      getopt_loop (argc, argv, "abp:q:",
+      opterr = 1;
+      getopt_loop (argc, argv, ":abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 1);
       ASSERT (b_seen == 0);
       ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -415,6 +524,201 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 'x');
       ASSERT (optind == 5);
+      ASSERT (!output);
+    }
+  for (start = OPTIND_MIN; start <= 1; start++)
+    {
+      int a_seen = 0;
+      int b_seen = 0;
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      bool output;
+      int argc = 0;
+      const char *argv[10];
+
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "-:";
+      argv[argc++] = "-a";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      opterr = 42;
+      getopt_loop (argc, argv, "abp:q:",
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      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);
+      ASSERT (output);
+    }
+  for (start = OPTIND_MIN; start <= 1; start++)
+    {
+      int a_seen = 0;
+      int b_seen = 0;
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      bool output;
+      int argc = 0;
+      const char *argv[10];
+
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "-:";
+      argv[argc++] = "-a";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      opterr = 0;
+      getopt_loop (argc, argv, "abp:q:",
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      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);
+      ASSERT (!output);
+    }
+  for (start = OPTIND_MIN; start <= 1; start++)
+    {
+      int a_seen = 0;
+      int b_seen = 0;
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      bool output;
+      int argc = 0;
+      const char *argv[10];
+
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "-:";
+      argv[argc++] = "-a";
+      argv[argc++] = "bar";
+      argv[argc] = NULL;
+      optind = start;
+      opterr = 1;
+      getopt_loop (argc, argv, ":abp:q:",
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      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);
+      ASSERT (!output);
+    }
+
+  /* Check for missing argument behavior.  */
+  for (start = OPTIND_MIN; start <= 1; start++)
+    {
+      int a_seen = 0;
+      int b_seen = 0;
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      bool output;
+      int argc = 0;
+      const char *argv[10];
+
+      argv[argc++] = "program";
+      argv[argc++] = "-ap";
+      argv[argc] = NULL;
+      optind = start;
+      opterr = 1;
+      getopt_loop (argc, argv, "abp:q:",
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 'p');
+      ASSERT (optind == 2);
+      ASSERT (output);
+    }
+  for (start = OPTIND_MIN; start <= 1; start++)
+    {
+      int a_seen = 0;
+      int b_seen = 0;
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      bool output;
+      int argc = 0;
+      const char *argv[10];
+
+      argv[argc++] = "program";
+      argv[argc++] = "-ap";
+      argv[argc] = NULL;
+      optind = start;
+      opterr = 0;
+      getopt_loop (argc, argv, "abp:q:",
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 'p');
+      ASSERT (optind == 2);
+      ASSERT (!output);
+    }
+  for (start = OPTIND_MIN; start <= 1; start++)
+    {
+      int a_seen = 0;
+      int b_seen = 0;
+      const char *p_value = NULL;
+      const char *q_value = NULL;
+      int non_options_count = 0;
+      const char *non_options[10];
+      int unrecognized = 0;
+      bool output;
+      int argc = 0;
+      const char *argv[10];
+
+      argv[argc++] = "program";
+      argv[argc++] = "-ap";
+      argv[argc] = NULL;
+      optind = start;
+      opterr = 1;
+      getopt_loop (argc, argv, ":abp:q:",
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      ASSERT (a_seen == 1);
+      ASSERT (b_seen == 0);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 'p');
+      ASSERT (optind == 2);
+      ASSERT (!output);
     }
 
   /* Check that by default, non-options arguments are moved to the end.  */
@@ -427,6 +731,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -439,9 +744,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       if (posixly)
         {
           ASSERT (strcmp (argv[0], "program") == 0);
@@ -459,6 +765,7 @@
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 1);
+          ASSERT (!output);
         }
       else
         {
@@ -477,6 +784,7 @@
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 4);
+          ASSERT (!output);
         }
     }
 
@@ -490,6 +798,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[20];
 
@@ -507,9 +816,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       if (posixly)
         {
           ASSERT (strcmp (argv[0], "program") == 0);
@@ -532,6 +842,7 @@
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 1);
+          ASSERT (!output);
         }
       else
         {
@@ -555,6 +866,7 @@
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 5);
+          ASSERT (!output);
         }
     }
 
@@ -569,6 +881,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -581,9 +894,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "-abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (strcmp (argv[0], "program") == 0);
       ASSERT (strcmp (argv[1], "donald") == 0);
       ASSERT (strcmp (argv[2], "-p") == 0);
@@ -602,6 +916,7 @@
       ASSERT (strcmp (non_options[2], "bar") == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 7);
+      ASSERT (!output);
     }
 
   /* Check that '--' ends the argument processing.  */
@@ -614,6 +929,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[20];
 
@@ -631,9 +947,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "-abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (strcmp (argv[0], "program") == 0);
       ASSERT (strcmp (argv[1], "donald") == 0);
       ASSERT (strcmp (argv[2], "-p") == 0);
@@ -651,6 +968,7 @@
       ASSERT (b_seen == 0);
       ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0);
       ASSERT (q_value == NULL);
+      ASSERT (!output);
       if (non_options_count == 2)
         {
           /* glibc behaviour.  */
@@ -687,6 +1005,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -699,9 +1018,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "abp:q:-",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       if (posixly)
         {
           ASSERT (strcmp (argv[0], "program") == 0);
@@ -719,6 +1039,7 @@
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 1);
+          ASSERT (!output);
         }
       else
         {
@@ -737,6 +1058,7 @@
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 4);
+          ASSERT (!output);
         }
     }
 
@@ -751,6 +1073,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -763,9 +1086,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "+abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (strcmp (argv[0], "program") == 0);
       ASSERT (strcmp (argv[1], "donald") == 0);
       ASSERT (strcmp (argv[2], "-p") == 0);
@@ -781,6 +1105,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 1);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -791,6 +1116,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -798,9 +1124,13 @@
       argv[argc++] = "-+";
       argv[argc] = NULL;
       optind = start;
+      /* Suppress output, since glibc is inconsistent on whether this
+         prints a message:
+         http://sources.redhat.com/bugzilla/show_bug.cgi?id=11039 */
+      opterr = 0;
       getopt_loop (argc, argv, "+abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 0);
       ASSERT (b_seen == 0);
       ASSERT (p_value == NULL);
@@ -808,6 +1138,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == '+');
       ASSERT (optind == 2);
+      ASSERT (!output);
     }
 
   /* Check that '--' ends the argument processing.  */
@@ -820,6 +1151,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[20];
 
@@ -837,9 +1169,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "+abp:q:",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (strcmp (argv[0], "program") == 0);
       ASSERT (strcmp (argv[1], "donald") == 0);
       ASSERT (strcmp (argv[2], "-p") == 0);
@@ -860,6 +1193,7 @@
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind = 1);
+      ASSERT (!output);
     }
 
   /* Check that the '+' flag has to come first.  */
@@ -872,6 +1206,7 @@
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -884,9 +1219,10 @@
       argv[argc++] = "bar";
       argv[argc] = NULL;
       optind = start;
+      opterr = 1;
       getopt_loop (argc, argv, "abp:q:+",
                    &a_seen, &b_seen, &p_value, &q_value,
-                   &non_options_count, non_options, &unrecognized);
+                   &non_options_count, non_options, &unrecognized, &output);
       if (posixly)
         {
           ASSERT (strcmp (argv[0], "program") == 0);
@@ -904,6 +1240,7 @@
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 1);
+          ASSERT (!output);
         }
       else
         {
@@ -922,6 +1259,10 @@
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 4);
+          ASSERT (!output);
         }
     }
+
+  /* No tests of "-:..." or "+:...", due to glibc bug:
+     http://sources.redhat.com/bugzilla/show_bug.cgi?id=11039 */
 }