parse-options: normalize arg and long_name before comparison

Strip "no-" from arg and long_name before comparing them. This way we no longer have to repeat the comparison with an offset of 3 for negated arguments. Note that we must not modify the "flags" value, which tracks whether arg is negated, inside the loop. When registering "--n", "--no" or "--no-" as abbreviation for any negative option, we used to OR it with OPT_UNSET and end the loop. We can simply hard-code OPT_UNSET and leave flags unchanged instead. 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 b1ce2b62fa4c6cf6d972698ac48be451cbc07718
1 file changed +22 -22
parse-options.c
+22 -22
@@ -382,28 +382,42 @@ static enum parse_opt_result parse_long_opt(
382 const struct option *options)
383 {
384 const char *arg_end = strchrnul(arg, '=');
385 + const char *arg_start = arg;
386 + enum opt_parsed flags = OPT_LONG;
387 + int arg_starts_with_no_no = 0;
388 struct parsed_option abbrev = { .option = NULL, .flags = OPT_LONG };
389 struct parsed_option ambiguous = { .option = NULL, .flags = OPT_LONG };
390
391 + if (skip_prefix(arg_start, "no-", &arg_start)) {
392 + if (skip_prefix(arg_start, "no-", &arg_start))
393 + arg_starts_with_no_no = 1;
394 + else
395 + flags |= OPT_UNSET;
396 + }
397 +
398 for (; options->type != OPTION_END; options++) {
399 const char *rest, *long_name = options->long_name;
390 - enum opt_parsed flags = OPT_LONG, opt_flags = OPT_LONG;
400 + enum opt_parsed opt_flags = OPT_LONG;
401 + int allow_unset = !(options->flags & PARSE_OPT_NONEG);
402
403 if (options->type == OPTION_SUBCOMMAND)
404 continue;
405 if (!long_name)
406 continue;
407
397 - if (!starts_with(arg, "no-") &&
398 - !(options->flags & PARSE_OPT_NONEG) &&
399 - skip_prefix(long_name, "no-", &long_name))
408 + if (skip_prefix(long_name, "no-", &long_name))
409 opt_flags |= OPT_UNSET;
410 + else if (arg_starts_with_no_no)
411 + continue;
412 +
413 + if (((flags ^ opt_flags) & OPT_UNSET) && !allow_unset)
414 + continue;
415
402 - if (!skip_prefix(arg, long_name, &rest))
416 + if (!skip_prefix(arg_start, long_name, &rest))
417 rest = NULL;
418 if (!rest) {
419 /* abbreviated? */
406 - if (!strncmp(long_name, arg, arg_end - arg)) {
420 + if (!strncmp(long_name, arg_start, arg_end - arg_start)) {
421 register_abbrev(p, options, flags ^ opt_flags,
422 &abbrev, &ambiguous);
423 }
@@ -412,24 +426,10 @@ static enum parse_opt_result parse_long_opt(
426 continue;
427 /* negated and abbreviated very much? */
428 if (starts_with("no-", arg)) {
415 - flags |= OPT_UNSET;
416 - register_abbrev(p, options, flags ^ opt_flags,
429 + register_abbrev(p, options, OPT_UNSET ^ opt_flags,
430 &abbrev, &ambiguous);
418 - continue;
419 - }
420 - /* negated? */
421 - if (!starts_with(arg, "no-"))
422 - continue;
423 - flags |= OPT_UNSET;
424 - if (!skip_prefix(arg + 3, long_name, &rest)) {
425 - /* abbreviated and negated? */
426 - if (!strncmp(long_name, arg + 3,
427 - arg_end - arg - 3))
428 - register_abbrev(p, options,
429 - flags ^ opt_flags,
430 - &abbrev, &ambiguous);
431 - continue;
431 }
432 + continue;
433 }
434 if (*rest) {
435 if (*rest != '=')