From patchwork Fri Jan 26 06:10:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136173 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 97BB2439CC; Fri, 26 Jan 2024 07:14:45 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 87F0E42E34; Fri, 26 Jan 2024 07:14:16 +0100 (CET) Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by mails.dpdk.org (Postfix) with ESMTP id 7033B42D28 for ; Fri, 26 Jan 2024 07:14:07 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.194]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4TLnRM2TffzvVJL; Fri, 26 Jan 2024 14:12:31 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id 84672140444; Fri, 26 Jan 2024 14:14:05 +0800 (CST) Received: from localhost.localdomain (10.50.165.33) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Fri, 26 Jan 2024 14:14:05 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH v3 4/8] argparse: support parse parameters Date: Fri, 26 Jan 2024 06:10:09 +0000 Message-ID: <20240126061013.53608-5-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240126061013.53608-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240126061013.53608-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems706-chm.china.huawei.com (10.3.19.183) To dggpeml500024.china.huawei.com (7.185.36.10) X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This commit supports parse parameters which described in [argc, argv]. Signed-off-by: Chengwen Feng --- app/test/test_argparse.c | 437 ++++++++++++++++++++++++++++++++++++ lib/argparse/rte_argparse.c | 295 +++++++++++++++++++++++- 2 files changed, 729 insertions(+), 3 deletions(-) diff --git a/app/test/test_argparse.c b/app/test/test_argparse.c index 24d108f992..59dc79c8c6 100644 --- a/app/test/test_argparse.c +++ b/app/test/test_argparse.c @@ -319,6 +319,434 @@ test_argparse_invalid_arg_repeat(void) return 0; } +static int +test_argparse_invalid_option(void) +{ + struct rte_argparse *obj; + char *argv[2]; + int ret; + + obj = test_argparse_init_obj(); + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("--invalid"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("invalid"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +test_argparse_opt_autosave_parse_int_of_no_val(void) +{ + uint32_t flags = RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT; + struct rte_argparse *obj; + int val_saver = 0; + char *argv[2]; + int ret; + + 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 *)100; + obj->args[0].flags = flags; + obj->args[1].name_long = NULL; + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("--test-long"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + obj->args[0].flags = flags; + val_saver = 0; + argv[1] = test_strdup("-t"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + return 0; +} + +static int +test_argparse_opt_autosave_parse_int_of_required_val(void) +{ + uint32_t flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT; + struct rte_argparse *obj; + int val_saver = 0; + char *argv[3]; + int ret; + + 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].flags = flags; + obj->args[1].name_long = NULL; + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("--test-long"); + argv[2] = test_strdup("100"); + ret = rte_argparse_parse(obj, 3, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + obj->args[0].flags = flags; + val_saver = 0; + argv[1] = test_strdup("-t"); + ret = rte_argparse_parse(obj, 3, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + /* test invalid value. */ + obj->args[0].flags = flags; + val_saver = 0; + argv[1] = test_strdup("-t"); + argv[2] = test_strdup("100a"); + ret = rte_argparse_parse(obj, 3, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +test_argparse_opt_autosave_parse_int_of_optional_val(void) +{ + uint32_t flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE | RTE_ARGPARSE_ARG_VALUE_INT; + struct rte_argparse *obj; + int val_saver = 0; + char *argv[2]; + int ret; + + 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 *)100; + obj->args[0].flags = flags; + obj->args[1].name_long = NULL; + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("--test-long"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + obj->args[0].flags = flags; + val_saver = 0; + argv[1] = test_strdup("-t"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + /* test with value. */ + obj->args[0].flags = flags; + val_saver = 0; + argv[1] = test_strdup("--test-long=200"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 200, "Argparse parse expect success!"); + obj->args[0].flags = flags; + val_saver = 0; + argv[1] = test_strdup("-t=200"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 200, "Argparse parse expect success!"); + + /* test with option value, but with wrong value. */ + obj->args[0].flags = flags; + val_saver = 0; + argv[1] = test_strdup("--test-long=200a"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + obj->args[0].flags = flags; + val_saver = 0; + argv[1] = test_strdup("-t=200a"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +opt_callback_parse_int_of_no_val(uint32_t index, const char *value, void *opaque) +{ + RTE_SET_USED(index); + if (value != NULL) + return -EINVAL; + *(int *)opaque = 100; + return 0; +} + +static int +test_argparse_opt_callback_parse_int_of_no_val(void) +{ + struct rte_argparse *obj; + int val_saver = 0; + char *argv[2]; + int ret; + + obj = test_argparse_init_obj(); + obj->callback = opt_callback_parse_int_of_no_val; + obj->opaque = (void *)&val_saver; + obj->args[0].name_long = "--test-long"; + obj->args[0].name_short = "-t"; + obj->args[0].val_saver = NULL; + obj->args[0].val_set = (void *)100; + obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE; + obj->args[1].name_long = NULL; + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("--test-long"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE; + val_saver = 0; + argv[1] = test_strdup("-t"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + return 0; +} + +static int +opt_callback_parse_int_of_required_val(uint32_t index, const char *value, void *opaque) +{ + char *s = NULL; + + if (index != 1) + return -EINVAL; + + if (value == NULL) + return -EINVAL; + *(int *)opaque = strtol(value, &s, 0); + + if (s[0] != '\0') + return -EINVAL; + + return 0; +} + +static int +test_argparse_opt_callback_parse_int_of_required_val(void) +{ + struct rte_argparse *obj; + int val_saver = 0; + char *argv[3]; + int ret; + + obj = test_argparse_init_obj(); + obj->callback = opt_callback_parse_int_of_required_val; + obj->opaque = (void *)&val_saver; + obj->args[0].name_long = "--test-long"; + obj->args[0].name_short = "-t"; + obj->args[0].val_saver = NULL; + obj->args[0].val_set = (void *)1; + obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE; + obj->args[1].name_long = NULL; + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("--test-long"); + argv[2] = test_strdup("100"); + ret = rte_argparse_parse(obj, 3, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE; + val_saver = 0; + argv[1] = test_strdup("-t"); + ret = rte_argparse_parse(obj, 3, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + /* test no more parameters. */ + obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE; + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + /* test callback return failed. */ + obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE; + argv[2] = test_strdup("100a"); + ret = rte_argparse_parse(obj, 3, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +opt_callback_parse_int_of_optional_val(uint32_t index, const char *value, void *opaque) +{ + char *s = NULL; + + if (index != 1) + return -EINVAL; + + if (value == NULL) { + *(int *)opaque = 10; + } else { + *(int *)opaque = strtol(value, &s, 0); + if (s[0] != '\0') + return -EINVAL; + } + + return 0; +} + +static int +test_argparse_opt_callback_parse_int_of_optional_val(void) +{ + struct rte_argparse *obj; + int val_saver = 0; + char *argv[2]; + int ret; + + obj = test_argparse_init_obj(); + obj->callback = opt_callback_parse_int_of_optional_val; + obj->opaque = (void *)&val_saver; + obj->args[0].name_long = "--test-long"; + obj->args[0].name_short = "-t"; + obj->args[0].val_saver = NULL; + obj->args[0].val_set = (void *)1; + obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE; + obj->args[1].name_long = NULL; + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("--test-long"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 10, "Argparse parse expect success!"); + + obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE; + val_saver = 0; + argv[1] = test_strdup("-t"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 10, "Argparse parse expect success!"); + + /* test with value. */ + obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE; + val_saver = 0; + argv[1] = test_strdup("--test-long=100"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE; + val_saver = 0; + argv[1] = test_strdup("-t=100"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + /* test callback return failed. */ + obj->args[0].flags = RTE_ARGPARSE_ARG_OPTIONAL_VALUE; + argv[1] = test_strdup("-t=100a"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +test_argparse_pos_autosave_parse_int(void) +{ + uint32_t flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT; + struct rte_argparse *obj; + int val_saver = 0; + char *argv[3]; + int ret; + + obj = test_argparse_init_obj(); + obj->args[0].name_long = "test-long"; + obj->args[0].name_short = NULL; + obj->args[0].val_saver = (void *)&val_saver; + obj->args[0].val_set = NULL; + obj->args[0].flags = flags; + obj->args[1].name_long = NULL; + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("100"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver == 100, "Argparse parse expect success!"); + + obj->args[0].flags = flags; + val_saver = 0; + argv[1] = test_strdup("100a"); + ret = rte_argparse_parse(obj, 2, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + /* test over position parameters. */ + obj->args[0].flags = flags; + argv[1] = test_strdup("100"); + argv[2] = test_strdup("200"); + ret = rte_argparse_parse(obj, 3, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +pos_callback_parse_int(uint32_t index, const char *value, void *opaque) +{ + uint32_t int_val; + char *s = NULL; + + if (index != 1 && index != 2) + return -EINVAL; + if (value == NULL) + return -EINVAL; + + int_val = strtol(value, &s, 0); + if (s[0] != '\0') + return -EINVAL; + + *((int *)opaque + index) = int_val; + + return 0; +} + +static int +test_argparse_pos_callback_parse_int(void) +{ + int val_saver[3] = { 0, 0, 0 }; + struct rte_argparse *obj; + char *argv[3]; + int ret; + + obj = test_argparse_init_obj(); + obj->callback = pos_callback_parse_int; + obj->opaque = (void *)val_saver; + obj->args[0].name_long = "test-long1"; + obj->args[0].name_short = NULL; + obj->args[0].val_saver = NULL; + obj->args[0].val_set = (void *)1; + obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE; + obj->args[1].name_long = "test-long2"; + obj->args[1].name_short = NULL; + obj->args[1].val_saver = NULL; + obj->args[1].val_set = (void *)2; + obj->args[1].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE; + obj->args[2].name_long = NULL; + argv[0] = test_strdup(obj->usage); + argv[1] = test_strdup("100"); + argv[2] = test_strdup("200"); + ret = rte_argparse_parse(obj, 3, argv); + TEST_ASSERT(ret == 0, "Argparse parse expect success!"); + TEST_ASSERT(val_saver[1] == 100, "Argparse parse expect success!"); + TEST_ASSERT(val_saver[2] == 200, "Argparse parse expect success!"); + + /* test callback return failed. */ + obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE; + obj->args[1].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE; + argv[2] = test_strdup("200a"); + ret = rte_argparse_parse(obj, 3, argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + static struct unit_test_suite argparse_test_suite = { .suite_name = "Argparse Unit Test Suite", .setup = test_argparse_setup, @@ -331,6 +759,15 @@ static struct unit_test_suite argparse_test_suite = { TEST_CASE(test_argparse_invalid_arg_saver), TEST_CASE(test_argparse_invalid_arg_flags), TEST_CASE(test_argparse_invalid_arg_repeat), + TEST_CASE(test_argparse_invalid_option), + TEST_CASE(test_argparse_opt_autosave_parse_int_of_no_val), + TEST_CASE(test_argparse_opt_autosave_parse_int_of_required_val), + TEST_CASE(test_argparse_opt_autosave_parse_int_of_optional_val), + TEST_CASE(test_argparse_opt_callback_parse_int_of_no_val), + TEST_CASE(test_argparse_opt_callback_parse_int_of_required_val), + TEST_CASE(test_argparse_opt_callback_parse_int_of_optional_val), + TEST_CASE(test_argparse_pos_autosave_parse_int), + TEST_CASE(test_argparse_pos_callback_parse_int), TEST_CASES_END() /**< NULL terminate unit test array */ } diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c index 9c516c4bea..ed9b2f778a 100644 --- a/lib/argparse/rte_argparse.c +++ b/lib/argparse/rte_argparse.c @@ -298,18 +298,307 @@ verify_argparse(const struct rte_argparse *obj) return 0; } +static uint32_t +calc_position_count(const struct rte_argparse *obj) +{ + const struct rte_argparse_arg *arg; + uint32_t count = 0; + uint32_t i; + + for (i = 0; /* NULL */; i++) { + arg = &obj->args[i]; + if (obj->args[i].name_long == NULL) + break; + if (is_arg_positional(arg)) + count++; + } + + return count; +} + +static struct rte_argparse_arg * +find_position_arg(struct rte_argparse *obj, uint32_t index) +{ + struct rte_argparse_arg *arg; + uint32_t count = 0; + uint32_t i; + + for (i = 0; /* NULL */; i++) { + arg = &obj->args[i]; + if (arg->name_long == NULL) + break; + if (!is_arg_positional(arg)) + continue; + count++; + if (count == index) + return arg; + } + + return NULL; +} + +static bool +is_arg_match(struct rte_argparse_arg *arg, const char *curr_argv, uint32_t len) +{ + if (strlen(arg->name_long) == len && strncmp(arg->name_long, curr_argv, len) == 0) + return true; + + if (arg->name_short == NULL) + return false; + + if (strlen(arg->name_short) == len && strncmp(arg->name_short, curr_argv, len) == 0) + return true; + + return false; +} + +static struct rte_argparse_arg * +find_option_arg(struct rte_argparse *obj, const char *curr_argv, const char *has_equal, + const char **arg_name) +{ + uint32_t len = strlen(curr_argv) - (has_equal != NULL ? strlen(has_equal) : 0); + struct rte_argparse_arg *arg; + uint32_t i; + bool match; + + for (i = 0; /* nothing */; i++) { + arg = &obj->args[i]; + if (arg->name_long == NULL) + break; + match = is_arg_match(arg, curr_argv, len); + if (match) { + /* Obtains the exact matching name (long or short). */ + *arg_name = len > 2 ? arg->name_long : arg->name_short; + return arg; + } + } + + return NULL; +} + +static int +parse_arg_int(struct rte_argparse_arg *arg, const char *value) +{ + char *s = NULL; + + if (value == NULL) { + *(int *)arg->val_saver = (int)(intptr_t)arg->val_set; + return 0; + } + + errno = 0; + *(int *)arg->val_saver = strtol(value, &s, 0); + if (errno == ERANGE) { + ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); + return -EINVAL; + } + + if (s[0] != '\0') { + ARGPARSE_LOG(ERR, "argument %s expect an integer value!", arg->name_long); + return -EINVAL; + } + + return 0; +} + +static int +parse_arg_autosave(struct rte_argparse_arg *arg, const char *value) +{ + static struct { + int (*f_parse_type)(struct rte_argparse_arg *arg, const char *value); + } map[] = { + /* Sort by RTE_ARGPARSE_ARG_VALUE_XXX. */ + { NULL }, + { parse_arg_int }, + }; + uint32_t index = arg_attr_val_type(arg); + int ret = -EINVAL; + + if (index > 0 && index < RTE_DIM(map)) + ret = map[index].f_parse_type(arg, value); + + return ret; +} + +static int +parse_arg_val(struct rte_argparse *obj, struct rte_argparse_arg *arg, char *value) +{ + int ret; + + if (arg->val_saver == NULL) + ret = obj->callback((uint32_t)(uintptr_t)arg->val_set, value, obj->opaque); + else + ret = parse_arg_autosave(arg, value); + if (ret != 0) { + ARGPARSE_LOG(ERR, "argument %s parse value fail!", arg->name_long); + return ret; + } + + return 0; +} + +static bool +is_help(const char *curr_argv) +{ + return strcmp(curr_argv, "-h") == 0 || strcmp(curr_argv, "--help") == 0; +} + +static int +parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help) +{ + uint32_t position_count = calc_position_count(obj); + struct rte_argparse_arg *arg; + uint32_t position_index = 0; + const char *arg_name; + char *curr_argv; + char *has_equal; + char *value; + int ret; + int i; + + for (i = 1; i < argc; i++) { + curr_argv = argv[i]; + if (curr_argv[0] != '-') { + /* process positional parameters. */ + position_index++; + if (position_index > position_count) { + ARGPARSE_LOG(ERR, "too much positional argument %s!", curr_argv); + return -EINVAL; + } + arg = find_position_arg(obj, position_index); + ret = parse_arg_val(obj, arg, curr_argv); + if (ret != 0) + return ret; + continue; + } + + /* process optional parameters. */ + if (is_help(curr_argv)) { + *show_help = true; + continue; + } + + has_equal = strchr(curr_argv, '='); + arg_name = NULL; + arg = find_option_arg(obj, curr_argv, has_equal, &arg_name); + if (arg == NULL || arg_name == NULL) { + ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv); + return -EINVAL; + } + + if ((arg->flags & ARG_ATTR_FLAG_PARSED_MASK) && !arg_attr_flag_multi(arg)) { + ARGPARSE_LOG(ERR, "argument %s should not occur multiple!", + arg_name); + return -EINVAL; + } + + value = (has_equal != NULL ? has_equal + 1 : NULL); + if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_NO_VALUE) { + if (value != NULL) { + ARGPARSE_LOG(ERR, "argument %s should not take value!", + arg_name); + return -EINVAL; + } + } else if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_REQUIRED_VALUE) { + if (value == NULL) { + if (i >= argc - 1) { + ARGPARSE_LOG(ERR, "argument %s doesn't have value!", + arg_name); + return -EINVAL; + } + /* Set value and make i move next. */ + value = argv[++i]; + } + } else { + /* Do nothing, because it's optional value, only support arg=val or arg. */ + } + + ret = parse_arg_val(obj, arg, value); + if (ret != 0) + return ret; + + /* This argument parsed success! then mark it parsed. */ + arg->flags |= ARG_ATTR_FLAG_PARSED_MASK; + } + + return 0; +} + +static void +show_args_pos_help(const struct rte_argparse *obj) +{ + uint32_t position_count = calc_position_count(obj); + const struct rte_argparse_arg *arg; + uint32_t i; + + if (position_count == 0) + return; + + printf("\npositional arguments:\n"); + for (i = 0; /* NULL */; i++) { + arg = &obj->args[i]; + if (arg->name_long == NULL) + break; + if (!is_arg_positional(arg)) + continue; + printf(" %s: %s\n", arg->name_long, arg->help); + } +} + +static void +show_args_opt_help(const struct rte_argparse *obj) +{ + const struct rte_argparse_arg *arg; + uint32_t i; + + printf("\noptions:\n" + " -h, --help: show this help message and exit.\n"); + for (i = 0; /* NULL */; i++) { + arg = &obj->args[i]; + if (arg->name_long == NULL) + break; + if (!is_arg_optional(arg)) + continue; + if (arg->name_short != NULL) + printf(" %s, %s: %s\n", arg->name_short, arg->name_long, arg->help); + else + printf(" %s: %s\n", arg->name_long, arg->help); + } +} + +static void +show_args_help(const struct rte_argparse *obj) +{ + printf("usage: %s %s\n", obj->prog_name, obj->usage); + if (obj->descriptor != NULL) + printf("\ndescriptor: %s\n", obj->descriptor); + + show_args_pos_help(obj); + show_args_opt_help(obj); + + if (obj->epilog != NULL) + printf("\n%s\n", obj->epilog); +} + int rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) { + bool show_help = false; int ret; - (void)argc; - (void)argv; - ret = verify_argparse(obj); if (ret != 0) goto error; + ret = parse_args(obj, argc, argv, &show_help); + if (ret != 0) + goto error; + + if (show_help) { + show_args_help(obj); + exit(0); + } + return 0; error: