From: Tomas Glozar Date: Thu, 28 May 2026 10:32:51 +0000 (+0200) Subject: tools subcmd: allow parsing distinct --opt and --no-opt X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=da62fc345846211442d01feeae34b376e4242c89;p=thirdparty%2Fkernel%2Flinux.git tools subcmd: allow parsing distinct --opt and --no-opt libsubcmd automatically generates for every option --opt an equivalent negated option, --no-opt, to unset the option. Vice versa, for every option declared as --no-opt, a shorthand --opt is declared for convenience. Add a flag, PARSE_OPT_NOAUTONEG, to disable this behavior. This new flag behaves similarly to the already existing PARSE_OPT_NONEG, only it does not reject the --no-opt variant, but leaves it undefined. That is useful when there is a conflicting distinct --no-opt option in the syntax of the tool. PARSE_OPT_NOAUTONEG is enabled per-option, allowing to unset other options that do not have this conflict. Link: https://lore.kernel.org/r/20260528103254.2990068-4-tglozar@redhat.com Signed-off-by: Tomas Glozar --- diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c index 664b2053bb77..e83200e9f56a 100644 --- a/tools/lib/subcmd/parse-options.c +++ b/tools/lib/subcmd/parse-options.c @@ -427,7 +427,8 @@ retry: return 0; } if (!rest) { - if (strstarts(options->long_name, "no-")) { + if (strstarts(options->long_name, "no-") && + !(options->flags & PARSE_OPT_NOAUTONEG)) { /* * The long name itself starts with "no-", so * accept the option without "no-" so that users @@ -465,12 +466,12 @@ is_abbreviated: continue; } /* negated and abbreviated very much? */ - if (strstarts("no-", arg)) { + if (strstarts("no-", arg) && !(options->flags & PARSE_OPT_NOAUTONEG)) { flags |= OPT_UNSET; goto is_abbreviated; } /* negated? */ - if (strncmp(arg, "no-", 3)) + if (strncmp(arg, "no-", 3) || (options->flags & PARSE_OPT_NOAUTONEG)) continue; flags |= OPT_UNSET; rest = skip_prefix(arg + 3, options->long_name); @@ -1019,7 +1020,8 @@ opt: if (strstarts(opts->long_name, optstr)) print_option_help(opts, 0); if (strstarts("no-", optstr) && - strstarts(opts->long_name, optstr + 3)) + strstarts(opts->long_name, optstr + 3) && + !(opts->flags & PARSE_OPT_NOAUTONEG)) print_option_help(opts, 0); } diff --git a/tools/lib/subcmd/parse-options.h b/tools/lib/subcmd/parse-options.h index c573a0ca5ca6..38df5fd21963 100644 --- a/tools/lib/subcmd/parse-options.h +++ b/tools/lib/subcmd/parse-options.h @@ -47,6 +47,7 @@ enum parse_opt_option_flags { PARSE_OPT_NOEMPTY = 128, PARSE_OPT_NOBUILD = 256, PARSE_OPT_CANSKIP = 512, + PARSE_OPT_NOAUTONEG = 1024, }; struct option; @@ -149,6 +150,8 @@ struct option { { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb } #define OPT_CALLBACK(s, l, v, a, h, f) \ { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f) } +#define OPT_CALLBACK_FLAG(s, l, v, a, h, f, fl) \ + { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .flags = (fl) } #define OPT_CALLBACK_SET(s, l, v, os, a, h, f) \ { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .set = check_vtype(os, bool *)} #define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \