error: depend on stdio
[gnulib.git] / tests / test-getopt.h
index bcc7fe6..450cf0d 100644 (file)
@@ -1,5 +1,5 @@
 /* Test of command line argument processing.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #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 && !defined __UCLIBC__)
+# 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,
              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)
@@ -50,6 +61,12 @@ getopt_loop (int argc, const char **argv,
           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;
@@ -58,6 +75,8 @@ getopt_loop (int argc, const char **argv,
           break;
         }
     }
+
+  *message_issued = pos < ftell (stderr);
 }
 
 static void
@@ -83,6 +102,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -92,9 +112,10 @@ test_getopt (void)
       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);
@@ -102,6 +123,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -112,6 +134,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -122,9 +145,10 @@ test_getopt (void)
       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);
@@ -132,6 +156,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 3);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -142,6 +167,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -151,9 +177,10 @@ test_getopt (void)
       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);
@@ -161,6 +188,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -171,6 +199,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -181,9 +210,10 @@ test_getopt (void)
       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);
@@ -191,6 +221,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 3);
+      ASSERT (!output);
     }
 
   /* Test processing of options with arguments.  */
@@ -203,6 +234,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -211,9 +243,10 @@ test_getopt (void)
       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);
@@ -221,6 +254,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -231,6 +265,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -240,9 +275,10 @@ test_getopt (void)
       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);
@@ -250,6 +286,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 3);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -260,6 +297,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -271,9 +309,10 @@ test_getopt (void)
       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);
@@ -281,9 +320,10 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 5);
+      ASSERT (!output);
     }
 
-#if GNULIB_GETOPT_GNU
+#if GNULIB_TEST_GETOPT_GNU
   /* Test processing of options with optional arguments.  */
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -294,6 +334,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -302,9 +343,10 @@ test_getopt (void)
       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);
@@ -312,6 +354,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -322,6 +365,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -331,9 +375,10 @@ test_getopt (void)
       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);
@@ -341,6 +386,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 2);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -351,6 +397,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -360,9 +407,10 @@ test_getopt (void)
       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 == 0);
       ASSERT (p_value == NULL);
@@ -370,10 +418,46 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 3);
+      ASSERT (!output);
     }
-#endif
+#endif /* GNULIB_TEST_GETOPT_GNU */
+
+  /* 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];
 
-  /* Check that invalid options are recognized.  */
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "-x";
+      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 == 'x');
+      ASSERT (optind == 5);
+      ASSERT (output);
+    }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
       int a_seen = 0;
@@ -383,6 +467,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -394,9 +479,44 @@ test_getopt (void)
       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);
+                   &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 == '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++] = "-x";
+      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);
@@ -404,6 +524,201 @@ test_getopt (void)
       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.  */
@@ -416,6 +731,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -428,9 +744,10 @@ test_getopt (void)
       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);
@@ -448,6 +765,7 @@ test_getopt (void)
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 1);
+          ASSERT (!output);
         }
       else
         {
@@ -466,6 +784,7 @@ test_getopt (void)
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 4);
+          ASSERT (!output);
         }
     }
 
@@ -479,6 +798,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[20];
 
@@ -496,9 +816,10 @@ test_getopt (void)
       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);
@@ -521,6 +842,7 @@ test_getopt (void)
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 1);
+          ASSERT (!output);
         }
       else
         {
@@ -544,10 +866,11 @@ test_getopt (void)
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 5);
+          ASSERT (!output);
         }
     }
 
-#if GNULIB_GETOPT_GNU
+#if GNULIB_TEST_GETOPT_GNU
   /* Check that the '-' flag causes non-options to be returned in order.  */
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -558,6 +881,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -570,9 +894,10 @@ test_getopt (void)
       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);
@@ -591,6 +916,7 @@ test_getopt (void)
       ASSERT (strcmp (non_options[2], "bar") == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 7);
+      ASSERT (!output);
     }
 
   /* Check that '--' ends the argument processing.  */
@@ -603,6 +929,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[20];
 
@@ -620,9 +947,10 @@ test_getopt (void)
       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);
