diff options
Diffstat (limited to 'parse-options.c')
-rw-r--r-- | parse-options.c | 193 |
1 files changed, 45 insertions, 148 deletions
diff --git a/parse-options.c b/parse-options.c index 0fa79bc31d..503ab5d500 100644 --- a/parse-options.c +++ b/parse-options.c @@ -11,7 +11,14 @@ static int parse_options_usage(struct parse_opt_ctx_t *ctx, #define OPT_SHORT 1 #define OPT_UNSET 2 -static int opterror(const struct option *opt, const char *reason, int flags) +int optbug(const struct option *opt, const char *reason) +{ + if (opt->long_name) + return error("BUG: option '%s' %s", opt->long_name, reason); + return error("BUG: switch '%c' %s", opt->short_name, reason); +} + +int opterror(const struct option *opt, const char *reason, int flags) { if (flags & OPT_SHORT) return error("switch `%c' %s", opt->short_name, reason); @@ -55,25 +62,13 @@ static int get_value(struct parse_opt_ctx_t *p, return opterror(opt, "takes no value", flags); if (unset && (opt->flags & PARSE_OPT_NONEG)) return opterror(opt, "isn't available", flags); - - if (!(flags & OPT_SHORT) && p->opt) { - switch (opt->type) { - case OPTION_CALLBACK: - if (!(opt->flags & PARSE_OPT_NOARG)) - break; - /* FALLTHROUGH */ - case OPTION_BOOLEAN: - case OPTION_BIT: - case OPTION_NEGBIT: - case OPTION_SET_INT: - case OPTION_SET_PTR: - return opterror(opt, "takes no value", flags); - default: - break; - } - } + if (!(flags & OPT_SHORT) && p->opt && (opt->flags & PARSE_OPT_NOARG)) + return opterror(opt, "takes no value", flags); switch (opt->type) { + case OPTION_LOWLEVEL_CALLBACK: + return (*(parse_opt_ll_cb *)opt->callback)(p, opt, unset); + case OPTION_BIT: if (unset) *(int *)opt->value &= ~opt->defval; @@ -281,13 +276,6 @@ static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg, for (; options->type != OPTION_END; options++) { if (!(options->flags & PARSE_OPT_NODASH)) continue; - if ((options->flags & PARSE_OPT_OPTARG) || - !(options->flags & PARSE_OPT_NOARG)) - die("BUG: dashless options don't support arguments"); - if (!(options->flags & PARSE_OPT_NONEG)) - die("BUG: dashless options don't support negation"); - if (options->long_name) - die("BUG: dashless options can't be long"); if (options->short_name == arg[0] && arg[1] == '\0') return get_value(p, options, OPT_SHORT); } @@ -320,25 +308,37 @@ static void parse_options_check(const struct option *opts) for (; opts->type != OPTION_END; opts++) { if ((opts->flags & PARSE_OPT_LASTARG_DEFAULT) && - (opts->flags & PARSE_OPT_OPTARG)) { - if (opts->long_name) { - error("`--%s` uses incompatible flags " - "LASTARG_DEFAULT and OPTARG", opts->long_name); - } else { - error("`-%c` uses incompatible flags " - "LASTARG_DEFAULT and OPTARG", opts->short_name); - } - err |= 1; + (opts->flags & PARSE_OPT_OPTARG)) + err |= optbug(opts, "uses incompatible flags " + "LASTARG_DEFAULT and OPTARG"); + if (opts->flags & PARSE_OPT_NODASH && + ((opts->flags & PARSE_OPT_OPTARG) || + !(opts->flags & PARSE_OPT_NOARG) || + !(opts->flags & PARSE_OPT_NONEG) || + opts->long_name)) + err |= optbug(opts, "uses feature " + "not supported for dashless options"); + switch (opts->type) { + case OPTION_BOOLEAN: + case OPTION_BIT: + case OPTION_NEGBIT: + case OPTION_SET_INT: + case OPTION_SET_PTR: + case OPTION_NUMBER: + if ((opts->flags & PARSE_OPT_OPTARG) || + !(opts->flags & PARSE_OPT_NOARG)) + err |= optbug(opts, "should not accept an argument"); + default: + ; /* ok. (usually accepts an argument) */ } } - if (err) - exit(129); + exit(128); } void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, const char **argv, const char *prefix, - int flags) + const struct option *options, int flags) { memset(ctx, 0, sizeof(*ctx)); ctx->argc = argc - 1; @@ -350,6 +350,7 @@ void parse_options_start(struct parse_opt_ctx_t *ctx, if ((flags & PARSE_OPT_KEEP_UNKNOWN) && (flags & PARSE_OPT_STOP_AT_NON_OPTION)) die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); + parse_options_check(options); } static int usage_with_options_internal(struct parse_opt_ctx_t *, @@ -362,8 +363,6 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, { int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); - parse_options_check(options); - /* we must reset ->opt, unknown short option leave it dangling */ ctx->opt = NULL; @@ -374,7 +373,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, if (parse_nodash_opt(ctx, arg, options) == 0) continue; if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) - break; + return PARSE_OPT_NON_OPTION; ctx->out[ctx->cpidx++] = ctx->argv[0]; continue; } @@ -452,10 +451,11 @@ int parse_options(int argc, const char **argv, const char *prefix, { struct parse_opt_ctx_t ctx; - parse_options_start(&ctx, argc, argv, prefix, flags); + parse_options_start(&ctx, argc, argv, prefix, options, flags); switch (parse_options_step(&ctx, options, usagestr)) { case PARSE_OPT_HELP: exit(129); + case PARSE_OPT_NON_OPTION: case PARSE_OPT_DONE: break; default: /* PARSE_OPT_UNKNOWN */ @@ -541,7 +541,8 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx, if (opts->type == OPTION_NUMBER) pos += fprintf(outfile, "-NUM"); - if (!(opts->flags & PARSE_OPT_NOARG)) + if ((opts->flags & PARSE_OPT_LITERAL_ARGHELP) || + !(opts->flags & PARSE_OPT_NOARG)) pos += usage_argh(opts, outfile); if (pos <= USAGE_OPTS_WIDTH) @@ -560,14 +561,14 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx, return PARSE_OPT_HELP; } -void usage_with_options(const char * const *usagestr, +void NORETURN usage_with_options(const char * const *usagestr, const struct option *opts) { usage_with_options_internal(NULL, usagestr, opts, 0, 1); exit(129); } -void usage_msg_opt(const char *msg, +void NORETURN usage_msg_opt(const char *msg, const char * const *usagestr, const struct option *options) { @@ -582,107 +583,3 @@ static int parse_options_usage(struct parse_opt_ctx_t *ctx, return usage_with_options_internal(ctx, usagestr, opts, 0, err); } - -/*----- some often used options -----*/ -#include "cache.h" - -int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset) -{ - int v; - - if (!arg) { - v = unset ? 0 : DEFAULT_ABBREV; - } else { - v = strtol(arg, (char **)&arg, 10); - if (*arg) - return opterror(opt, "expects a numerical value", 0); - if (v && v < MINIMUM_ABBREV) - v = MINIMUM_ABBREV; - else if (v > 40) - v = 40; - } - *(int *)(opt->value) = v; - return 0; -} - -int parse_opt_approxidate_cb(const struct option *opt, const char *arg, - int unset) -{ - *(unsigned long *)(opt->value) = approxidate(arg); - return 0; -} - -int parse_opt_color_flag_cb(const struct option *opt, const char *arg, - int unset) -{ - int value; - - if (!arg) - arg = unset ? "never" : (const char *)opt->defval; - value = git_config_colorbool(NULL, arg, -1); - if (value < 0) - return opterror(opt, - "expects \"always\", \"auto\", or \"never\"", 0); - *(int *)opt->value = value; - return 0; -} - -int parse_opt_verbosity_cb(const struct option *opt, const char *arg, - int unset) -{ - int *target = opt->value; - - if (unset) - /* --no-quiet, --no-verbose */ - *target = 0; - else if (opt->short_name == 'v') { - if (*target >= 0) - (*target)++; - else - *target = 1; - } else { - if (*target <= 0) - (*target)--; - else - *target = -1; - } - return 0; -} - -int parse_opt_with_commit(const struct option *opt, const char *arg, int unset) -{ - unsigned char sha1[20]; - struct commit *commit; - - if (!arg) - return -1; - if (get_sha1(arg, sha1)) - return error("malformed object name %s", arg); - commit = lookup_commit_reference(sha1); - if (!commit) - return error("no such commit %s", arg); - commit_list_insert(commit, opt->value); - return 0; -} - -int parse_opt_tertiary(const struct option *opt, const char *arg, int unset) -{ - int *target = opt->value; - *target = unset ? 2 : 1; - return 0; -} - -int parse_options_concat(struct option *dst, size_t dst_size, struct option *src) -{ - int i, j; - - for (i = 0; i < dst_size; i++) - if (dst[i].type == OPTION_END) - break; - for (j = 0; i < dst_size; i++, j++) { - dst[i] = src[j]; - if (src[j].type == OPTION_END) - return 0; - } - return -1; -} |