[PATCH 02/25] parse-options: be able to generate usages automatically

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

 



Signed-off-by: Pierre Habouzit <madcoder@xxxxxxxxxx>
---
 parse-options.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 parse-options.h |   15 ++++++++---
 2 files changed, 79 insertions(+), 9 deletions(-)

diff --git a/parse-options.c b/parse-options.c
index 17a68ff..e0fc25a 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -124,7 +124,7 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
 }
 
 int parse_options(int argc, const char **argv, const struct option *options,
-                  const char *usagestr, int flags)
+                  const char * const usagestr[], int flags)
 {
 	struct optparse_t args = { argv + 1, argc - 1, NULL };
 	int j = 0;
@@ -141,9 +141,9 @@ int parse_options(int argc, const char **argv, const struct option *options,
 			args.opt = arg + 1;
 			do {
 				if (*args.opt == 'h')
-					usage(usagestr);
+					usage_with_options(usagestr, options);
 				if (parse_short_opt(&args, options) < 0)
-					usage(usagestr);
+					usage_with_options(usagestr, options);
 			} while (args.opt);
 			continue;
 		}
@@ -157,12 +157,75 @@ int parse_options(int argc, const char **argv, const struct option *options,
 		}
 
 		if (!strcmp(arg + 2, "help"))
-			usage(usagestr);
+			usage_with_options(usagestr, options);
 		if (parse_long_opt(&args, arg + 2, options))
-			usage(usagestr);
+			usage_with_options(usagestr, options);
 	}
 
 	memmove(argv + j, args.argv, args.argc * sizeof(argv));
 	argv[j + args.argc] = NULL;
 	return j + args.argc;
 }
+
+#define USAGE_OPTS_WIDTH 24
+#define USAGE_GAP         2
+
+void usage_with_options(const char * const *usagestr,
+                        const struct option *opts)
+{
+	struct strbuf sb;
+
+	strbuf_init(&sb, 4096);
+	strbuf_addstr(&sb, *usagestr);
+	strbuf_addch(&sb, '\n');
+	while (*++usagestr)
+		strbuf_addf(&sb, "    %s\n", *usagestr);
+
+	if (opts->type != OPTION_GROUP)
+		strbuf_addch(&sb, '\n');
+
+	for (; opts->type != OPTION_END; opts++) {
+		size_t pos;
+
+		if (opts->type == OPTION_GROUP) {
+			strbuf_addch(&sb, '\n');
+			if (*opts->help)
+				strbuf_addf(&sb, "%s\n", opts->help);
+			continue;
+		}
+
+		pos = sb.len;
+		strbuf_addstr(&sb, "    ");
+		if (opts->short_name)
+			strbuf_addf(&sb, "-%c", opts->short_name);
+		if (opts->long_name && opts->short_name)
+			strbuf_addstr(&sb, ", ");
+		if (opts->long_name)
+			strbuf_addf(&sb, "--%s", opts->long_name);
+
+		switch (opts->type) {
+		case OPTION_INTEGER:
+			strbuf_addstr(&sb, " <n>");
+			break;
+		case OPTION_STRING:
+			if (opts->argh) {
+				strbuf_addf(&sb, " <%s>", opts->argh);
+			} else {
+				strbuf_addstr(&sb, " ...");
+			}
+			break;
+		default:
+			break;
+		}
+
+		if (sb.len - pos <= USAGE_OPTS_WIDTH) {
+			int pad = USAGE_OPTS_WIDTH - (sb.len - pos) + USAGE_GAP;
+			strbuf_addf(&sb, "%*s%s\n", pad, "", opts->help);
+		} else {
+			strbuf_addf(&sb, "\n%*s%s\n",
+			            USAGE_OPTS_WIDTH + USAGE_GAP,
+			            "", opts->help);
+		}
+	}
+	usage(sb.buf);
+}
diff --git a/parse-options.h b/parse-options.h
index 76d73b2..3006a76 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -3,6 +3,7 @@
 
 enum parse_opt_type {
 	OPTION_END,
+	OPTION_GROUP,
 	OPTION_BOOLEAN,
 	OPTION_STRING,
 	OPTION_INTEGER,
@@ -17,12 +18,15 @@ struct option {
 	int short_name;
 	const char *long_name;
 	void *value;
+	const char *argh;
+	const char *help;
 };
 
 #define OPT_END()                   { OPTION_END }
-#define OPT_BOOLEAN(s, l, v, h)     { OPTION_BOOLEAN, (s), (l), (v) }
-#define OPT_INTEGER(s, l, v, h)     { OPTION_INTEGER, (s), (l), (v) }
-#define OPT_STRING(s, l, v, a, h)   { OPTION_STRING,  (s), (l), (v) }
+#define OPT_GROUP(h)                { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
+#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) }
 
 /* parse_options() will filter out the processed options and leave the
  * non-option argments in argv[].
@@ -30,6 +34,9 @@ struct option {
  */
 extern int parse_options(int argc, const char **argv,
                          const struct option *options,
-                         const char *usagestr, int flags);
+                         const char * const usagestr[], int flags);
+
+extern NORETURN void usage_with_options(const char * const *usagestr,
+                                        const struct option *options);
 
 #endif
-- 
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