From 7f275b91520d31bfbe43ec5a9bbaf8ac6e663ce0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 14 Oct 2007 17:54:06 +0100 Subject: [PATCH] parse-options: Allow abbreviated options when unambiguous When there is an option "--amend", the option parser now recognizes "--am" for that option, provided that there is no other option beginning with "--am". Signed-off-by: Johannes Schindelin Signed-off-by: Shawn O. Pearce --- parse-options.c | 37 +++++++++++++++++++++++++++++++++++++ t/t0040-parse-options.sh | 23 +++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/parse-options.c b/parse-options.c index 12a9f9ea6..b4a3b63e9 100644 --- a/parse-options.c +++ b/parse-options.c @@ -113,6 +113,13 @@ static int parse_short_opt(struct optparse_t *p, const struct option *options) static int parse_long_opt(struct optparse_t *p, const char *arg, const struct option *options) { + const char *arg_end = strchr(arg, '='); + const struct option *abbrev_option = NULL; + int abbrev_flags = 0; + + if (!arg_end) + arg_end = arg + strlen(arg); + for (; options->type != OPTION_END; options++) { const char *rest; int flags = 0; @@ -122,10 +129,38 @@ static int parse_long_opt(struct optparse_t *p, const char *arg, rest = skip_prefix(arg, options->long_name); if (!rest) { + /* abbreviated? */ + if (!strncmp(options->long_name, arg, arg_end - arg)) { +is_abbreviated: + if (abbrev_option) + return error("Ambiguous option: %s " + "(could be --%s%s or --%s%s)", + arg, + (flags & OPT_UNSET) ? + "no-" : "", + options->long_name, + (abbrev_flags & OPT_UNSET) ? + "no-" : "", + abbrev_option->long_name); + if (!(flags & OPT_UNSET) && *arg_end) + p->opt = arg_end + 1; + abbrev_option = options; + abbrev_flags = flags; + continue; + } + /* negated and abbreviated very much? */ + if (!prefixcmp("no-", arg)) { + flags |= OPT_UNSET; + goto is_abbreviated; + } + /* negated? */ if (strncmp(arg, "no-", 3)) continue; flags |= OPT_UNSET; rest = skip_prefix(arg + 3, options->long_name); + /* abbreviated and negated? */ + if (!rest && !prefixcmp(options->long_name, arg + 3)) + goto is_abbreviated; if (!rest) continue; } @@ -136,6 +171,8 @@ static int parse_long_opt(struct optparse_t *p, const char *arg, } return get_value(p, options, flags); } + if (abbrev_option) + return get_value(p, abbrev_option, abbrev_flags); return error("unknown option `%s'", arg); } diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 8e4d74b20..ae49424aa 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -67,4 +67,27 @@ test_expect_success 'intermingled arguments' ' git diff expect output ' +cat > expect << EOF +boolean: 0 +integer: 2 +string: (not set) +EOF + +test_expect_success 'unambiguously abbreviated option' ' + test-parse-options --int 2 --boolean --no-bo > output 2> output.err && + test ! -s output.err && + git diff expect output +' + +test_expect_success 'unambiguously abbreviated option with "="' ' + test-parse-options --int=2 > output 2> output.err && + test ! -s output.err && + git diff expect output +' + +test_expect_failure 'ambiguously abbreviated option' ' + test-parse-options --strin 123; + test $? != 129 +' + test_done -- 2.30.2