@@ -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,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".
@@ -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,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 <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_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 */
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',