parse-options: Allow abbreviated options when unambiguous
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Sun, 14 Oct 2007 16:54:06 +0000 (17:54 +0100)
committerJunio C Hamano <gitster@pobox.com>
Tue, 30 Oct 2007 04:03:30 +0000 (21:03 -0700)
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 <johannes.schindelin@gmx.de>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
parse-options.c
t/t0040-parse-options.sh
index 12a9f9ea68f5ceac24aa4d2f530b68e8c0468983..b4a3b63e9f33b9f2af40fd8cf17dd2aeff312a35 100644 (file)
@@ -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);
 }
 
index 8e4d74b2005b4c55eefc460d47ed121f664b85f5..ae49424aa02a37df1b00813aa1478d570020c66b 100755 (executable)
@@ -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