[PATCH 07/25] parse-options: make some arguments optional, add callbacks.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



* add the possibility to use callbacks to parse some options, this can
  help implementing new options kinds with great flexibility. struct option
  gains a callback pointer and a `defval' where callbacks user can put
  either integers or pointers. callbacks also can use the `value' pointer
  for anything, preferably to the pointer to the final storage for the value
  though.

* add a `flag' member to struct option to make explicit that this option may
  have an optional argument. The semantics depends on the option type. For
  INTEGERS, it means that if the switch is not used in its
  --long-form=<value> form, and that there is no token after it or that the
  token does not starts with a digit, then it's assumed that the switch has
  no argument. For STRING or CALLBACK it works the same, except that the
  condition is that the next atom starts with a dash. This is needed to
  implement backward compatible behaviour with existing ways to parse the
  command line. Its use for new options is discouraged.

Signed-off-by: Pierre Habouzit <madcoder@xxxxxxxxxx>
---
 parse-options.c |   47 +++++++++++++++++++++++++++++++++++++++++------
 parse-options.h |   16 ++++++++++++++++
 2 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/parse-options.c b/parse-options.c
index 7084dee..f4ba9ce 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -39,7 +39,8 @@ static int opterror(const struct option *opt, const char *reason, int flags)
 static int get_value(struct optparse_t *p,
                      const struct option *opt, int flags)
 {
-	const char *s;
+	const char *s, *arg;
+	arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
 
 	if (p->opt && (flags & OPT_UNSET))
 		return opterror(opt, "takes no value", flags);
@@ -60,18 +61,42 @@ static int get_value(struct optparse_t *p,
 			*(const char **)opt->value = (const char *)NULL;
 			return 0;
 		}
-		if (!p->opt && p->argc <= 1)
+		if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) {
+			*(const char **)opt->value = (const char *)opt->defval;
+			return 0;
+		}
+		if (!arg)
 			return opterror(opt, "requires a value", flags);
 		*(const char **)opt->value = get_arg(p);
 		return 0;
 
+	case OPTION_CALLBACK:
+		if (flags & OPT_UNSET)
+			return (*opt->callback)(opt, NULL, 1);
+		if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-'))
+			return (*opt->callback)(opt, NULL, 0);
+		if (!arg)
+			return opterror(opt, "requires a value", flags);
+		return (*opt->callback)(opt, get_arg(p), 0);
+
 	case OPTION_INTEGER:
 		if (flags & OPT_UNSET) {
 			*(int *)opt->value = 0;
 			return 0;
 		}
-		if (!p->opt && p->argc <= 1)
+		if (opt->flags & PARSE_OPT_OPTARG && (!arg || !isdigit(*arg))) {
+			*(int *)opt->value = opt->defval;
+			return 0;
+		}
+		if (!arg)
 			return opterror(opt, "requires a value", flags);
+#if 0
+		/* can be used to understand -A1B1 like -A1 -B1 */
+		if (flag & OPT_SHORT && opt->opt && isdigit(*opt->opt)) {
+			*(int *)opt->value = strtol(opt->opt, (char **)&opt->opt, 10);
+			return 0;
+		}
+#endif
 		*(int *)opt->value = strtol(get_arg(p), (char **)&s, 10);
 		if (*s)
 			return opterror(opt, "expects a numerical value", flags);
@@ -238,13 +263,23 @@ void usage_with_options(const char * const *usagestr,
 
 		switch (opts->type) {
 		case OPTION_INTEGER:
-			pos += fprintf(stderr, " <n>");
+			if (opts->flags & PARSE_OPT_OPTARG)
+				pos += fprintf(stderr, " [<n>]");
+			else
+				pos += fprintf(stderr, " <n>");
 			break;
 		case OPTION_STRING:
+		case OPTION_CALLBACK:
 			if (opts->argh) {
-				pos += fprintf(stderr, " <%s>", opts->argh);
+				if (opts->flags & PARSE_OPT_OPTARG)
+					pos += fprintf(stderr, " [<%s>]", opts->argh);
+				else
+					pos += fprintf(stderr, " <%s>", opts->argh);
 			} else {
-				pos += fprintf(stderr, " ...");
+				if (opts->flags & PARSE_OPT_OPTARG)
+					pos += fprintf(stderr, " [...]");
+				else
+					pos += fprintf(stderr, " ...");
 			}
 			break;
 		default:
diff --git a/parse-options.h b/parse-options.h
index a0343bd..1f07d33 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -7,12 +7,20 @@ enum parse_opt_type {
 	OPTION_BOOLEAN,
 	OPTION_STRING,
 	OPTION_INTEGER,
+	OPTION_CALLBACK,
 };
 
 enum parse_opt_flags {
 	PARSE_OPT_KEEP_DASHDASH = 1,
 };
 
+enum parse_opt_option_flags {
+	PARSE_OPT_OPTARG  = 1,
+};
+
+struct option;
+typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
+
 struct option {
 	enum parse_opt_type type;
 	int short_name;
@@ -20,6 +28,12 @@ struct option {
 	void *value;
 	const char *argh;
 	const char *help;
+
+	int flags;
+	parse_opt_cb *callback;
+	/* holds default value for PARSE_OPT_OPTARG,
+	   though callbacks can use it like they want */
+	intptr_t defval;
 };
 
 #define OPT_END()                   { OPTION_END }
@@ -27,6 +41,8 @@ struct option {
 #define OPT_BOOLEAN(s, l, v, h)     { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
 #define OPT_INTEGER(s, l, v, h)     { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
 #define OPT_STRING(s, l, v, a, h)   { OPTION_STRING,  (s), (l), (v), (a), (h) }
+#define OPT_CALLBACK(s, l, v, a, h, f) \
+	{ OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
 
 /* parse_options() will filter out the processed options and leave the
  * non-option argments in argv[].
-- 
1.5.3.4.1231.g62b9a

-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux