diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2013-06-08 22:47:57 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2013-06-08 22:47:57 +0000 |
commit | b338b534346855a8f1d8fed88487a5671d49d20c (patch) | |
tree | 88c917f579df400b05e2e8e8ff7d3cd41249c2d1 /lib/libc/stdlib/getopt_long.c | |
parent | ff11d3867468575fa182403699dba5ba440d338c (diff) |
Fix parsing of ambiguous options, the whole loop must be processed.
From FreeBSD. OK miod@
Diffstat (limited to 'lib/libc/stdlib/getopt_long.c')
-rw-r--r-- | lib/libc/stdlib/getopt_long.c | 37 |
1 files changed, 22 insertions, 15 deletions
diff --git a/lib/libc/stdlib/getopt_long.c b/lib/libc/stdlib/getopt_long.c index e149fe0ace2..f46cd8bf4e4 100644 --- a/lib/libc/stdlib/getopt_long.c +++ b/lib/libc/stdlib/getopt_long.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getopt_long.c,v 1.25 2011/03/05 22:10:11 guenther Exp $ */ +/* $OpenBSD: getopt_long.c,v 1.26 2013/06/08 22:47:56 millert Exp $ */ /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ /* @@ -77,7 +77,7 @@ char *optarg; /* argument associated with option */ static int getopt_internal(int, char * const *, const char *, const struct option *, int *, int); static int parse_long_options(char * const *, const char *, - const struct option *, int *, int); + const struct option *, int *, int, int); static int gcd(int, int); static void permute_args(int, int, int, char * const *); @@ -157,14 +157,16 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end, */ static int parse_long_options(char * const *nargv, const char *options, - const struct option *long_options, int *idx, int short_too) + const struct option *long_options, int *idx, int short_too, int flags) { char *current_argv, *has_equal; size_t current_argv_len; - int i, match; + int i, match, exact_match, second_partial_match; current_argv = place; match = -1; + exact_match = 0; + second_partial_match = 0; optind++; @@ -184,6 +186,7 @@ parse_long_options(char * const *nargv, const char *options, if (strlen(long_options[i].name) == current_argv_len) { /* exact match */ match = i; + exact_match = 1; break; } /* @@ -193,16 +196,20 @@ parse_long_options(char * const *nargv, const char *options, if (short_too && current_argv_len == 1) continue; - if (match == -1) /* partial match */ + if (match == -1) /* first partial match */ match = i; - else { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - warnx(ambig, (int)current_argv_len, - current_argv); - optopt = 0; - return (BADCH); - } + else if ((flags & FLAG_LONGONLY) || + long_options[i].has_arg != long_options[match].has_arg || + long_options[i].flag != long_options[match].flag || + long_options[i].val != long_options[match].val) + second_partial_match = 1; + } + if (!exact_match && second_partial_match) { + /* 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 @@ -398,7 +405,7 @@ start: short_too = 1; /* could be short option too */ optchar = parse_long_options(nargv, options, long_options, - idx, short_too); + idx, short_too, flags); if (optchar != -1) { place = EMSG; return (optchar); @@ -435,7 +442,7 @@ start: } else /* white space */ place = nargv[optind]; optchar = parse_long_options(nargv, options, long_options, - idx, 0); + idx, 0, flags); place = EMSG; return (optchar); } |