@@ -1650,6 +1650,10 @@ F: doc/guides/sample_app_ug/qos_metering.rst
Other libraries
---------------
+Argument parsing
+M: Chengwen Feng <fengchengwen@huawei.com>
+F: lib/argparse/
+
Configuration file
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
F: lib/cfgfile/
@@ -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)
@@ -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 \
new file mode 100644
@@ -0,0 +1,185 @@
+.. 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 ways: 1) autosave: used for parsing known value
+ types; 2) callback: will invoke user callback to parse.
+
+Usage Guide
+-----------
+
+The following code demonstrates how to use:
+
+.. code-block:: C
+
+ static int
+ argparse_user_callback(uint32_t index, const char *value, void *opaque)
+ {
+ if (index == 1) {
+ /* process "--ddd" argument, because it is configured as no-value,
+ * the parameter 'value' is NULL.
+ */
+ ...
+ } else if (index == 2) {
+ /* process "--eee" argument, because it is configured as
+ * required-value, the parameter 'value' must not be NULL.
+ */
+ ...
+ } else if (index == 3) {
+ /* process "--fff" argument, because it is configured as
+ * 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 be NULL.
+ */
+ ...
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ static 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);
+ ...
+ }
+
+In this example, the arguments which start with a hyphen (-) are optional
+arguments (they're "--aaa"/"--bbb"/"--ccc"/"--ddd"/"--eee"/"--fff"); and the
+arguments which don't start with a hyper (-) are positional arguments (they're
+"ooo"/"ppp").
+
+Every argument must be set whether to carry a value (one of
+``RTE_ARGPARSE_ARG_NO_VALUE``, ``RTE_ARGPARSE_ARG_REQUIRED_VALUE`` and
+``RTE_ARGPARSE_ARG_OPTIONAL_VALUE``).
+
+.. note::
+
+ Positional argument much be set ``RTE_ARGPARSE_ARG_REQUIRED_VALUE``.
+
+User Input Requirements
+~~~~~~~~~~~~~~~~~~~~~~~
+
+For optional arguments which take no-value, the following mode is supported
+(take above "--aaa" as an example):
+
+- The single mode: "--aaa" or "-a".
+
+For optional arguments which take required-value, the following two modes are
+supported (take above "--bbb" as an example):
+
+- The kv mode: "--bbb=1234" or "-b=1234".
+
+- The split mode: "--bbb 1234" or "-b 1234".
+
+For optional arguments which take optional-value, the following two modes are
+supported (take above "--ccc" as an example):
+
+- The single mode: "--ccc" or "-c".
+
+- The kv mode: "--ccc=123" or "-c=123".
+
+For positional arguments which must take required-value, their values are
+parsing in the order defined.
+
+.. note::
+
+ The compact mode is not supported. Take above "-a" and "-d" as an example,
+ don't support "-ad" input.
+
+Parsing by autosave way
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Argument of known value type (e.g. ``RTE_ARGPARSE_ARG_VALUE_INT``) could be
+parsed using this autosave way, and its result will save in the ``val_saver``
+field.
+
+In the above example, the arguments "--aaa"/"--bbb"/"--ccc" and "ooo" both use
+this way, the parsing is as follows:
+
+- For argument "--aaa", it is configured as no-value, so the ``aaa_val`` will
+ be set to ``val_set`` field which is 100 in the above example.
+
+- For argument "--bbb", it is configured as required-value, so the ``bbb_val``
+ will be set to user input's value (e.g. will be set to 1234 with input
+ "--bbb 1234").
+
+- For argument "--ccc", it is configured as optional-value, if user only input
+ "--ccc" then the ``ccc_val`` will be set to ``val_set`` field which is 200 in
+ the above example; if user input "--ccc=123", then the ``ccc_val`` will be set
+ to 123.
+
+- For argument "ooo", it is positional argument, the ``ooo_val`` will be set
+ to user input's value.
+
+Parsing by callback way
+~~~~~~~~~~~~~~~~~~~~~~~
+
+It could also choose to use callback to parse, just define a unique index for
+the argument and make the ``val_save`` field to be NULL also zero value-type.
+
+In the above example, the arguments "--ddd"/"--eee"/"--fff" and "ppp" both use
+this way.
+
+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 the ``flags`` field. For
+example:
+
+.. code-block:: C
+
+ ...
+ { "--xyz", "-x", "xyz argument", NULL, (void *)10, RTE_ARGPARSE_ARG_REQUIRED_VALUE | RTE_ARGPARSE_ARG_SUPPORT_MULTI },
+ ...
+
+Then the user input could contain multiple "--xyz" arguments.
+
+.. note::
+
+ The multiple times argument only support with optional argument and must be
+ parsed by callback way.
@@ -13,6 +13,7 @@ Programmer's Guide
source_org
env_abstraction_layer
log_lib
+ argparse_lib
cmdline
service_cores
trace_lib
@@ -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
-------------
new file mode 100644
@@ -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']
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -0,0 +1,190 @@
+/* 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 <stdbool.h>
+#include <stdint.h>
+
+#include <rte_bitops.h>
+#include <rte_compat.h>
+
+#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_SHIFT_VAL64(1, 0),
+ /** The argument must have a value. */
+ RTE_ARGPARSE_ARG_REQUIRED_VALUE = RTE_SHIFT_VAL64(2, 0),
+ /** The argument has optional value. */
+ RTE_ARGPARSE_ARG_OPTIONAL_VALUE = RTE_SHIFT_VAL64(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_SHIFT_VAL64(1, 2),
+ /** Max value type. */
+ RTE_ARGPARSE_ARG_VALUE_MAX = RTE_SHIFT_VAL64(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 be set to val_set.
+ * 2) If argument has optional value but doesn't take value this
+ * time, *val_saver will be set to val_set.
+ * 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 field.
+ * @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 */
new file mode 100644
@@ -0,0 +1,7 @@
+EXPERIMENTAL {
+ global:
+
+ rte_argparse_parse;
+
+ local: *;
+};
@@ -11,6 +11,7 @@
libraries = [
'log',
'kvargs', # eal depends on kvargs
+ 'argparse',
'telemetry', # basic info querying
'eal', # everything depends on eal
'ring',