Browse Source

parse-options: abbreviation engine fix.

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>
maint
Johannes Schindelin 18 years ago committed by Junio C Hamano
parent
commit
243e0614e0
  1. 33
      parse-options.c
  2. 13
      t/t0040-parse-options.sh
  3. 1
      test-parse-options.c

33
parse-options.c

@ -119,8 +119,8 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
const struct option *options) const struct option *options)
{ {
const char *arg_end = strchr(arg, '='); const char *arg_end = strchr(arg, '=');
const struct option *abbrev_option = NULL; const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
int abbrev_flags = 0; int abbrev_flags = 0, ambiguous_flags = 0;


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

13
t/t0040-parse-options.sh

@ -18,6 +18,7 @@ string options
-s, --string <string> -s, --string <string>
get a string get a string
--string2 <str> get another string --string2 <str> get another string
--st <st> get another string (pervert ordering)


EOF EOF


@ -90,4 +91,16 @@ test_expect_failure 'ambiguously abbreviated option' '
test $? != 129 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 test_done

1
test-parse-options.c

@ -18,6 +18,7 @@ int main(int argc, const char **argv)
OPT_GROUP("string options"), OPT_GROUP("string options"),
OPT_STRING('s', "string", &string, "string", "get a string"), OPT_STRING('s', "string", &string, "string", "get a string"),
OPT_STRING(0, "string2", &string, "str", "get another string"), OPT_STRING(0, "string2", &string, "str", "get another string"),
OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"),
OPT_END(), OPT_END(),
}; };
int i; int i;

Loading…
Cancel
Save