[PATCH 3/3] parseopt: do not list options with the same name twice

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

 



The option parser will take the first exact match, and happily ignore
it when a later option has the same name.  For example, when you have
something like

	OPT_BOOLEAN('i', NULL, &troz, "blah"),
	OPT_BOOLEAN('i', NULL, &brain, "blub"),

in your options array, a command line "prog -i" will increment the
variable "troz", and leave the variable "brain" alone.

This behavior is all good and well, especially since we plan to
have recursive options, e.g. for the diff options, and in some cases
options should be overridden (see for example format-patch's "-n").

This patch matches the usage to this behavior: whenever an option name
was overridden by another option, it is no longer shown.  In the
example above, that means that the usage would only show

    -i    blah

and not print anything about "blub".

Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx>
---

	Okay, my plan was borked: the options struct is passed as a
	const.  So this is plan B.

 parse-options.c      |   37 ++++++++++++++++++++++++++-----------
 test-parse-options.c |    2 ++
 2 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/parse-options.c b/parse-options.c
index ed8e951..83a221b 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -1,5 +1,6 @@
 #include "git-compat-util.h"
 #include "parse-options.h"
+#include "path-list.h"
 
 #define OPT_SHORT 1
 #define OPT_UNSET 2
@@ -261,15 +262,18 @@ int parse_options(int argc, const char **argv, const struct option *options,
 #define USAGE_OPTS_WIDTH 24
 #define USAGE_GAP         2
 
-static void usage_show_options(const struct option *opts)
+static void usage_show_options(const struct option *opts,
+		char *seen_short_names, struct path_list *seen_long_names)
 {
 	for (; opts->type != OPTION_END; opts++) {
-		size_t pos;
+		const char *before_option = "    ";
+		size_t pos = 0;
 		int pad;
 
 		if (opts->type == OPTION_RECURSE) {
 			const struct option *sub = opts->value;
-			usage_show_options(sub);
+			usage_show_options(sub,
+					seen_short_names, seen_long_names);
 			continue;
 		}
 
@@ -280,13 +284,19 @@ static void usage_show_options(const struct option *opts)
 			continue;
 		}
 
-		pos = fprintf(stderr, "    ");
-		if (opts->short_name)
-			pos += fprintf(stderr, "-%c", opts->short_name);
-		if (opts->long_name && opts->short_name)
-			pos += fprintf(stderr, ", ");
-		if (opts->long_name)
-			pos += fprintf(stderr, "--%s", opts->long_name);
+		if (opts->short_name && !seen_short_names[opts->short_name]) {
+			pos += fprintf(stderr, "%s-%c",
+					before_option, opts->short_name);
+			seen_short_names[opts->short_name] = 1;
+			before_option = ", ";
+		}
+		if (opts->long_name && !path_list_has_path(seen_long_names,
+					opts->long_name)) {
+			pos += fprintf(stderr, "%s--%s",
+					before_option, opts->long_name);
+			path_list_insert(opts->long_name, seen_long_names);
+		} else if (*before_option != ',')
+			continue;
 
 		switch (opts->type) {
 		case OPTION_INTEGER:
@@ -329,6 +339,9 @@ static void usage_show_options(const struct option *opts)
 void usage_with_options(const char * const *usagestr,
                         const struct option *opts)
 {
+	char seen_short_names[256];
+	struct path_list seen_long_names = { NULL, 0, 0, 0 };
+
 	fprintf(stderr, "usage: %s\n", *usagestr++);
 	while (*usagestr && **usagestr)
 		fprintf(stderr, "   or: %s\n", *usagestr++);
@@ -338,7 +351,9 @@ void usage_with_options(const char * const *usagestr,
 	if (opts->type != OPTION_GROUP)
 		fputc('\n', stderr);
 
-	usage_show_options(opts);
+	memset(seen_short_names, 0, sizeof(seen_short_names));
+	usage_show_options(opts, seen_short_names, &seen_long_names);
+	path_list_clear(&seen_long_names, 0);
 
 	fputc('\n', stderr);
 
diff --git a/test-parse-options.c b/test-parse-options.c
index ee64fb3..56f6f24 100644
--- a/test-parse-options.c
+++ b/test-parse-options.c
@@ -16,6 +16,7 @@ int main(int argc, const char **argv)
 	struct option sub[] = {
 		OPT_BOOLEAN('n', "narf", &narf, "what are we doing tonight?"),
 		OPT_INTEGER('z', "zort", &zort, "try to take over the world"),
+		OPT_INTEGER('j', NULL, &boolean, "ignored option"),
 		OPT_END(),
 	};
 	struct option options[] = {
@@ -27,6 +28,7 @@ int main(int argc, const char **argv)
 		OPT_STRING('s', "string", &string, "string", "get a string"),
 		OPT_STRING(0, "string2", &string, "str", "get another string"),
 		OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"),
+		OPT_INTEGER(0, "string", &boolean, "ignored option"),
 		OPT_END(),
 	};
 	int i;
-- 
1.5.3.5.1549.g91a3


-
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