parse-options: abbreviation engine fix.
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Mon, 5 Nov 2007 13:15:21 +0000 (13:15 +0000)
committerJunio C Hamano <gitster@pobox.com>
Tue, 6 Nov 2007 06:46:45 +0000 (22:46 -0800)
When an option could be an ambiguous abbreviation of two options, the code
used to error out.  Even if an exact match would have occured later.

Test and original patch by Pierre Habouzit.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
parse-options.c
t/t0040-parse-options.sh
test-parse-options.c

index cc09c98ec3fe19d6f9f5f7a58a3c5956bd7c0578..15b32f741b6b8bf47321b9ce78da43e9378f22b3 100644 (file)
@@ -119,8 +119,8 @@ 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;
+       const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
+       int abbrev_flags = 0, ambiguous_flags = 0;
 
        if (!arg_end)
                arg_end = arg + strlen(arg);
@@ -137,16 +137,16 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
                        /* 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 (abbrev_option) {
+                                       /*
+                                        * If this is abbreviated, it is
+                                        * ambiguous. So when there is no
+                                        * exact match later, we need to
+                                        * error out.
+                                        */
+                                       ambiguous_option = abbrev_option;
+                                       ambiguous_flags = abbrev_flags;
+                               }
                                if (!(flags & OPT_UNSET) && *arg_end)
                                        p->opt = arg_end + 1;
                                abbrev_option = options;
@@ -176,6 +176,15 @@ is_abbreviated:
                }
                return get_value(p, options, flags);
        }
+
+       if (ambiguous_option)
+               return error("Ambiguous option: %s "
+                       "(could be --%s%s or --%s%s)",
+                       arg,
+                       (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
+                       ambiguous_option->long_name,
+                       (abbrev_flags & OPT_UNSET) ?  "no-" : "",
+                       abbrev_option->long_name);
        if (abbrev_option)
                return get_value(p, abbrev_option, abbrev_flags);
        return error("unknown option `%s'", arg);
index ae49424aa02a37df1b00813aa1478d570020c66b..462fdf262fe451c14679753018a415e1cc778732 100755 (executable)
@@ -18,6 +18,7 @@ string options
     -s, --string <string>
                           get a string
     --string2 <str>       get another string
+    --st <st>             get another string (pervert ordering)
 
 EOF
 
@@ -90,4 +91,16 @@ test_expect_failure 'ambiguously abbreviated option' '
         test $? != 129
 '
 
+cat > expect << EOF
+boolean: 0
+integer: 0
+string: 123
+EOF
+
+test_expect_success 'non ambiguous option (after two options it abbreviates)' '
+       test-parse-options --st 123 > output 2> output.err &&
+       test ! -s output.err &&
+       git diff expect output
+'
+
 test_done
index 277cfe4d6dceb5ebe2ce9f141b6eb21a4dc37912..4d3e2ec39e33f6301cc6df162dab7de9dbb2ea80 100644 (file)
@@ -18,6 +18,7 @@ int main(int argc, const char **argv)
                OPT_GROUP("string options"),
                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_END(),
        };
        int i;