Skip to content

Commit 91febfb

Browse files
committed
Merge branch 'js/parseopt-abbrev-fix'
* js/parseopt-abbrev-fix: parse-options: abbreviation engine fix.
2 parents 82527cf + 243e061 commit 91febfb

File tree

3 files changed

+35
-12
lines changed

3 files changed

+35
-12
lines changed

parse-options.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
119119
const struct option *options)
120120
{
121121
const char *arg_end = strchr(arg, '=');
122-
const struct option *abbrev_option = NULL;
123-
int abbrev_flags = 0;
122+
const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
123+
int abbrev_flags = 0, ambiguous_flags = 0;
124124

125125
if (!arg_end)
126126
arg_end = arg + strlen(arg);
@@ -137,16 +137,16 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
137137
/* abbreviated? */
138138
if (!strncmp(options->long_name, arg, arg_end - arg)) {
139139
is_abbreviated:
140-
if (abbrev_option)
141-
return error("Ambiguous option: %s "
142-
"(could be --%s%s or --%s%s)",
143-
arg,
144-
(flags & OPT_UNSET) ?
145-
"no-" : "",
146-
options->long_name,
147-
(abbrev_flags & OPT_UNSET) ?
148-
"no-" : "",
149-
abbrev_option->long_name);
140+
if (abbrev_option) {
141+
/*
142+
* If this is abbreviated, it is
143+
* ambiguous. So when there is no
144+
* exact match later, we need to
145+
* error out.
146+
*/
147+
ambiguous_option = abbrev_option;
148+
ambiguous_flags = abbrev_flags;
149+
}
150150
if (!(flags & OPT_UNSET) && *arg_end)
151151
p->opt = arg_end + 1;
152152
abbrev_option = options;
@@ -176,6 +176,15 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
176176
}
177177
return get_value(p, options, flags);
178178
}
179+
180+
if (ambiguous_option)
181+
return error("Ambiguous option: %s "
182+
"(could be --%s%s or --%s%s)",
183+
arg,
184+
(ambiguous_flags & OPT_UNSET) ? "no-" : "",
185+
ambiguous_option->long_name,
186+
(abbrev_flags & OPT_UNSET) ? "no-" : "",
187+
abbrev_option->long_name);
179188
if (abbrev_option)
180189
return get_value(p, abbrev_option, abbrev_flags);
181190
return error("unknown option `%s'", arg);

t/t0040-parse-options.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ string options
1818
-s, --string <string>
1919
get a string
2020
--string2 <str> get another string
21+
--st <st> get another string (pervert ordering)
2122
2223
EOF
2324

@@ -90,4 +91,16 @@ test_expect_failure 'ambiguously abbreviated option' '
9091
test $? != 129
9192
'
9293

94+
cat > expect << EOF
95+
boolean: 0
96+
integer: 0
97+
string: 123
98+
EOF
99+
100+
test_expect_success 'non ambiguous option (after two options it abbreviates)' '
101+
test-parse-options --st 123 > output 2> output.err &&
102+
test ! -s output.err &&
103+
git diff expect output
104+
'
105+
93106
test_done

test-parse-options.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ int main(int argc, const char **argv)
1818
OPT_GROUP("string options"),
1919
OPT_STRING('s', "string", &string, "string", "get a string"),
2020
OPT_STRING(0, "string2", &string, "str", "get another string"),
21+
OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"),
2122
OPT_END(),
2223
};
2324
int i;

0 commit comments

Comments
 (0)