diff options
| author | ginsbach <ginsbach@NetBSD.org> | 2007-07-05 16:05:40 +0000 |
|---|---|---|
| committer | ginsbach <ginsbach@NetBSD.org> | 2007-07-05 16:05:40 +0000 |
| commit | 15b661abe9a97cb22cc41bf4a7590ddfb5e3587c (patch) | |
| tree | d3c1cc6be9bb266da879619afc882073eb5b8b4a /lib/libc/stdlib | |
| parent | 8a70d8724963b8bcde693b8839410791c7ba38d0 (diff) | |
Fix several end cases:
o If a long option looks like an ambiguous abbreviation of two or more long
options, but all the possible interpretations would return the same
value, then just return that value without complaining that it's
ambiguous.
o If a long option could be interpreted either as an exact match for one
long option, or as an abbreviation for one or more other long options,
then treat it as the exact match.
These changes align NetBSD's getopt_long(3) with the current behavior of
GNU getopt_long(3), the de facto standard, and FreeBSD's getopt_long(3).
Diffstat (limited to 'lib/libc/stdlib')
| -rw-r--r-- | lib/libc/stdlib/getopt_long.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/lib/libc/stdlib/getopt_long.c b/lib/libc/stdlib/getopt_long.c index 4a1af664cd2..7e9a625d526 100644 --- a/lib/libc/stdlib/getopt_long.c +++ b/lib/libc/stdlib/getopt_long.c @@ -1,4 +1,4 @@ -/* $NetBSD: getopt_long.c,v 1.20 2006/10/04 17:29:42 wiz Exp $ */ +/* $NetBSD: getopt_long.c,v 1.21 2007/07/05 16:05:40 ginsbach Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: getopt_long.c,v 1.20 2006/10/04 17:29:42 wiz Exp $"); +__RCSID("$NetBSD: getopt_long.c,v 1.21 2007/07/05 16:05:40 ginsbach Exp $"); #endif /* LIBC_SCCS and not lint */ #include "namespace.h" @@ -362,6 +362,11 @@ getopt_long(nargc, nargv, options, long_options, idx) { int retval; +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); _DIAGASSERT(long_options != NULL); @@ -371,10 +376,11 @@ getopt_long(nargc, nargv, options, long_options, idx) if (retval == -2) { char *current_argv, *has_equal; size_t current_argv_len; - int i, match; + int i, ambiguous, match; current_argv = __UNCONST(place); match = -1; + ambiguous = 0; optind++; place = EMSG; @@ -409,18 +415,21 @@ getopt_long(nargc, nargv, options, long_options, idx) (unsigned)current_argv_len) { /* exact match */ match = i; + ambiguous = 0; break; } if (match == -1) /* partial match */ match = i; - else { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - warnx(ambig, (int)current_argv_len, - current_argv); - optopt = 0; - return BADCH; - } + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return BADCH; } if (match != -1) { /* option found */ if (long_options[match].has_arg == no_argument @@ -485,5 +494,6 @@ getopt_long(nargc, nargv, options, long_options, idx) *idx = match; } return retval; +#undef IDENTICAL_INTERPRETATION } #endif /* !GETOPT_LONG */ |
