diff options
author | Ulrich Drepper <drepper@gmail.com> | 2011-05-15 13:35:09 -0400 |
---|---|---|
committer | Ulrich Drepper <drepper@gmail.com> | 2011-05-15 13:35:09 -0400 |
commit | bd25564e1e98910ed69043ed6a6f884ce60e5780 (patch) | |
tree | 76b63ae4d281a28b7a00956504eb8ea13e8e2118 /posix | |
parent | bac102db9293f3f619c319312e05dfeb7051a7ad (diff) | |
download | glibc-bd25564e1e98910ed69043ed6a6f884ce60e5780.zip glibc-bd25564e1e98910ed69043ed6a6f884ce60e5780.tar.gz glibc-bd25564e1e98910ed69043ed6a6f884ce60e5780.tar.bz2 |
Provide more helpful error message in getopt
If provide with an ambiguous long option we now show all the possibilities.
Diffstat (limited to 'posix')
-rw-r--r-- | posix/Makefile | 4 | ||||
-rw-r--r-- | posix/getopt.c | 79 | ||||
-rw-r--r-- | posix/tst-getopt_long1.c | 62 |
3 files changed, 124 insertions, 21 deletions
diff --git a/posix/Makefile b/posix/Makefile index 373e50b..e89f21e 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 2746364..db89abf 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 0000000..e0ecd12 --- /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; +} |