1
0
mirror of https://git.savannah.gnu.org/git/gnulib.git synced 2025-08-17 12:41:05 +03:00

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.
This commit is contained in:
Eric Blake
2010-04-09 16:34:16 -06:00
parent db3e280624
commit 61c96af09d
7 changed files with 173 additions and 35 deletions

View File

@@ -1,5 +1,16 @@
2010-04-13 Eric Blake <eblake@redhat.com> 2010-04-13 Eric Blake <eblake@redhat.com>
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 getopt: merge bug fixes from glibc
* lib/getopt.c (_getopt_internal_r): Use correct message for 'W;' * lib/getopt.c (_getopt_internal_r): Use correct message for 'W;'
diagnostics. Honor '+:' correctly. Reject ';'. diagnostics. Honor '+:' correctly. Reject ';'.

View File

@@ -7,6 +7,14 @@ Gnulib module: getopt-gnu
Portability problems fixed by Gnulib: Portability problems fixed by Gnulib:
@itemize @itemize
@item @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 function @code{getopt_long} does not support the @samp{+} flag in
the options string on some platforms: the options string on some platforms:
MacOS X 10.5, AIX 5.2, OSF/1 5.1, Solaris 10. 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: Portability problems not fixed by Gnulib:
@itemize @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 @end itemize

View File

@@ -7,6 +7,14 @@ Gnulib module: getopt-gnu
Portability problems fixed by Gnulib: Portability problems fixed by Gnulib:
@itemize @itemize
@item @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{+} The function @code{getopt_long_only} does not support the @samp{+}
flag in the options string on some platforms: flag in the options string on some platforms:
MacOS X 10.5, AIX 5.2, OSF/1 5.1, Solaris 10. 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: Portability problems not fixed by Gnulib:
@itemize @itemize
@item @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 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. FreeBSD.
@item @item
Mixing a leading @samp{-} or @samp{+} with a leading @samp{:} in the The GNU Coding Standards discourage the use of @code{getopt_long_only}
optstring argument has inconsistent effects across platforms. in new programs.
@end itemize @end itemize

View File

@@ -29,6 +29,10 @@ The function @code{getopt} does not support the @samp{+} flag in the options
string on some platforms: string on some platforms:
MacOS X 10.5, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10. MacOS X 10.5, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10.
@item @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 The function @code{getopt} does not obey the @samp{-} flag in the options
string when @env{POSIXLY_CORRECT} is set on some platforms: string when @env{POSIXLY_CORRECT} is set on some platforms:
Cygwin 1.7.0. Cygwin 1.7.0.
@@ -58,10 +62,9 @@ testsuite.
@item @item
The glibc implementation allows a complete reset of the environment, The glibc implementation allows a complete reset of the environment,
including re-checking for @env{POSIXLY_CORRECT}, by setting 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 causing a reset by setting it non-zero, although it does not
necessarily re-read @env{POSIXLY_CORRECT}. necessarily re-read @env{POSIXLY_CORRECT}. Solaris @code{getopt} does
@item not support either reset method, but does not maintain state that
Mixing a leading @samp{-} or @samp{+} with a leading @samp{:} in the needs the extra level of reset.
optstring argument has inconsistent effects across platforms.
@end itemize @end itemize

View File

@@ -1,4 +1,4 @@
# getopt.m4 serial 27 # getopt.m4 serial 28
dnl Copyright (C) 2002-2006, 2008-2010 Free Software Foundation, Inc. dnl Copyright (C) 2002-2006, 2008-2010 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it, 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 is left over from earlier calls, and neither setting optind = 0 nor
dnl setting optreset = 1 get rid of this internal state. 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 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 if test -z "$gl_replace_getopt"; then
AC_CACHE_CHECK([whether getopt is POSIX compatible], AC_CACHE_CHECK([whether getopt is POSIX compatible],
[gl_cv_func_getopt_posix], [gl_cv_func_getopt_posix],
@@ -254,6 +258,15 @@ main ()
if (getopt (3, argv, "-p") != 'p') if (getopt (3, argv, "-p") != 'p')
return 7; 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; return 0;
]])], ]])],
[gl_cv_func_getopt_gnu=yes], [gl_cv_func_getopt_gnu=yes],

