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).
This commit is contained in:
parent
8a70d87249
commit
15b661abe9
|
@ -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 */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: opttest,v 1.1 2007/01/18 16:29:21 ginsbach Exp $
|
||||
# $NetBSD: opttest,v 1.2 2007/07/05 16:05:40 ginsbach Exp $
|
||||
#
|
||||
# GNU libc tests with these
|
||||
#
|
||||
|
@ -19,9 +19,9 @@ result: -optional=bazbug|0
|
|||
# This is promblematic
|
||||
args: foo --col
|
||||
# GNU libc 2.1.3 this fails with ambiguous
|
||||
result: !?|0
|
||||
#result: !?|0
|
||||
# GNU libc 2.2 >= this works
|
||||
#result: color|0
|
||||
result: color|0
|
||||
#
|
||||
args: foo --colour
|
||||
result: -colour|0
|
||||
|
@ -30,6 +30,18 @@ result: -colour|0
|
|||
args: foo -a -b -cfoobar --required foobar --optional=bazbug --none random \
|
||||
--col --color --colour
|
||||
# GNU libc 2.1.3 this fails with ambiguous
|
||||
result: a,b,c=foobar,-required=foobar,-optional=bazbug,-none,!?,-color,-colour|1
|
||||
#result: a,b,c=foobar,-required=foobar,-optional=bazbug,-none,!?,-color,-colour|1
|
||||
# GNU libc 2.2 >= this works
|
||||
#result: a,b,c=foobar,-required=foobar,-optional=bazbug,-none,-color,-color,-colour|1
|
||||
result: a,b,c=foobar,-required=foobar,-optional=bazbug,-none,-color,-color,-colour|1
|
||||
#
|
||||
# The order of long options in the long option array should not matter.
|
||||
# An exact match should never be treated as ambiguous.
|
||||
#
|
||||
optstring: fgl
|
||||
longopts: 3
|
||||
longopt: list-foobar, no_argument, lopt, 'f'
|
||||
longopt: list-goobar, no_argument, lopt, 'g'
|
||||
longopt: list, no_argument, lopt, 'l'
|
||||
#
|
||||
args: foo --list
|
||||
result: -list|0
|
||||
|
|
Loading…
Reference in New Issue