maint: update copyright
[gnulib.git] / tests / test-getopt.h
index 352fe32..c982d57 100644 (file)
@@ -1,5 +1,5 @@
 /* Test of command line argument processing.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009-2014 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
 
 /* Written by Bruno Haible <bruno@clisp.org>, 2009.  */
 
+#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, 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)
+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, bool *message_issued)
 {
   int c;
+  int pos = ftell (stderr);
 
-  opterr = 0;
-  while ((c = getopt (argc, argv, options)) != -1)
+  while ((c = getopt (argc, (char **) argv, options)) != -1)
     {
       switch (c)
-       {
-       case 'a':
-         (*a_seen)++;
-         break;
-       case 'b':
-         (*b_seen)++;
-         break;
-       case 'p':
-         *p_value = optarg;
-         break;
-       case 'q':
-         *q_value = optarg;
-         break;
-       case '\1':
-         /* Must only happen with option '-' at the beginning.  */
-         ASSERT (options[0] == '-');
-         non_options[(*non_options_count)++] = optarg;
-         break;
-       case '?':
-         *unrecognized = optopt;
-         break;
-       default:
-         *unrecognized = c;
-         break;
-       }
+        {
+        case 'a':
+          (*a_seen)++;
+          break;
+        case 'b':
+          (*b_seen)++;
+          break;
+        case 'p':
+          *p_value = optarg;
+          break;
+        case 'q':
+          *q_value = optarg;
+          break;
+        case '\1':
+          /* Must only happen with option '-' at the beginning.  */
+          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;
+        default:
+          *unrecognized = c;
+          break;
+        }
     }
+
+  *message_issued = pos < ftell (stderr);
 }
 
 static void
 test_getopt (void)
 {
   int start;
+  bool posixly = !!getenv ("POSIXLY_CORRECT");
+  /* See comment in getopt.c:
+     glibc gets a LSB-compliant getopt.
+     Standalone applications get a POSIX-compliant getopt.  */
+#if defined __GETOPT_PREFIX || !(__GLIBC__ >= 2 || defined __MINGW32__)
+  /* Using getopt from gnulib or from a non-glibc system.  */
+  posixly = true;
+#endif
 
   /* Test processing of boolean options.  */
   for (start = OPTIND_MIN; start <= 1; start++)
@@ -73,17 +102,20 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-a";
       argv[argc++] = "foo";
       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);
+                   &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);
@@ -91,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++)
     {
@@ -101,18 +134,21 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-b";
       argv[argc++] = "-a";
       argv[argc++] = "foo";
       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);
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 1);
       ASSERT (b_seen == 1);
       ASSERT (p_value == NULL);
@@ -120,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++)
     {
@@ -130,17 +167,20 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-ba";
       argv[argc++] = "foo";
       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);
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 1);
       ASSERT (b_seen == 1);
       ASSERT (p_value == NULL);
@@ -148,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++)
     {
@@ -158,18 +199,21 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-ab";
       argv[argc++] = "-a";
       argv[argc++] = "foo";
       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);
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 2);
       ASSERT (b_seen == 1);
       ASSERT (p_value == NULL);
@@ -177,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.  */
@@ -189,16 +234,19 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-pfoo";
       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);
+                   &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 && strcmp (p_value, "foo") == 0);
@@ -206,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++)
     {
@@ -216,17 +265,20 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      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);
+                   &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 && strcmp (p_value, "foo") == 0);
@@ -234,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++)
     {
@@ -244,8 +297,9 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-ab";
@@ -253,10 +307,12 @@ test_getopt (void)
       argv[argc++] = "baz";
       argv[argc++] = "-pfoo";
       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);
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
       ASSERT (a_seen == 1);
       ASSERT (b_seen == 1);
       ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -264,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++)
     {
@@ -277,16 +334,19 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-pfoo";
       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);
