bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 5/5] getopt-gnu: match recent glibc fixes and posix ruling


From: Eric Blake
Subject: [PATCH 5/5] getopt-gnu: match recent glibc fixes and posix ruling
Date: Tue, 13 Apr 2010 17:17:20 -0600

The POSIX folks admitted that codifying the behavior of GNU
getopt on a leading '+' in optstring is worthwhile, for writing
programs such as env(1) even when POSIXLY_CORRECT is not defined.
http://austingroupbugs.net/view.php?id=191
However, the ruling is an enhancement request for the next
version of POSIX, and is not binding on platforms that comply
with POSIX 2008, so it should only be enforced for getopt-gnu.

* tests/test-getopt.h (test_getopt): Strengthen tests of leading
'+' handling, when requesting extensions.
* tests/test-getopt_long.h (test_getopt_long): Strengthen test of
'W;' handling.
* m4/getopt.m4 (gl_GETOPT_CHECK_HEADERS): Detect glibc 2.11 bug.
* doc/posix-functions/getopt.texi (getopt): Document this.
* doc/glibc-functions/getopt_long.texi (getopt_long): Likewise.
* doc/glibc-functions/getopt_long_only.texi (getopt_long_only):
Likewise.
---
 ChangeLog                                 |   11 +++
 doc/glibc-functions/getopt_long.texi      |   15 ++--
 doc/glibc-functions/getopt_long_only.texi |   18 +++--
 doc/posix-functions/getopt.texi           |   13 ++-
 m4/getopt.m4                              |   15 ++++-
 tests/test-getopt.h                       |  119 ++++++++++++++++++++++++++--
 tests/test-getopt_long.h                  |   17 +++--
 7 files changed, 173 insertions(+), 35 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 19c3ad5..f1ccfdc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2010-04-13  Eric Blake  <address@hidden>

+       getopt-gnu: match recent glibc fixes and posix ruling
+       * tests/test-getopt.h (test_getopt): Strengthen tests of leading
+       '+' handling, when requesting extensions.
+       * tests/test-getopt_long.h (test_getopt_long): Strengthen test of
+       'W;' handling.
+       * m4/getopt.m4 (gl_GETOPT_CHECK_HEADERS): Detect glibc 2.11 bug.
+       * doc/posix-functions/getopt.texi (getopt): Document this.
+       * doc/glibc-functions/getopt_long.texi (getopt_long): Likewise.
+       * doc/glibc-functions/getopt_long_only.texi (getopt_long_only):
+       Likewise.
+
        getopt: merge bug fixes from glibc
        * lib/getopt.c (_getopt_internal_r): Use correct message for 'W;'
        diagnostics.  Honor '+:' correctly.  Reject ';'.
diff --git a/doc/glibc-functions/getopt_long.texi 
b/doc/glibc-functions/getopt_long.texi
index 3cf17f0..e014a3c 100644
--- a/doc/glibc-functions/getopt_long.texi
+++ b/doc/glibc-functions/getopt_long.texi
@@ -7,6 +7,14 @@ getopt_long
 Portability problems fixed by Gnulib:
 @itemize
 @item
+The function @code{getopt_long} does not obey the combination of
address@hidden and @samp{:} flags in the options string on some platforms:
+glibc 2.11.
address@hidden
+The use of @samp{W;} in the optstring argument to does not always
+allow @code{-W foo} to behave synonymously with @code{--foo}:
+glibc 2.11.
address@hidden
 The function @code{getopt_long} does not support the @samp{+} flag in
 the options string on some platforms:
 MacOS X 10.5, AIX 5.2, OSF/1 5.1, Solaris 10.
@@ -33,11 +41,4 @@ getopt_long

 Portability problems not fixed by Gnulib:
 @itemize
address@hidden
-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.
address@hidden
-Mixing a leading @samp{-} or @samp{+} with a leading @samp{:} in the
-optstring argument has inconsistent effects across platforms.
 @end itemize
diff --git a/doc/glibc-functions/getopt_long_only.texi 
b/doc/glibc-functions/getopt_long_only.texi
index edc832b..309c5b6 100644
--- a/doc/glibc-functions/getopt_long_only.texi
+++ b/doc/glibc-functions/getopt_long_only.texi
@@ -7,6 +7,14 @@ getopt_long_only
 Portability problems fixed by Gnulib:
 @itemize
 @item
+The function @code{getopt_long_only} does not obey the combination of
address@hidden and @samp{:} flags in the options string on some platforms:
+glibc 2.11.
address@hidden
+The use of @samp{W;} in the optstring argument to does not always
+allow @code{-W foo} to behave synonymously with @code{--foo}:
+glibc 2.11.
address@hidden
 The function @code{getopt_long_only} does not support the @samp{+}
 flag in the options string on some platforms:
 MacOS X 10.5, AIX 5.2, OSF/1 5.1, Solaris 10.
@@ -35,14 +43,10 @@ getopt_long_only
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-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.
address@hidden
 Some implementations return success instead of reporting an ambiguity
-if user's option is a prefix of two long options with the same flag:
+if user's option is a prefix of two long options with the same outcome:
 FreeBSD.
 @item
-Mixing a leading @samp{-} or @samp{+} with a leading @samp{:} in the
-optstring argument has inconsistent effects across platforms.
+The GNU Coding Standards discourage the use of @code{getopt_long_only}
+in new programs.
 @end itemize
diff --git a/doc/posix-functions/getopt.texi b/doc/posix-functions/getopt.texi
index d4d03f0..50640a8 100644
--- a/doc/posix-functions/getopt.texi
+++ b/doc/posix-functions/getopt.texi
@@ -29,6 +29,10 @@ getopt
 string on some platforms:
 MacOS X 10.5, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10.
 @item
