Skip to content

Commit

Permalink
parse-options: abbreviation engine fix.
Browse files Browse the repository at this point in the history
When an option could be an ambiguous abbreviation of two options, the code
used to error out.  Even if an exact match would have occured later.

Test and original patch by Pierre Habouzit.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Johannes Schindelin authored and Junio C Hamano committed Nov 6, 2007
1 parent fe61935 commit 243e061
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 12 deletions.
33 changes: 21 additions & 12 deletions parse-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
const struct option *options)
{
const char *arg_end = strchr(arg, '=');
const struct option *abbrev_option = NULL;
int abbrev_flags = 0;
const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
int abbrev_flags = 0, ambiguous_flags = 0;

if (!arg_end)
arg_end = arg + strlen(arg);
Expand All @@ -137,16 +137,16 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
/* abbreviated? */
if (!strncmp(options->long_name, arg, arg_end - arg)) {
is_abbreviated:
if (abbrev_option)
return error("Ambiguous option: %s "
"(could be --%s%s or --%s%s)",
arg,
(flags & OPT_UNSET) ?
"no-" : "",
options->long_name,
(abbrev_flags & OPT_UNSET) ?
"no-" : "",
abbrev_option->long_name);
if (abbrev_option) {
/*
* If this is abbreviated, it is
* ambiguous. So when there is no
* exact match later, we need to
* error out.
*/
ambiguous_option = abbrev_option;
ambiguous_flags = abbrev_flags;
}
if (!(flags & OPT_UNSET) && *arg_end)
p->opt = arg_end + 1;
abbrev_option = options;
Expand Down Expand Up @@ -176,6 +176,15 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
}
return get_value(p, options, flags);
}

if (ambiguous_option)
return error("Ambiguous option: %s "
"(could be --%s%s or --%s%s)",
arg,
(ambiguous_flags & OPT_UNSET) ? "no-" : "",
ambiguous_option->long_name,
(abbrev_flags & OPT_UNSET) ? "no-" : "",
abbrev_option->long_name);
if (abbrev_option)
return get_value(p, abbrev_option, abbrev_flags);
return error("unknown option `%s'", arg);
Expand Down
13 changes: 13 additions & 0 deletions t/t0040-parse-options.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ string options
-s, --string <string>
get a string
--string2 <str> get another string
--st <st> get another string (pervert ordering)
EOF

Expand Down Expand Up @@ -90,4 +91,16 @@ test_expect_failure 'ambiguously abbreviated option' '
test $? != 129
'

cat > expect << EOF
boolean: 0
integer: 0
string: 123
EOF

test_expect_success 'non ambiguous option (after two options it abbreviates)' '
test-parse-options --st 123 > output 2> output.err &&
test ! -s output.err &&
git diff expect output
'

test_done
1 change: 1 addition & 0 deletions test-parse-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ int main(int argc, const char **argv)
OPT_GROUP("string options"),
OPT_STRING('s', "string", &string, "string", "get a string"),
OPT_STRING(0, "string2", &string, "str", "get another string"),
OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"),
OPT_END(),
};
int i;
Expand Down

0 comments on commit 243e061

Please sign in to comment.