mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00:00
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:
parent
bac102db92
commit
bd25564e1e
@ -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
14
NEWS
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
62
posix/tst-getopt_long1.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user