All of lore.kernel.org
 help / color / mirror / Atom feed
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


  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.