shared/options: add new helper option_parser_get_arg

option_parser_next_arg() is renamed to option_parser_peek_next_arg()
to match option_parser_consume_next_arg().

A new helper is added option_parser_get_arg(…, n). It is a common pattern
to only need a single arg, and getting an array and extracting a single
item from it is too verbose.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-04-29 15:28:05 +02:00
parent 408d18f4d2
commit ab9acf8c8c
6 changed files with 36 additions and 21 deletions
+5 -8
View File
@@ -31,7 +31,6 @@
#include "process-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "tpm2-pcr.h"
#include "tpm2-util.h"
@@ -579,14 +578,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
char **args = option_parser_get_args(&opts);
if (option_parser_get_n_args(&opts) > 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many arguments, refusing.");
if (strv_length(args) > 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Too many arguments, refusing.");
if (args[0])
r = parse_path_argument(args[0], false, &arg_node);
const char *arg = option_parser_get_arg(&opts, 0);
if (arg)
r = parse_path_argument(arg, false, &arg_node);
else if (!wipe_requested())
r = determine_default_node();
else
+1 -2
View File
@@ -181,8 +181,7 @@ static int parse_argv(int argc, char *argv[]) {
"%s expects exactly one argument (the mount point).",
program_invocation_short_name);
arg_target = option_parser_get_args(&opts)[0];
arg_target = option_parser_get_arg(&opts, 0);
return 1;
}
+1 -1
View File
@@ -1420,7 +1420,7 @@ static int parse_argv(int argc, char *argv[]) {
* the old container user functionality. To maintain backwards compatibility
* with the space-separated form (--user NAME), if the next opts.arg does not look
* like an option, interpret it as a user name. */
const char *t = option_parser_next_arg(&opts);
const char *t = option_parser_peek_next_arg(&opts);
if (t && t[0] != '-') {
opts.arg = option_parser_consume_next_arg(&opts);
log_warning("--user NAME is deprecated, use --uid=NAME instead.");
+10 -2
View File
@@ -344,7 +344,7 @@ int option_parse(
return r;
}
char* option_parser_next_arg(const OptionParser *state) {
char* option_parser_peek_next_arg(const OptionParser *state) {
/* Peek at the next argument, whatever it is (option or position arg).
* May return NULL. */
@@ -360,7 +360,7 @@ char* option_parser_consume_next_arg(OptionParser *state) {
* so we won't try to interpret it as an option.
* May return NULL. */
char *t = option_parser_next_arg(state);
char *t = option_parser_peek_next_arg(state);
if (t)
shift_arg(state->argv, state->positional_offset++, state->optind++);
return t;
@@ -388,6 +388,14 @@ size_t option_parser_get_n_args(const OptionParser *state) {
return state->argc - state->positional_offset;
}
char* option_parser_get_arg(const OptionParser *state, size_t i) {
assert(state->optind > 0);
assert(state->state == OPTION_PARSER_DONE);
assert(state->positional_offset <= state->argc);
return (size_t) (state->argc - state->positional_offset) > i ? state->argv[state->positional_offset + i] : NULL;
}
char* option_get_synopsis(const Option *opt, const char *joiner, bool show_metavar) {
assert(opt);
assert(!(opt->flags & (OPTION_NAMESPACE_MARKER |
+7 -1
View File
@@ -224,11 +224,17 @@ int option_parse(
break; \
} else
char* option_parser_next_arg(const OptionParser *state);
/* Those helpers are used *during* option parsing and allow looking at or taking the next item in
* the argv array, either an option or a positional parameter. */
char* option_parser_peek_next_arg(const OptionParser *state);
char* option_parser_consume_next_arg(OptionParser *state);
/* Those helpers are used *after* option parsing and return the positional arguments (and unparsed
* options in case option parsing was stopped early, e.g. via "--"). */
char** option_parser_get_args(const OptionParser *state);
size_t option_parser_get_n_args(const OptionParser *state);
char* option_parser_get_arg(const OptionParser *state, size_t i);
char* option_get_synopsis(const Option *opt, const char *joiner, bool show_metavar);
int _option_parser_get_help_table_full(
+12 -7
View File
@@ -58,7 +58,12 @@ static void test_option_parse_one(
ASSERT_TRUE(strv_equal(args, remaining));
ASSERT_STREQ(argv[0], saved_argv0);
ASSERT_EQ(option_parser_get_n_args(&opts), strv_length(remaining));
size_t l = strv_length(remaining);
ASSERT_EQ(option_parser_get_n_args(&opts), l);
ASSERT_STREQ(option_parser_get_arg(&opts, 0), l > 0 ? remaining[0] : NULL);
ASSERT_STREQ(option_parser_get_arg(&opts, 1), l > 1 ? remaining[1] : NULL);
ASSERT_STREQ(option_parser_get_arg(&opts, 2), l > 2 ? remaining[2] : NULL);
ASSERT_STREQ(option_parser_get_arg(&opts, 3), l > 3 ? remaining[3] : NULL);
}
static void test_option_invalid_one(
@@ -1331,7 +1336,7 @@ TEST(option_optional_arg_consume) {
/* --user without arg: next arg is positional (doesn't start with -).
* The option parser returns NULL for the arg. The caller would then
* use option_parser_next_arg/consume_next_arg to grab it. */
* use option_parser_peek_next_arg/consume_next_arg to grab it. */
{
char **argv = STRV_MAKE("arg0", "--user", "someuser", "pos1");
int argc = strv_length(argv);
@@ -1341,7 +1346,7 @@ TEST(option_optional_arg_consume) {
ASSERT_OK_POSITIVE(option_parse(options, options + 3, &opts));
ASSERT_STREQ(opts.opt->long_code, "user");
ASSERT_NULL(opts.arg);
ASSERT_STREQ(option_parser_next_arg(&opts), "someuser");
ASSERT_STREQ(option_parser_peek_next_arg(&opts), "someuser");
ASSERT_STREQ(option_parser_consume_next_arg(&opts), "someuser");
ASSERT_EQ(option_parse(options, options + 3, &opts), 0);
@@ -1361,7 +1366,7 @@ TEST(option_optional_arg_consume) {
ASSERT_OK_POSITIVE(option_parse(options, options + 3, &opts));
ASSERT_STREQ(opts.opt->long_code, "user");
ASSERT_NULL(opts.arg);
ASSERT_NULL(option_parser_next_arg(&opts));
ASSERT_NULL(option_parser_peek_next_arg(&opts));
ASSERT_NULL(option_parser_consume_next_arg(&opts));
ASSERT_EQ(option_parse(options, options + 3, &opts), 0);
@@ -1381,12 +1386,12 @@ TEST(option_optional_arg_consume) {
ASSERT_OK_POSITIVE(option_parse(options, options + 3, &opts));
ASSERT_STREQ(opts.opt->long_code, "user");
ASSERT_NULL(opts.arg);
ASSERT_STREQ(option_parser_next_arg(&opts), "-u");
ASSERT_STREQ(option_parser_peek_next_arg(&opts), "-u");
ASSERT_OK_POSITIVE(option_parse(options, options + 3, &opts));
ASSERT_STREQ(opts.opt->long_code, "uid");
ASSERT_STREQ(opts.arg, "nobody");
ASSERT_NULL(option_parser_next_arg(&opts));
ASSERT_NULL(option_parser_peek_next_arg(&opts));
ASSERT_NULL(option_parser_consume_next_arg(&opts));
ASSERT_EQ(option_parse(options, options + 3, &opts), 0);
@@ -1413,7 +1418,7 @@ TEST(option_optional_arg_consume) {
const char *arg = opts.arg;
if (!arg) {
const char *t = option_parser_next_arg(&opts);
const char *t = option_parser_peek_next_arg(&opts);
if (t && t[0] != '-')
arg = option_parser_consume_next_arg(&opts);
}