diff mbox

[PATCHv7,01/35] helpers: adding command line argument parsing

Message ID 1463490282-23277-2-git-send-email-christophe.milard@linaro.org
State Superseded
Headers show

Commit Message

Christophe Milard May 17, 2016, 1:04 p.m. UTC
A function (odph_merge_getopt_options()) to merge command line arguments
is added. This function can be called by intermediate clients
(e.g c_unit_common) before calling odph_parse_options().
The new function, odph_parse_options() is also added
to parse options meant for the helpers out of a the command line. This
parse function picks up options altering the behaviour of the helpers out
of the command line, and also checks for unknown options (i.e. options not
belonging to the caller set of options or to the helpers.)
No helper options are definied (yet).

Signed-off-by: Christophe Milard <christophe.milard@linaro.org>
---
 helper/include/odp/helper/linux.h |  71 ++++++++++++++++++++++
 helper/linux.c                    | 123 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 194 insertions(+)
diff mbox

Patch

diff --git a/helper/include/odp/helper/linux.h b/helper/include/odp/helper/linux.h
index e2dca35..d47abef 100644
--- a/helper/include/odp/helper/linux.h
+++ b/helper/include/odp/helper/linux.h
@@ -25,6 +25,7 @@  extern "C" {
 #include <odp_api.h>
 
 #include <pthread.h>
+#include <getopt.h>
 #include <sys/types.h>
 
 /** @addtogroup odph_linux ODPH LINUX
@@ -134,6 +135,76 @@  int odph_linux_process_fork_n(odph_linux_process_t *proc_tbl,
 int odph_linux_process_wait_n(odph_linux_process_t *proc_tbl, int num);
 
 /**
+ * Merge getopt options
+ *
+ * Given two sets of getopt options (each containing possibly both short
+ * options -a string- and long options -a option array-) this function
+ * return a single set (i.e. a string for short and an array for long)
+ * being the concatenation of the two given sets.
+ * Due to the fact that the size of these arrays is unknown at compilation
+ * time, this function actually mallocs the the resulting arrays.
+ * The fourth and fith parameters are actually pointers where these malloc'ed
+ * areas are returned.
+ * This means that the caller of this function has to free the two returned
+ * areas!
+ *
+ * @param shortopts1 first set of short options (a string)
+ * @param shortopts2 second set of short options (a string)
+ * @param longopts1  first set of long options (a getopt option array)
+ * @param longopts2  second set of long options (a getopt option array)
+ * @param shortopts  a pointer where the address of the short options list
+ *		     (a string) is returned. It contains the concatenation of
+ *		     the two given short option strings.
+ * @param longopts   a pointer where the address of the long options list
+ *		     (a getopt option array) is returned.
+ *		     It contains the concatenation of the two given long
+ *		     option arrays.
+ * if any of shortopts1, shortopts2, longopts1, longopts2 is NULL, the
+ * corresponding list as assumed to be empty.
+ * if any of shortopts, longopts is NULL, the corresponding malloc is not
+ * performed.
+ *
+ * @return On success: 0 : both shortopts and longopts are returned (assuming
+ *			   the given pointer where not null), possibly
+ *			   pointing to an empty string or an empty option array.
+ *			   On success, the caller is due to free these areas.
+ *	   On failure: -1: Nothing is malloc'ed.
+ */
+int odph_merge_getopt_options(const char *shortopts1,
+			      const char *shortopts2,
+			      const struct option *longopts1,
+			      const struct option *longopts2,
+			      char **shortopts,
+			      struct option **longopts);
+
+/**
+ * Parse linux helper options
+ *
+ * Parse the command line options. Pick up options meant for the helper itself.
+ * If the caller is also having a set of option to parse, it should include
+ * their description here (shortopts desribes the short options and longopts
+ * describes the long options, as for getopt_long()).
+ * This function will issue errors on unknown arguments, so callers failing
+ * to pass their own command line options description here will see their
+ * options rejected.
+ * (the caller wants to set opterr to zero when parsing its own stuff
+ * with getopts to avoid reacting on helper's options).
+ *
+ * @param argc argument count
+ * @param argv argument values
+ * @param caller_shortopts caller's set of short options (string). or NULL.
+ * @param caller_longopts  caller's set of long options (getopt option array).
+ *			   or NULL.
+ *
+ * @return On success: 0
+ *	   On failure: -1 failure occurs if a value passed for a helper
+ *			  option is invalid, or on meeting unknown options.
+ */
+int odph_parse_options(int argc, char *argv[],
+		       const char *caller_shortopts,
+		       const struct option *caller_longopts);
+
+/**
  * @}
  */
 
diff --git a/helper/linux.c b/helper/linux.c
index 24e243b..ef435bd 100644
--- a/helper/linux.c
+++ b/helper/linux.c
@@ -236,3 +236,126 @@  int odph_linux_process_wait_n(odph_linux_process_t *proc_tbl, int num)
 
 	return 0;
 }