+                   &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 && strcmp (p_value, "foo") == 0);
@@ -294,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++)
     {
@@ -304,17 +365,20 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      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);
+                   &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);
@@ -322,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++)
     {
@@ -332,17 +397,20 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      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);
+                   &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);
@@ -350,10 +418,12 @@ 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.  */
+  /* 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;
@@ -363,8 +433,9 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-p";
@@ -372,10 +443,12 @@ test_getopt (void)
       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);
+                   &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);
@@ -383,9 +456,42 @@ 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];
 
-  /* Check that by default, non-options arguments are moved to the end.  */
+      argv[argc++] = "program";
+      argv[argc++] = "-p";
+      argv[argc++] = "foo";
+      argv[argc++] = "-x";
+      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 == 'x');
+      ASSERT (optind == 5);
+      ASSERT (!output);
+    }
   for (start = OPTIND_MIN; start <= 1; start++)
     {
       int a_seen = 0;
@@ -395,56 +501,291 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
-      argv[argc++] = "donald";
       argv[argc++] = "-p";
-      argv[argc++] = "billy";
-      argv[argc++] = "duck";
+      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);
+      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++] = "-:";
+      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);
-      /* See comment in getopt.c:
-         glibc gets a LSB-compliant getopt.
-         Standalone applications get a POSIX-compliant getopt.  */
-#if defined __GETOPT_PREFIX || !(__GLIBC__ >= 2 || defined __MINGW32__)
-      /* Using getopt from gnulib or from a non-glibc system.  */
-      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 (a_seen == 0);
+                   &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 == 0);
-      ASSERT (optind == 1);
-#else
-      /* Using getopt from glibc.  */
-      ASSERT (strcmp (argv[0], "program") == 0);
-      ASSERT (strcmp (argv[1], "-p") == 0);
-      ASSERT (strcmp (argv[2], "billy") == 0);
-      ASSERT (strcmp (argv[3], "-a") == 0);
-      ASSERT (strcmp (argv[4], "donald") == 0);
-      ASSERT (strcmp (argv[5], "duck") == 0);
-      ASSERT (strcmp (argv[6], "bar") == 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 && strcmp (p_value, "billy") == 0);
+      ASSERT (p_value == NULL);
       ASSERT (q_value == NULL);
       ASSERT (non_options_count == 0);
-      ASSERT (unrecognized == 0);
-      ASSERT (optind == 4);
-#endif
+      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.  */
+  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);
+      if (posixly)
+        {
+          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);
+        }
+      else
+        {
+          ASSERT (strcmp (argv[0], "program") == 0);
+          ASSERT (strcmp (argv[1], "-p") == 0);
+          ASSERT (strcmp (argv[2], "billy") == 0);
+          ASSERT (strcmp (argv[3], "-a") == 0);
+          ASSERT (strcmp (argv[4], "donald") == 0);
+          ASSERT (strcmp (argv[5], "duck") == 0);
+          ASSERT (strcmp (argv[6], "bar") == 0);
+          ASSERT (argv[7] == NULL);
+          ASSERT (a_seen == 1);
+          ASSERT (b_seen == 0);
+          ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0);
+          ASSERT (q_value == NULL);
+          ASSERT (non_options_count == 0);
+          ASSERT (unrecognized == 0);
+          ASSERT (optind == 4);
+          ASSERT (!output);
+        }
     }
 
   /* Check that '--' ends the argument processing.  */
@@ -457,8 +798,9 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[20];
+      const char *argv[20];
 
       argv[argc++] = "program";
       argv[argc++] = "donald";
@@ -472,59 +814,63 @@ test_getopt (void)
       argv[argc++] = "-q";
       argv[argc++] = "johnny";
       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);
