Skip to content

Commit cb46c3f

Browse files
rscharfegitster
authored andcommitted
parse-options: factor out register_abbrev() and struct parsed_option
Add a function, register_abbrev(), for storing the necessary details for remembering an abbreviated and thus potentially ambiguous option. Call it instead of sharing the code using goto, to make the control flow more explicit. Conveniently collect these details in the new struct parsed_option to reduce the number of necessary function arguments. Signed-off-by: René Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 597f9d0 commit cb46c3f

File tree

1 file changed

+49
-34
lines changed

1 file changed

+49
-34
lines changed

parse-options.c

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -350,14 +350,40 @@ static int is_alias(struct parse_opt_ctx_t *ctx,
350350
return 0;
351351
}
352352

353+
struct parsed_option {
354+
const struct option *option;
355+
enum opt_parsed flags;
356+
};
357+
358+
static void register_abbrev(struct parse_opt_ctx_t *p,
359+
const struct option *option, enum opt_parsed flags,
360+
struct parsed_option *abbrev,
361+
struct parsed_option *ambiguous)
362+
{
363+
if (p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)
364+
return;
365+
if (abbrev->option &&
366+
!is_alias(p, abbrev->option, option)) {
367+
/*
368+
* If this is abbreviated, it is
369+
* ambiguous. So when there is no
370+
* exact match later, we need to
371+
* error out.
372+
*/
373+
ambiguous->option = abbrev->option;
374+
ambiguous->flags = abbrev->flags;
375+
}
376+
abbrev->option = option;
377+
abbrev->flags = flags;
378+
}
379+
353380
static enum parse_opt_result parse_long_opt(
354381
struct parse_opt_ctx_t *p, const char *arg,
355382
const struct option *options)
356383
{
357384
const char *arg_end = strchrnul(arg, '=');
358-
const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
359-
enum opt_parsed abbrev_flags = OPT_LONG, ambiguous_flags = OPT_LONG;
360-
int allow_abbrev = !(p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT);
385+
struct parsed_option abbrev = { .option = NULL, .flags = OPT_LONG };
386+
struct parsed_option ambiguous = { .option = NULL, .flags = OPT_LONG };
361387

362388
for (; options->type != OPTION_END; options++) {
363389
const char *rest, *long_name = options->long_name;
@@ -377,44 +403,33 @@ static enum parse_opt_result parse_long_opt(
377403
rest = NULL;
378404
if (!rest) {
379405
/* abbreviated? */
380-
if (allow_abbrev &&
381-
!strncmp(long_name, arg, arg_end - arg)) {
382-
is_abbreviated:
383-
if (abbrev_option &&
384-
!is_alias(p, abbrev_option, options)) {
385-
/*
386-
* If this is abbreviated, it is
387-
* ambiguous. So when there is no
388-
* exact match later, we need to
389-
* error out.
390-
*/
391-
ambiguous_option = abbrev_option;
392-
ambiguous_flags = abbrev_flags;
393-
}
394-
abbrev_option = options;
395-
abbrev_flags = flags ^ opt_flags;
406+
if (!strncmp(long_name, arg, arg_end - arg)) {
407+
register_abbrev(p, options, flags ^ opt_flags,
408+
&abbrev, &ambiguous);
396409
continue;
397410
}
398411
/* negation allowed? */
399412
if (options->flags & PARSE_OPT_NONEG)
400413
continue;
401414
/* negated and abbreviated very much? */
402-
if (allow_abbrev && starts_with("no-", arg)) {
415+
if (starts_with("no-", arg)) {
403416
flags |= OPT_UNSET;
404-
goto is_abbreviated;
417+
register_abbrev(p, options, flags ^ opt_flags,
418+
&abbrev, &ambiguous);
419+
continue;
405420
}
406421
/* negated? */
407422
if (!starts_with(arg, "no-"))
408423
continue;
409424
flags |= OPT_UNSET;
410425
if (!skip_prefix(arg + 3, long_name, &rest)) {
411426
/* abbreviated and negated? */
412-
if (allow_abbrev &&
413-
!strncmp(long_name, arg + 3,
427+
if (!strncmp(long_name, arg + 3,
414428
arg_end - arg - 3))
415-
goto is_abbreviated;
416-
else
417-
continue;
429+
register_abbrev(p, options,
430+
flags ^ opt_flags,
431+
&abbrev, &ambiguous);
432+
continue;
418433
}
419434
}
420435
if (*rest) {
@@ -425,24 +440,24 @@ static enum parse_opt_result parse_long_opt(
425440
return get_value(p, options, flags ^ opt_flags);
426441
}
427442

428-
if (disallow_abbreviated_options && (ambiguous_option || abbrev_option))
443+
if (disallow_abbreviated_options && (ambiguous.option || abbrev.option))
429444
die("disallowed abbreviated or ambiguous option '%.*s'",
430445
(int)(arg_end - arg), arg);
431446

432-
if (ambiguous_option) {
447+
if (ambiguous.option) {
433448
error(_("ambiguous option: %s "
434449
"(could be --%s%s or --%s%s)"),
435450
arg,
436-
(ambiguous_flags & OPT_UNSET) ? "no-" : "",
437-
ambiguous_option->long_name,
438-
(abbrev_flags & OPT_UNSET) ? "no-" : "",
439-
abbrev_option->long_name);
451+
(ambiguous.flags & OPT_UNSET) ? "no-" : "",
452+
ambiguous.option->long_name,
453+
(abbrev.flags & OPT_UNSET) ? "no-" : "",
454+
abbrev.option->long_name);
440455
return PARSE_OPT_HELP;
441456
}
442-
if (abbrev_option) {
457+
if (abbrev.option) {
443458
if (*arg_end)
444459
p->opt = arg_end + 1;
445-
return get_value(p, abbrev_option, abbrev_flags);
460+
return get_value(p, abbrev.option, abbrev.flags);
446461
}
447462
return PARSE_OPT_UNKNOWN;
448463
}

0 commit comments

Comments
 (0)