+The function @code{getopt} does not obey the combination of @samp{+}
+and @samp{:} flags in the options string on some platforms:
+glibc 2.11.
address@hidden
 The function @code{getopt} does not obey the @samp{-} flag in the options
 string when @env{POSIXLY_CORRECT} is set on some platforms:
 Cygwin 1.7.0.
@@ -58,10 +62,9 @@ getopt
 @item
 The glibc implementation allows a complete reset of the environment,
 including re-checking for @env{POSIXLY_CORRECT}, by setting
address@hidden to 0.  Other implementations provide @code{optreset},
address@hidden to 0.  Several BSD implementations provide @code{optreset},
 causing a reset by setting it non-zero, although it does not
-necessarily re-read @env{POSIXLY_CORRECT}.
address@hidden
-Mixing a leading @samp{-} or @samp{+} with a leading @samp{:} in the
-optstring argument has inconsistent effects across platforms.
+necessarily re-read @env{POSIXLY_CORRECT}.  Solaris @code{getopt} does
+not support either reset method, but does not maintain state that
+needs the extra level of reset.
 @end itemize
diff --git a/m4/getopt.m4 b/m4/getopt.m4
index 2cd7499..5b211e5 100644
--- a/m4/getopt.m4
+++ b/m4/getopt.m4
@@ -1,4 +1,4 @@
-# getopt.m4 serial 27
+# getopt.m4 serial 28
 dnl Copyright (C) 2002-2006, 2008-2010 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -94,6 +94,10 @@ AC_DEFUN([gl_GETOPT_CHECK_HEADERS],
   dnl is left over from earlier calls, and neither setting optind = 0 nor
   dnl setting optreset = 1 get rid of this internal state.
   dnl POSIX is silent on optind vs. optreset, so we allow either behavior.
+  dnl POSIX 2008 does not specify leading '+' behavior, but see
+  dnl http://austingroupbugs.net/view.php?id=191 for a recommendation on
+  dnl the next version of POSIX.  For now, we only guarantee leading '+'
+  dnl behavior with getopt-gnu.
   if test -z "$gl_replace_getopt"; then
     AC_CACHE_CHECK([whether getopt is POSIX compatible],
       [gl_cv_func_getopt_posix],
@@ -254,6 +258,15 @@ main ()
                if (getopt (3, argv, "-p") != 'p')
                  return 7;
              }
+             /* This code fails on glibc 2.11.  */
+             {
+               char *argv[] = { "program", "-b", "-a", NULL };
+               optind = opterr = 0;
+               if (getopt (3, argv, "+:a:b") != 'b')
+                 return 8;
+               if (getopt (3, argv, "+:a:b") != ':')
+                 return 9;
+             }
              return 0;
            ]])],
         [gl_cv_func_getopt_gnu=yes],
diff --git a/tests/test-getopt.h b/tests/test-getopt.h
index 96db7a5..8baa39d 100644
--- a/tests/test-getopt.h
+++ b/tests/test-getopt.h
@@ -420,7 +420,7 @@ test_getopt (void)
       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.  */
@@ -993,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++)
@@ -1124,10 +1123,6 @@ test_getopt (void)
       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, &output);
@@ -1138,7 +1133,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == '+');
       ASSERT (optind == 2);
-      ASSERT (!output);
+      ASSERT (output);
     }

   /* Check that '--' ends the argument processing.  */
@@ -1195,6 +1190,7 @@ test_getopt (void)
       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++)
@@ -1263,6 +1259,111 @@ test_getopt (void)
         }
     }

-  /* No tests of "-:..." or "+:...", due to glibc bug:
-     http://sources.redhat.com/bugzilla/show_bug.cgi?id=11039 */
+#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);
+    }
+#endif /* GNULIB_TEST_GETOPT_GNU */
 }
diff --git a/tests/test-getopt_long.h b/tests/test-getopt_long.h
index 5f103c8..0e58fec 100644
--- a/tests/test-getopt_long.h
+++ b/tests/test-getopt_long.h
@@ -1151,8 +1151,7 @@ test_getopt_long (void)
                         &non_options_count, non_options, &unrecognized);
       ASSERT (a_seen == 0);
       ASSERT (b_seen == 0);
-      /* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */
-      /* ASSERT (p_value == NULL); */
+      ASSERT (p_value == NULL);
       ASSERT (q_value == NULL);
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == 0);
@@ -2079,8 +2078,11 @@ test_getopt_long_only (void)
     opterr = 0;
     c = do_getopt_long_only (argc, argv, "ab", long_options_required,
                              &option_index);
-    /* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */
-    /* ASSERT (c == 1003); */
+    /* glibc getopt_long_only is intentionally different from
+       getopt_long when handling a prefix that is common to two
+       spellings, when both spellings have the same option directives.
+       BSD getopt_long_only treats both cases the same.  */
+    ASSERT (c == 1003 || c == '?');
     ASSERT (optind == 2);
   }
   {
@@ -2096,8 +2098,11 @@ test_getopt_long_only (void)
     opterr = 0;
     c = do_getopt_long_only (argc, argv, "abx::", long_options_required,
                              &option_index);
-    /* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */
-    /* ASSERT (c == 1003); */
+    /* glibc getopt_long_only is intentionally different from
+       getopt_long when handling a prefix that is common to two
+       spellings, when both spellings have the same option directives.
+       BSD getopt_long_only treats both cases the same.  */
+    ASSERT (c == 1003 || c == '?');
     ASSERT (optind == 2);
     ASSERT (optarg == NULL);
   }
-- 
1.6.6.1





reply via email to

[Prev in Thread] Current Thread [Next in Thread]