@@ -640,6 +968,7 @@ test_getopt (void)
       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.  */
@@ -664,7 +993,6 @@ test_getopt (void)
           ASSERT (optind == 12);
         }
     }
-#endif
 
   /* Check that the '-' flag has to come first.  */
   for (start = OPTIND_MIN; start <= 1; start++)
@@ -676,6 +1004,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -688,9 +1017,10 @@ test_getopt (void)
       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);
@@ -708,6 +1038,7 @@ test_getopt (void)
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 1);
+          ASSERT (!output);
         }
       else
         {
@@ -726,6 +1057,7 @@ test_getopt (void)
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 4);
+          ASSERT (!output);
         }
     }
 
@@ -740,6 +1072,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -752,9 +1085,10 @@ test_getopt (void)
       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);
@@ -770,6 +1104,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 1);
+      ASSERT (!output);
     }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
@@ -780,6 +1115,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -789,7 +1125,7 @@ test_getopt (void)
       optind = start;
       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);
@@ -797,6 +1133,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == '+');
       ASSERT (optind == 2);
+      ASSERT (output);
     }
 
   /* Check that '--' ends the argument processing.  */
@@ -809,6 +1146,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[20];
 
@@ -826,9 +1164,10 @@ test_getopt (void)
       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);
@@ -848,8 +1187,10 @@ test_getopt (void)
       ASSERT (q_value == NULL);
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
-      ASSERT (optind = 1);
+      ASSERT (optind == 1);
+      ASSERT (!output);
     }
+#endif /* GNULIB_TEST_GETOPT_GNU */
 
   /* Check that the '+' flag has to come first.  */
   for (start = OPTIND_MIN; start <= 1; start++)
@@ -861,6 +1202,7 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
       const char *argv[10];
 
@@ -873,9 +1215,10 @@ test_getopt (void)
       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);
@@ -893,6 +1236,7 @@ test_getopt (void)
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 1);
+          ASSERT (!output);
         }
       else
         {
@@ -911,6 +1255,137 @@ test_getopt (void)
           ASSERT (non_options_count == 0);
           ASSERT (unrecognized == 0);
           ASSERT (optind == 4);
+          ASSERT (!output);
         }
     }
+
+#if GNULIB_TEST_GETOPT_GNU
+  /* If GNU extensions are supported, require compliance with POSIX
+     interpretation on leading '+' behavior.
+     http://austingroupbugs.net/view.php?id=191  */
+  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++] = "donald";
+      argv[argc++] = "-p";
+      argv[argc++] = "billy";
+      argv[argc++] = "duck";
+      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 (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);
+      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] = NULL;
+      optind = start;
+      getopt_loop (argc, argv, "+:abp: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 == '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++] = "-b";
+      argv[argc++] = "-p";
+      argv[argc] = NULL;
+      optind = start;
+      getopt_loop (argc, argv, "+:abp:q:",
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      ASSERT (a_seen == 0);
+      ASSERT (b_seen == 1);
+      ASSERT (p_value == NULL);
+      ASSERT (q_value == NULL);
+      ASSERT (non_options_count == 0);
+      ASSERT (unrecognized == 'p');
+      ASSERT (optind == 3);
+      ASSERT (!output);
+    }
+
+  /* Check that 'W' does not dump core:
+     http://sourceware.org/bugzilla/show_bug.cgi?id=12922
+     Technically, POSIX says the presence of ';' in the opt-string
+     gives unspecified behavior, so we only test this when GNU compliance
+     is desired.  */
+  for (start = OPTIND_MIN; start <= 1; start++)
+    {
+      int argc = 0;
+      const char *argv[10];
+      int pos = ftell (stderr);
+
+      argv[argc++] = "program";
+      argv[argc++] = "-W";
+      argv[argc++] = "dummy";
+      argv[argc] = NULL;
+      optind = start;
+      opterr = 1;
+      ASSERT (getopt (argc, (char **) argv, "W;") == 'W');
+      ASSERT (ftell (stderr) == pos);
+      ASSERT (optind == 2);
+    }
+#endif /* GNULIB_TEST_GETOPT_GNU */
 }