-      /* See comment in getopt.c:
-         glibc gets a LSB-compliant getopt.
-         Standalone applications get a POSIX-compliant getopt.  */
-#if defined __GETOPT_PREFIX || !(__GLIBC__ >= 2 || defined __MINGW32__)
-      /* Using getopt from gnulib or from a non-glibc system.  */
-      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], "--") == 0);
-      ASSERT (strcmp (argv[7], "-b") == 0);
-      ASSERT (strcmp (argv[8], "foo") == 0);
-      ASSERT (strcmp (argv[9], "-q") == 0);
-      ASSERT (strcmp (argv[10], "johnny") == 0);
-      ASSERT (strcmp (argv[11], "bar") == 0);
-      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);
-#else
-      /* Using getopt from glibc.  */
-      ASSERT (strcmp (argv[0], "program") == 0);
-      ASSERT (strcmp (argv[1], "-p") == 0);
-      ASSERT (strcmp (argv[2], "billy") == 0);
-      ASSERT (strcmp (argv[3], "-a") == 0);
-      ASSERT (strcmp (argv[4], "--") == 0);
-      ASSERT (strcmp (argv[5], "donald") == 0);
-      ASSERT (strcmp (argv[6], "duck") == 0);
-      ASSERT (strcmp (argv[7], "-b") == 0);
-      ASSERT (strcmp (argv[8], "foo") == 0);
-      ASSERT (strcmp (argv[9], "-q") == 0);
-      ASSERT (strcmp (argv[10], "johnny") == 0);
-      ASSERT (strcmp (argv[11], "bar") == 0);
-      ASSERT (a_seen == 1);
-      ASSERT (b_seen == 0);
-      ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0);
-      ASSERT (q_value == NULL);
-      ASSERT (non_options_count == 0);
-      ASSERT (unrecognized == 0);
-      ASSERT (optind == 5);
-#endif
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      if (posixly)
+        {
+          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], "--") == 0);
+          ASSERT (strcmp (argv[7], "-b") == 0);
+          ASSERT (strcmp (argv[8], "foo") == 0);
+          ASSERT (strcmp (argv[9], "-q") == 0);
+          ASSERT (strcmp (argv[10], "johnny") == 0);
+          ASSERT (strcmp (argv[11], "bar") == 0);
+          ASSERT (argv[12] == 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);
+        }
+      else
+        {
+          ASSERT (strcmp (argv[0], "program") == 0);
+          ASSERT (strcmp (argv[1], "-p") == 0);
+          ASSERT (strcmp (argv[2], "billy") == 0);
+          ASSERT (strcmp (argv[3], "-a") == 0);
+          ASSERT (strcmp (argv[4], "--") == 0);
+          ASSERT (strcmp (argv[5], "donald") == 0);
+          ASSERT (strcmp (argv[6], "duck") == 0);
+          ASSERT (strcmp (argv[7], "-b") == 0);
+          ASSERT (strcmp (argv[8], "foo") == 0);
+          ASSERT (strcmp (argv[9], "-q") == 0);
+          ASSERT (strcmp (argv[10], "johnny") == 0);
+          ASSERT (strcmp (argv[11], "bar") == 0);
+          ASSERT (argv[12] == NULL);
+          ASSERT (a_seen == 1);
+          ASSERT (b_seen == 0);
+          ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0);
+          ASSERT (q_value == NULL);
+          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++)
     {
@@ -535,8 +881,9 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "donald";
@@ -545,10 +892,12 @@ test_getopt (void)
       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);
+                   &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);
@@ -556,6 +905,7 @@ test_getopt (void)
       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 == 1);
       ASSERT (b_seen == 0);
       ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0);
@@ -566,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.  */
@@ -578,8 +929,9 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[20];
+      const char *argv[20];
 
       argv[argc++] = "program";
       argv[argc++] = "donald";
@@ -593,10 +945,12 @@ test_getopt (void)
       argv[argc++] = "-q";
       argv[argc++] = "johnny";
       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);
+                   &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);
@@ -609,35 +963,36 @@ test_getopt (void)
       ASSERT (strcmp (argv[9], "-q") == 0);
       ASSERT (strcmp (argv[10], "johnny") == 0);
       ASSERT (strcmp (argv[11], "bar") == 0);
+      ASSERT (argv[12] == NULL);
       ASSERT (a_seen == 1);
       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.  */
