aboutsummaryrefslogtreecommitdiff
path: root/parse-options.c
diff options
context:
space:
mode:
Diffstat (limited to 'parse-options.c')
-rw-r--r--parse-options.c37
1 files changed, 37 insertions, 0 deletions
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);
}