static bool option_is_metadata(const Option *opt) {
/* A metadata entry that is not a real option, like the group marker */
- return ASSERT_PTR(opt)->flags & (OPTION_GROUP_MARKER |
+ return ASSERT_PTR(opt)->flags & (OPTION_NAMESPACE_MARKER |
+ OPTION_GROUP_MARKER |
OPTION_POSITIONAL_ENTRY |
OPTION_HELP_ENTRY |
OPTION_HELP_ENTRY_VERBATIM);
/* Check and initialize */
switch (state->state) {
- case OPTION_PARSER_INIT:
+ case OPTION_PARSER_INIT: {
assert(state->mode >= 0 && state->mode < _OPTION_PARSER_MODE_MAX);
if (state->argc < 1) {
}
assert_se((size_t) state->argc == strv_length(state->argv)); /* Make sure argc/argv are consistent */
+
+ /* Figure out the right range of options */
+ bool in_ns = state->namespace == NULL; /* Are we currently in the section of the array that
+ * forms namespace <namespace>? The first part is the
+ * default unnamed namespace, so if the namespace was
+ * not specified, we are in it. */
+ if (in_ns)
+ state->namespace_start = options;
+
+ const Option *opt;
+ for (opt = options; opt < options_end; opt++) {
+ bool ns_marker = FLAGS_SET(opt->flags, OPTION_NAMESPACE_MARKER);
+ if (!in_ns) {
+ in_ns = ns_marker && streq(state->namespace, opt->long_code);
+ if (in_ns)
+ state->namespace_start = opt + 1;
+ continue;
+ }
+ if (ns_marker)
+ break; /* End of namespace */
+ }
+ assert(state->namespace_start);
+ state->namespace_end = opt;
+
state->optind = state->positional_offset = 1;
state->state = OPTION_PARSER_RUNNING;
break;
+ }
case OPTION_PARSER_RUNNING:
case OPTION_PARSER_STOPPING:
if (handling_positional_arg)
/* We are supposed to return the positional arg to be handled. */
- for (option = options;; option++) {
+ for (option = state->namespace_start;; option++) {
/* If OPTION_PARSER_RETURN_POSITIONAL_ARGS is specified,
* OPTION_POSITIONAL must be used. */
- assert(option < options_end);
+ assert(option < state->namespace_end);
if (FLAGS_SET(option->flags, OPTION_POSITIONAL_ENTRY))
break;
const Option *last_partial = NULL;
unsigned n_partial_matches = 0; /* The commandline option matches a defined prefix. */
- for (option = options;; option++) {
- if (option >= options_end) {
+ for (option = state->namespace_start;; option++) {
+ if (option >= state->namespace_end) {
if (n_partial_matches == 0) {
r = log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: unrecognized option '%s'",
goto fail;
}
if (n_partial_matches > 1) {
- r = partial_match_error(options, options_end, optname, n_partial_matches);
+ r = partial_match_error(
+ state->namespace_start,
+ state->namespace_end,
+ optname,
+ n_partial_matches);
goto fail;
}
}
optname = _optname;
- for (option = options;; option++) {
- if (option >= options_end) {
+ for (option = state->namespace_start;; option++) {
+ if (option >= state->namespace_end) {
r = log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: unrecognized option '%s'",
program_invocation_short_name, optname);
char* option_get_synopsis(const char *prefix, const Option *opt, const char *joiner, bool show_metavar) {
assert(opt);
- assert(!FLAGS_SET(opt->flags, OPTION_GROUP_MARKER)); /* A group marker should not be displayed */
+ assert(!(opt->flags & (OPTION_NAMESPACE_MARKER |
+ OPTION_GROUP_MARKER))); /* The markers should not be displayed */
if (!prefix)
prefix = "";
option_arg_optional(opt) ? "]" : "");
}
-int _option_parser_get_help_table(
+int _option_parser_get_help_table_full(
const Option options[],
const Option options_end[],
+ const char *namespace,
const char *group,
Table **ret) {
int r;
if (!table)
return log_oom();
- bool in_group = group == NULL; /* Are we currently in the section on the array that forms
- * group <group>? The first part is the default group, so
- * if the group was not specified, we are in. */
+ bool in_ns = namespace == NULL; /* Are we currently in the section of the array that forms namespace
+ * <namespace>? The first part is the default unnamed namespace, so
+ * if the namespace was not specified, we are in it. */
+
+ bool in_group = group == NULL; /* Are we currently in the section of the array that forms group
+ * <group>? The first part is the default group, so if the group was
+ * not specified, we are in it. */
for (const Option *opt = options; opt < options_end; opt++) {
+ bool ns_marker = FLAGS_SET(opt->flags, OPTION_NAMESPACE_MARKER);
+ if (!in_ns) {
+ in_ns = ns_marker && streq(namespace, opt->long_code);
+ continue;
+ }
+ if (ns_marker)
+ break; /* End of namespace */
+
bool group_marker = FLAGS_SET(opt->flags, OPTION_GROUP_MARKER);
if (!in_group) {
in_group = group_marker && streq(group, opt->long_code);
return table_log_add_error(r);
}
+ assert(!table_isempty(table)); /* The namespace or group were not found. Something is off. */
+
table_set_header(table, false);
*ret = TAKE_PTR(table);
return 0;
#include "memory-util.h"
#include "shared-forward.h"
+/* Option namespace/group explanation:
+ * the list of options is split into namespaces, and a namespace is split into groups.
+ * By default, options defined in a single program are all placed in a single (unnamed) namespace
+ * and in a single (unnamed) group. OPTION_NAMESPACE() marks the beginning of a named namespace.
+ * OPTION_GROUP() marks the beginning of a named group.
+ */
+
typedef enum OptionFlags {
OPTION_OPTIONAL_ARG = 1U << 0, /* Same as optional_argument in getopt */
OPTION_POSITIONAL_ENTRY = 1U << 1, /* The "option" to handle positional arguments */
OPTION_STOPS_PARSING = 1U << 2, /* This option acts like "--" */
- OPTION_GROUP_MARKER = 1U << 3, /* Fake option entry to separate groups */
- OPTION_HELP_ENTRY = 1U << 4, /* Fake option entry to insert an additional help line */
- OPTION_HELP_ENTRY_VERBATIM = 1U << 5, /* Same, but use the long_code in the first column as written */
+ OPTION_NAMESPACE_MARKER = 1U << 3, /* Fake option entry to separate namespaces */
+ OPTION_GROUP_MARKER = 1U << 4, /* Fake option entry to separate groups */
+ OPTION_HELP_ENTRY = 1U << 5, /* Fake option entry to insert an additional help line */
+ OPTION_HELP_ENTRY_VERBATIM = 1U << 6, /* Same, but use the long_code in the first column as written */
} OptionFlags;
typedef struct Option {
}; \
case (0x100 + counter)
+/* Magic entry in the table (which will not be returned) that designates the start of the namespace <ns>.
+ * The define is structured as 'case' so that it can be followed by ':' and indented appropriately. */
+#define OPTION_NAMESPACE(ns) \
+ _OPTION(__COUNTER__, OPTION_NAMESPACE_MARKER, /* sc= */ 0, /* lc= */ ns, /* mv= */ NULL, /* d= */ 0u, /* h= */ NULL)
+
/* Magic entry in the table (which will not be returned) that designates the start of the group <gr>.
- * The define is structured as 'case' so that it can be followed by ':' and indented appropriately.
- */
+ * The define is structured as 'case' so that it can be followed by ':' and indented appropriately. */
#define OPTION_GROUP(gr) \
_OPTION(__COUNTER__, OPTION_GROUP_MARKER, /* sc= */ 0, /* lc= */ gr, /* mv= */ NULL, /* d= */ 0u, /* h= */ NULL)
} OptionParserState;
typedef struct OptionParser {
- /* Those three should stay first so that it's possible to initialize the struct as { argc, argv }
- * or { argc, argv, mode }. */
+ /* Those four should stay first so that it's possible to initialize the struct as { argc, argv }
+ * or { argc, argv, mode } or { argc, argv, mode, namespace }. */
int argc; /* The original argc. */
char **argv; /* The argv array, possibly reordered. */
OptionParserMode mode;
+ const char *namespace; /* The namespace, may be NULL. */
+
+ const Option *namespace_start, *namespace_end; /* The range of options that are part of our namespace. */
+
OptionParserState state;
int optind; /* Position of the parameter being handled.
* 0 → option parsing hasn't been started yet. */
size_t option_parser_get_n_args(const OptionParser *state);
char* option_get_synopsis(const char *prefix, const Option *opt, const char *joiner, bool show_metavar);
-int _option_parser_get_help_table(
+int _option_parser_get_help_table_full(
const Option options[],
const Option options_end[],
+ const char *namespace,
const char *group,
Table **ret);
+#define option_parser_get_help_table_full(namespace, group, ret) \
+ _option_parser_get_help_table_full(ALIGN_PTR(__start_SYSTEMD_OPTIONS), __stop_SYSTEMD_OPTIONS, namespace, group, ret)
#define option_parser_get_help_table_group(group, ret) \
- _option_parser_get_help_table(ALIGN_PTR(__start_SYSTEMD_OPTIONS), __stop_SYSTEMD_OPTIONS, group, ret)
+ option_parser_get_help_table_full(/* namespace= */ NULL, group, ret)
#define option_parser_get_help_table(ret) \
option_parser_get_help_table_group(/* group= */ NULL, ret)
const Option options[],
const Entry *entries,
char **remaining,
- OptionParserMode mode) {
+ OptionParserMode mode,
+ const char *namespace) {
_cleanup_free_ char *joined = strv_join(argv, ", ");
log_debug("/* %s(%s) */", __func__, joined);
for (const Entry *e = entries; e && (e->long_code || e->short_code != 0); e++)
n_entries++;
- OptionParser opts = { argc, argv, mode };
+ OptionParser opts = { argc, argv, mode, namespace };
for (int c; (c = option_parse(options, options + n_options, &opts)) != 0; ) {
ASSERT_OK(c);
ASSERT_NOT_NULL(opts.opt);
{ 4, .long_code = "required2", .metavar = "ARG" },
{ 5, .short_code = 'o', .long_code = "optional1", .metavar = "ARG", .flags = OPTION_OPTIONAL_ARG },
{ 6, .long_code = "optional2", .metavar = "ARG", .flags = OPTION_OPTIONAL_ARG },
+ { 7, .long_code = "NS2", .flags = OPTION_NAMESPACE_MARKER },
+ { 8, .short_code = 'h', .long_code = "help2" },
+ { 9, .long_code = "version2" },
+ { 10, .long_code = "NS3", .flags = OPTION_NAMESPACE_MARKER },
+ { 11, .short_code = 'h', .long_code = "help3" },
+ { 12, .long_code = "version3" },
{}
};
options,
NULL,
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"--",
"--help",
"-h",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
"string2",
"--",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"--help"),
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"--help",
},
STRV_MAKE("string1",
"--help"),
- OPTION_PARSER_STOP_AT_FIRST_NONOPTION);
+ OPTION_PARSER_STOP_AT_FIRST_NONOPTION,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"-h"),
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"--help",
"string2",
"string3",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"-h",
"string2",
"string3",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"--required1", "reqarg1"),
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"-r", "reqarg1"),
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
},
STRV_MAKE("string1",
"string2"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
STRV_MAKE("string1",
"string2",
"-r", "reqarg1"),
- OPTION_PARSER_STOP_AT_FIRST_NONOPTION);
+ OPTION_PARSER_STOP_AT_FIRST_NONOPTION,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"--optional1=optarg1"),
{}
},
NULL,
- OPTION_PARSER_STOP_AT_FIRST_NONOPTION);
+ OPTION_PARSER_STOP_AT_FIRST_NONOPTION,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"--optional1", "string1"),
{}
},
STRV_MAKE("string1"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"-ooptarg1"),
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"-o", "string1"),
{}
},
STRV_MAKE("string1"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
test_option_parse_one(STRV_MAKE("arg0",
"string1",
"--help",
"--required1",
"--optional1"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
+
+ /* Check that we can access options from NS2 */
+ test_option_parse_one(STRV_MAKE("arg0",
+ "-h", /* This verifies that we're using the right namespace */
+ "--help2",
+ "--version2",
+ "string1"),
+ options,
+ (Entry[]) {
+ { "help2" },
+ { "help2" },
+ { "version2" },
+ {}
+ },
+ STRV_MAKE("string1"),
+ OPTION_PARSER_NORMAL,
+ "NS2");
+
+ /* Check that we can access options from NS3 */
+ test_option_parse_one(STRV_MAKE("arg0",
+ "-h", /* This verifies that we're using the right namespace */
+ "--help3",
+ "--version3",
+ "string1"),
+ options,
+ (Entry[]) {
+ { "help3" },
+ { "help3" },
+ { "version3" },
+ {}
+ },
+ STRV_MAKE("string1"),
+ OPTION_PARSER_NORMAL,
+ "NS3");
}
TEST(option_stops_parsing) {
},
STRV_MAKE("--help",
"foo"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Options before --exec are still parsed */
test_option_parse_one(STRV_MAKE("arg0",
},
STRV_MAKE("--version",
"bar"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* --exec with no trailing args */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* --exec after positional args */
test_option_parse_one(STRV_MAKE("arg0",
"--help",
"--required",
"val"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* "--" 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
{}
},
STRV_MAKE("--help"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* "--" before --exec: "--" terminates first, --exec is positional */
test_option_parse_one(STRV_MAKE("arg0",
NULL,
STRV_MAKE("--exec",
"--help"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Multiple options then --exec then more option-like args */
test_option_parse_one(STRV_MAKE("arg0",
STRV_MAKE("-h",
"--required",
"val2"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
}
TEST(option_group_marker) {
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Check that group marker name is ignored */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Verify that the group marker is not mistaken for an option */
test_option_invalid_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Partial match with multiple candidates */
test_option_invalid_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Long option without = does NOT consume the next arg */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
STRV_MAKE("foo.txt"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Short option with inline arg */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Short option without inline arg does NOT consume the next arg */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
STRV_MAKE("foo.txt"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Optional arg option at end of argv */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Mixed: optional arg with other options */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Short combo: -ho (h then o with no arg) */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
STRV_MAKE("pos1"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Short combo: -hobar (h then o with inline arg "bar") */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
}
/* Test the OPTION, OPTION_LONG, OPTION_SHORT, OPTION_FULL, OPTION_GROUP macros
char **argv,
const Entry *entries,
char **remaining,
- OptionParserMode mode) {
+ OptionParserMode mode,
+ const char *namespace) {
_cleanup_free_ char *joined = strv_join(argv, ", ");
log_debug("/* %s(%s) */", __func__, joined);
for (const Entry *e = entries; e && (e->long_code || e->short_code != 0); e++)
n_entries++;
- OptionParser opts = { argc, argv, mode };
+ OptionParser opts = { argc, argv, mode, namespace };
FOREACH_OPTION(c, &opts, assert_not_reached()) {
log_debug("%c %s: %s=%s",
OPTION_POSITIONAL:
break;
+ OPTION_NAMESPACE("namespaced options"): {}
+
+ OPTION('r', "required2", "ARG", "Required arg option"):
+ break;
+
default:
log_error("Unexpected option id: %d", c);
- ASSERT_TRUE(false);
+ assert_not_reached();
}
}
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION: short form */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_LONG: only accessible via long form */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_SHORT: only accessible via short form */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION with required arg: long --required=ARG */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION with required arg: long --required ARG */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION with required arg: short -r ARG */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION with required arg: short -rARG */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_FULL with OPTION_OPTIONAL_ARG: long with = */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_FULL with OPTION_OPTIONAL_ARG: long without = doesn't consume next */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
STRV_MAKE("pos1"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_FULL with OPTION_OPTIONAL_ARG: short inline */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_FULL with OPTION_OPTIONAL_ARG: short without inline */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
STRV_MAKE("pos1"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_FULL with OPTION_STOPS_PARSING: stops further option parsing */
test_macros_parse_one(STRV_MAKE("arg0",
},
STRV_MAKE("--help",
"--version"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_STOPS_PARSING: options before are still parsed */
test_macros_parse_one(STRV_MAKE("arg0",
},
STRV_MAKE("-h",
"--debug"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_STOPS_PARSING with "--": "--" after exec is still consumed */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
STRV_MAKE("--help"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_STOPS_PARSING with "--": "--" before exec takes precedence */
test_macros_parse_one(STRV_MAKE("arg0",
},
STRV_MAKE("--exec",
"--help"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_GROUP: group marker is transparent to parsing, --debug in Advanced group works */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Mixed: all macro types together */
test_macros_parse_one(STRV_MAKE("arg0",
},
STRV_MAKE("pos1",
"pos2"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Short option combos with macros: -hv (help + verbose) */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Short option combo with required arg: -hrval (help + required with arg "val") */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Short option combo with optional arg: -hoval (help + optional with arg "val") */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_STOPS_PARSING then "--": "--" is still consumed after exec */
test_macros_parse_one(STRV_MAKE("arg0",
},
STRV_MAKE("--version",
"-h"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_STOPS_PARSING then later "--": "--" is not consumed */
test_macros_parse_one(STRV_MAKE("arg0",
STRV_MAKE("--version",
"--",
"-h"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* OPTION_STOPS_PARSING then "--" twice: second "--" is not consumed */
test_macros_parse_one(STRV_MAKE("arg0",
STRV_MAKE("--",
"--version",
"-h"),
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* Basic OPTION_POSITIONAL use */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_RETURN_POSITIONAL_ARGS);
+ OPTION_PARSER_RETURN_POSITIONAL_ARGS,
+ NULL);
/* OPTION_POSITIONAL combined with OPTION_STOPS_PARSING */
test_macros_parse_one(STRV_MAKE("arg0",
{}
},
STRV_MAKE("arg2"),
- OPTION_PARSER_RETURN_POSITIONAL_ARGS);
+ OPTION_PARSER_RETURN_POSITIONAL_ARGS,
+ NULL);
+
+ /* Second namespace, OPTION: long form */
+ test_macros_parse_one(STRV_MAKE("arg0",
+ "--required2=arg"),
+ (Entry[]) {
+ { "required2", "arg" },
+ {}
+ },
+ NULL,
+ OPTION_PARSER_NORMAL,
+ "namespaced options");
+
+ /* Second namespace, OPTION: short form */
+ test_macros_parse_one(STRV_MAKE("arg0",
+ "-rarg"),
+ (Entry[]) {
+ { "required2", "arg" },
+ {}
+ },
+ NULL,
+ OPTION_PARSER_NORMAL,
+ "namespaced options");
}
/* Test the pattern used by nspawn's --user: an optional-arg option that also
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* --user without arg: next arg is an option, so no consumption */
test_option_parse_one(STRV_MAKE("arg0",
{}
},
NULL,
- OPTION_PARSER_NORMAL);
+ OPTION_PARSER_NORMAL,
+ NULL);
/* --user without arg: next arg is positional (doesn't start with -).
* The option parser returns NULL for the arg. The caller would then