-         ASSERT (non_options_count == 2);
-         ASSERT (strcmp (non_options[0], "donald") == 0);
-         ASSERT (strcmp (non_options[1], "duck") == 0);
-         ASSERT (unrecognized == 0);
-         ASSERT (optind == 7);
+          /* glibc behaviour.  */
+          ASSERT (non_options_count == 2);
+          ASSERT (strcmp (non_options[0], "donald") == 0);
+          ASSERT (strcmp (non_options[1], "duck") == 0);
+          ASSERT (unrecognized == 0);
+          ASSERT (optind == 7);
         }
       else
         {
-         /* Another valid behaviour.  */
-         ASSERT (non_options_count == 7);
-         ASSERT (strcmp (non_options[0], "donald") == 0);
-         ASSERT (strcmp (non_options[1], "duck") == 0);
-         ASSERT (strcmp (non_options[2], "-b") == 0);
-         ASSERT (strcmp (non_options[3], "foo") == 0);
-         ASSERT (strcmp (non_options[4], "-q") == 0);
-         ASSERT (strcmp (non_options[5], "johnny") == 0);
-         ASSERT (strcmp (non_options[6], "bar") == 0);
-         ASSERT (unrecognized == 0);
-         ASSERT (optind == 12);
+          /* Another valid behaviour.  */
+          ASSERT (non_options_count == 7);
+          ASSERT (strcmp (non_options[0], "donald") == 0);
+          ASSERT (strcmp (non_options[1], "duck") == 0);
+          ASSERT (strcmp (non_options[2], "-b") == 0);
+          ASSERT (strcmp (non_options[3], "foo") == 0);
+          ASSERT (strcmp (non_options[4], "-q") == 0);
+          ASSERT (strcmp (non_options[5], "johnny") == 0);
+          ASSERT (strcmp (non_options[6], "bar") == 0);
+          ASSERT (unrecognized == 0);
+          ASSERT (optind == 12);
         }
     }
-#endif
 
   /* Check that the '-' flag has to come first.  */
   for (start = OPTIND_MIN; start <= 1; start++)
@@ -649,8 +1004,9 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "donald";
@@ -659,46 +1015,50 @@ test_getopt (void)
       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);
-      /* See comment in getopt.c:
-         glibc gets a LSB-compliant getopt.
-         Standalone applications get a POSIX-compliant getopt.  */
-#if defined __GETOPT_PREFIX || !(__GLIBC__ >= 2 || defined __MINGW32__)
-      /* Using getopt from gnulib or from a non-glibc system.  */
-      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 (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);
-#else
-      /* Using getopt from glibc.  */
-      ASSERT (strcmp (argv[0], "program") == 0);
-      ASSERT (strcmp (argv[1], "-p") == 0);
-      ASSERT (strcmp (argv[2], "billy") == 0);
-      ASSERT (strcmp (argv[3], "-a") == 0);
-      ASSERT (strcmp (argv[4], "donald") == 0);
-      ASSERT (strcmp (argv[5], "duck") == 0);
-      ASSERT (strcmp (argv[6], "bar") == 0);
-      ASSERT (a_seen == 1);
-      ASSERT (b_seen == 0);
-      ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0);
-      ASSERT (q_value == NULL);
-      ASSERT (non_options_count == 0);
-      ASSERT (unrecognized == 0);
-      ASSERT (optind == 4);
-#endif
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      if (posixly)
+        {
+          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);
+        }
+      else
+        {
+          ASSERT (strcmp (argv[0], "program") == 0);
+          ASSERT (strcmp (argv[1], "-p") == 0);
+          ASSERT (strcmp (argv[2], "billy") == 0);
+          ASSERT (strcmp (argv[3], "-a") == 0);
+          ASSERT (strcmp (argv[4], "donald") == 0);
+          ASSERT (strcmp (argv[5], "duck") == 0);
+          ASSERT (strcmp (argv[6], "bar") == 0);
+          ASSERT (argv[7] == NULL);
+          ASSERT (a_seen == 1);
+          ASSERT (b_seen == 0);
+          ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0);
+          ASSERT (q_value == NULL);
+          ASSERT (non_options_count == 0);
+          ASSERT (unrecognized == 0);
+          ASSERT (optind == 4);
+          ASSERT (!output);
+        }
     }
 
   /* Check that the '+' flag causes the first non-option to terminate the
@@ -712,8 +1072,9 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "donald";
@@ -722,10 +1083,12 @@ test_getopt (void)
       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);
+                   &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);
@@ -733,6 +1096,7 @@ test_getopt (void)
       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);
@@ -740,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++)
     {
@@ -750,15 +1115,17 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "-+";
+      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);
+                   &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);
@@ -766,6 +1133,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == '+');
       ASSERT (optind == 2);
+      ASSERT (output);
     }
 
   /* Check that '--' ends the argument processing.  */
