[24.03 RFC] argparse: add argparse library
Chengwen Feng
fengchengwen at huawei.com
Tue Nov 21 13:26:51 CET 2023
Introduce argparse library (which was inspired by the thread [1]),
compared with getopt, the argparse has following advantages:
1) Set the help information when defining parameters.
2) Support positional parameters.
The parameters parsing according following:
1) positional: use callback to parse (passed the long-name as the key
for callback).
2) optional:
In addition to callback to parse, but also support:
2.1) no-val: support set default value to saver.
2.2) has-val: support set value to saver, the value must be conform
RTE_ARGPARSE_ARG_VAL_xxx.
2.3) opt-val: if current without value then treat as no-val, else could
treat as has-val.
Examples: (take dmafwd as example):
1) If parse with callback:
static int
func(const char *key, const char *value, const char *opaque)
{
if (!strcmp("--mac-updating", key)) {
mac_updating = 1;
} else if (!strcmp("--no-mac-updating", key)) {
mac_updating = 0;
} else if (!strcmp("--portmask", key)) {
dma_enabled_port_mask = dma_parse_portmask(optarg);
if (dma_enabled_port_mask & ~default_port_mask ||
dma_enabled_port_mask <= 0) {
...
}
} else {
...
}
}
static int
dma_parse_args(int argc, char **argv, unsigned int nb_ports)
{
static struct rte_argparse opts[] = {
.prog = "dma",
.usage = NULL,
.descriptor = "dma and nic fwd example",
.epilog = NULL,
.exit_on_error = true,
.opt = {
{ "--mac-updating", NULL, "Enable MAC addresses updating", func, 0, NULL, NULL, RTE_ARGPARSE_ARG_NO_VAL },
{ "--no-mac-updating", NULL, "disable MAC addresses updating", func, 0, NULL, NULL, RTE_ARGPARSE_ARG_NO_VAL },
{ "--portmask", "-p", "hexadecimal bitmask of ports to configure", func, 0, NULL, NULL, RTE_ARGPARSE_ARG_HAS_VAL },
{ NULL, NULL, NULL, NULL, 0, NULL, NULL, 0}
}
};
return rte_argparse_parse(opts, argc, argv);
}
2) If parse with value:
static int
dma_parse_args(int argc, char **argv, unsigned int nb_ports)
{
static struct rte_argparse opts[] = {
.prog = "dma",
.usage = NULL,
.descriptor = "dma and nic fwd example",
.epilog = NULL,
.exit_on_error = true,
.opt = {
{ "--mac-updating", NULL, "Enable MAC addresses updating", NULL, 0, &mac_updating, (void *)1, RTE_ARGPARSE_ARG_NO_VAL },
{ "--no-mac-updating", NULL, "disable MAC addresses updating", NULL, 0, &mac_updating, (void *)0, RTE_ARGPARSE_ARG_NO_VAL },
{ "--portmask", "-p", "hexadecimal bitmask of ports to configure", NULL, 0, &dma_enabled_port_mask, NULL, RTE_ARGPARSE_ARG_HAS_VAL },
{ NULL, NULL, NULL, NULL, 0, NULL, NULL, 0}
}
};
int ret;
ret = rte_argparse_parse(opts, argc, argv);
if (ret != 0)
return ret;
if (dma_enabled_port_mask & ~default_port_mask ||
dma_enabled_port_mask <= 0) {
...
}
}
3) Also could mix parse with func and with value.
[1] https://patchwork.dpdk.org/project/dpdk/patch/20231105054539.22303-2-fengchengwen@huawei.com/
Signed-off-by: Chengwen Feng <fengchengwen at huawei.com>
---
lib/argparse/meson.build | 6 ++
lib/argparse/rte_argparse.h | 139 ++++++++++++++++++++++++++++++++++++
lib/argparse/version.map | 7 ++
lib/meson.build | 1 +
4 files changed, 153 insertions(+)
create mode 100644 lib/argparse/meson.build
create mode 100644 lib/argparse/rte_argparse.h
create mode 100644 lib/argparse/version.map
diff --git a/lib/argparse/meson.build b/lib/argparse/meson.build
new file mode 100644
index 0000000000..ac4a883b8d
--- /dev/null
+++ b/lib/argparse/meson.build
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2023 HiSilicon Limited.
+
+headers = files('rte_argparse.h')
+
+deps += ['kvargs']
diff --git a/lib/argparse/rte_argparse.h b/lib/argparse/rte_argparse.h
new file mode 100644
index 0000000000..21157a9436
--- /dev/null
+++ b/lib/argparse/rte_argparse.h
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 HiSilicon Limited
+ */
+
+#ifndef RTE_ARGPARSE_H
+#define RTE_ARGPARSE_H
+
+/**
+ * @file rte_argparse.h
+ *
+ * This API provides argparse function.
+ *
+ * Compare with getopt, the argparse has following advantages:
+ * 1) Set the help information when defining parameters.
+ * 2) Support positional parameters.
+ *
+ * The parameters parsing according following:
+ * 1) positional: use callback to parse (passed the long-name as the key for
+ * callback).
+ * 2) optional:
+ * In addition to callback to parse, but also support:
+ * 2.1) no-val: support set default value to saver.
+ * 2.2) has-val: support set value to saver, the value must be conform
+ * RTE_ARGPARSE_ARG_VAL_xxx.
+ * 2.3) opt-val: if current without value then treat as no-val, else could
+ * treat as has-val.
+ *
+ */
+
+#include <stdint.h>
+
+#include <rte_kvargs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum rte_argparse_arg_flags {
+ /**
+ * Bit0-1 represent whether has value
+ */
+ RTE_ARGPARSE_ARG_NO_VAL = 1u << 0, /**< The arg has no value. */
+ RTE_ARGPARSE_ARG_HAS_VAL = 2u << 0, /**< The arg has value. */
+ RTE_ARGPARSE_ARG_OPT_VAL = 3u << 0, /**< The arg has optional value. */
+
+ /**
+ * Bit2-4 represent the value type
+ */
+ RTE_ARGPARSE_ARG_VAL_INT = 1u << 2, /**< The arg's value is int type. */
+ RTE_ARGPARSE_ARG_VAL_FLOAT = 2u << 2, /**< The arg's value is float type. */
+ RTE_ARGPARSE_ARG_VAL_BOOL = 3u << 2, /**< The arg's value is bool type. */
+ RTE_ARGPARSE_ARG_VAL_STRING = 4u << 2, /**< The arg's value is string type. */
+};
+
+/**
+ * A structure used to hold opt config.
+ */
+struct rte_argparse_arg {
+ /**
+ * The long name of arg:
+ * 1) If the arg is optional, it must start with '--',
+ * 2) If it is a positional arg, it must not start with '-'.
+ * Note: only one '-' will treat as error.
+ */
+ const char *long_name;
+ /**
+ * The short name of arg:
+ * 1) This field could be set only if long_name is optional, and must
+ * start with only one '-' and one letter,
+ * 2) Other case it should be set NULL.
+ */
+ const char *short_name;
+ /** The help info of arg. */
+ const char *help;
+
+ /*
+ * Parse the arg's callback, it will be used to parse the arg if
+ * it is not NULL.
+ */
+ arg_handler_t callback;
+ /** The opaque which used to invoke callback */
+ void *opaque;
+
+ /*
+ * The saver for the arg. If not NULL, set value to default_val or
+ * parse from input.
+ * Note: the flags of the arg must be RTE_ARGPARSE_VAL_* if this value
+ * is not NULL.
+ */
+ void *saver;
+ /*
+ * Default value for the arg, cover following case:
+ * 1) The arg don't require value, the saver will set to default_val
+ * when option found.
+ * 2) The arg has option value but don't take value this time, the
+ * saver will set to default_val when option found.
+ */
+ void *default_val;
+
+ /** @see rte_argparse_arg_flags. */
+ uint32_t flags;
+};
+
+/**
+ * A structure used to hold argparse basic info.
+ */
+struct rte_argparse {
+ const char *prog; /**< Program name */
+ const char *usage; /**< How to use the program */
+ const char *descriptor; /**< Explain what the program does */
+ const char *epilog; /**< Text at the bottom of help */
+ bool exit_on_error; /**< Whether exit when error */
+ struct rte_argparse_arg opt[]; /**< */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Parse parameters
+ *
+ * @param self
+ * Parser handler.
+ * @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 *self, 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..36b0902167
--- /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',
--
2.17.1
More information about the dev
mailing list