+
+/*
+ * return the number of elements in an array of getopt options, excluding the
+ * terminating {0,0,0,0}
+ */
+static int get_getopt_options_length(const struct option *longopts)
+{
+	int l = 0;
+
+	if (!longopts)
+		return 0;
+
+	while (longopts[l].name)
+		l++;
+
+	return l;
+}
+
+/* Merge getopt options */
+int odph_merge_getopt_options(const char *shortopts1,
+			      const char *shortopts2,
+			      const struct option *longopts1,
+			      const struct option *longopts2,
+			      char **shortopts,
+			      struct option **longopts)
+{
+	int shortopts1_len;
+	int shortopts2_len;
+	int longopts1_len;
+	int longopts2_len;
+	int index;
+	int res_index = 0;
+	struct option termination = {0, 0, 0, 0};
+
+	/* merge short options: */
+	if (shortopts) {
+		shortopts1_len = (shortopts1) ? strlen(shortopts1) : 0;
+		shortopts2_len = (shortopts2) ? strlen(shortopts2) : 0;
+		*shortopts = malloc(shortopts1_len + shortopts2_len + 1);
+		if (!*shortopts)
+			return -1;
+
+		(*shortopts)[0] = 0;
+
+		if (shortopts1)
+			strcpy((*shortopts), shortopts1);
+		if (shortopts2)
+			strcat((*shortopts), shortopts2);
+	}
+
+	/* merge long options */
+	if (!longopts)
+		return 0;
+
+	longopts1_len = get_getopt_options_length(longopts1);
+	longopts2_len = get_getopt_options_length(longopts2);
+	*longopts = malloc(sizeof(struct option) *
+					(longopts1_len + longopts2_len + 1));
+	if (!*longopts) {
+		if (shortopts)
+			free(*shortopts);
+		return -1;
+	}
+
+	for (index = 0; (longopts1) && (longopts1[index].name); index++)
+		(*longopts)[res_index++] = longopts1[index];
+
+	for (index = 0; (longopts2) && (longopts2[index].name); index++)
+		(*longopts)[res_index++] = longopts2[index];
+
+	(*longopts)[res_index] = termination;
+
+	return 0;
+}
+
+/*
+ * Parse command line options to extract options affecting helpers.
+ */
+int odph_parse_options(int argc, char *argv[],
+		       const char *caller_shortopts,
+		       const struct option *caller_longopts)
+{
+	int c;
+	char *shortopts;
+	struct option *longopts;
+	int res = 0;
+
+	static struct option helper_long_options[] = {
+		/* These options set a flag. */
+		{0, 0, 0, 0}
+		};
+
+	static char *helper_short_options = "";
+
+	/* merge caller's command line options descriptions with helper's: */
+	if (odph_merge_getopt_options(caller_shortopts, helper_short_options,
+				      caller_longopts, helper_long_options,
+				      &shortopts, &longopts) < 0)
+		return -1;
+
+	while (1) {
+		/* getopt_long stores the option index here. */
+		int option_index = 0;
+
+		c = getopt_long (argc, argv,
+				 shortopts, longopts, &option_index);
+
+		/* Detect the end of the options. */
+		if (c == -1)
+			break;
+
+		/* check for unknown options or missing arguments */
+		if (c == '?' || c == ':')
+			res = -1;
+	}
+
+	optind = 0; /* caller expects this to be zero if it parses too*/
+
+	free(shortopts);
+	free(longopts);
+
+	return res;
+}