From: Bruce Richardson <bruce.richardson@intel.com>
To: dev@dpdk.org
Cc: Bruce Richardson <bruce.richardson@intel.com>
Subject: [24.03 RFC 3/3] args: add functions to check parameter validity
Date: Thu, 2 Nov 2023 17:28:49 +0000 [thread overview]
Message-ID: <20231102172849.7400-4-bruce.richardson@intel.com> (raw)
In-Reply-To: <20231102172849.7400-1-bruce.richardson@intel.com>
Add in functions which can be used to check for valid arguments for EAL
or for the application. This can be used to separate out mixed arguments.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
lib/args/args.c | 122 +++++++++++++++++++++++++++++++++++++++++++
lib/args/rte_args.h | 56 ++++++++++++++++++++
lib/args/version.map | 3 ++
3 files changed, 181 insertions(+)
diff --git a/lib/args/args.c b/lib/args/args.c
index 80eb6670da..c04faa6323 100644
--- a/lib/args/args.c
+++ b/lib/args/args.c
@@ -22,6 +22,15 @@ struct rte_args {
#define DEFAULT_SIZE_HINT 8
+#define INVALID_ARG '?'
+#define VALID_ARG 'x'
+#define PARAM_ARG ':'
+
+static char *app_shortopts;
+static struct option *app_longopts;
+static char *eal_shortopts;
+static struct option *eal_longopts;
+
struct rte_args *
rte_args_alloc(uint32_t size_hint)
{
@@ -177,3 +186,116 @@ rte_args_eal_init(struct rte_args *a)
return rte_eal_init(argc, argv);
}
+
+static int
+args_register_opts(const char *shortopts, const struct option *longopts,
+ char **sopt_var, struct option **lopt_var)
+{
+ static struct option emptyopt = {0};
+ struct option *lopts = &emptyopt;
+ char *sopts;
+
+ if (shortopts == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ /* for short options, we need to pre-pend ':' for extra argument reporting */
+ if (shortopts[0] != '\0' && shortopts[0] != ':') {
+ size_t len = strlen(shortopts);
+
+ sopts = malloc(len + 2);
+ if (sopts == NULL) {
+ rte_errno = ENOMEM;
+ return -1;
+ }
+ snprintf(sopts, len + 2, ":%s", shortopts);
+ } else
+ sopts = strdup(shortopts);
+
+ /* for long options, we need to ensure we always return a value, not setting a flag */
+ if (longopts != NULL) {
+ int i, n = 0;
+ while (memcmp(&longopts[n], &emptyopt, sizeof(emptyopt)) != 0)
+ n++;
+ lopts = calloc(n + 1, sizeof(emptyopt));
+ if (lopts == NULL) {
+ free(sopts);
+ rte_errno = ENOMEM;
+ return -1;
+ }
+ for (i = 0; i < n; i++) {
+ lopts[i].name = longopts[i].name;
+ lopts[i].has_arg = longopts[i].has_arg;
+ lopts[i].flag = NULL;
+ lopts[i].val = VALID_ARG;
+ }
+ memset(&lopts[i], 0, sizeof(lopts[i]));
+ }
+
+ if (*sopt_var != NULL)
+ free(*sopt_var);
+ if (*lopt_var != NULL)
+ free(*lopt_var);
+
+ *sopt_var = sopts;
+ *lopt_var = lopts;
+ return 0;
+}
+
+int
+rte_args_register_app_opts(const char *shortopts, const struct option *longopts)
+{
+ return args_register_opts(shortopts, longopts, &app_shortopts, &app_longopts);
+}
+
+static int
+args_is_valid_arg(const char *arg, const char *sopts, const struct option *lopts)
+{
+ const int save_optind = optind,
+ save_opterr = opterr,
+ save_optopt = optopt;
+
+ int ret = getopt_long(1, (void *)&arg, sopts, lopts, NULL);
+ switch (ret) {
+ case INVALID_ARG:
+ ret = 0; break;
+ case VALID_ARG:
+ ret = 1; break;
+ case PARAM_ARG:
+ ret = 2; break;
+ default:
+ ret = -1; break;
+ }
+
+ /* restore saved values */
+ optind = save_optind;
+ opterr = save_opterr;
+ optopt = save_optopt;
+ return ret;
+}
+
+int
+rte_args_is_app_arg(const char *arg)
+{
+ if (app_shortopts == NULL || app_longopts == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return args_is_valid_arg(arg, app_shortopts, app_longopts);
+}
+
+int
+rte_args_is_eal_arg(const char *arg)
+{
+ if (eal_shortopts == NULL || eal_longopts == NULL) {
+ const struct option *l;
+ const char *s;
+
+ rte_eal_getopt_params(&s, &l);
+ if (args_register_opts(s, l, &eal_shortopts, &eal_longopts) < 0)
+ return -1;
+ }
+ return args_is_valid_arg(arg, eal_shortopts, eal_longopts);;
+}
diff --git a/lib/args/rte_args.h b/lib/args/rte_args.h
index 3b80b9a39c..7e2ba5348d 100644
--- a/lib/args/rte_args.h
+++ b/lib/args/rte_args.h
@@ -191,6 +191,62 @@ __rte_experimental
int
rte_args_eal_init(struct rte_args *a);
+/**
+ * Register the application arguments to allow testing args for validity
+ *
+ * This function should only be called once per application, and each call
+ * will replace any previouly registered values. This function is not
+ * multi-thread safe and should only be called from one thread at a time.
+ *
+ * @param shortopts
+ * The array of short options, as passed to getopt/getopt_long
+ * @param longopts
+ * The array of longer options, as passed to getopt_long
+ * @return
+ * -1 on error, with rte_errno set appropriately;
+ * 0 otherwise
+ */
+__rte_experimental
+int
+rte_args_register_app_opts(const char *shortopts, const struct option *longopts);
+
+/**
+ * Determine if a given argument is valid or not for the app
+ *
+ * Determine if the passed argument is valid or not, based on previously registered
+ * application arguments. This function uses getopt, and so is not multi-thread safe.
+ *
+ * @param arg
+ * The argument to test
+ * @return
+ * 0 - the argument is not a valid one
+ * 1 - the argument is valid
+ * 2 - the argument is valid, but it takes the next argument as parameter
+ * or -1 on error, with rte_errno set appropriately
+ */
+__rte_experimental
+int
+rte_args_is_app_arg(const char *arg);
+
+
+/**
+ * Determine if a given argument is an EAL argument or not
+ *
+ * Determine if the passed argument is valid or not for EAL initialization.
+ * This function uses getopt, and so is not multi-thread safe.
+
+ * @param arg
+ * The argument to test
+ * @return
+ * 0 - the argument is not a valid one for EAL
+ * 1 - the argument is valid for EAL
+ * 2 - the argument is valid for EAL, but it takes the next argument as parameter
+ * or -1 on error, with rte_errno set appropriately
+ */
+__rte_experimental
+int
+rte_args_is_eal_arg(const char *arg);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/args/version.map b/lib/args/version.map
index 776bd22b82..ef80f0d762 100644
--- a/lib/args/version.map
+++ b/lib/args/version.map
@@ -16,4 +16,7 @@ EXPERIMENTAL {
rte_args_get_argc;
rte_args_get_argv;
rte_args_has_arg;
+ rte_args_is_app_arg;
+ rte_args_is_eal_arg;
+ rte_args_register_app_opts;
};
--
2.39.2
next prev parent reply other threads:[~2023-11-02 17:33 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-02 17:28 [24.03 RFC 0/3] Add argument manipulation library Bruce Richardson
2023-11-02 17:28 ` [24.03 RFC 1/3] args: new library to allow easier manipulation of cmdline args Bruce Richardson
2024-01-24 12:03 ` Thomas Monjalon
2024-01-24 13:57 ` Honnappa Nagarahalli
2023-11-02 17:28 ` [24.03 RFC 2/3] eal: allow export of the cmdline argument parsing options Bruce Richardson
2023-11-02 17:28 ` Bruce Richardson [this message]
2024-01-24 11:53 ` [24.03 RFC 3/3] args: add functions to check parameter validity Thomas Monjalon
2023-11-02 17:50 ` [24.03 RFC 0/3] Add argument manipulation library Stephen Hemminger
2023-11-02 18:12 ` Bruce Richardson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231102172849.7400-4-bruce.richardson@intel.com \
--to=bruce.richardson@intel.com \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).