From patchwork Mon Jan 22 03:57:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136018 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 6137843922; Mon, 22 Jan 2024 05:02:00 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 9303A40A6B; Mon, 22 Jan 2024 05:01:55 +0100 (CET) Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by mails.dpdk.org (Postfix) with ESMTP id 9891C409FA for ; Mon, 22 Jan 2024 05:01:51 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.163.174]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4TJGjF1C8mzsWK4; Mon, 22 Jan 2024 12:00:49 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id 0FCDF1400FD; Mon, 22 Jan 2024 12:01:49 +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; Mon, 22 Jan 2024 12:01:48 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 01/12] eal: introduce more macro for bit definition Date: Mon, 22 Jan 2024 03:57:51 +0000 Message-ID: <20240122035802.31491-2-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 Introduce macros: RTE_MBIT64/RTE_MBIT32, RTE_GENMASK64/RTE_GENMASK32, and RTE_FIELD_GET64/RTE_FIELD_GET32. Signed-off-by: Chengwen Feng --- lib/eal/include/rte_bitops.h | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/lib/eal/include/rte_bitops.h b/lib/eal/include/rte_bitops.h index 6bd8bae21a..e1f3c4b195 100644 --- a/lib/eal/include/rte_bitops.h +++ b/lib/eal/include/rte_bitops.h @@ -39,6 +39,70 @@ extern "C" { */ #define RTE_BIT32(nr) (UINT32_C(1) << (nr)) +/** + * Get the uint64_t value for a multiple bits set. + * + * @param val + * The value may not all 1s. + * @param nr + * The bit number in range of 0 to (64 - width of val). + */ +#define RTE_MBIT64(val, nr) (UINT64_C(val) << (nr)) + +/** + * Get the uint32_t value for a multiple bits set. + * + * @param val + * The value may not all 1s. + * @param nr + * The bit number in range of 0 to (32 - width of val). + */ +#define RTE_MBIT32(val, nr) (UINT32_C(val) << (nr)) + +/** + * Generate a contiguous 64bit bitmask starting at bit position low + * and ending at position high. + * + * @param high + * High bit position. + * @param low + * Low bit position. + */ +#define RTE_GENMASK64(high, low) (((~UINT64_C(0)) << (low)) & (~UINT64_C(0) >> (63u - (high)))) + +/** + * Generate a contiguous 32bit bitmask starting at bit position low + * and ending at position high. + * + * @param high + * High bit position. + * @param low + * Low bit position. + */ +#define RTE_GENMASK32(high, low) (((~UINT32_C(0)) << (low)) & (~UINT32_C(0) >> (31u - (high)))) + +/** + * Extract a 64bit field element. + * + * @param mask + * shifted mask. + * @param reg + * value of entire bitfield. + */ +#define RTE_FIELD_GET64(mask, reg) \ + (typeof(mask))(((reg) & (mask)) >> rte_ctz64(mask)) + +/** + * Extract a 32bit field element. + * + * @param mask + * shifted mask. + * @param reg + * value of entire bitfield. + */ +#define RTE_FIELD_GET32(mask, reg) \ + (typeof(mask))(((reg) & (mask)) >> rte_ctz32(mask)) + /*------------------------ 32-bit relaxed operations ------------------------*/ /** From patchwork Mon Jan 22 03:57:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136022 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 AED0943922; Mon, 22 Jan 2024 05:02:29 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 570A7427E0; Mon, 22 Jan 2024 05:02:00 +0100 (CET) Received: from szxga05-in.huawei.com (szxga05-in.huawei.com [45.249.212.191]) by mails.dpdk.org (Postfix) with ESMTP id 858A840685 for ; Mon, 22 Jan 2024 05:01:51 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.163]) by szxga05-in.huawei.com (SkyGuard) with ESMTP id 4TJGdQ0mp2z1FJd6; Mon, 22 Jan 2024 11:57:30 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id 32C0818002F; Mon, 22 Jan 2024 12:01:49 +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; Mon, 22 Jan 2024 12:01:48 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 02/12] argparse: add argparse library Date: Mon, 22 Jan 2024 03:57:52 +0000 Message-ID: <20240122035802.31491-3-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 Introduce argparse library (which was inspired by the thread [1]). This commit provides public API and doc. [1] https://patchwork.dpdk.org/project/dpdk/patch/20231105054539.22303-2-fengchengwen@huawei.com/ Signed-off-by: Chengwen Feng --- doc/api/doxy-api-index.md | 1 + doc/api/doxy-api.conf.in | 1 + doc/guides/prog_guide/argparse_lib.rst | 141 ++++++++++++++++++ doc/guides/prog_guide/index.rst | 1 + doc/guides/rel_notes/release_24_03.rst | 5 + lib/argparse/meson.build | 7 + lib/argparse/rte_argparse.c | 14 ++ lib/argparse/rte_argparse.h | 191 +++++++++++++++++++++++++ lib/argparse/version.map | 7 + lib/meson.build | 1 + 10 files changed, 369 insertions(+) create mode 100644 doc/guides/prog_guide/argparse_lib.rst create mode 100644 lib/argparse/meson.build create mode 100644 lib/argparse/rte_argparse.c create mode 100644 lib/argparse/rte_argparse.h create mode 100644 lib/argparse/version.map diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index a6a768bd7c..fe41fba6ec 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -220,6 +220,7 @@ The public API headers are grouped by topics: [random](@ref rte_random.h), [config file](@ref rte_cfgfile.h), [key/value args](@ref rte_kvargs.h), + [argument parse](@ref rte_argparse.h), [string](@ref rte_string_fns.h), [thread](@ref rte_thread.h) diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index e94c9e4e46..76f89afe71 100644 --- a/doc/api/doxy-api.conf.in +++ b/doc/api/doxy-api.conf.in @@ -28,6 +28,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \ @TOPDIR@/lib/eal/include \ @TOPDIR@/lib/eal/include/generic \ @TOPDIR@/lib/acl \ + @TOPDIR@/lib/argparse \ @TOPDIR@/lib/bbdev \ @TOPDIR@/lib/bitratestats \ @TOPDIR@/lib/bpf \ diff --git a/doc/guides/prog_guide/argparse_lib.rst b/doc/guides/prog_guide/argparse_lib.rst new file mode 100644 index 0000000000..012b29bbfb --- /dev/null +++ b/doc/guides/prog_guide/argparse_lib.rst @@ -0,0 +1,141 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2024 HiSilicon Limited + +Argparse Library +================ + +The argparse library provides argument parse functionality, this library makes +it easy to write user-friendly command-line program. + +Features and Capabilities +------------------------- + +- Support parse optional argument (which could take with no-value, + required-value and optional-value). + +- Support parse positional argument (which must take with required-value). + +- Support automatic generate usage information. + +- Support issue errors when provide with invalid arguments. + +- Support parse argument by two way: 1) autosave: for which known value types, + this way can be used; 2) callback: will invoke user callback to parse. + +Usage Guide +----------- + +The following code demonstrates how to initialize: + +.. code-block:: C + + static int + argparse_user_callback(uint32_t index, const char *value, void *opaque) + { + if (index == 1) { + /* process "--ddd" argument, because it has no-value, the parameter value is NULL. */ + ... + } else if (index == 2) { + /* process "--eee" argument, because it has required-value, the parameter value must not NULL. */ + ... + } else if (index == 3) { + /* process "--fff" argument, because it has optional-value, the parameter value maybe NULL or not NULL, depend on input. */ + ... + } else if (index == 300) { + /* process "ppp" argument, because it's a positional argument, the parameter value must not NULL. */ + ... + } else { + return -EINVAL; + } + } + + int aaa_val, bbb_val, ccc_val, ooo_val; + + static struct rte_argparse obj = { + .prog_name = "test-demo", + .usage = "[EAL options] -- [optional parameters] [positional parameters]", + .descriptor = NULL, + .epilog = NULL, + .exit_on_error = true, + .callback = argparse_user_callback, + .args = { + { "--aaa", "-a", "aaa argument", &aaa_val, (void *)100, RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT }, + { "--bbb", "-b", "bbb argument", &bbb_val, NULL, RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT }, + { "--ccc", "-c", "ccc argument", &ccc_val, (void *)200, RTE_ARGPARSE_ARG_OPTIONAL_VALUE | RTE_ARGPARSE_ARG_VALUE_INT }, + { "--ddd", "-d", "ddd argument", NULL, (void *)1, RTE_ARGPARSE_ARG_NO_VALUE }, + { "--eee", "-e", "eee argument", NULL, (void *)2, RTE_ARGPARSE_ARG_REQUIRED_VALUE }, + { "--fff", "-f", "fff argument", NULL, (void *)3, RTE_ARGPARSE_ARG_OPTIONAL_VALUE }, + { "ooo", NULL, "ooo argument", &ooo_val, NULL, RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT }, + { "ppp", NULL, "ppp argument", NULL, (void *)300, RTE_ARGPARSE_ARG_REQUIRED_VALUE }, + }, + }; + + int + main(int argc, char **argv) + { + ... + ret = rte_argparse_parse(&obj, argc, argv); + ... + } + +Parsing by autosave way +~~~~~~~~~~~~~~~~~~~~~~~ + +For which known value types (just like ``RTE_ARGPARSE_ARG_VALUE_INT``"), could +parse by autosave way, just like above "--aaa"/"--bbb"/"--ccc" optional +arguments: + +If the user input parameter are: "program --aaa --bbb 1234 --ccc=20 ...", then +the aaa_val will equal 100, the bbb_val will equal 1234 and the ccc_val will +equal 20. + +If the user input parameter are: "program --ccc ...", then the aaa_val and +bbb_val will not modify, and ccc_val will equal 200. + +Parsing by callback way +~~~~~~~~~~~~~~~~~~~~~~~ + +It could also choose to use callback to parse, just define a unique index for +the argument and make the field val_save to be NULL also zero value-type. Just +like above "--ddd"/"--eee"/"--fff" optional arguments: + +If the user input parameter are: "program --ddd --eee 2345 --fff=30 ...", the +function argparse_user_callback() will be invoke to parse the value. + +Positional arguments +~~~~~~~~~~~~~~~~~~~~ + +The positional arguments could not start with a hyphen (-). The above code show +that there are two positional arguments "ooo"/"ppp", it must be flags with +``RTE_ARGPARSE_ARG_REQUIRED_VALUE``, and it also could use autosave or callback +to parsing: + +If the user input parameter are: "program [optionals] 456 789", then the ooo_val +will equal 456, and ppp_val will equal 789. + +Multiple times argument +~~~~~~~~~~~~~~~~~~~~~~~ + +If want to support the ability to enter the same argument multiple times, then +should mark ``RTE_ARGPARSE_ARG_SUPPORT_MULTI`` in flags field. For examples: + +.. code-block:: C + + ... + { "--xyz", "-x", "xyz argument", NULL, (void *)10, RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_SUPPORT_MULTI }, + ... + +Then the user input parameter could be: "program --xyz 123 --xyz 456 ...". + +It's important to note that the multiple times flag only support with optional +argument and must be parsing by callback way. + +Other Notes +~~~~~~~~~~~ + +For optional arguments, short-name can be defined or not defined. For arguments +that have required value, the following inputs are supported: +"program --bbb=123 --eee 456 ..." or "program -b=123 -e 456 ...". + +For arguments that have optional value, the following inputs are supported: +"program --ccc --fff=100 ..." or "program -c -f=100". diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst index 94964357ff..d09d958e6c 100644 --- a/doc/guides/prog_guide/index.rst +++ b/doc/guides/prog_guide/index.rst @@ -13,6 +13,7 @@ Programmer's Guide source_org env_abstraction_layer log_lib + argparse_lib cmdline service_cores trace_lib diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst index 6f8ad27808..724b7b673e 100644 --- a/doc/guides/rel_notes/release_24_03.rst +++ b/doc/guides/rel_notes/release_24_03.rst @@ -55,6 +55,11 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Introduce argument parse library.** + + Introduce argparse library, compared with getopt, it makes it easy to write + user-friendly command-like program. + Removed Items ------------- diff --git a/lib/argparse/meson.build b/lib/argparse/meson.build new file mode 100644 index 0000000000..b6a08ca049 --- /dev/null +++ b/lib/argparse/meson.build @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2024 HiSilicon Limited. + +sources = files('rte_argparse.c') +headers = files('rte_argparse.h') + +deps += ['log'] diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c new file mode 100644 index 0000000000..3471c5e757 --- /dev/null +++ b/lib/argparse/rte_argparse.c @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 HiSilicon Limited + */ + +#include "rte_argparse.h" + +int +rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) +{ + (void)obj; + (void)argc; + (void)argv; + return 0; +} diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h new file mode 100644 index 0000000000..3e94711280 --- /dev/null +++ b/lib/argparse/rte_argparse.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 HiSilicon Limited + */ + +#ifndef RTE_ARGPARSE_H +#define RTE_ARGPARSE_H + +/** + * @file rte_argparse.h + * + * Argument parse API. + * + * The argument parse API makes it easy to write user-friendly command-line + * program. The program defines what arguments it requires, and the API + * will parse those arguments which described in [argc, argv]. + * + * The API provides following functions: + * 1) Support parse optional argument (which could take with no-value, + * required-value and optional-value. + * 2) Support parse positional argument (which must take with required-value). + * 3) Support automatic generate usage information. + * 4) Support issue errors when provided with invalid arguments. + * + * There are two ways to parse arguments: + * 1) AutoSave: for which known value types, the way can be used. + * 2) Callback: will invoke user callback to parse. + * + */ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Flag definition (in bitmask form) for an argument. + */ +enum rte_argparse_flag { + /* + * Bit0-1: represent the argument whether has value. + */ + + /** The argument has no value. */ + RTE_ARGPARSE_ARG_NO_VALUE = RTE_MBIT64(1, 0), + /** The argument must have a value. */ + RTE_ARGPARSE_ARG_REQUIRED_VALUE = RTE_MBIT64(2, 0), + /** The argument has optional value. */ + RTE_ARGPARSE_ARG_OPTIONAL_VALUE = RTE_MBIT64(3, 0), + + + /* + * Bit2-9: represent the value type which used when autosave + */ + + /** The argument's value is int type. */ + RTE_ARGPARSE_ARG_VALUE_INT = RTE_MBIT64(1, 2), + /** Max value type. */ + RTE_ARGPARSE_ARG_VALUE_MAX = RTE_MBIT64(2, 2), + + + /** + * Bit10: flag for that argument support occur multiple times. + * This flag can be set only when the argument is optional. + * When this flag is set, the callback type must be used for parsing. + */ + RTE_ARGPARSE_ARG_SUPPORT_MULTI = RTE_BIT64(10), + + /** + * Bit48-63: reserved for this library implement usage. + */ + RTE_ARGPARSE_ARG_RESERVED_FIELD = RTE_GENMASK64(63, 48), +}; + +/** + * A structure used to hold argument's configuration. + */ +struct rte_argparse_arg { + /** + * Long name of the argument: + * 1) If the argument is optional, it must start with '--'. + * 2) If the argument is positional, it must not start with '-'. + * 3) Other case will be considered as error. + */ + const char *name_long; + /** + * Short name of the argument: + * 1) This field could be set only when name_long is optional, and + * must start with a hyphen (-) followed by an English letter. + * 2) Other case it should be set NULL. + */ + const char *name_short; + + /** Help information of the argument, must not be NULL. */ + const char *help; + + /** + * Saver for the argument's value. + * 1) If the filed is NULL, the callback way is used for parsing + * argument. + * 2) If the field is not NULL, the autosave way is used for parsing + * argument. + */ + void *val_saver; + /** + * If val_saver is NULL, this filed (cast as (uint32_t)val_set) will be + * used as the first parameter to invoke callback. + * + * If val_saver is not NULL, then: + * 1) If argument has no value, val_saver will set to val_set when + * argument found. + * 2) If argument has optional value but doesn't take value this + * time, val_saver will set to val_set when argument found. + * 3) Other case it should be set NULL. + */ + void *val_set; + + /** @see rte_argparse_flag */ + uint64_t flags; +}; + +/** + * Callback prototype used by parsing specified arguments. + * + * @param index + * The argument's index, coming from argument's val_set. + * @param value + * The value corresponding to the argument, it may be NULL (e.g. the + * argument has no value, or the argument has optional value but doesn't + * provided value). + * @param opaque + * An opaque pointer coming from the caller. + * @return + * 0 on success. Otherwise negative value is returned. + */ +typedef int (*arg_parser_t)(uint32_t index, const char *value, void *opaque); + +/** + * A structure used to hold argparse's configuration. + */ +struct rte_argparse { + /** Program name. Must not be NULL. */ + const char *prog_name; + /** How to use the program. Must not be NULL. */ + const char *usage; + /** Explain what the program does. Could be NULL. */ + const char *descriptor; + /** Text at the bottom of help. Could be NULL. */ + const char *epilog; + /** Whether exit when error. */ + bool exit_on_error; + /** User callback for parsing arguments. */ + arg_parser_t callback; + /** Opaque which used to invoke callback. */ + void *opaque; + /** Reserved field used for future extension. */ + void *reserved[16]; + /** Arguments configuration. Must ended with ARGPARSE_ARG_END(). */ + struct rte_argparse_arg args[]; +}; + +#define ARGPARSE_ARG_END() { NULL } + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Parse parameters. + * + * @param obj + * Parser object. + * @param argc + * Parameters count. + * @param argv + * Array of parameters points. + * + * @return + * 0 on success. Otherwise negative value is returned. + */ +__rte_experimental +int rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv); + +#ifdef __cplusplus +} +#endif + +#endif /* RTE_ARGPARSE_H */ diff --git a/lib/argparse/version.map b/lib/argparse/version.map new file mode 100644 index 0000000000..1c176f69e9 --- /dev/null +++ b/lib/argparse/version.map @@ -0,0 +1,7 @@ +EXPERIMENTAL { + global: + + rte_argparse_parse; + + local: *; +}; diff --git a/lib/meson.build b/lib/meson.build index 6c143ce5a6..cdd2d3c536 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -11,6 +11,7 @@ libraries = [ 'log', 'kvargs', # eal depends on kvargs + 'argparse', 'telemetry', # basic info querying 'eal', # everything depends on eal 'ring', From patchwork Mon Jan 22 03:57:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136019 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 1B1F443922; Mon, 22 Jan 2024 05:02:07 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id BBA7540A77; Mon, 22 Jan 2024 05:01:56 +0100 (CET) Received: from szxga08-in.huawei.com (szxga08-in.huawei.com [45.249.212.255]) by mails.dpdk.org (Postfix) with ESMTP id 8009F40633 for ; Mon, 22 Jan 2024 05:01:51 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.105]) by szxga08-in.huawei.com (SkyGuard) with ESMTP id 4TJGjF4VwQz1Q88n; Mon, 22 Jan 2024 12:00:49 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id 575C91402E2; Mon, 22 Jan 2024 12:01:49 +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; Mon, 22 Jan 2024 12:01:49 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 03/12] argparse: support verify argument config Date: Mon, 22 Jan 2024 03:57:53 +0000 Message-ID: <20240122035802.31491-4-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 verify argument config. Signed-off-by: Chengwen Feng --- lib/argparse/rte_argparse.c | 307 +++++++++++++++++++++++++++++++++++- 1 file changed, 306 insertions(+), 1 deletion(-) diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c index 3471c5e757..3dbae8868b 100644 --- a/lib/argparse/rte_argparse.c +++ b/lib/argparse/rte_argparse.c @@ -2,13 +2,318 @@ * Copyright(c) 2024 HiSilicon Limited */ +#include +#include +#include + +#include + #include "rte_argparse.h" +RTE_LOG_REGISTER_DEFAULT(rte_argparse_logtype, INFO); +#define ARGPARSE_LOG(level, ...) \ + rte_log(RTE_LOG_ ## level, rte_argparse_logtype, RTE_FMT("argparse: " \ + RTE_FMT_HEAD(__VA_ARGS__,) "\n", RTE_FMT_TAIL(__VA_ARGS__,))) + +#define ARG_ATTR_HAS_VAL_MASK RTE_GENMASK64(1, 0) +#define ARG_ATTR_VAL_TYPE_MASK RTE_GENMASK64(9, 2) +#define ARG_ATTR_SUPPORT_MULTI_MASK RTE_BIT64(10) +#define ARG_ATTR_FLAG_PARSED_MASK RTE_BIT64(63) + +static inline bool +is_arg_optional(const struct rte_argparse_arg *arg) +{ + return arg->name_long[0] == '-'; +} + +static inline bool +is_arg_positional(const struct rte_argparse_arg *arg) +{ + return arg->name_long[0] != '-'; +} + +static inline uint32_t +arg_attr_has_val(const struct rte_argparse_arg *arg) +{ + return RTE_FIELD_GET64(ARG_ATTR_HAS_VAL_MASK, arg->flags); +} + +static inline uint32_t +arg_attr_val_type(const struct rte_argparse_arg *arg) +{ + return RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, arg->flags); +} + +static inline bool +arg_attr_flag_multi(const struct rte_argparse_arg *arg) +{ + return RTE_FIELD_GET64(ARG_ATTR_SUPPORT_MULTI_MASK, arg->flags); +} + +static inline uint32_t +arg_attr_unused_bits(const struct rte_argparse_arg *arg) +{ +#define USED_BIT_MASK (ARG_ATTR_HAS_VAL_MASK | ARG_ATTR_VAL_TYPE_MASK | \ + ARG_ATTR_SUPPORT_MULTI_MASK) + return arg->flags & ~USED_BIT_MASK; +} + +static int +verify_arg_name(const struct rte_argparse_arg *arg) +{ + if (is_arg_optional(arg)) { + if (strlen(arg->name_long) <= 3) { + ARGPARSE_LOG(ERR, "optional long name %s too short!", arg->name_long); + return -EINVAL; + } + if (arg->name_long[1] != '-') { + ARGPARSE_LOG(ERR, "optional long name %s must only start with '--'", + arg->name_long); + return -EINVAL; + } + if (arg->name_long[2] == '-') { + ARGPARSE_LOG(ERR, "optional long name %s should not start with '---'", + arg->name_long); + return -EINVAL; + } + } + + if (arg->name_short == NULL) + return 0; + + if (!is_arg_optional(arg)) { + ARGPARSE_LOG(ERR, "short name %s corresponding long name must be optional!", + arg->name_short); + return -EINVAL; + } + + if (strlen(arg->name_short) != 2 || arg->name_short[0] != '-' || + arg->name_short[1] == '-') { + ARGPARSE_LOG(ERR, "short name %s must start with a hyphen (-) followed by an English letter", + arg->name_short); + return -EINVAL; + } + + return 0; +} + +static int +verify_arg_help(const struct rte_argparse_arg *arg) +{ + if (arg->help == NULL) { + ARGPARSE_LOG(ERR, "argument %s must have help info!", arg->name_long); + return -EINVAL; + } + + return 0; +} + +static int +verify_arg_has_val(const struct rte_argparse_arg *arg) +{ + uint32_t has_val = arg_attr_has_val(arg); + + if (is_arg_positional(arg)) { + if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE) + return 0; + ARGPARSE_LOG(ERR, "argument %s is positional, should has zero or required-val!", + arg->name_long); + return -EINVAL; + } + + if (has_val == 0) { + ARGPARSE_LOG(ERR, "argument %s is optional, has-val config wrong!", + arg->name_long); + return -EINVAL; + } + + return 0; +} + +static int +verify_arg_saver(const struct rte_argparse *obj, uint32_t index) +{ + uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX); + const struct rte_argparse_arg *arg = &obj->args[index]; + uint32_t val_type = arg_attr_val_type(arg); + uint32_t has_val = arg_attr_has_val(arg); + + if (arg->val_saver == NULL) { + if (val_type != 0) { + ARGPARSE_LOG(ERR, "argument %s parse by callback, val-type must be zero!", + arg->name_long); + return -EINVAL; + } + + if (obj->callback == NULL) { + ARGPARSE_LOG(ERR, "argument %s parse by callback, but callback is NULL!", + arg->name_long); + return -EINVAL; + } + + return 0; + } + + if (val_type == 0 || val_type >= cmp_max) { + ARGPARSE_LOG(ERR, "argument %s val-type config wrong!", arg->name_long); + return -EINVAL; + } + + if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE && arg->val_set != NULL) { + ARGPARSE_LOG(ERR, "argument %s has required value, val-set should be NULL!", + arg->name_long); + return -EINVAL; + } + + return 0; +} + +static int +verify_arg_flags(const struct rte_argparse *obj, uint32_t index) +{ + const struct rte_argparse_arg *arg = &obj->args[index]; + uint32_t unused_bits = arg_attr_unused_bits(arg); + + if (unused_bits != 0) { + ARGPARSE_LOG(ERR, "argument %s flags set wrong!", arg->name_long); + return -EINVAL; + } + + if (!(arg->flags & RTE_ARGPARSE_ARG_SUPPORT_MULTI)) + return 0; + + if (is_arg_positional(arg)) { + ARGPARSE_LOG(ERR, "argument %s is positional, don't support multiple times!", + arg->name_long); + return -EINVAL; + } + + if (arg->val_saver != NULL) { + ARGPARSE_LOG(ERR, "argument %s could occur multiple times, should use callback to parse!", + arg->name_long); + return -EINVAL; + } + + if (obj->callback == NULL) { + ARGPARSE_LOG(ERR, "argument %s should use callback to parse, but callback is NULL!", + arg->name_long); + return -EINVAL; + } + + return 0; +} + +static int +verify_arg_repeat(const struct rte_argparse *self, uint32_t index) +{ + const struct rte_argparse_arg *arg = &self->args[index]; + uint32_t i; + + for (i = 0; i < index; i++) { + if (!strcmp(arg->name_long, self->args[i].name_long)) { + ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_long); + return -EINVAL; + } + } + + if (arg->name_short == NULL) + return 0; + + for (i = 0; i < index; i++) { + if (self->args[i].name_short == NULL) + continue; + if (!strcmp(arg->name_short, self->args[i].name_short)) { + ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_short); + return -EINVAL; + } + } + + return 0; +} + +static int +verify_argparse_arg(const struct rte_argparse *obj, uint32_t index) +{ + const struct rte_argparse_arg *arg = &obj->args[index]; + int ret; + + ret = verify_arg_name(arg); + if (ret != 0) + return ret; + + ret = verify_arg_help(arg); + if (ret != 0) + return ret; + + ret = verify_arg_has_val(arg); + if (ret != 0) + return ret; + + ret = verify_arg_saver(obj, index); + if (ret != 0) + return ret; + + ret = verify_arg_flags(obj, index); + if (ret != 0) + return ret; + + ret = verify_arg_repeat(obj, index); + if (ret != 0) + return ret; + + return 0; +} + +static int +verify_argparse(const struct rte_argparse *obj) +{ + uint32_t idx; + int ret; + + if (obj->prog_name == NULL) { + ARGPARSE_LOG(ERR, "program name is NULL!"); + return -EINVAL; + } + + if (obj->usage == NULL) { + ARGPARSE_LOG(ERR, "usage is NULL!"); + return -EINVAL; + } + + for (idx = 0; idx < RTE_DIM(obj->reserved); idx++) { + if (obj->reserved[idx] != 0) { + ARGPARSE_LOG(ERR, "reserved field must be zero!"); + return -EINVAL; + } + } + + idx = 0; + while (obj->args[idx].name_long != NULL) { + ret = verify_argparse_arg(obj, idx); + if (ret != 0) + return ret; + idx++; + } + + return 0; +} + int rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) { - (void)obj; + int ret; + (void)argc; (void)argv; + + ret = verify_argparse(obj); + if (ret != 0) + goto error; + return 0; + +error: + if (obj->exit_on_error) + exit(ret); + return ret; } From patchwork Mon Jan 22 03:57:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136020 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 C133F43922; Mon, 22 Jan 2024 05:02:12 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id D977A40A84; Mon, 22 Jan 2024 05:01:57 +0100 (CET) Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by mails.dpdk.org (Postfix) with ESMTP id 9056B406A2 for ; Mon, 22 Jan 2024 05:01:51 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.163.48]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4TJGjz3M3lzbcF2; Mon, 22 Jan 2024 12:01:27 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id 757E8180076; Mon, 22 Jan 2024 12:01:49 +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; Mon, 22 Jan 2024 12:01:49 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 04/12] test/argparse: add verify argument config test Date: Mon, 22 Jan 2024 03:57:54 +0000 Message-ID: <20240122035802.31491-5-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 adds verify argument config test. Signed-off-by: Chengwen Feng --- app/test/meson.build | 1 + app/test/test_argparse.c | 327 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 328 insertions(+) create mode 100644 app/test/test_argparse.c diff --git a/app/test/meson.build b/app/test/meson.build index dcc93f4a43..864b79d39f 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -27,6 +27,7 @@ source_file_deps = { # the various test_*.c files 'test_acl.c': ['net', 'acl'], 'test_alarm.c': [], + 'test_argparse.c': ['argparse'], 'test_atomic.c': ['hash'], 'test_barrier.c': [], 'test_bitcount.c': [], diff --git a/app/test/test_argparse.c b/app/test/test_argparse.c new file mode 100644 index 0000000000..31c46ecccf --- /dev/null +++ b/app/test/test_argparse.c @@ -0,0 +1,327 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 HiSilicon Limited + */ + +#include +#include + +#include + +#include "test.h" + +static int default_argc; +static char *default_argv[1]; + +/* + * Define strdup wrapper. + * 1. Mainly to fix compile error "warning: assignment discards 'const' + * qualifier from pointer target type [-Wdiscarded-qualifiers]" for + * following code: + * argv[x] = "100"; + * 2. Because this is a test, the memory release which allocated by this + * wrapper in the subtest is not considered. + */ +static char * +test_strdup(const char *str) +{ + char *s = strdup(str); + if (s == NULL) + exit(-ENOMEM); + return s; +} + +static int +test_argparse_setup(void) +{ + default_argc = 1; + default_argv[0] = test_strdup("test_argparse"); + return 0; +} + +static void +test_argparse_teardown(void) +{ + free(default_argv[0]); +} + +static int +test_argparse_callback(uint32_t index, const char *value, void *opaque) +{ + RTE_SET_USED(index); + RTE_SET_USED(value); + RTE_SET_USED(opaque); + return 0; +} + +/* valid templater, must contain at least two args. */ +#define argparse_templater() { \ + .prog_name = "test_argparse", \ + .usage = "-a xx -b yy", \ + .descriptor = NULL, \ + .epilog = NULL, \ + .exit_on_error = false, \ + .callback = test_argparse_callback, \ + .args = { \ + { "--abc", "-a", "abc argument", (void *)1, (void *)1, RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT }, \ + { "--xyz", "-x", "xyz argument", (void *)1, (void *)2, RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT }, \ + ARGPARSE_ARG_END(), \ + }, \ +} + +static void +test_argparse_copy(struct rte_argparse *dst, struct rte_argparse *src) +{ + uint32_t i; + memcpy(dst, src, sizeof(*src)); + for (i = 0; /* NULL */; i++) { + memcpy(&dst->args[i], &src->args[i], sizeof(src->args[i])); + if (src->args[i].name_long == NULL) + break; + } +} + +static struct rte_argparse * +test_argparse_init_obj(void) +{ + static struct rte_argparse backup = argparse_templater(); + static struct rte_argparse obj = argparse_templater(); + test_argparse_copy(&obj, &backup); + return &obj; +} + +static int +test_argparse_invalid_basic_param(void) +{ + struct rte_argparse *obj; + int ret; + + obj = test_argparse_init_obj(); + obj->prog_name = NULL; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->usage = NULL; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return TEST_SUCCESS; +} + +static int +test_argparse_invalid_arg_name(void) +{ + struct rte_argparse *obj; + int ret; + + obj = test_argparse_init_obj(); + obj->args[0].name_long = "-ab"; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->args[0].name_long = "-abc"; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->args[0].name_long = "---c"; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->args[0].name_long = "abc"; + obj->args[0].name_short = "-a"; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->args[0].name_short = "a"; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->args[0].name_short = "abc"; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->args[0].name_short = "ab"; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +test_argparse_invalid_arg_help(void) +{ + struct rte_argparse *obj; + int ret; + + obj = test_argparse_init_obj(); + obj->args[0].help = NULL; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +test_argparse_invalid_has_val(void) +{ + uint32_t set_mask[] = { 0, + RTE_ARGPARSE_ARG_NO_VALUE, + RTE_ARGPARSE_ARG_OPTIONAL_VALUE + }; + struct rte_argparse *obj; + uint32_t index; + int ret; + + obj = test_argparse_init_obj(); + obj->args[0].flags &= ~0x3u; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + for (index = 0; index < RTE_DIM(set_mask); index++) { + obj = test_argparse_init_obj(); + obj->args[0].name_long = "abc"; + obj->args[0].name_short = NULL; + obj->args[0].flags &= ~0x3u; + obj->args[0].flags |= set_mask[index]; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + } + + return 0; +} + +static int +test_argparse_invalid_arg_saver(void) +{ + struct rte_argparse *obj; + int ret; + + /* test saver == NULL with val-type != 0. */ + obj = test_argparse_init_obj(); + obj->args[0].val_saver = NULL; + obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + /* test saver == NULL with callback is NULL. */ + obj = test_argparse_init_obj(); + obj->args[0].val_saver = NULL; + obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE; + obj->callback = NULL; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + /* test saver != NULL with val-type is zero! */ + obj = test_argparse_init_obj(); + obj->args[0].val_saver = (void *)1; + obj->args[0].val_set = (void *)1; + obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + /* test saver != NULL with val-type is max. */ + obj = test_argparse_init_obj(); + obj->args[0].val_saver = (void *)1; + obj->args[0].val_set = (void *)1; + obj->args[0].flags = RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_MAX; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + /* test saver != NULL with required value, but val-set is not NULL. */ + obj = test_argparse_init_obj(); + obj->args[0].val_saver = (void *)1; + obj->args[0].val_set = (void *)1; + obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +test_argparse_invalid_arg_flags(void) +{ + struct rte_argparse *obj; + int ret; + + obj = test_argparse_init_obj(); + obj->args[0].flags |= ~0x107FFu; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->args[0].name_long = "positional"; + obj->args[0].name_short = NULL; + obj->args[0].val_saver = (void *)1; + obj->args[0].val_set = (void *)1; + obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_INT | + RTE_ARGPARSE_ARG_SUPPORT_MULTI; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->args[0].flags |= RTE_ARGPARSE_ARG_SUPPORT_MULTI; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + obj = test_argparse_init_obj(); + obj->args[0].val_saver = NULL; + obj->args[0].flags = RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_SUPPORT_MULTI; + obj->callback = NULL; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + return 0; +} + +static int +test_argparse_invalid_arg_repeat(void) +{ + struct rte_argparse *obj; + int ret; + + /* test for long name repeat! */ + obj = test_argparse_init_obj(); + obj->args[1].name_long = obj->args[0].name_long; + ret = rte_argparse_parse(obj, default_argc, default_argv); + TEST_ASSERT(ret == -EINVAL, "Argparse parse expect failed!"); + + /* test for short name repeat! */ + obj = test_argparse_init_obj(); + obj->args[1].name_short = obj->args[0].name_short; + ret = rte_argparse_parse(obj, default_argc, default_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, + .teardown = test_argparse_teardown, + .unit_test_cases = { + TEST_CASE(test_argparse_invalid_basic_param), + TEST_CASE(test_argparse_invalid_arg_name), + TEST_CASE(test_argparse_invalid_arg_help), + TEST_CASE(test_argparse_invalid_has_val), + TEST_CASE(test_argparse_invalid_arg_saver), + TEST_CASE(test_argparse_invalid_arg_flags), + TEST_CASE(test_argparse_invalid_arg_repeat), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static int +test_argparse(void) +{ + return unit_test_suite_runner(&argparse_test_suite); +} + +REGISTER_FAST_TEST(argparse_autotest, true, true, test_argparse); From patchwork Mon Jan 22 03:57:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136021 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 C231A43922; Mon, 22 Jan 2024 05:02:20 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 13A2D40DCD; Mon, 22 Jan 2024 05:01:59 +0100 (CET) Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) by mails.dpdk.org (Postfix) with ESMTP id 9552E406BA for ; Mon, 22 Jan 2024 05:01:51 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.163.17]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4TJGhR2NM9z29kbf; Mon, 22 Jan 2024 12:00:07 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id 9AF8A1A0172; Mon, 22 Jan 2024 12:01:49 +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; Mon, 22 Jan 2024 12:01:49 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 05/12] argparse: support parse parameters Date: Mon, 22 Jan 2024 03:57:55 +0000 Message-ID: <20240122035802.31491-6-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 --- lib/argparse/rte_argparse.c | 289 +++++++++++++++++++++++++++++++++++- 1 file changed, 286 insertions(+), 3 deletions(-) diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c index 3dbae8868b..9c5bce6ddf 100644 --- a/lib/argparse/rte_argparse.c +++ b/lib/argparse/rte_argparse.c @@ -298,18 +298,301 @@ 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) +{ + 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) + 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; + 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 = find_option_arg(obj, curr_argv, has_equal); + if (arg == 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_long); + 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_long); + 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_long); + 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: From patchwork Mon Jan 22 03:57:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136023 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 E146E43922; Mon, 22 Jan 2024 05:02:40 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 6B89C42DA6; Mon, 22 Jan 2024 05:02:08 +0100 (CET) Received: from szxga07-in.huawei.com (szxga07-in.huawei.com [45.249.212.35]) by mails.dpdk.org (Postfix) with ESMTP id B6CD1427E9 for ; Mon, 22 Jan 2024 05:02:06 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.214]) by szxga07-in.huawei.com (SkyGuard) with ESMTP id 4TJGhk0yMlz1S5M5; Mon, 22 Jan 2024 12:00:22 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id BE16E1A0173; Mon, 22 Jan 2024 12:01:49 +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; Mon, 22 Jan 2024 12:01:49 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 06/12] test/argparse: add parse parameters test Date: Mon, 22 Jan 2024 03:57:56 +0000 Message-ID: <20240122035802.31491-7-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 adds parse parameters test. Signed-off-by: Chengwen Feng --- app/test/test_argparse.c | 437 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) diff --git a/app/test/test_argparse.c b/app/test/test_argparse.c index 31c46ecccf..f55b57a21f 100644 --- a/app/test/test_argparse.c +++ b/app/test/test_argparse.c @@ -301,6 +301,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, @@ -313,6 +741,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 */ } From patchwork Mon Jan 22 03:57:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136024 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 DE2E843922; Mon, 22 Jan 2024 05:02:46 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id AF18442DD2; Mon, 22 Jan 2024 05:02:23 +0100 (CET) Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) by mails.dpdk.org (Postfix) with ESMTP id 2CF0042DCD for ; Mon, 22 Jan 2024 05:02:22 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.214]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4TJGk15c34z1xmXr; Mon, 22 Jan 2024 12:01:29 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id C28611A0170; Mon, 22 Jan 2024 12:02:04 +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; Mon, 22 Jan 2024 12:01:49 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 07/12] argparse: provide parsing known type API Date: Mon, 22 Jan 2024 03:57:57 +0000 Message-ID: <20240122035802.31491-8-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 Provide API which could parsing the value from the input string based on the value type. This API could used in user callback when parsing string by argparse or kvargs library. Signed-off-by: Chengwen Feng --- lib/argparse/rte_argparse.c | 19 +++++++++++++++++++ lib/argparse/rte_argparse.h | 19 +++++++++++++++++++ lib/argparse/version.map | 1 + 3 files changed, 39 insertions(+) diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c index 9c5bce6ddf..f536a7f92b 100644 --- a/lib/argparse/rte_argparse.c +++ b/lib/argparse/rte_argparse.c @@ -600,3 +600,22 @@ rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) exit(ret); return ret; } + +int +rte_argparse_parse_type(const char *str, uint64_t val_type, void *val) +{ + uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX); + struct rte_argparse_arg arg = { + .name_long = str, + .name_short = NULL, + .val_saver = val, + .val_set = NULL, + .flags = val_type, + }; + uint32_t value_type = arg_attr_val_type(&arg); + + if (value_type == 0 || value_type >= cmp_max) + return -EINVAL; + + return parse_arg_autosave(&arg, str); +} diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h index 3e94711280..d4e074d3d7 100644 --- a/lib/argparse/rte_argparse.h +++ b/lib/argparse/rte_argparse.h @@ -184,6 +184,25 @@ struct rte_argparse { __rte_experimental int rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv); +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Parse the value from the input string based on the value type. + * + * @param str + * Input string. + * @param val_type + * The value type, @see RTE_ARGPARSE_ARG_VALUE_INT or other type. + * @param val + * Saver for the value. + * + * @return + * 0 on success. Otherwise negative value is returned. + */ +__rte_experimental +int rte_argparse_parse_type(const char *str, uint64_t val_type, void *val); + #ifdef __cplusplus } #endif diff --git a/lib/argparse/version.map b/lib/argparse/version.map index 1c176f69e9..9b68464600 100644 --- a/lib/argparse/version.map +++ b/lib/argparse/version.map @@ -2,6 +2,7 @@ EXPERIMENTAL { global: rte_argparse_parse; + rte_argparse_parse_type; local: *; }; From patchwork Mon Jan 22 03:57:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136025 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 034AB43922; Mon, 22 Jan 2024 05:02:53 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id DC64A42DC7; Mon, 22 Jan 2024 05:02:37 +0100 (CET) Received: from szxga06-in.huawei.com (szxga06-in.huawei.com [45.249.212.32]) by mails.dpdk.org (Postfix) with ESMTP id 6355740685 for ; Mon, 22 Jan 2024 05:02:36 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.214]) by szxga06-in.huawei.com (SkyGuard) with ESMTP id 4TJGks4xqHz1wnBd; Mon, 22 Jan 2024 12:02:13 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id C67371A016F; Mon, 22 Jan 2024 12:02:19 +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; Mon, 22 Jan 2024 12:01:49 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 08/12] test/argparse: add parse type test Date: Mon, 22 Jan 2024 03:57:58 +0000 Message-ID: <20240122035802.31491-9-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 adds parse type test. Signed-off-by: Chengwen Feng --- app/test/test_argparse.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/test/test_argparse.c b/app/test/test_argparse.c index f55b57a21f..98c6cd6b80 100644 --- a/app/test/test_argparse.c +++ b/app/test/test_argparse.c @@ -729,6 +729,27 @@ test_argparse_pos_callback_parse_int(void) return 0; } +static int +test_argparse_parse_type(void) +{ + char *str_erange = test_strdup("9999999999999999999999999999999999"); + char *str_invalid = test_strdup("1a"); + char *str_ok = test_strdup("123"); + int value; + int ret; + + /* test for int parsing */ + ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_INT, &value); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_INT, &value); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_INT, &value); + TEST_ASSERT(ret == 0, "Argparse parse type expect failed!"); + TEST_ASSERT(value == 123, "Argparse parse type expect failed!"); + + return 0; +} + static struct unit_test_suite argparse_test_suite = { .suite_name = "Argparse Unit Test Suite", .setup = test_argparse_setup, @@ -750,6 +771,7 @@ static struct unit_test_suite argparse_test_suite = { 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_CASE(test_argparse_parse_type), TEST_CASES_END() /**< NULL terminate unit test array */ } From patchwork Mon Jan 22 03:57:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136026 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 6733B43922; Mon, 22 Jan 2024 05:02:59 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 361D140A87; Mon, 22 Jan 2024 05:02:53 +0100 (CET) Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) by mails.dpdk.org (Postfix) with ESMTP id 6805540A77 for ; Mon, 22 Jan 2024 05:02:51 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.214]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4TJGjb3ftPz29kc3; Mon, 22 Jan 2024 12:01:07 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id CA90A1A016E; Mon, 22 Jan 2024 12:02:34 +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; Mon, 22 Jan 2024 12:01:49 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 09/12] argparse: support parse unsigned base type Date: Mon, 22 Jan 2024 03:57:59 +0000 Message-ID: <20240122035802.31491-10-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 parsing unsigned base type (u8/u16/u32/u64). Signed-off-by: Chengwen Feng --- lib/argparse/rte_argparse.c | 116 ++++++++++++++++++++++++++++++++++++ lib/argparse/rte_argparse.h | 10 +++- 2 files changed, 125 insertions(+), 1 deletion(-) diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c index f536a7f92b..cfd9bcf5f6 100644 --- a/lib/argparse/rte_argparse.c +++ b/lib/argparse/rte_argparse.c @@ -397,6 +397,118 @@ parse_arg_int(struct rte_argparse_arg *arg, const char *value) return 0; } +static int +parse_arg_u8(struct rte_argparse_arg *arg, const char *value) +{ + unsigned long val; + char *s = NULL; + + if (value == NULL) { + *(uint8_t *)arg->val_saver = (uint8_t)(intptr_t)arg->val_set; + return 0; + } + + errno = 0; + val = strtoul(value, &s, 0); + if (errno == ERANGE || val > UINT8_MAX) { + 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 uint8 value!", arg->name_long); + return -EINVAL; + } + + *(uint8_t *)arg->val_saver = val; + + return 0; +} + +static int +parse_arg_u16(struct rte_argparse_arg *arg, const char *value) +{ + unsigned long val; + char *s = NULL; + + if (value == NULL) { + *(uint16_t *)arg->val_saver = (uint16_t)(intptr_t)arg->val_set; + return 0; + } + + errno = 0; + val = strtoul(value, &s, 0); + if (errno == ERANGE || val > UINT16_MAX) { + 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 uint16 value!", arg->name_long); + return -EINVAL; + } + + *(uint16_t *)arg->val_saver = val; + + return 0; +} + +static int +parse_arg_u32(struct rte_argparse_arg *arg, const char *value) +{ + unsigned long val; + char *s = NULL; + + if (value == NULL) { + *(uint32_t *)arg->val_saver = (uint32_t)(intptr_t)arg->val_set; + return 0; + } + + errno = 0; + val = strtoul(value, &s, 0); + if (errno == ERANGE || val > UINT32_MAX) { + 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 uint32 value!", arg->name_long); + return -EINVAL; + } + + *(uint32_t *)arg->val_saver = val; + + return 0; +} + +static int +parse_arg_u64(struct rte_argparse_arg *arg, const char *value) +{ + unsigned long val; + char *s = NULL; + + if (value == NULL) { + *(uint64_t *)arg->val_saver = (uint64_t)(intptr_t)arg->val_set; + return 0; + } + + errno = 0; + val = strtoull(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 uint64 value!", arg->name_long); + return -EINVAL; + } + + *(uint64_t *)arg->val_saver = val; + + return 0; +} + static int parse_arg_autosave(struct rte_argparse_arg *arg, const char *value) { @@ -406,6 +518,10 @@ parse_arg_autosave(struct rte_argparse_arg *arg, const char *value) /* Sort by RTE_ARGPARSE_ARG_VALUE_XXX. */ { NULL }, { parse_arg_int }, + { parse_arg_u8 }, + { parse_arg_u16 }, + { parse_arg_u32 }, + { parse_arg_u64 }, }; uint32_t index = arg_attr_val_type(arg); int ret = -EINVAL; diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h index d4e074d3d7..2059fe11da 100644 --- a/lib/argparse/rte_argparse.h +++ b/lib/argparse/rte_argparse.h @@ -59,8 +59,16 @@ enum rte_argparse_flag { /** The argument's value is int type. */ RTE_ARGPARSE_ARG_VALUE_INT = RTE_MBIT64(1, 2), + /** The argument's value is uint8 type. */ + RTE_ARGPARSE_ARG_VALUE_U8 = RTE_MBIT64(2, 2), + /** The argument's value is uint16 type. */ + RTE_ARGPARSE_ARG_VALUE_U16 = RTE_MBIT64(3, 2), + /** The argument's value is uint32 type. */ + RTE_ARGPARSE_ARG_VALUE_U32 = RTE_MBIT64(4, 2), + /** The argument's value is uint64 type. */ + RTE_ARGPARSE_ARG_VALUE_U64 = RTE_MBIT64(5, 2), /** Max value type. */ - RTE_ARGPARSE_ARG_VALUE_MAX = RTE_MBIT64(2, 2), + RTE_ARGPARSE_ARG_VALUE_MAX = RTE_MBIT64(6, 2), /** From patchwork Mon Jan 22 03:58:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136027 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 8621B43922; Mon, 22 Jan 2024 05:03:08 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5E30D40A84; Mon, 22 Jan 2024 05:03:08 +0100 (CET) Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) by mails.dpdk.org (Postfix) with ESMTP id E5E0940A80 for ; Mon, 22 Jan 2024 05:03:05 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.214]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4TJGjt3qsYz29kbd; Mon, 22 Jan 2024 12:01:22 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id CE7F61A016C; Mon, 22 Jan 2024 12:02:49 +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; Mon, 22 Jan 2024 12:01:50 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 10/12] test/argparse: add parse unsigned base type test Date: Mon, 22 Jan 2024 03:58:00 +0000 Message-ID: <20240122035802.31491-11-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 adds parsing unsigned base type (u8/u16/u32/u64) test. Signed-off-by: Chengwen Feng --- app/test/test_argparse.c | 59 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/app/test/test_argparse.c b/app/test/test_argparse.c index 98c6cd6b80..470c1bd2b6 100644 --- a/app/test/test_argparse.c +++ b/app/test/test_argparse.c @@ -733,19 +733,68 @@ static int test_argparse_parse_type(void) { char *str_erange = test_strdup("9999999999999999999999999999999999"); + char *str_erange_u32 = test_strdup("4294967296"); + char *str_erange_u16 = test_strdup("65536"); + char *str_erange_u8 = test_strdup("256"); char *str_invalid = test_strdup("1a"); char *str_ok = test_strdup("123"); - int value; + uint16_t val_u16; + uint32_t val_u32; + uint64_t val_u64; + uint8_t val_u8; + int val_int; int ret; /* test for int parsing */ - ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_INT, &value); + ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_INT, &val_int); TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); - ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_INT, &value); + ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_INT, &val_int); TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); - ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_INT, &value); + ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_INT, &val_int); TEST_ASSERT(ret == 0, "Argparse parse type expect failed!"); - TEST_ASSERT(value == 123, "Argparse parse type expect failed!"); + TEST_ASSERT(val_int == 123, "Argparse parse type expect failed!"); + + /* test for u8 parsing */ + ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_erange_u8, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U8, &val_u8); + TEST_ASSERT(ret == 0, "Argparse parse type expect failed!"); + TEST_ASSERT(val_u8 == 123, "Argparse parse type expect failed!"); + + /* test for u16 parsing */ + ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_erange_u16, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U16, &val_u16); + TEST_ASSERT(ret == 0, "Argparse parse type expect failed!"); + TEST_ASSERT(val_u16 == 123, "Argparse parse type expect failed!"); + + /* test for u32 parsing */ + ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_erange_u32, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U32, &val_u32); + TEST_ASSERT(ret == 0, "Argparse parse type expect failed!"); + TEST_ASSERT(val_u32 == 123, "Argparse parse type expect failed!"); + + /* test for u64 parsing */ + ret = rte_argparse_parse_type(str_erange, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_invalid, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64); + TEST_ASSERT(ret != 0, "Argparse parse type expect failed!"); + ret = rte_argparse_parse_type(str_ok, RTE_ARGPARSE_ARG_VALUE_U64, &val_u64); + TEST_ASSERT(ret == 0, "Argparse parse type expect failed!"); + TEST_ASSERT(val_u64 == 123, "Argparse parse type expect failed!"); return 0; } From patchwork Mon Jan 22 03:58:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136028 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 B0E9A43922; Mon, 22 Jan 2024 05:03:22 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 9EF5440A6B; Mon, 22 Jan 2024 05:03:22 +0100 (CET) Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) by mails.dpdk.org (Postfix) with ESMTP id EF395406A2 for ; Mon, 22 Jan 2024 05:03:20 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.214]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4TJGk93v75z29kbG; Mon, 22 Jan 2024 12:01:37 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id D2A491A0175; Mon, 22 Jan 2024 12:03:04 +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; Mon, 22 Jan 2024 12:01:50 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 11/12] argparse: pretty help info Date: Mon, 22 Jan 2024 03:58:01 +0000 Message-ID: <20240122035802.31491-12-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 aligns help info. Take dmafwd as an example, previous: options: -h, --help: show this help message and exit. --mac-updating: Enable MAC addresses updating --no-mac-updating: Disable MAC addresses updating -p, --portmask: hexadecimal bitmask of ports to configure -q, --nb-queue: number of RX queues per port (default is 1) -c, --copy-type: type of copy: sw|hw -s, --ring-size: size of dmadev descriptor ring for hardware copy mode or rte_ring for software copy mode -b, --dma-batch-size: number of requests per DMA batch -f, --max-frame-size: max frame size -m, --force-min-copy-size: force a minimum copy length, even for smaller packets -i, --stats-interval: interval, in seconds, between stats prints (default is 1) Now: options: -h, --help show this help message and exit. --mac-updating Enable MAC addresses updating --no-mac-updating Disable MAC addresses updating -p, --portmask hexadecimal bitmask of ports to configure -q, --nb-queue number of RX queues per port (default is 1) -c, --copy-type type of copy: sw|hw -s, --ring-size size of dmadev descriptor ring for hardware copy mode or rte_ring for software copy mode -b, --dma-batch-size number of requests per DMA batch -f, --max-frame-size max frame size -m, --force-min-copy-size force a minimum copy length, even for smaller packets -i, --stats-interval interval, in seconds, between stats prints (default is 1) Signed-off-by: Chengwen Feng --- lib/argparse/rte_argparse.c | 67 +++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/lib/argparse/rte_argparse.c b/lib/argparse/rte_argparse.c index cfd9bcf5f6..88c418d1f9 100644 --- a/lib/argparse/rte_argparse.c +++ b/lib/argparse/rte_argparse.c @@ -634,8 +634,47 @@ parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help) return 0; } +static uint32_t +calc_help_align(const struct rte_argparse *obj) +{ + const struct rte_argparse_arg *arg; + uint32_t width = 12; /* Default "-h, --help " len. */ + uint32_t len; + uint32_t i; + + for (i = 0; /* NULL */; i++) { + arg = &obj->args[i]; + if (arg->name_long == NULL) + break; + len = strlen(arg->name_long); + if (is_arg_optional(arg) && arg->name_short != NULL) { + len += strlen(", "); + len += strlen(arg->name_short); + } + width = RTE_MAX(width, 1 + len + 2); /* start with 1 & end with 2 space. */ + } + + return width; +} + +static void +show_oneline_help(const struct rte_argparse_arg *arg, uint32_t width) +{ + uint32_t len = 0; + uint32_t i; + + if (arg->name_short != NULL) + len = printf(" %s,", arg->name_short); + len += printf(" %s", arg->name_long); + + for (i = len; i < width; i++) + printf(" "); + + printf("%s\n", arg->help); +} + static void -show_args_pos_help(const struct rte_argparse *obj) +show_args_pos_help(const struct rte_argparse *obj, uint32_t align) { uint32_t position_count = calc_position_count(obj); const struct rte_argparse_arg *arg; @@ -651,43 +690,49 @@ show_args_pos_help(const struct rte_argparse *obj) break; if (!is_arg_positional(arg)) continue; - printf(" %s: %s\n", arg->name_long, arg->help); + show_oneline_help(arg, align); } } static void -show_args_opt_help(const struct rte_argparse *obj) +show_args_opt_help(const struct rte_argparse *obj, uint32_t align) { + static const struct rte_argparse_arg help = { + .name_long = "--help", + .name_short = "-h", + .help = "show this help message and exit.", + }; const struct rte_argparse_arg *arg; uint32_t i; - printf("\noptions:\n" - " -h, --help: show this help message and exit.\n"); + printf("\noptions:\n"); + show_oneline_help(&help, align); 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); + show_oneline_help(arg, align); } } static void show_args_help(const struct rte_argparse *obj) { + uint32_t align = calc_help_align(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); + show_args_pos_help(obj, align); + show_args_opt_help(obj, align); if (obj->epilog != NULL) printf("\n%s\n", obj->epilog); + else + printf("\n"); } int From patchwork Mon Jan 22 03:58:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 136029 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 EB83743922; Mon, 22 Jan 2024 05:03:37 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id D3F9F427E0; Mon, 22 Jan 2024 05:03:37 +0100 (CET) Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) by mails.dpdk.org (Postfix) with ESMTP id 073A0406A2 for ; Mon, 22 Jan 2024 05:03:36 +0100 (CET) Received: from mail.maildlp.com (unknown [172.19.88.214]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4TJGlS6CY1z1xmY7; Mon, 22 Jan 2024 12:02:44 +0800 (CST) Received: from dggpeml500024.china.huawei.com (unknown [7.185.36.10]) by mail.maildlp.com (Postfix) with ESMTPS id D72D91A0174; Mon, 22 Jan 2024 12:03:19 +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; Mon, 22 Jan 2024 12:01:50 +0800 From: Chengwen Feng To: , , , CC: Subject: [PATCH 12/12] examples/dma: replace getopt with argparse Date: Mon, 22 Jan 2024 03:58:02 +0000 Message-ID: <20240122035802.31491-13-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240122035802.31491-1-fengchengwen@huawei.com> References: <20231121122651.7078-1-fengchengwen@huawei.com> <20240122035802.31491-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.165.33] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) 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 Replace getopt with argparse. Signed-off-by: Chengwen Feng --- examples/dma/dmafwd.c | 279 ++++++++++++++++++--------------------- examples/dma/meson.build | 2 +- 2 files changed, 127 insertions(+), 154 deletions(-) diff --git a/examples/dma/dmafwd.c b/examples/dma/dmafwd.c index f27317a622..4cc0913240 100644 --- a/examples/dma/dmafwd.c +++ b/examples/dma/dmafwd.c @@ -4,11 +4,11 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -18,16 +18,18 @@ #define MAX_PKT_BURST 32 #define MEMPOOL_CACHE_SIZE 512 #define MIN_POOL_SIZE 65536U -#define CMD_LINE_OPT_MAC_UPDATING "mac-updating" -#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" -#define CMD_LINE_OPT_PORTMASK "portmask" -#define CMD_LINE_OPT_NB_QUEUE "nb-queue" -#define CMD_LINE_OPT_COPY_TYPE "copy-type" -#define CMD_LINE_OPT_RING_SIZE "ring-size" -#define CMD_LINE_OPT_BATCH_SIZE "dma-batch-size" -#define CMD_LINE_OPT_FRAME_SIZE "max-frame-size" -#define CMD_LINE_OPT_FORCE_COPY_SIZE "force-min-copy-size" -#define CMD_LINE_OPT_STATS_INTERVAL "stats-interval" +#define CMD_LINE_OPT_MAC_UPDATING "--mac-updating" +#define CMD_LINE_OPT_NO_MAC_UPDATING "--no-mac-updating" +#define CMD_LINE_OPT_PORTMASK "--portmask" +#define CMD_LINE_OPT_PORTMASK_INDEX 1 +#define CMD_LINE_OPT_NB_QUEUE "--nb-queue" +#define CMD_LINE_OPT_COPY_TYPE "--copy-type" +#define CMD_LINE_OPT_COPY_TYPE_INDEX 2 +#define CMD_LINE_OPT_RING_SIZE "--ring-size" +#define CMD_LINE_OPT_BATCH_SIZE "--dma-batch-size" +#define CMD_LINE_OPT_FRAME_SIZE "--max-frame-size" +#define CMD_LINE_OPT_FORCE_COPY_SIZE "--force-min-copy-size" +#define CMD_LINE_OPT_STATS_INTERVAL "--stats-interval" /* configurable number of RX/TX ring descriptors */ #define RX_DEFAULT_RINGSIZE 1024 @@ -95,10 +97,10 @@ static copy_mode_t copy_mode = COPY_MODE_DMA_NUM; /* size of descriptor ring for hardware copy mode or * rte_ring for software copy mode */ -static unsigned short ring_size = 2048; +static uint16_t ring_size = 2048; /* interval, in seconds, between stats prints */ -static unsigned short stats_interval = 1; +static uint16_t stats_interval = 1; /* global mbuf arrays for tracking DMA bufs */ #define MBUF_RING_SIZE 2048 #define MBUF_RING_MASK (MBUF_RING_SIZE - 1) @@ -583,26 +585,6 @@ static void start_forwarding_cores(void) } /* >8 End of starting to process for each lcore. */ -/* Display usage */ -static void -dma_usage(const char *prgname) -{ - printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" - " -b --dma-batch-size: number of requests per DMA batch\n" - " -f --max-frame-size: max frame size\n" - " -m --force-min-copy-size: force a minimum copy length, even for smaller packets\n" - " -p --portmask: hexadecimal bitmask of ports to configure\n" - " -q NQ: number of RX queues per port (default is 1)\n" - " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" - " When enabled:\n" - " - The source MAC address is replaced by the TX port MAC address\n" - " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n" - " -c --copy-type CT: type of copy: sw|hw\n" - " -s --ring-size RS: size of dmadev descriptor ring for hardware copy mode or rte_ring for software copy mode\n" - " -i --stats-interval SI: interval, in seconds, between stats prints (default is 1)\n", - prgname); -} - static int dma_parse_portmask(const char *portmask) { @@ -628,142 +610,133 @@ dma_parse_copy_mode(const char *copy_mode) return COPY_MODE_INVALID_NUM; } +static int +dma_parse_args_cb(uint32_t index, const char *value, void *opaque) +{ + int port_mask; + + RTE_SET_USED(opaque); + + if (index == CMD_LINE_OPT_PORTMASK_INDEX) { + port_mask = dma_parse_portmask(value); + if (port_mask & ~dma_enabled_port_mask || port_mask <= 0) { + printf("Invalid portmask, %s, suggest 0x%x\n", + value, dma_enabled_port_mask); + return -1; + } + dma_enabled_port_mask = port_mask; + } else if (index == CMD_LINE_OPT_COPY_TYPE_INDEX) { + copy_mode = dma_parse_copy_mode(value); + if (copy_mode == COPY_MODE_INVALID_NUM) { + printf("Invalid copy type. Use: sw, hw\n"); + return -1; + } + } else { + printf("Invalid index %u\n", index); + return -1; + } + + return 0; +} + /* Parse the argument given in the command line of the application */ static int dma_parse_args(int argc, char **argv, unsigned int nb_ports) { - static const char short_options[] = - "b:" /* dma batch size */ - "c:" /* copy type (sw|hw) */ - "f:" /* max frame size */ - "m:" /* force min copy size */ - "p:" /* portmask */ - "q:" /* number of RX queues per port */ - "s:" /* ring size */ - "i:" /* interval, in seconds, between stats prints */ - ; - - static const struct option lgopts[] = { - {CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1}, - {CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0}, - {CMD_LINE_OPT_PORTMASK, required_argument, NULL, 'p'}, - {CMD_LINE_OPT_NB_QUEUE, required_argument, NULL, 'q'}, - {CMD_LINE_OPT_COPY_TYPE, required_argument, NULL, 'c'}, - {CMD_LINE_OPT_RING_SIZE, required_argument, NULL, 's'}, - {CMD_LINE_OPT_BATCH_SIZE, required_argument, NULL, 'b'}, - {CMD_LINE_OPT_FRAME_SIZE, required_argument, NULL, 'f'}, - {CMD_LINE_OPT_FORCE_COPY_SIZE, required_argument, NULL, 'm'}, - {CMD_LINE_OPT_STATS_INTERVAL, required_argument, NULL, 'i'}, - {NULL, 0, 0, 0} + static struct rte_argparse obj = { + .prog_name = "dma", + .usage = "[EAL options] -- [optional parameters]", + .descriptor = NULL, + .epilog = NULL, + .exit_on_error = false, + .callback = dma_parse_args_cb, + .opaque = NULL, + .args = { + { CMD_LINE_OPT_MAC_UPDATING, NULL, "Enable MAC addresses updating", + &mac_updating, (void *)1, + RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT, + }, + { CMD_LINE_OPT_NO_MAC_UPDATING, NULL, "Disable MAC addresses updating", + &mac_updating, (void *)0, + RTE_ARGPARSE_ARG_NO_VALUE | RTE_ARGPARSE_ARG_VALUE_INT, + }, + { CMD_LINE_OPT_PORTMASK, "-p", "hexadecimal bitmask of ports to configure", + NULL, (void *)CMD_LINE_OPT_PORTMASK_INDEX, + RTE_ARGPARSE_ARG_REQUIRED_VALUE, + }, + { CMD_LINE_OPT_NB_QUEUE, "-q", "number of RX queues per port (default is 1)", + &nb_queues, NULL, + RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_U16, + }, + { CMD_LINE_OPT_COPY_TYPE, "-c", "type of copy: sw|hw", + NULL, (void *)CMD_LINE_OPT_COPY_TYPE_INDEX, + RTE_ARGPARSE_ARG_REQUIRED_VALUE, + }, + { CMD_LINE_OPT_RING_SIZE, "-s", "size of dmadev descriptor ring for hardware copy mode or rte_ring for software copy mode", + &ring_size, NULL, + RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_U16, + }, + { CMD_LINE_OPT_BATCH_SIZE, "-b", "number of requests per DMA batch", + &dma_batch_sz, NULL, + RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_U32, + }, + { CMD_LINE_OPT_FRAME_SIZE, "-f", "max frame size", + &max_frame_size, NULL, + RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_U32, + }, + { CMD_LINE_OPT_FORCE_COPY_SIZE, "-m", "force a minimum copy length, even for smaller packets", + &force_min_copy_size, NULL, + RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_U32, + }, + { CMD_LINE_OPT_STATS_INTERVAL, "-i", "interval, in seconds, between stats prints (default is 1)", + &stats_interval, NULL, + RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_VALUE_U16, + }, + ARGPARSE_ARG_END(), + }, }; const unsigned int default_port_mask = (1 << nb_ports) - 1; - int opt, ret; - char **argvopt; - int option_index; - char *prgname = argv[0]; + int ret; dma_enabled_port_mask = default_port_mask; - argvopt = argv; - - while ((opt = getopt_long(argc, argvopt, short_options, - lgopts, &option_index)) != EOF) { - - switch (opt) { - case 'b': - dma_batch_sz = atoi(optarg); - if (dma_batch_sz > MAX_PKT_BURST) { - printf("Invalid dma batch size, %s.\n", optarg); - dma_usage(prgname); - return -1; - } - break; - case 'f': - max_frame_size = atoi(optarg); - if (max_frame_size > RTE_ETHER_MAX_JUMBO_FRAME_LEN) { - printf("Invalid max frame size, %s.\n", optarg); - dma_usage(prgname); - return -1; - } - break; - - case 'm': - force_min_copy_size = atoi(optarg); - break; - - /* portmask */ - case 'p': - dma_enabled_port_mask = dma_parse_portmask(optarg); - if (dma_enabled_port_mask & ~default_port_mask || - dma_enabled_port_mask <= 0) { - printf("Invalid portmask, %s, suggest 0x%x\n", - optarg, default_port_mask); - dma_usage(prgname); - return -1; - } - break; - - case 'q': - nb_queues = atoi(optarg); - if (nb_queues == 0 || nb_queues > MAX_RX_QUEUES_COUNT) { - printf("Invalid RX queues number %s. Max %u\n", - optarg, MAX_RX_QUEUES_COUNT); - dma_usage(prgname); - return -1; - } - break; - - case 'c': - copy_mode = dma_parse_copy_mode(optarg); - if (copy_mode == COPY_MODE_INVALID_NUM) { - printf("Invalid copy type. Use: sw, hw\n"); - dma_usage(prgname); - return -1; - } - break; + ret = rte_argparse_parse(&obj, argc, argv); + if (ret != 0) + return ret; - case 's': - ring_size = atoi(optarg); - if (ring_size == 0) { - printf("Invalid ring size, %s.\n", optarg); - dma_usage(prgname); - return -1; - } - /* ring_size must be less-than or equal to MBUF_RING_SIZE - * to avoid overwriting bufs - */ - if (ring_size > MBUF_RING_SIZE) { - printf("Max ring_size is %d, setting ring_size to max", - MBUF_RING_SIZE); - ring_size = MBUF_RING_SIZE; - } - break; + /* check argument's value which parsing by autosave. */ + if (dma_batch_sz <= 0 || dma_batch_sz > MAX_PKT_BURST) { + printf("Invalid dma batch size, %d.\n", dma_batch_sz); + return -1; + } - case 'i': - stats_interval = atoi(optarg); - if (stats_interval == 0) { - printf("Invalid stats interval, setting to 1\n"); - stats_interval = 1; /* set to default */ - } - break; + if (max_frame_size <= 0 || max_frame_size > RTE_ETHER_MAX_JUMBO_FRAME_LEN) { + printf("Invalid max frame size, %d.\n", max_frame_size); + return -1; + } - /* long options */ - case 0: - break; + if (nb_queues <= 0 || nb_queues > MAX_RX_QUEUES_COUNT) { + printf("Invalid RX queues number %d. Max %u\n", + nb_queues, MAX_RX_QUEUES_COUNT); + return -1; + } - default: - dma_usage(prgname); - return -1; - } + if (ring_size <= 0) { + printf("Invalid ring size, %d.\n", ring_size); + return -1; + } + if (ring_size > MBUF_RING_SIZE) { + printf("Max ring_size is %d, setting ring_size to max", + MBUF_RING_SIZE); + ring_size = MBUF_RING_SIZE; } - printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled"); - if (optind >= 0) - argv[optind - 1] = prgname; + if (stats_interval <= 0) { + printf("Invalid stats interval, setting to 1\n"); + stats_interval = 1; /* set to default */ + } - ret = optind - 1; - optind = 1; /* reset getopt lib */ - return ret; + return 0; } /* check link status, return true if at least one port is up */ diff --git a/examples/dma/meson.build b/examples/dma/meson.build index 9fdcad660e..124f9476fc 100644 --- a/examples/dma/meson.build +++ b/examples/dma/meson.build @@ -8,7 +8,7 @@ allow_experimental_apis = true -deps += ['dmadev'] +deps += ['argparse', 'dmadev'] sources = files( 'dmafwd.c',