git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 3/4] Add OPTION_BASEOFFSET/OPTION_SUBARRAY.

From
Pierre Habouzit <madcoder@debian.org>
Date
Nov 5, 2007, 12:03 UTC
Message-ID
<1194264204-3475-4-git-send-email-madcoder@debian.org>
In-Reply-To
<1194264204-3475-3-git-send-email-madcoder@debian.org>

Currently make the implementation die() if SUBARRAYs are encountered. Refactor the rest of the code to be ready for recursion.

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 parse-options.c |  114 ++++++++++++++++++++++++++++++++++++++-----------------
 parse-options.h |    6 +++
 2 files changed, 85 insertions(+), 35 deletions(-)
diff --git a/parse-options.c b/parse-options.c
index d2e32c1..5cea511 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -8,6 +8,9 @@ struct optparse_t {
 	const char **argv;
 	int argc;
 	const char *opt;
+
+	const struct option *abbrev_option, *conflict_option;
+	int abbrev_flags, conflict_flags;
 };
 
 static inline const char *get_arg(struct optparse_t *p)
@@ -104,23 +107,35 @@ static int get_value(struct optparse_t *p,
 	}
 }
 
-static int parse_short_opt(struct optparse_t *p, const struct option *options)
+static int parse_short_opt(struct optparse_t *p, const struct option *options,
+                           int level)
 {
-	for (; options->type != OPTION_END; options++) {
-		if (options->short_name == *p->opt) {
+	for (;; options++) {
+		switch (options->type) {
+		case OPTION_END:
+			return level > 0 ? -1 : error("unknown switch `%c'", *p->opt);
+		case OPTION_GROUP:
+		case OPTION_BASEOFFSET:
+			continue;
+		case OPTION_SUBARRAY:
+			die("unsupported yet");
+			break;
+		default:
+			if (options->short_name != *p->opt)
+				continue;
 			p->opt = p->opt[1] ? p->opt + 1 : NULL;
 			return get_value(p, options, OPT_SHORT);
 		}
 	}
-	return error("unknown switch `%c'", *p->opt);
 }
 
 static int parse_long_opt(struct optparse_t *p, const char *arg,
-                          const struct option *options)
+                          const struct option *options, int level)
 {
 	const char *arg_end = strchr(arg, '=');
-	const struct option *abbrev_option = NULL, *conflict_option = NULL;
-	int abbrev_flags = 0, conflict_flags = 0;
+
+	if (level == 0)
+		p->conflict_option = p->abbrev_option = NULL;
 
 	if (!arg_end)
 		arg_end = arg + strlen(arg);
@@ -129,6 +144,17 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
 		const char *rest;
 		int flags = 0;
 
+		switch (options->type) {
+		case OPTION_GROUP:
+		case OPTION_BASEOFFSET:
+			continue;
+		case OPTION_SUBARRAY:
+			die("unsupported yet");
+			break;
+		default:
+			break;
+		}
+
 		if (!options->long_name)
 			continue;
 
@@ -138,13 +164,16 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
 
 		rest = skip_prefix(arg, options->long_name);
 		if (!rest) {
+			/* negated and abbreviated very much? */
+			if (!prefixcmp("no-", arg))
+				die("--n,--no,--no- are never proper abbreviated options");
 			/* abbreviated? */
 			if (!strncmp(options->long_name, arg, arg_end - arg)) {
 is_abbreviated:
-				conflict_option = abbrev_option;
-				conflict_flags = abbrev_flags;
-				abbrev_option = options;
-				abbrev_flags = flags;
+				p->conflict_option = p->abbrev_option;
+				p->conflict_flags = p->abbrev_flags;
+				p->abbrev_option = options;
+				p->abbrev_flags = flags;
 				continue;
 			}
 			/* negated? */
@@ -167,16 +196,18 @@ is_abbreviated:
 		}
 		return get_value(p, options, flags);
 	}
-	if (conflict_option)
+	if (level > 0)
+		return -1;
+	if (p->conflict_option)
 		return error("Ambiguous option: %s (could be --%s%s or --%s%s)",
-			arg, (conflict_flags & OPT_UNSET) ?  "no-" : "",
-			conflict_option->long_name,
-			(abbrev_flags & OPT_UNSET) ?  "no-" : "",
-			abbrev_option->long_name);
-	if (abbrev_option) {
-		if (!(abbrev_flags & OPT_UNSET) && *arg_end)
+			arg, (p->conflict_flags & OPT_UNSET) ?  "no-" : "",
+			p->conflict_option->long_name,
+			(p->abbrev_flags & OPT_UNSET) ?  "no-" : "",
+			p->abbrev_option->long_name);
+	if (p->abbrev_option) {
+		if (!(p->abbrev_flags & OPT_UNSET) && *arg_end)
 			p->opt = arg_end + 1;
-		return get_value(p, abbrev_option, abbrev_flags);
+		return get_value(p, p->abbrev_option, p->abbrev_flags);
 	}
 	return error("unknown option `%s'", arg);
 }
