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 <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
René Scharfe committed
Mar 3, 2024 at 13:19 UTC
cb46c3faf843fa46ce2df22baeb02ad2f60da6fb
1 file changed
+49
-34
parse-options.c
+49
-34
@@ -350,14 +350,40 @@ static int is_alias(struct parse_opt_ctx_t *ctx,
350
return 0;
351
}
352
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
+
380
static enum parse_opt_result parse_long_opt(
381
struct parse_opt_ctx_t *p, const char *arg,
382
const struct option *options)
383
{
384
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 };
387
388
for (; options->type != OPTION_END; options++) {
389
const char *rest, *long_name = options->long_name;
@@ -377,31 +403,20 @@ static enum parse_opt_result parse_long_opt(
403
rest = NULL;
404
if (!rest) {
405
/* 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);
409
continue;
410
}
411
/* negation allowed? */
412
if (options->flags & PARSE_OPT_NONEG)
413
continue;
414
/* negated and abbreviated very much? */
402
- if (allow_abbrev && starts_with("no-", arg)) {
415
+ if (starts_with("no-", arg)) {
416
flags |= OPT_UNSET;
404
- goto is_abbreviated;
417
+ register_abbrev(p, options, flags ^ opt_flags,
418
+ &abbrev, &ambiguous);
419
+ continue;
420
}
421
/* negated? */
422
if (!starts_with(arg, "no-"))
@@ -409,12 +424,12 @@ is_abbreviated:
424
flags |= OPT_UNSET;
425
if (!skip_prefix(arg + 3, long_name, &rest)) {
426
/* abbreviated and negated? */
412
- if (allow_abbrev &&
413
- !strncmp(long_name, arg + 3,
427
+ if (!strncmp(long_name, arg + 3,
428
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;
433
}
434
}
435
if (*rest) {
@@ -425,24 +440,24 @@ is_abbreviated:
440
return get_value(p, options, flags ^ opt_flags);
441
}
442
428
- if (disallow_abbreviated_options && (ambiguous_option || abbrev_option))
443
+ if (disallow_abbreviated_options && (ambiguous.option || abbrev.option))
444
die("disallowed abbreviated or ambiguous option '%.*s'",
445
(int)(arg_end - arg), arg);
446
432
- if (ambiguous_option) {
447
+ if (ambiguous.option) {
448
error(_("ambiguous option: %s "
449
"(could be --%s%s or --%s%s)"),
450
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);
455
return PARSE_OPT_HELP;
456
}
442
- if (abbrev_option) {
457
+ if (abbrev.option) {
458
if (*arg_end)
459
p->opt = arg_end + 1;
445
- return get_value(p, abbrev_option, abbrev_flags);
460
+ return get_value(p, abbrev.option, abbrev.flags);
461
}
462
return PARSE_OPT_UNKNOWN;
463
}