From 6229a28f54486e8c623fd516db498a289d5ac0d7 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 Apr 2010 16:34:16 -0600 Subject: [PATCH] getopt-gnu: match recent glibc fixes and posix ruling 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. (cherry picked from commit 61c96af09d3d2c917c69b17cc827e28a280db66c) --- 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 c00c0f0d9..d68f2f6a1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2010-04-13 Eric Blake + 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 3cf17f025..e014a3cb5 100644 --- a/doc/glibc-functions/getopt_long.texi +++ b/doc/glibc-functions/getopt_long.texi @@ -7,6 +7,14 @@ Gnulib module: getopt-gnu Portability problems fixed by Gnulib: @itemize @item +The function @code{getopt_long} does not obey the combination of +@samp{+} and @samp{:} flags in the options string on some platforms: +glibc 2.11. +@item +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. +@item 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 @@ AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Interix 3.5. 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, even in glibc. -@item -Mixing a leading @samp{-} or @samp{+} with a leading @samp{:} in the -optstring argument has inconsistent effects across platforms. @end itemize diff --git a/doc/glibc-functions/getopt_long_only.texi b/doc/glibc-functions/getopt_long_only.texi index edc832be2..309c5b6b7 100644 --- a/doc/glibc-functions/getopt_long_only.texi +++ b/doc/glibc-functions/getopt_long_only.texi @@ -7,6 +7,14 @@ Gnulib module: getopt-gnu Portability problems fixed by Gnulib: @itemize @item +The function @code{getopt_long_only} does not obey the combination of +@samp{+} and @samp{:} flags in the options string on some platforms: +glibc 2.11. +@item +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. +@item 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 @@ OSF/1 5.1, mingw, Interix 3.5. 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. -@item 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 d4d03f0c2..50640a850 100644 --- a/doc/posix-functions/getopt.texi +++ b/doc/posix-functions/getopt.texi @@ -29,6 +29,10 @@ 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. @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. +@item 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 @@ testsuite. @item The glibc implementation allows a complete reset of the environment, including re-checking for @env{POSIXLY_CORRECT}, by setting -@code{optind} to 0. Other implementations provide @code{optreset}, +@code{optind} 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}. -@item -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 2cd74992c..5b211e567 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 96db7a5f8..8baa39d02 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 5f103c8e4..0e58fecbb 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); } -- 2.11.0