Provide more helpful error message in getopt

If provide with an ambiguous long option we now show all the possibilities.
This commit is contained in:
Ulrich Drepper 2011-05-15 13:35:09 -04:00
parent bac102db92
commit bd25564e1e
5 changed files with 137 additions and 28 deletions

View File

@ -1,5 +1,11 @@
2011-05-15 Ulrich Drepper <drepper@gmail.com>
[BZ #7101]
* posix/getopt.c (_getopt_internal_r): List all ambigious possibilities
when an incomplete long option is used.
* posix/tst-getopt_long1.c: New file.
* posix/Makefile (tests): Add tst-getopt_long1.
[BZ #10138]
* scripts/config.guess: Update from autoconf-2.68.
* scripts/config.sub: Likewise.

14
NEWS
View File

@ -9,13 +9,13 @@ Version 2.14
* The following bugs are resolved with this release:
386, 9730, 9732, 9809, 10138, 10149, 10157, 11257, 11258, 11487, 11532,
11578, 11653, 11668, 11724, 11901, 11945, 11947, 11952, 12052, 12083,
12158, 12178, 12200, 12346, 12393, 12420, 12432, 12445, 12449, 12453,
12454, 12460, 12469, 12489, 12509, 12510, 12511, 12518, 12527, 12541,
12545, 12551, 12582, 12583, 12587, 12597, 12601, 12611, 12625, 12626,
12631, 12650, 12653, 12655, 12660, 12681, 12685, 12711, 12713, 12714,
12717, 12723, 12724, 12734, 12738
386, 7101, 9730, 9732, 9809, 10138, 10149, 10157, 11257, 11258, 11487,
11532, 11578, 11653, 11668, 11724, 11901, 11945, 11947, 11952, 12052,
12083, 12158, 12178, 12200, 12346, 12393, 12420, 12432, 12445, 12449,
12453, 12454, 12460, 12469, 12489, 12509, 12510, 12511, 12518, 12527,
12541, 12545, 12551, 12582, 12583, 12587, 12597, 12601, 12611, 12625,
12626, 12631, 12650, 12653, 12655, 12660, 12681, 12685, 12711, 12713,
12714, 12717, 12723, 12724, 12734, 12738
* The RPC implementation in libc is obsoleted. Old programs keep working
but new programs cannot be linked with the routines in libc anymore.

View File

@ -1,4 +1,4 @@
# Copyright (C) 1991-1999, 2000-2007, 2009, 2010 Free Software Foundation, Inc.
# Copyright (C) 1991-2007, 2009, 2010, 2011 Free Software Foundation, Inc.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
@ -94,7 +94,7 @@ tests := tstgetopt testfnm runtests runptests \
tst-rfc3484-3 \
tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset \
bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \
bug-getopt5
bug-getopt5 tst-getopt_long1
xtests := bug-ga2
ifeq (yes,$(build-shared))
test-srcs := globtest

View File

@ -2,7 +2,7 @@
NOTE: getopt is part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to drepper@gnu.org
before changing it!
Copyright (C) 1987-1996,1998-2004,2008,2009,2010
Copyright (C) 1987-1996,1998-2004,2008,2009,2010,2011
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@ -526,23 +526,28 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring,
|| !strchr (optstring, argv[d->optind][1])))))
{
char *nameend;
unsigned int namelen;
const struct option *p;
const struct option *pfound = NULL;
struct option_list
{
const struct option *p;
struct option_list *next;
} *ambig_list = NULL;
int exact = 0;
int ambig = 0;
int indfound = -1;
int option_index;
for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
namelen = nameend - d->__nextchar;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar))
if (!strncmp (p->name, d->__nextchar, namelen))
{
if ((unsigned int) (nameend - d->__nextchar)
== (unsigned int) strlen (p->name))
if (namelen == (unsigned int) strlen (p->name))
{
/* Exact match found. */
pfound = p;
@ -560,35 +565,71 @@ _getopt_internal_r (int argc, char *const *argv, const char *optstring,
|| pfound->has_arg != p->has_arg
|| pfound->flag != p->flag
|| pfound->val != p->val)
/* Second or later nonexact match found. */
ambig = 1;
{
/* Second or later nonexact match found. */
struct option_list *newp = alloca (sizeof (*newp));
newp->p = p;
newp->next = ambig_list;
ambig_list = newp;
}
}
if (ambig && !exact)
if (ambig_list != NULL && !exact)
{
if (print_errors)
{
struct option_list first;
first.p = pfound;
first.next = ambig_list;
ambig_list = &first;
#if defined _LIBC && defined USE_IN_LIBIO
char *buf;
char *buf = NULL;
size_t buflen = 0;
if (__asprintf (&buf, _("%s: option '%s' is ambiguous\n"),
argv[0], argv[d->optind]) >= 0)
FILE *fp = open_memstream (&buf, &buflen);
if (fp != NULL)
{
_IO_flockfile (stderr);
fprintf (fp,
_("%s: option '%s' is ambiguous; possibilities:"),
argv[0], argv[d->optind]);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
do
{
fprintf (fp, " '--%s'", ambig_list->p->name);
ambig_list = ambig_list->next;
}
while (ambig_list != NULL);
__fxprintf (NULL, "%s", buf);
fputc_unlocked ('\n', fp);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
if (__builtin_expect (fclose (fp) != EOF, 1))
{
_IO_flockfile (stderr);
free (buf);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
free (buf);
}
}
#else
fprintf (stderr, _("%s: option '%s' is ambiguous\n"),
fprintf (stderr,
_("%s: option '%s' is ambiguous; possibilities:"),
argv[0], argv[d->optind]);
do
{
fprintf (stderr, " '--%s'", ambig_list->p->name);
ambig_list = ambig_list->next;
}
while (ambig_list != NULL);
fputc ('\n', stderr);
#endif
}
d->__nextchar += strlen (d->__nextchar);

62
posix/tst-getopt_long1.c Normal file
View File

@ -0,0 +1,62 @@
static void do_prepare (void);
#define PREPARE(argc, argv) do_prepare ()
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
static char *fname;
static void
do_prepare (void)
{
if (create_temp_file ("tst-getopt_long1", &fname) < 0)
{
printf ("cannot create temp file: %m\n");
exit (1);
}
}
static const struct option opts[] =
{
{ "one", no_argument, NULL, '1' },
{ "two", no_argument, NULL, '2' },
{ "one-one", no_argument, NULL, '3' },
{ "four", no_argument, NULL, '4' },
{ "onto", no_argument, NULL, '5' },
{ NULL, 0, NULL, 0 }
};
static int
do_test (void)
{
if (freopen (fname, "w+", stderr) == NULL)
{
printf ("freopen failed: %m\n");
return 1;
}
char *argv[] = { "program", "--on" };
int argc = 2;
int c = getopt_long (argc, argv, "12345", opts, NULL);
printf ("return value: %c\n", c);
rewind (stderr);
char *line = NULL;
size_t len = 0;
if (getline (&line, &len, stderr) < 0)
{
printf ("cannot read stderr redirect: %m\n");
return 1;
}
printf ("message = \"%s\"\n", line);
static const char expected[] = "\
program: option '--on' is ambiguous; possibilities: '--one' '--onto' '--one-one'\n";
return c != '?' || strcmp (line, expected) != 0;
}