Skip to content

Commit da62fc3

Browse files
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 <tglozar@redhat.com>
1 parent 534d9a9 commit da62fc3

2 files changed

Lines changed: 9 additions & 4 deletions

File tree

tools/lib/subcmd/parse-options.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,8 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
427427
return 0;
428428
}
429429
if (!rest) {
430-
if (strstarts(options->long_name, "no-")) {
430+
if (strstarts(options->long_name, "no-") &&
431+
!(options->flags & PARSE_OPT_NOAUTONEG)) {
431432
/*
432433
* The long name itself starts with "no-", so
433434
* accept the option without "no-" so that users
@@ -465,12 +466,12 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
465466
continue;
466467
}
467468
/* negated and abbreviated very much? */
468-
if (strstarts("no-", arg)) {
469+
if (strstarts("no-", arg) && !(options->flags & PARSE_OPT_NOAUTONEG)) {
469470
flags |= OPT_UNSET;
470471
goto is_abbreviated;
471472
}
472473
/* negated? */
473-
if (strncmp(arg, "no-", 3))
474+
if (strncmp(arg, "no-", 3) || (options->flags & PARSE_OPT_NOAUTONEG))
474475
continue;
475476
flags |= OPT_UNSET;
476477
rest = skip_prefix(arg + 3, options->long_name);
@@ -1019,7 +1020,8 @@ int parse_options_usage(const char * const *usagestr,
10191020
if (strstarts(opts->long_name, optstr))
10201021
print_option_help(opts, 0);
10211022
if (strstarts("no-", optstr) &&
1022-
strstarts(opts->long_name, optstr + 3))
1023+
strstarts(opts->long_name, optstr + 3) &&
1024+
!(opts->flags & PARSE_OPT_NOAUTONEG))
10231025
print_option_help(opts, 0);
10241026
}
10251027

tools/lib/subcmd/parse-options.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ enum parse_opt_option_flags {
4747
PARSE_OPT_NOEMPTY = 128,
4848
PARSE_OPT_NOBUILD = 256,
4949
PARSE_OPT_CANSKIP = 512,
50+
PARSE_OPT_NOAUTONEG = 1024,
5051
};
5152

5253
struct option;
@@ -149,6 +150,8 @@ struct option {
149150
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
150151
#define OPT_CALLBACK(s, l, v, a, h, f) \
151152
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f) }
153+
#define OPT_CALLBACK_FLAG(s, l, v, a, h, f, fl) \
154+
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .flags = (fl) }
152155
#define OPT_CALLBACK_SET(s, l, v, os, a, h, f) \
153156
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .set = check_vtype(os, bool *)}
154157
#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \

0 commit comments

Comments
 (0)