[PATCH v11 08/21] argparse: support parameters to short options without "="

Bruce Richardson bruce.richardson at intel.com
Thu Oct 9 15:00:43 CEST 2025


When passing an optional parameter to a argparse argument, the only way
to do so has been to pass the argument using "=arg" on the end of the
option, for example "--foo=bar". However, for short options, i.e. those
of the form "-x", this requirement is unusual as getopt also supports
taking additional characters after the option as the parameter, e.g.
"-xarg".

Add support for this form of parameter for short options to argparse.

Signed-off-by: Bruce Richardson <bruce.richardson at intel.com>
---
 app/test/test_argparse.c    | 131 ++++++++++++++++++++++++++++++++++++
 lib/argparse/rte_argparse.c |  10 +--
 2 files changed, 137 insertions(+), 4 deletions(-)

diff --git a/app/test/test_argparse.c b/app/test/test_argparse.c
index cce637ce22..71a85ea960 100644
--- a/app/test/test_argparse.c
+++ b/app/test/test_argparse.c
@@ -1442,6 +1442,136 @@ test_argparse_ignore_non_flag_args_short_and_long(void)
 	return 0;
 }
 
+static int
+test_argparse_short_opt_value_without_equal(void)
+{
+	struct rte_argparse *obj;
+	int val_saver = 0;
+	char *argv[3];
+	int ret;
+
+	/* Test short option with required value using -a3 syntax (no '=') */
+	obj = test_argparse_init_obj();
+	obj->args[0].name_long = "--test-long";
+	obj->args[0].name_short = "-t";
+	obj->args[0].val_saver = (void *)&val_saver;
+	obj->args[0].val_set = NULL;
+	obj->args[0].value_required = RTE_ARGPARSE_VALUE_REQUIRED;
+	obj->args[0].value_type = RTE_ARGPARSE_VALUE_TYPE_INT;
+	obj->args[1].name_long = NULL;
+	argv[0] = test_strdup(obj->prog_name);
+	argv[1] = test_strdup("-t42");
+	ret = rte_argparse_parse(obj, 2, argv);
+	TEST_ASSERT(ret == 2, "Argparse parse with -t42 expect success, got %d!", ret);
+	TEST_ASSERT(val_saver == 42, "Argparse parse -t42 should set value to 42, got %d!",
+			val_saver);
+
+	/* Test short option with optional value using -t100 syntax (no '=') */
+	obj = test_argparse_init_obj();
+	obj->args[0].name_long = "--test-long";
+	obj->args[0].name_short = "-t";
+	obj->args[0].val_saver = (void *)&val_saver;
+	obj->args[0].val_set = (void *)99;
+	obj->args[0].value_required = RTE_ARGPARSE_VALUE_OPTIONAL;
+	obj->args[0].value_type = RTE_ARGPARSE_VALUE_TYPE_INT;
+	obj->args[1].name_long = NULL;
+	val_saver = 0;
+	argv[0] = test_strdup(obj->prog_name);
+	argv[1] = test_strdup("-t123");
+	ret = rte_argparse_parse(obj, 2, argv);
+	TEST_ASSERT(ret == 2, "Argparse parse with -t123 expect success, got %d!", ret);
+	TEST_ASSERT(val_saver == 123, "Argparse parse -t123 should set value to 123, got %d!",
+			val_saver);
+
+	/* Test that -t alone with optional value uses default */
+	obj = test_argparse_init_obj();
+	obj->args[0].name_long = "--test-long";
+	obj->args[0].name_short = "-t";
+	obj->args[0].val_saver = (void *)&val_saver;
+	obj->args[0].val_set = (void *)99;
+	obj->args[0].value_required = RTE_ARGPARSE_VALUE_OPTIONAL;
+	obj->args[0].value_type = RTE_ARGPARSE_VALUE_TYPE_INT;
+	obj->args[1].name_long = NULL;
+	val_saver = 0;
+	argv[0] = test_strdup(obj->prog_name);
+	argv[1] = test_strdup("-t");
+	ret = rte_argparse_parse(obj, 2, argv);
+	TEST_ASSERT(ret == 2, "Argparse parse with -t expect success, got %d!", ret);
+	TEST_ASSERT(val_saver == 99, "Argparse parse -t should use default 99, got %d!",
+			val_saver);
+
+	/* Test short option with '=' still works */
+	obj = test_argparse_init_obj();
+	obj->args[0].name_long = "--test-long";
+	obj->args[0].name_short = "-t";
+	obj->args[0].val_saver = (void *)&val_saver;
+	obj->args[0].val_set = NULL;
+	obj->args[0].value_required = RTE_ARGPARSE_VALUE_REQUIRED;
+	obj->args[0].value_type = RTE_ARGPARSE_VALUE_TYPE_INT;
+	obj->args[1].name_long = NULL;
+	val_saver = 0;
+	argv[0] = test_strdup(obj->prog_name);
+	argv[1] = test_strdup("-t=55");
+	ret = rte_argparse_parse(obj, 2, argv);
+	TEST_ASSERT(ret == 2, "Argparse parse with -t=55 expect success, got %d!", ret);
+	TEST_ASSERT(val_saver == 55, "Argparse parse -t=55 should set value to 55, got %d!",
+			val_saver);
+
+	/* Test that long option with value works with '=' */
+	obj = test_argparse_init_obj();
+	obj->args[0].name_long = "--test-long";
+	obj->args[0].name_short = "-t";
+	obj->args[0].val_saver = (void *)&val_saver;
+	obj->args[0].val_set = (void *)88;
+	obj->args[0].value_required = RTE_ARGPARSE_VALUE_OPTIONAL;
+	obj->args[0].value_type = RTE_ARGPARSE_VALUE_TYPE_INT;
+	obj->args[1].name_long = NULL;
+	val_saver = 0;
+	argv[0] = test_strdup(obj->prog_name);
+	argv[1] = test_strdup("--test-long=66");
+	ret = rte_argparse_parse(obj, 2, argv);
+	TEST_ASSERT(ret == 2, "Argparse parse with --test-long=66 expect success, got %d!", ret);
+	TEST_ASSERT(val_saver == 66, "Argparse parse --test-long=66 should set value to 66, got %d!",
+			val_saver);
+
+	/* Test short option with string value without '=' */
+	const char *str_saver = NULL;
+	obj = test_argparse_init_obj();
+	obj->args[0].name_long = "--test-string";
+	obj->args[0].name_short = "-s";
+	obj->args[0].val_saver = (void *)&str_saver;
+	obj->args[0].val_set = NULL;
+	obj->args[0].value_required = RTE_ARGPARSE_VALUE_REQUIRED;
+	obj->args[0].value_type = RTE_ARGPARSE_VALUE_TYPE_STR;
+	obj->args[1].name_long = NULL;
+	argv[0] = test_strdup(obj->prog_name);
+	argv[1] = test_strdup("-shello");
+	ret = rte_argparse_parse(obj, 2, argv);
+	TEST_ASSERT(ret == 2, "Argparse parse with -shello expect success, got %d!", ret);
+	TEST_ASSERT(str_saver != NULL && strcmp(str_saver, "hello") == 0,
+		"Argparse parse -shello should set string to 'hello', got '%s'!",
+		str_saver ? str_saver : "(null)");
+
+	/* Test short option with negative number without '=' */
+	obj = test_argparse_init_obj();
+	obj->args[0].name_long = "--test-long";
+	obj->args[0].name_short = "-t";
+	obj->args[0].val_saver = (void *)&val_saver;
+	obj->args[0].val_set = NULL;
+	obj->args[0].value_required = RTE_ARGPARSE_VALUE_REQUIRED;
+	obj->args[0].value_type = RTE_ARGPARSE_VALUE_TYPE_INT;
+	obj->args[1].name_long = NULL;
+	val_saver = 0;
+	argv[0] = test_strdup(obj->prog_name);
+	argv[1] = test_strdup("-t-42");
+	ret = rte_argparse_parse(obj, 2, argv);
+	TEST_ASSERT(ret == 2, "Argparse parse with -t-42 expect success, got %d!", ret);
+	TEST_ASSERT(val_saver == -42, "Argparse parse -t-42 should set value to -42, got %d!",
+			val_saver);
+
+	return 0;
+}
+
 static struct unit_test_suite argparse_test_suite = {
 	.suite_name = "Argparse Unit Test Suite",
 	.setup = test_argparse_setup,
@@ -1477,6 +1607,7 @@ static struct unit_test_suite argparse_test_suite = {
 		TEST_CASE(test_argparse_ignore_non_flag_args_trailing_non_flags),
 		TEST_CASE(test_argparse_ignore_non_flag_args_with_positional),
 		TEST_CASE(test_argparse_ignore_non_flag_args_short_and_long),
+		TEST_CASE(test_argparse_short_opt_value_without_equal),
 
 		TEST_CASES_END() /**< NULL terminate unit test array */
 	}
diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c
index 1e320749b4..cc16ba6edc 100644
--- a/lib/argparse/rte_argparse.c
+++ b/lib/argparse/rte_argparse.c
@@ -693,7 +693,6 @@ parse_args(const struct rte_argparse *obj, bool *arg_parsed,
 	char **args_to_move;
 	uint32_t arg_idx;
 	char *curr_argv;
-	char *has_equal;
 	char *value;
 	int ret;
 	int i;
@@ -740,9 +739,11 @@ parse_args(const struct rte_argparse *obj, bool *arg_parsed,
 			continue;
 		}
 
-		has_equal = strchr(curr_argv, '=');
+		value = strchr(curr_argv, '=');
+		if (value == NULL && curr_argv[1] != '-' && strlen(curr_argv) > 2)
+			value = &curr_argv[2];
 		arg_name = NULL;
-		arg = find_option_arg(obj, &arg_idx, curr_argv, has_equal, &arg_name);
+		arg = find_option_arg(obj, &arg_idx, curr_argv, value, &arg_name);
 		if (arg == NULL || arg_name == NULL) {
 			ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv);
 			ret = -EINVAL;
@@ -755,7 +756,8 @@ parse_args(const struct rte_argparse *obj, bool *arg_parsed,
 			goto err_out;
 		}
 
-		value = (has_equal != NULL ? has_equal + 1 : NULL);
+		if (value != NULL && value[0] == '=')
+			value++; /* skip '=' */
 		if (arg->value_required == RTE_ARGPARSE_VALUE_NONE) {
 			if (value != NULL) {
 				ARGPARSE_LOG(ERR, "argument %s should not take value!", arg_name);
-- 
2.48.1



More information about the dev mailing list