summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar Johannes Schindelin <Johannes.Schindelin@gmx.de>2007-10-14 17:54:06 +0100
committerLibravatar Junio C Hamano <gitster@pobox.com>2007-10-29 21:03:30 -0700
commit7f275b91520d31bfbe43ec5a9bbaf8ac6e663ce0 (patch)
tree3e21e4a89617c56b47b7d4d1f2312198a8641de9
parentAdd shortcuts for very often used options. (diff)
downloadtgif-7f275b91520d31bfbe43ec5a9bbaf8ac6e663ce0.tar.xz
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 <johannes.schindelin@gmx.de> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
-rw-r--r--parse-options.c37
-rwxr-xr-xt/t0040-parse-options.sh23
2 files changed, 60 insertions, 0 deletions
diff --git a/parse-options.c b/parse-options.c
index 12a9f9ea68..b4a3b63e9f 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 8e4d74b200..ae49424aa0 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