From: Zbigniew Jędrzejewski-Szmek Date: Thu, 16 Apr 2026 07:05:01 +0000 (+0200) Subject: shared/options: convert mode boolean to an enum X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6133fc0e1cb6f79a3b60e812732151b451291496;p=thirdparty%2Fsystemd.git shared/options: convert mode boolean to an enum This will make it easier to add new modes of operation later. But I'm happy with how this came out — I think the mode setting is nicer to read then the old bool. --- diff --git a/src/journal/cat.c b/src/journal/cat.c index e2419d36ab3..62249663c58 100644 --- a/src/journal/cat.c +++ b/src/journal/cat.c @@ -59,7 +59,7 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { assert(argc >= 0); assert(argv); - OptionParser state = { argc, argv, /* stop_at_first_nonoption= */ true }; + OptionParser state = { argc, argv, OPTION_PARSER_STOP_AT_FIRST_NONOPTION }; const char *arg; int r; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index accf448ea97..92c0c03177c 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -586,7 +586,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - OptionParser state = { argc, argv, /* stop_at_first_nonoption= */ true }; + OptionParser state = { argc, argv, OPTION_PARSER_STOP_AT_FIRST_NONOPTION }; const Option *opt; const char *arg; diff --git a/src/shared/options.c b/src/shared/options.c index dc2fb34cf62..5d4df946b83 100644 --- a/src/shared/options.c +++ b/src/shared/options.c @@ -75,6 +75,8 @@ int option_parse( /* Check and initialize */ if (state->optind == 0) { + assert(state->mode >= 0 && state->mode < _OPTION_PARSER_MODE_MAX); + if (state->argc < 1 || strv_isempty(state->argv)) return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN), "argv cannot be empty"); @@ -109,7 +111,7 @@ int option_parse( /* Looks like we found an option parameter */ break; - if (state->stop_at_first_nonoption) { + if (state->mode == OPTION_PARSER_STOP_AT_FIRST_NONOPTION) { state->parsing_stopped = true; return 0; } diff --git a/src/shared/options.h b/src/shared/options.h index 262196c8d95..a10f914da26 100644 --- a/src/shared/options.h +++ b/src/shared/options.h @@ -92,13 +92,22 @@ typedef struct Option { extern const Option __start_SYSTEMD_OPTIONS[]; extern const Option __stop_SYSTEMD_OPTIONS[]; +typedef enum OptionParserMode { + /* The default mode. This is the implicit default and doesn't have to be specified. */ + OPTION_PARSER_NORMAL = 0, + + /* Same as "+…" for getopt_long — only parse options before the first positional argument. */ + OPTION_PARSER_STOP_AT_FIRST_NONOPTION, + + _OPTION_PARSER_MODE_MAX, +} OptionParserMode; + typedef struct OptionParser { /* Those three should stay first so that it's possible to initialize the struct as { argc, argv } - * or { argc, argv, true/false }. */ + * or { argc, argv, mode }. */ int argc; /* The original argc. */ char **argv; /* The argv array, possibly reordered. */ - bool stop_at_first_nonoption; /* Same as "+…" for getopt_long — only parse options before the first - * positional argument. */ + OptionParserMode mode; bool parsing_stopped; /* We processed "--" or an option that terminates option parsing. */ int optind; /* Position of the parameter being handled. diff --git a/src/test/test-options.c b/src/test/test-options.c index b91ac54884c..e6b18d7a7ea 100644 --- a/src/test/test-options.c +++ b/src/test/test-options.c @@ -15,7 +15,7 @@ static void test_option_parse_one( const Option options[], const Entry *entries, char **remaining, - bool stop_at_first_nonoption) { + OptionParserMode mode) { _cleanup_free_ char *joined = strv_join(argv, ", "); log_debug("/* %s(%s) */", __func__, joined); @@ -32,7 +32,7 @@ static void test_option_parse_one( for (const Entry *e = entries; e && (e->long_code || e->short_code != 0); e++) n_entries++; - OptionParser state = { argc, argv, stop_at_first_nonoption }; + OptionParser state = { argc, argv, mode }; const Option *opt; const char *arg; for (int c; (c = option_parse(options, options + n_options, &state, &opt, &arg)) != 0; ) { @@ -101,7 +101,7 @@ TEST(option_parse) { options, NULL, NULL, - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -114,7 +114,7 @@ TEST(option_parse) { "string2", "string3", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "--", @@ -128,7 +128,7 @@ TEST(option_parse) { "--help", "-h", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -142,7 +142,7 @@ TEST(option_parse) { "string2", "--", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -156,7 +156,7 @@ TEST(option_parse) { "string2", "string3", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "--help"), @@ -166,7 +166,7 @@ TEST(option_parse) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "--help", @@ -179,7 +179,7 @@ TEST(option_parse) { }, STRV_MAKE("string1", "--help"), - true); + OPTION_PARSER_STOP_AT_FIRST_NONOPTION); test_option_parse_one(STRV_MAKE("arg0", "-h"), @@ -189,7 +189,7 @@ TEST(option_parse) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "--help", @@ -206,7 +206,7 @@ TEST(option_parse) { "string2", "string3", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "-h", @@ -223,7 +223,7 @@ TEST(option_parse) { "string2", "string3", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -240,7 +240,7 @@ TEST(option_parse) { "string2", "string3", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -257,7 +257,7 @@ TEST(option_parse) { "string2", "string3", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -274,7 +274,7 @@ TEST(option_parse) { "string2", "string3", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -291,7 +291,7 @@ TEST(option_parse) { "string2", "string3", "string4"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "--required1", "reqarg1"), @@ -301,7 +301,7 @@ TEST(option_parse) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "-r", "reqarg1"), @@ -311,7 +311,7 @@ TEST(option_parse) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -324,7 +324,7 @@ TEST(option_parse) { }, STRV_MAKE("string1", "string2"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -335,7 +335,7 @@ TEST(option_parse) { STRV_MAKE("string1", "string2", "-r", "reqarg1"), - true); + OPTION_PARSER_STOP_AT_FIRST_NONOPTION); test_option_parse_one(STRV_MAKE("arg0", "--optional1=optarg1"), @@ -345,7 +345,7 @@ TEST(option_parse) { {} }, NULL, - true); + OPTION_PARSER_STOP_AT_FIRST_NONOPTION); test_option_parse_one(STRV_MAKE("arg0", "--optional1", "string1"), @@ -355,7 +355,7 @@ TEST(option_parse) { {} }, STRV_MAKE("string1"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "-ooptarg1"), @@ -365,7 +365,7 @@ TEST(option_parse) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "-o", "string1"), @@ -375,7 +375,7 @@ TEST(option_parse) { {} }, STRV_MAKE("string1"), - false); + OPTION_PARSER_NORMAL); test_option_parse_one(STRV_MAKE("arg0", "string1", @@ -445,7 +445,7 @@ TEST(option_parse) { "--help", "--required1", "--optional1"), - false); + OPTION_PARSER_NORMAL); } TEST(option_stops_parsing) { @@ -469,7 +469,7 @@ TEST(option_stops_parsing) { }, STRV_MAKE("--help", "foo"), - false); + OPTION_PARSER_NORMAL); /* Options before --exec are still parsed */ test_option_parse_one(STRV_MAKE("arg0", @@ -485,7 +485,7 @@ TEST(option_stops_parsing) { }, STRV_MAKE("--version", "bar"), - false); + OPTION_PARSER_NORMAL); /* --exec with no trailing args */ test_option_parse_one(STRV_MAKE("arg0", @@ -496,7 +496,7 @@ TEST(option_stops_parsing) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); /* --exec after positional args */ test_option_parse_one(STRV_MAKE("arg0", @@ -513,7 +513,7 @@ TEST(option_stops_parsing) { "--help", "--required", "val"), - false); + OPTION_PARSER_NORMAL); /* "--" after --exec: "--" is still consumed as end-of-options marker. This is needed for * backwards compatibility, systemd-dissect implemented this behaviour. But also, it makes @@ -529,7 +529,7 @@ TEST(option_stops_parsing) { {} }, STRV_MAKE("--help"), - false); + OPTION_PARSER_NORMAL); /* "--" before --exec: "--" terminates first, --exec is positional */ test_option_parse_one(STRV_MAKE("arg0", @@ -540,7 +540,7 @@ TEST(option_stops_parsing) { NULL, STRV_MAKE("--exec", "--help"), - false); + OPTION_PARSER_NORMAL); /* Multiple options then --exec then more option-like args */ test_option_parse_one(STRV_MAKE("arg0", @@ -559,7 +559,7 @@ TEST(option_stops_parsing) { STRV_MAKE("-h", "--required", "val2"), - false); + OPTION_PARSER_NORMAL); } TEST(option_group_marker) { @@ -584,7 +584,7 @@ TEST(option_group_marker) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); /* Check that group marker name is ignored */ test_option_parse_one(STRV_MAKE("arg0", @@ -597,7 +597,7 @@ TEST(option_group_marker) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); /* Verify that the group marker is not mistaken for an option */ test_option_invalid_one(STRV_MAKE("arg0", @@ -625,7 +625,7 @@ TEST(option_group_marker) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); /* Partial match with multiple candidates */ test_option_invalid_one(STRV_MAKE("arg0", @@ -649,7 +649,7 @@ TEST(option_optional_arg) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); /* Long option without = does NOT consume the next arg */ test_option_parse_one(STRV_MAKE("arg0", @@ -660,7 +660,7 @@ TEST(option_optional_arg) { {} }, STRV_MAKE("foo.txt"), - false); + OPTION_PARSER_NORMAL); /* Short option with inline arg */ test_option_parse_one(STRV_MAKE("arg0", @@ -671,7 +671,7 @@ TEST(option_optional_arg) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); /* Short option without inline arg does NOT consume the next arg */ test_option_parse_one(STRV_MAKE("arg0", @@ -682,7 +682,7 @@ TEST(option_optional_arg) { {} }, STRV_MAKE("foo.txt"), - false); + OPTION_PARSER_NORMAL); /* Optional arg option at end of argv */ test_option_parse_one(STRV_MAKE("arg0", @@ -693,7 +693,7 @@ TEST(option_optional_arg) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); /* Mixed: optional arg with other options */ test_option_parse_one(STRV_MAKE("arg0", @@ -708,7 +708,7 @@ TEST(option_optional_arg) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); /* Short combo: -ho (h then o with no arg) */ test_option_parse_one(STRV_MAKE("arg0", @@ -720,7 +720,7 @@ TEST(option_optional_arg) { {} }, STRV_MAKE("pos1"), - false); + OPTION_PARSER_NORMAL); /* Short combo: -hobar (h then o with inline arg "bar") */ test_option_parse_one(STRV_MAKE("arg0", @@ -732,7 +732,7 @@ TEST(option_optional_arg) { {} }, NULL, - false); + OPTION_PARSER_NORMAL); } /* Test the OPTION, OPTION_LONG, OPTION_SHORT, OPTION_FULL, OPTION_GROUP macros @@ -1110,7 +1110,7 @@ TEST(option_optional_arg_consume) { {} }, NULL, - /* stop_at_first_nonoption= */ false); + OPTION_PARSER_NORMAL); /* --user without arg: next arg is an option, so no consumption */ test_option_parse_one(STRV_MAKE("arg0", @@ -1123,7 +1123,7 @@ TEST(option_optional_arg_consume) { {} }, NULL, - /* stop_at_first_nonoption= */ false); + OPTION_PARSER_NORMAL); /* --user without arg: next arg is positional (doesn't start with -). * The option parser returns NULL for the arg. The caller would then diff --git a/src/vmspawn/vmspawn.c b/src/vmspawn/vmspawn.c index c1b913217a7..d95a2ccf647 100644 --- a/src/vmspawn/vmspawn.c +++ b/src/vmspawn/vmspawn.c @@ -319,7 +319,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - OptionParser state = { argc, argv, /* stop_at_first_nonoption= */ true }; + OptionParser state = { argc, argv, OPTION_PARSER_STOP_AT_FIRST_NONOPTION }; const Option *current; const char *arg;