summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-05-15 13:35:09 -0400
committerUlrich Drepper <drepper@gmail.com>2011-05-15 13:35:09 -0400
commitbd25564e1e98910ed69043ed6a6f884ce60e5780 (patch)
tree76b63ae4d281a28b7a00956504eb8ea13e8e2118
parentbac102db9293f3f619c319312e05dfeb7051a7ad (diff)
Provide more helpful error message in getopt
If provide with an ambiguous long option we now show all the possibilities.
-rw-r--r--ChangeLog6
-rw-r--r--NEWS14
-rw-r--r--posix/Makefile4
-rw-r--r--posix/getopt.c79
-rw-r--r--posix/tst-getopt_long1.c62
5 files changed, 137 insertions, 28 deletions
diff --git a/ChangeLog b/ChangeLog
index 47ca10d25e..0c0aa6a2ff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/NEWS b/NEWS
index 43c3a6cd73..7100e1dbcb 100644
--- a/NEWS
+++ b/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.
diff --git a/posix/Makefile b/posix/Makefile
index 373e50b0a9..e89f21e5b3 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -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
diff --git a/posix/getopt.c b/posix/getopt.c
index 2746364fc7..db89abf6a7 100644
--- a/posix/getopt.c
+++ b/posix/getopt.c
@@ -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);
diff --git a/posix/tst-getopt_long1.c b/posix/tst-getopt_long1.c
new file mode 100644
index 0000000000..e0ecd12190
--- /dev/null
+++ b/posix/tst-getopt_long1.c
@@ -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;
+}