@@ -778,8 +1146,9 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[20];
+      const char *argv[20];
 
       argv[argc++] = "program";
       argv[argc++] = "donald";
@@ -793,10 +1162,12 @@ test_getopt (void)
       argv[argc++] = "-q";
       argv[argc++] = "johnny";
       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);
+                   &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);
@@ -809,14 +1180,17 @@ test_getopt (void)
       ASSERT (strcmp (argv[9], "-q") == 0);
       ASSERT (strcmp (argv[10], "johnny") == 0);
       ASSERT (strcmp (argv[11], "bar") == 0);
+      ASSERT (argv[12] == 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 (optind == 1);
+      ASSERT (!output);
     }
+#endif /* GNULIB_TEST_GETOPT_GNU */
 
   /* Check that the '+' flag has to come first.  */
   for (start = OPTIND_MIN; start <= 1; start++)
@@ -828,8 +1202,9 @@ test_getopt (void)
       int non_options_count = 0;
       const char *non_options[10];
       int unrecognized = 0;
+      bool output;
       int argc = 0;
-      char *argv[10];
+      const char *argv[10];
 
       argv[argc++] = "program";
       argv[argc++] = "donald";
@@ -838,15 +1213,82 @@ test_getopt (void)
       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);
-      /* See comment in getopt.c:
-         glibc gets a LSB-compliant getopt.
-         Standalone applications get a POSIX-compliant getopt.  */
-#if defined __GETOPT_PREFIX || !(__GLIBC__ >= 2 || defined __MINGW32__)
-      /* Using getopt from gnulib or from a non-glibc system.  */
+                   &a_seen, &b_seen, &p_value, &q_value,
+                   &non_options_count, non_options, &unrecognized, &output);
+      if (posixly)
+        {
+          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);
+        }
+      else
+        {
+          ASSERT (strcmp (argv[0], "program") == 0);
+          ASSERT (strcmp (argv[1], "-p") == 0);
+          ASSERT (strcmp (argv[2], "billy") == 0);
+          ASSERT (strcmp (argv[3], "-a") == 0);
+          ASSERT (strcmp (argv[4], "donald") == 0);
+          ASSERT (strcmp (argv[5], "duck") == 0);
+          ASSERT (strcmp (argv[6], "bar") == 0);
+          ASSERT (argv[7] == NULL);
+          ASSERT (a_seen == 1);
+          ASSERT (b_seen == 0);
+          ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0);
+          ASSERT (q_value == NULL);
+          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);
@@ -854,6 +1296,7 @@ test_getopt (void)
       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);
@@ -861,22 +1304,88 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
       ASSERT (optind == 1);
-#else
-      /* Using getopt from glibc.  */
-      ASSERT (strcmp (argv[0], "program") == 0);
-      ASSERT (strcmp (argv[1], "-p") == 0);
-      ASSERT (strcmp (argv[2], "billy") == 0);
-      ASSERT (strcmp (argv[3], "-a") == 0);
-      ASSERT (strcmp (argv[4], "donald") == 0);
-      ASSERT (strcmp (argv[5], "duck") == 0);
-      ASSERT (strcmp (argv[6], "bar") == 0);
-      ASSERT (a_seen == 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 && strcmp (p_value, "billy") == 0);
+      ASSERT (p_value == NULL);
       ASSERT (q_value == NULL);
       ASSERT (non_options_count == 0);
-      ASSERT (unrecognized == 0);
-      ASSERT (optind == 4);
-#endif
+      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 */
 }