summaryrefslogtreecommitdiff
path: root/lib/libc/stdlib
diff options
context:
space:
mode:
authorginsbach <ginsbach@NetBSD.org>2007-07-05 16:05:40 +0000
committerginsbach <ginsbach@NetBSD.org>2007-07-05 16:05:40 +0000
commit15b661abe9a97cb22cc41bf4a7590ddfb5e3587c (patch)
treed3c1cc6be9bb266da879619afc882073eb5b8b4a /lib/libc/stdlib
parent8a70d8724963b8bcde693b8839410791c7ba38d0 (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.c32
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 */