Skip to content

Commit

Permalink
parse-options: add OPT_CMDMODE()
Browse files Browse the repository at this point in the history
This can be used to define a set of mutually exclusive "command
mode" options, and automatically catch use of more than one from
that set as an error.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
gitster committed Jul 30, 2013
1 parent 35f5eaa commit 1158826
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 5 deletions.
58 changes: 53 additions & 5 deletions parse-options.c
Expand Up @@ -43,8 +43,42 @@ static void fix_filename(const char *prefix, const char **file)
*file = xstrdup(prefix_filename(prefix, strlen(prefix), *file));
}

static int opt_command_mode_error(const struct option *opt,
const struct option *all_opts,
int flags)
{
const struct option *that;
struct strbuf message = STRBUF_INIT;
struct strbuf that_name = STRBUF_INIT;

/*
* Find the other option that was used to set the variable
* already, and report that this is not compatible with it.
*/
for (that = all_opts; that->type != OPTION_END; that++) {
if (that == opt ||
that->type != OPTION_CMDMODE ||
that->value != opt->value ||
that->defval != *(int *)opt->value)
continue;

if (that->long_name)
strbuf_addf(&that_name, "--%s", that->long_name);
else
strbuf_addf(&that_name, "-%c", that->short_name);
strbuf_addf(&message, ": incompatible with %s", that_name.buf);
strbuf_release(&that_name);
opterror(opt, message.buf, flags);
strbuf_release(&message);
return -1;
}
return opterror(opt, ": incompatible with something else", flags);
}

static int get_value(struct parse_opt_ctx_t *p,
const struct option *opt, int flags)
const struct option *opt,
const struct option *all_opts,
int flags)
{
const char *s, *arg;
const int unset = flags & OPT_UNSET;
Expand Down Expand Up @@ -83,6 +117,16 @@ static int get_value(struct parse_opt_ctx_t *p,
*(int *)opt->value = unset ? 0 : opt->defval;
return 0;

case OPTION_CMDMODE:
/*
* Giving the same mode option twice, although is unnecessary,
* is not a grave error, so let it pass.
*/
if (*(int *)opt->value && *(int *)opt->value != opt->defval)
return opt_command_mode_error(opt, all_opts, flags);
*(int *)opt->value = opt->defval;
return 0;

case OPTION_SET_PTR:
*(void **)opt->value = unset ? NULL : (void *)opt->defval;
return 0;
Expand Down Expand Up @@ -143,12 +187,13 @@ static int get_value(struct parse_opt_ctx_t *p,

static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
{
const struct option *all_opts = options;
const struct option *numopt = NULL;

for (; options->type != OPTION_END; options++) {
if (options->short_name == *p->opt) {
p->opt = p->opt[1] ? p->opt + 1 : NULL;
return get_value(p, options, OPT_SHORT);
return get_value(p, options, all_opts, OPT_SHORT);
}

/*
Expand Down Expand Up @@ -177,6 +222,7 @@ static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *optio
static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
const struct option *options)
{
const struct option *all_opts = options;
const char *arg_end = strchr(arg, '=');
const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
int abbrev_flags = 0, ambiguous_flags = 0;
Expand Down Expand Up @@ -253,7 +299,7 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
continue;
p->opt = rest + 1;
}
return get_value(p, options, flags ^ opt_flags);
return get_value(p, options, all_opts, flags ^ opt_flags);
}

if (ambiguous_option)
Expand All @@ -265,18 +311,20 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
(abbrev_flags & OPT_UNSET) ? "no-" : "",
abbrev_option->long_name);
if (abbrev_option)
return get_value(p, abbrev_option, abbrev_flags);
return get_value(p, abbrev_option, all_opts, abbrev_flags);
return -2;
}

static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg,
const struct option *options)
{
const struct option *all_opts = options;

for (; options->type != OPTION_END; options++) {
if (!(options->flags & PARSE_OPT_NODASH))
continue;
if (options->short_name == arg[0] && arg[1] == '\0')
return get_value(p, options, OPT_SHORT);
return get_value(p, options, all_opts, OPT_SHORT);
}
return -2;
}
Expand Down
3 changes: 3 additions & 0 deletions parse-options.h
Expand Up @@ -13,6 +13,7 @@ enum parse_opt_type {
OPTION_COUNTUP,
OPTION_SET_INT,
OPTION_SET_PTR,
OPTION_CMDMODE,
/* options with arguments (usually) */
OPTION_STRING,
OPTION_INTEGER,
Expand Down Expand Up @@ -130,6 +131,8 @@ struct option {
#define OPT_BOOL(s, l, v, h) OPT_SET_INT(s, l, v, h, 1)
#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG, NULL, (p) }
#define OPT_CMDMODE(s, l, v, h, i) { OPTION_CMDMODE, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) }
#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), N_("n"), (h) }
#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
#define OPT_STRING_LIST(s, l, v, a, h) \
Expand Down

0 comments on commit 1158826

Please sign in to comment.