@@ -200,7 +231,7 @@ int parse_options(int argc, const char **argv, const struct option *options,
 			do {
 				if (*args.opt == 'h')
 					usage_with_options(usagestr, options);
-				if (parse_short_opt(&args, options) < 0)
+				if (parse_short_opt(&args, options, 0) < 0)
 					usage_with_options(usagestr, options);
 			} while (args.opt);
 			continue;
@@ -216,7 +247,7 @@ int parse_options(int argc, const char **argv, const struct option *options,
 
 		if (!strcmp(arg + 2, "help"))
 			usage_with_options(usagestr, options);
-		if (parse_long_opt(&args, arg + 2, options))
+		if (parse_long_opt(&args, arg + 2, options, 0))
 			usage_with_options(usagestr, options);
 	}
 
@@ -228,27 +259,27 @@ int parse_options(int argc, const char **argv, const struct option *options,
 #define USAGE_OPTS_WIDTH 24
 #define USAGE_GAP         2
 
-void usage_with_options(const char * const *usagestr,
-                        const struct option *opts)
+static void dump_options(const struct option *opts)
 {
-	fprintf(stderr, "usage: %s\n", *usagestr++);
-	while (*usagestr && **usagestr)
-		fprintf(stderr, "   or: %s\n", *usagestr++);
-	while (*usagestr)
-		fprintf(stderr, "    %s\n", *usagestr++);
-
-	if (opts->type != OPTION_GROUP)
-		fputc('\n', stderr);
-
-	for (; opts->type != OPTION_END; opts++) {
+	for (;; opts++) {
 		size_t pos;
 		int pad;
 
-		if (opts->type == OPTION_GROUP) {
+		switch (opts->type) {
+		case OPTION_END:
+			return;
+		case OPTION_GROUP:
 			fputc('\n', stderr);
 			if (*opts->help)
 				fprintf(stderr, "%s\n", opts->help);
 			continue;
+		case OPTION_BASEOFFSET:
+			continue;
+		case OPTION_SUBARRAY:
+			dump_options((struct option *)opts->defval);
+			continue;
+		default:
+			break;
 		}
 
 		pos = fprintf(stderr, "    ");
@@ -295,8 +326,21 @@ void usage_with_options(const char * const *usagestr,
 		}
 		fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
 	}
-	fputc('\n', stderr);
+}
 
+void usage_with_options(const char * const *usagestr,
+                        const struct option *opts)
+{
+	fprintf(stderr, "usage: %s\n", *usagestr++);
+	while (*usagestr && **usagestr)
+		fprintf(stderr, "   or: %s\n", *usagestr++);
+	while (*usagestr)
+		fprintf(stderr, "    %s\n", *usagestr++);
+
+	if (opts->type != OPTION_GROUP)
+		fputc('\n', stderr);
+	dump_options(opts);
+	fputc('\n', stderr);
 	exit(129);
 }
 
diff --git a/parse-options.h b/parse-options.h
index 65bce6e..6668924 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -4,6 +4,8 @@
 enum parse_opt_type {
 	OPTION_END,
 	OPTION_GROUP,
+	OPTION_BASEOFFSET,
+	OPTION_SUBARRAY,
 	OPTION_BOOLEAN,
 	OPTION_STRING,
 	OPTION_INTEGER,
@@ -35,6 +37,7 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
  *
  * `value`::
  *   stores pointers to the values to be filled.
+ *   BASEOFFSET use it to store the offset wrt which the struct was filled.
  *
  * `argh`::
  *   token to explain the kind of argument this option wants. Keep it
@@ -56,6 +59,9 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
  * `defval`::
  *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
  *   CALLBACKS can use it like they want.
+ *   SUBARRAYs use it to store the subarray address.
+ *   BASEOFFSET use it to store the sizeof the struct used to fill the array.
+ *              Any `value` that does not points into it is not relocated.
  */
 struct option {
 	enum parse_opt_type type;
-- 
1.5.3.5.1531.g59008
Previous: Pierre HabouzitNext: Pierre Habouzit
Message 4 of 17 in “proposal for an OPTION_SUBARRAY (recursive parser)”
  1. Pierre HabouzitNov 5, 2007
  2. 1/4 parse-options: abbreviation engine fix.Pierre Habouzit, Nov 5, 2007
  3. 2/4 Some better parse-options documentation.Pierre Habouzit, Nov 5, 2007
  4. 3/4 Add OPTION_BASEOFFSET/OPTION_SUBARRAY.Pierre Habouzit, Nov 5, 2007
  5. 4/4 Implement OPTION_SUBARRAY handling.Pierre Habouzit, Nov 5, 2007
  6. parse-options: abbreviation engine fix.Johannes Schindelin, Nov 5, 2007
  7. Johannes SchindelinNov 5, 2007
  8. 1/3 parse-options: abbreviation engine fix.Johannes Schindelin, Nov 5, 2007
  9. 2/3 parseopt: introduce OPT_RECURSE to specify shared optionsJohannes Schindelin, Nov 5, 2007
  10. Johannes SchindelinNov 5, 2007
  11. Linus TorvaldsNov 5, 2007
  12. Johannes SchindelinNov 5, 2007
  13. Pierre HabouzitNov 5, 2007
  14. Junio C HamanoNov 5, 2007
  15. Pierre HabouzitNov 5, 2007
  16. 3/3 parseopt: do not list options with the same name twiceJohannes Schindelin, Nov 5, 2007
  17. Pierre HabouzitNov 5, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.