View File

@@ -420,7 +420,7 @@ test_getopt (void)
ASSERT (optind == 3); ASSERT (optind == 3);
ASSERT (!output); ASSERT (!output);
} }
#endif #endif /* GNULIB_TEST_GETOPT_GNU */
/* Check that invalid options are recognized; and that both opterr /* Check that invalid options are recognized; and that both opterr
and leading ':' can silence output. */ and leading ':' can silence output. */
@@ -993,7 +993,6 @@ test_getopt (void)
ASSERT (optind == 12); ASSERT (optind == 12);
} }
} }
#endif
/* Check that the '-' flag has to come first. */ /* Check that the '-' flag has to come first. */
for (start = OPTIND_MIN; start <= 1; start++) for (start = OPTIND_MIN; start <= 1; start++)
@@ -1124,10 +1123,6 @@ test_getopt (void)
argv[argc++] = "-+"; argv[argc++] = "-+";
argv[argc] = NULL; argv[argc] = NULL;
optind = start; 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:", getopt_loop (argc, argv, "+abp:q:",
&a_seen, &b_seen, &p_value, &q_value, &a_seen, &b_seen, &p_value, &q_value,
&non_options_count, non_options, &unrecognized, &output); &non_options_count, non_options, &unrecognized, &output);
@@ -1138,7 +1133,7 @@ test_getopt (void)
ASSERT (non_options_count == 0); ASSERT (non_options_count == 0);
ASSERT (unrecognized == '+'); ASSERT (unrecognized == '+');
ASSERT (optind == 2); ASSERT (optind == 2);
ASSERT (!output); ASSERT (output);
} }
/* Check that '--' ends the argument processing. */ /* Check that '--' ends the argument processing. */
@@ -1195,6 +1190,7 @@ test_getopt (void)
ASSERT (optind = 1); ASSERT (optind = 1);
ASSERT (!output); ASSERT (!output);
} }
#endif /* GNULIB_TEST_GETOPT_GNU */
/* Check that the '+' flag has to come first. */ /* Check that the '+' flag has to come first. */
for (start = OPTIND_MIN; start <= 1; start++) for (start = OPTIND_MIN; start <= 1; start++)
@@ -1263,6 +1259,111 @@ test_getopt (void)
} }
} }
/* No tests of "-:..." or "+:...", due to glibc bug: #if GNULIB_TEST_GETOPT_GNU
http://sources.redhat.com/bugzilla/show_bug.cgi?id=11039 */ /* 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 */
} }

View File

@@ -1151,8 +1151,7 @@ test_getopt_long (void)
&non_options_count, non_options, &unrecognized); &non_options_count, non_options, &unrecognized);
ASSERT (a_seen == 0); ASSERT (a_seen == 0);
ASSERT (b_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 (q_value == NULL);
ASSERT (non_options_count == 0); ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0); ASSERT (unrecognized == 0);
@@ -2079,8 +2078,11 @@ test_getopt_long_only (void)
opterr = 0; opterr = 0;
c = do_getopt_long_only (argc, argv, "ab", long_options_required, c = do_getopt_long_only (argc, argv, "ab", long_options_required,
&option_index); &option_index);
/* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */ /* glibc getopt_long_only is intentionally different from
/* ASSERT (c == 1003); */ 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 (optind == 2);
} }
{ {
@@ -2096,8 +2098,11 @@ test_getopt_long_only (void)
opterr = 0; opterr = 0;
c = do_getopt_long_only (argc, argv, "abx::", long_options_required, c = do_getopt_long_only (argc, argv, "abx::", long_options_required,
&option_index); &option_index);
/* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */ /* glibc getopt_long_only is intentionally different from
/* ASSERT (c == 1003); */ 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 (optind == 2);
ASSERT (optarg == NULL); ASSERT (optarg == NULL);
} }