Skip to content

Commit 237e520

Browse files
rscharfegitster
authored andcommitted
parseopt: check for duplicate long names and numerical options
We already check for duplicate short names. Check for and report duplicate long names and numerical options as well. Perform the slightly expensive string duplicate check only when showing the usage to keep the cost of normal invocations low. t0012-help.sh covers it. Helped-by: Jeff King <peff@peff.net> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent a5f2ff6 commit 237e520

1 file changed

Lines changed: 23 additions & 0 deletions

File tree

parse-options.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "gettext.h"
66
#include "strbuf.h"
77
#include "string-list.h"
8+
#include "strmap.h"
89
#include "utf8.h"
910

1011
static int disallow_abbreviated_options;
@@ -634,6 +635,7 @@ static void check_typos(const char *arg, const struct option *options)
634635
static void parse_options_check(const struct option *opts)
635636
{
636637
char short_opts[128];
638+
bool saw_number_option = false;
637639
void *subcommand_value = NULL;
638640

639641
memset(short_opts, '\0', sizeof(short_opts));
@@ -648,6 +650,11 @@ static void parse_options_check(const struct option *opts)
648650
else if (short_opts[opts->short_name]++)
649651
optbug(opts, "short name already used");
650652
}
653+
if (opts->type == OPTION_NUMBER) {
654+
if (saw_number_option)
655+
optbug(opts, "duplicate numerical option");
656+
saw_number_option = true;
657+
}
651658
if (opts->flags & PARSE_OPT_NODASH &&
652659
((opts->flags & PARSE_OPT_OPTARG) ||
653660
!(opts->flags & PARSE_OPT_NOARG) ||
@@ -707,6 +714,20 @@ static void parse_options_check(const struct option *opts)
707714
BUG_if_bug("invalid 'struct option'");
708715
}
709716

717+
static void parse_options_check_harder(const struct option *opts)
718+
{
719+
struct strset long_names = STRSET_INIT;
720+
721+
for (; opts->type != OPTION_END; opts++) {
722+
if (opts->long_name) {
723+
if (!strset_add(&long_names, opts->long_name))
724+
optbug(opts, "long name already used");
725+
}
726+
}
727+
BUG_if_bug("invalid 'struct option'");
728+
strset_clear(&long_names);
729+
}
730+
710731
static int has_subcommands(const struct option *options)
711732
{
712733
for (; options->type != OPTION_END; options++)
@@ -1324,6 +1345,8 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
13241345
const char *prefix = usage_prefix;
13251346
int saw_empty_line = 0;
13261347

1348+
parse_options_check_harder(opts);
1349+
13271350
if (!usagestr)
13281351
return PARSE_OPT_HELP;
13291352

0 commit comments

Comments
 (0)