bug-gnulib
[Top][All Lists]
Advanced

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

[PATCH 2/2] getopt: match recent glibc fixes and posix ruling


From: Eric Blake
Subject: [PATCH 2/2] getopt: match recent glibc fixes and posix ruling
Date: Sat, 10 Apr 2010 13:29:36 -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

Although it technically isn't part of POSIX 2008, there are
enough existing non-GNU implementations that already comply
that it is worth enforcing.

* tests/test-getopt.h (test_getopt): Strengthen tests of leading
'+' handling.
* 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 |   15 ++--
 doc/posix-functions/getopt.texi           |   13 ++--
 m4/getopt.m4                              |   24 ++++++-
 tests/test-getopt.h                       |  112 +++++++++++++++++++++++++++--
 tests/test-getopt_long.h                  |   17 +++--
 7 files changed, 173 insertions(+), 34 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index fea598f..5c72a7e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2010-04-10  Eric Blake  <address@hidden>

+       getopt: match recent glibc fixes and posix ruling
+       * tests/test-getopt.h (test_getopt): Strengthen tests of leading
+       '+' handling.
+       * 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 0472514..b06797d 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.
@@ -29,11 +37,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 13edfb4..73352a1 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.
@@ -31,14 +39,7 @@ 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:
 FreeBSD.
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/posix-functions/getopt.texi b/doc/posix-functions/getopt.texi
index 822dbb3..b55fd26 100644
--- a/doc/posix-functions/getopt.texi
+++ b/doc/posix-functions/getopt.texi
@@ -13,6 +13,10 @@ getopt
 Portability problems fixed by either Gnulib module @code{getopt-posix} or 
@code{getopt-gnu}:
 @itemize
 @item
+The function @code{getopt} does not support the @samp{+} flag in the options
+string on some platforms:
+MacOS X 10.5, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10.
address@hidden
 The @code{getopt} function keeps some internal state that cannot be explicitly
 reset on some platforms:
 mingw.
@@ -21,9 +25,9 @@ getopt
 Portability problems fixed by Gnulib module @code{getopt-gnu}:
 @itemize
 @item
-The function @code{getopt} does not support the @samp{+} flag in the options
-string on some platforms:
-MacOS X 10.5, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10.
+The function @code{getopt} does not obey the combination of @samp{+}
+and @samp{:} flags in the options string on some platforms:
+glibc 2.11.
 @item
 The function @code{getopt} does not obey the @samp{-} flag in the options
 string when @env{POSIXLY_CORRECT} is set on some platforms:
@@ -57,7 +61,4 @@ getopt
 @code{optind} to 0.  Other implementations provide @code{optreset},
 causing a reset by setting it non-zero, although it does not
 necessarily re-read @env{POSIXLY_CORRECT}.
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/m4/getopt.m4 b/m4/getopt.m4
index a19805e..8449034 100644
--- a/m4/getopt.m4
+++ b/m4/getopt.m4
@@ -1,4 +1,4 @@
-# getopt.m4 serial 24
+# getopt.m4 serial 25
 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,
@@ -88,6 +88,8 @@ AC_DEFUN([gl_GETOPT_CHECK_HEADERS],
   dnl strings starts with '+' and it's not the first call.  Some internal state
   dnl is left over from earlier calls, and neither setting optind = 0 nor
   dnl setting optreset = 1 get rid of this internal state.
+  dnl glibc 2.11 mishandles optstring starting with "+:", in conflict with
+  dnl the POSIX recommendation http://austingroupbugs.net/view.php?id=191.
   dnl POSIX is silent on optind vs. optreset, so we allow either behavior.
   if test -z "$gl_replace_getopt"; then
     AC_CACHE_CHECK([whether getopt is POSIX compatible],
@@ -167,6 +169,26 @@ main ()
     if (!(optind == 1))
       return 12;
   }
+  /* Detect glibc 2.11 bug.  */
+  {
+    int argc = 0;
+    char *argv[4];
+    int c;
+
+    argv[argc++] = "program";
+    argv[argc++] = "-b";
+    argv[argc++] = "-a";
+    argv[argc] = NULL;
+    optind = OPTIND_MIN;
+    opterr = 0;
+
+    c = getopt (argc, argv, "+:a:b");
+    if (!(c == 'b'))
+      return 13;
+    c = getopt (argc, argv, "+:a:b");
+    if (!(c == ':'))
+      return 14;
+  }

   return 0;
 }
diff --git a/tests/test-getopt.h b/tests/test-getopt.h
index 96db7a5..7bfef0b 100644
--- a/tests/test-getopt.h
+++ b/tests/test-getopt.h
@@ -1124,10 +1124,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 +1134,7 @@ test_getopt (void)
       ASSERT (non_options_count == 0);
       ASSERT (unrecognized == '+');
       ASSERT (optind == 2);
-      ASSERT (!output);
+      ASSERT (output);
     }

   /* Check that '--' ends the argument processing.  */
@@ -1263,6 +1259,108 @@ test_getopt (void)
         }
     }

-  /* No tests of "-:..." or "+:...", due to glibc bug:
-     http://sources.redhat.com/bugzilla/show_bug.cgi?id=11039 */
+  /* Require compliance with POSIX interpretation that leading '+'
+     must be supported.  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);
+    }
 }
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]