parse-options.con commit diff --dirstat-by-file: count changed files, not lines (fd33777)
   1#include "git-compat-util.h"
   2#include "parse-options.h"
   3#include "cache.h"
   4
   5#define OPT_SHORT 1
   6#define OPT_UNSET 2
   7
   8static int opterror(const struct option *opt, const char *reason, int flags)
   9{
  10        if (flags & OPT_SHORT)
  11                return error("switch `%c' %s", opt->short_name, reason);
  12        if (flags & OPT_UNSET)
  13                return error("option `no-%s' %s", opt->long_name, reason);
  14        return error("option `%s' %s", opt->long_name, reason);
  15}
  16
  17static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
  18                   int flags, const char **arg)
  19{
  20        if (p->opt) {
  21                *arg = p->opt;
  22                p->opt = NULL;
  23        } else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) {
  24                *arg = (const char *)opt->defval;
  25        } else if (p->argc > 1) {
  26                p->argc--;
  27                *arg = *++p->argv;
  28        } else
  29                return opterror(opt, "requires a value", flags);
  30        return 0;
  31}
  32
  33static int get_value(struct parse_opt_ctx_t *p,
  34                     const struct option *opt, int flags)
  35{
  36        const char *s, *arg;
  37        const int unset = flags & OPT_UNSET;
  38
  39        if (unset && p->opt)
  40                return opterror(opt, "takes no value", flags);
  41        if (unset && (opt->flags & PARSE_OPT_NONEG))
  42                return opterror(opt, "isn't available", flags);
  43
  44        if (!(flags & OPT_SHORT) && p->opt) {
  45                switch (opt->type) {
  46                case OPTION_CALLBACK:
  47                        if (!(opt->flags & PARSE_OPT_NOARG))
  48                                break;
  49                        /* FALLTHROUGH */
  50                case OPTION_BOOLEAN:
  51                case OPTION_BIT:
  52                case OPTION_SET_INT:
  53                case OPTION_SET_PTR:
  54                        return opterror(opt, "takes no value", flags);
  55                default:
  56                        break;
  57                }
  58        }
  59
  60        switch (opt->type) {
  61        case OPTION_BIT:
  62                if (unset)
  63                        *(int *)opt->value &= ~opt->defval;
  64                else
  65                        *(int *)opt->value |= opt->defval;
  66                return 0;
  67
  68        case OPTION_BOOLEAN:
  69                *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
  70                return 0;
  71
  72        case OPTION_SET_INT:
  73                *(int *)opt->value = unset ? 0 : opt->defval;
  74                return 0;
  75
  76        case OPTION_SET_PTR:
  77                *(void **)opt->value = unset ? NULL : (void *)opt->defval;
  78                return 0;
  79
  80        case OPTION_STRING:
  81                if (unset)
  82                        *(const char **)opt->value = NULL;
  83                else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
  84                        *(const char **)opt->value = (const char *)opt->defval;
  85                else
  86                        return get_arg(p, opt, flags, (const char **)opt->value);
  87                return 0;
  88
  89        case OPTION_CALLBACK:
  90                if (unset)
  91                        return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
  92                if (opt->flags & PARSE_OPT_NOARG)
  93                        return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
  94                if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
  95                        return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
  96                if (get_arg(p, opt, flags, &arg))
  97                        return -1;
  98                return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
  99
 100        case OPTION_INTEGER:
 101                if (unset) {
 102                        *(int *)opt->value = 0;
 103                        return 0;
 104                }
 105                if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
 106                        *(int *)opt->value = opt->defval;
 107                        return 0;
 108                }
 109                if (get_arg(p, opt, flags, &arg))
 110                        return -1;
 111                *(int *)opt->value = strtol(arg, (char **)&s, 10);
 112                if (*s)
 113                        return opterror(opt, "expects a numerical value", flags);
 114                return 0;
 115
 116        default:
 117                die("should not happen, someone must be hit on the forehead");
 118        }
 119}
 120
 121static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
 122{
 123        for (; options->type != OPTION_END; options++) {
 124                if (options->short_name == *p->opt) {
 125                        p->opt = p->opt[1] ? p->opt + 1 : NULL;
 126                        return get_value(p, options, OPT_SHORT);
 127                }
 128        }
 129        return -2;
 130}
 131
 132static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
 133                          const struct option *options)
 134{
 135        const char *arg_end = strchr(arg, '=');
 136        const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
 137        int abbrev_flags = 0, ambiguous_flags = 0;
 138
 139        if (!arg_end)
 140                arg_end = arg + strlen(arg);
 141
 142        for (; options->type != OPTION_END; options++) {
 143                const char *rest;
 144                int flags = 0;
 145
 146                if (!options->long_name)
 147                        continue;
 148
 149                rest = skip_prefix(arg, options->long_name);
 150                if (options->type == OPTION_ARGUMENT) {
 151                        if (!rest)
 152                                continue;
 153                        if (*rest == '=')
 154                                return opterror(options, "takes no value", flags);
 155                        if (*rest)
 156                                continue;
 157                        p->out[p->cpidx++] = arg - 2;
 158                        return 0;
 159                }
 160                if (!rest) {
 161                        /* abbreviated? */
 162                        if (!strncmp(options->long_name, arg, arg_end - arg)) {
 163is_abbreviated:
 164                                if (abbrev_option) {
 165                                        /*
 166                                         * If this is abbreviated, it is
 167                                         * ambiguous. So when there is no
 168                                         * exact match later, we need to
 169                                         * error out.
 170                                         */
 171                                        ambiguous_option = abbrev_option;
 172                                        ambiguous_flags = abbrev_flags;
 173                                }
 174                                if (!(flags & OPT_UNSET) && *arg_end)
 175                                        p->opt = arg_end + 1;
 176                                abbrev_option = options;
 177                                abbrev_flags = flags;
 178                                continue;
 179                        }
 180                        /* negated and abbreviated very much? */
 181                        if (!prefixcmp("no-", arg)) {
 182                                flags |= OPT_UNSET;
 183                                goto is_abbreviated;
 184                        }
 185                        /* negated? */
 186                        if (strncmp(arg, "no-", 3))
 187                                continue;
 188                        flags |= OPT_UNSET;
 189                        rest = skip_prefix(arg + 3, options->long_name);
 190                        /* abbreviated and negated? */
 191                        if (!rest && !prefixcmp(options->long_name, arg + 3))
 192                                goto is_abbreviated;
 193                        if (!rest)
 194                                continue;
 195                }
 196                if (*rest) {
 197                        if (*rest != '=')
 198                                continue;
 199                        p->opt = rest + 1;
 200                }
 201                return get_value(p, options, flags);
 202        }
 203
 204        if (ambiguous_option)
 205                return error("Ambiguous option: %s "
 206                        "(could be --%s%s or --%s%s)",
 207                        arg,
 208                        (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
 209                        ambiguous_option->long_name,
 210                        (abbrev_flags & OPT_UNSET) ?  "no-" : "",
 211                        abbrev_option->long_name);
 212        if (abbrev_option)
 213                return get_value(p, abbrev_option, abbrev_flags);
 214        return -2;
 215}
 216
 217static void check_typos(const char *arg, const struct option *options)
 218{
 219        if (strlen(arg) < 3)
 220                return;
 221
 222        if (!prefixcmp(arg, "no-")) {
 223                error ("did you mean `--%s` (with two dashes ?)", arg);
 224                exit(129);
 225        }
 226
 227        for (; options->type != OPTION_END; options++) {
 228                if (!options->long_name)
 229                        continue;
 230                if (!prefixcmp(options->long_name, arg)) {
 231                        error ("did you mean `--%s` (with two dashes ?)", arg);
 232                        exit(129);
 233                }
 234        }
 235}
 236
 237void parse_options_start(struct parse_opt_ctx_t *ctx,
 238                         int argc, const char **argv, int flags)
 239{
 240        memset(ctx, 0, sizeof(*ctx));
 241        ctx->argc = argc - 1;
 242        ctx->argv = argv + 1;
 243        ctx->out  = argv;
 244        ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
 245        ctx->flags = flags;
 246}
 247
 248static int usage_with_options_internal(const char * const *,
 249                                       const struct option *, int);
 250
 251int parse_options_step(struct parse_opt_ctx_t *ctx,
 252                       const struct option *options,
 253                       const char * const usagestr[])
 254{
 255        /* we must reset ->opt, unknown short option leave it dangling */
 256        ctx->opt = NULL;
 257
 258        for (; ctx->argc; ctx->argc--, ctx->argv++) {
 259                const char *arg = ctx->argv[0];
 260
 261                if (*arg != '-' || !arg[1]) {
 262                        if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
 263                                break;
 264                        ctx->out[ctx->cpidx++] = ctx->argv[0];
 265                        continue;
 266                }
 267
 268                if (arg[1] != '-') {
 269                        ctx->opt = arg + 1;
 270                        if (*ctx->opt == 'h')
 271                                return parse_options_usage(usagestr, options);
 272                        switch (parse_short_opt(ctx, options)) {
 273                        case -1:
 274                                return parse_options_usage(usagestr, options);
 275                        case -2:
 276                                return PARSE_OPT_UNKNOWN;
 277                        }
 278                        if (ctx->opt)
 279                                check_typos(arg + 1, options);
 280                        while (ctx->opt) {
 281                                if (*ctx->opt == 'h')
 282                                        return parse_options_usage(usagestr, options);
 283                                switch (parse_short_opt(ctx, options)) {
 284                                case -1:
 285                                        return parse_options_usage(usagestr, options);
 286                                case -2:
 287                                        /* fake a short option thing to hide the fact that we may have
 288                                         * started to parse aggregated stuff
 289                                         *
 290                                         * This is leaky, too bad.
 291                                         */
 292                                        ctx->argv[0] = xstrdup(ctx->opt - 1);
 293                                        *(char *)ctx->argv[0] = '-';
 294                                        return PARSE_OPT_UNKNOWN;
 295                                }
 296                        }
 297                        continue;
 298                }
 299
 300                if (!arg[2]) { /* "--" */
 301                        if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
 302                                ctx->argc--;
 303                                ctx->argv++;
 304                        }
 305                        break;
 306                }
 307
 308                if (!strcmp(arg + 2, "help-all"))
 309                        return usage_with_options_internal(usagestr, options, 1);
 310                if (!strcmp(arg + 2, "help"))
 311                        return parse_options_usage(usagestr, options);
 312                switch (parse_long_opt(ctx, arg + 2, options)) {
 313                case -1:
 314                        return parse_options_usage(usagestr, options);
 315                case -2:
 316                        return PARSE_OPT_UNKNOWN;
 317                }
 318        }
 319        return PARSE_OPT_DONE;
 320}
 321
 322int parse_options_end(struct parse_opt_ctx_t *ctx)
 323{
 324        memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
 325        ctx->out[ctx->cpidx + ctx->argc] = NULL;
 326        return ctx->cpidx + ctx->argc;
 327}
 328
 329int parse_options(int argc, const char **argv, const struct option *options,
 330                  const char * const usagestr[], int flags)
 331{
 332        struct parse_opt_ctx_t ctx;
 333
 334        parse_options_start(&ctx, argc, argv, flags);
 335        switch (parse_options_step(&ctx, options, usagestr)) {
 336        case PARSE_OPT_HELP:
 337                exit(129);
 338        case PARSE_OPT_DONE:
 339                break;
 340        default: /* PARSE_OPT_UNKNOWN */
 341                if (ctx.argv[0][1] == '-') {
 342                        error("unknown option `%s'", ctx.argv[0] + 2);
 343                } else {
 344                        error("unknown switch `%c'", *ctx.opt);
 345                }
 346                usage_with_options(usagestr, options);
 347        }
 348
 349        return parse_options_end(&ctx);
 350}
 351
 352#define USAGE_OPTS_WIDTH 24
 353#define USAGE_GAP         2
 354
 355int usage_with_options_internal(const char * const *usagestr,
 356                                const struct option *opts, int full)
 357{
 358        fprintf(stderr, "usage: %s\n", *usagestr++);
 359        while (*usagestr && **usagestr)
 360                fprintf(stderr, "   or: %s\n", *usagestr++);
 361        while (*usagestr) {
 362                fprintf(stderr, "%s%s\n",
 363                                **usagestr ? "    " : "",
 364                                *usagestr);
 365                usagestr++;
 366        }
 367
 368        if (opts->type != OPTION_GROUP)
 369                fputc('\n', stderr);
 370
 371        for (; opts->type != OPTION_END; opts++) {
 372                size_t pos;
 373                int pad;
 374
 375                if (opts->type == OPTION_GROUP) {
 376                        fputc('\n', stderr);
 377                        if (*opts->help)
 378                                fprintf(stderr, "%s\n", opts->help);
 379                        continue;
 380                }
 381                if (!full && (opts->flags & PARSE_OPT_HIDDEN))
 382                        continue;
 383
 384                pos = fprintf(stderr, "    ");
 385                if (opts->short_name)
 386                        pos += fprintf(stderr, "-%c", opts->short_name);
 387                if (opts->long_name && opts->short_name)
 388                        pos += fprintf(stderr, ", ");
 389                if (opts->long_name)
 390                        pos += fprintf(stderr, "--%s", opts->long_name);
 391
 392                switch (opts->type) {
 393                case OPTION_ARGUMENT:
 394                        break;
 395                case OPTION_INTEGER:
 396                        if (opts->flags & PARSE_OPT_OPTARG)
 397                                if (opts->long_name)
 398                                        pos += fprintf(stderr, "[=<n>]");
 399                                else
 400                                        pos += fprintf(stderr, "[<n>]");
 401                        else
 402                                pos += fprintf(stderr, " <n>");
 403                        break;
 404                case OPTION_CALLBACK:
 405                        if (opts->flags & PARSE_OPT_NOARG)
 406                                break;
 407                        /* FALLTHROUGH */
 408                case OPTION_STRING:
 409                        if (opts->argh) {
 410                                if (opts->flags & PARSE_OPT_OPTARG)
 411                                        if (opts->long_name)
 412                                                pos += fprintf(stderr, "[=<%s>]", opts->argh);
 413                                        else
 414                                                pos += fprintf(stderr, "[<%s>]", opts->argh);
 415                                else
 416                                        pos += fprintf(stderr, " <%s>", opts->argh);
 417                        } else {
 418                                if (opts->flags & PARSE_OPT_OPTARG)
 419                                        if (opts->long_name)
 420                                                pos += fprintf(stderr, "[=...]");
 421                                        else
 422                                                pos += fprintf(stderr, "[...]");
 423                                else
 424                                        pos += fprintf(stderr, " ...");
 425                        }
 426                        break;
 427                default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
 428                        break;
 429                }
 430
 431                if (pos <= USAGE_OPTS_WIDTH)
 432                        pad = USAGE_OPTS_WIDTH - pos;
 433                else {
 434                        fputc('\n', stderr);
 435                        pad = USAGE_OPTS_WIDTH;
 436                }
 437                fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
 438        }
 439        fputc('\n', stderr);
 440
 441        return PARSE_OPT_HELP;
 442}
 443
 444void usage_with_options(const char * const *usagestr,
 445                        const struct option *opts)
 446{
 447        usage_with_options_internal(usagestr, opts, 0);
 448        exit(129);
 449}
 450
 451int parse_options_usage(const char * const *usagestr,
 452                        const struct option *opts)
 453{
 454        return usage_with_options_internal(usagestr, opts, 0);
 455}
 456
 457
 458/*----- some often used options -----*/
 459#include "cache.h"
 460
 461int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)
 462{
 463        int v;
 464
 465        if (!arg) {
 466                v = unset ? 0 : DEFAULT_ABBREV;
 467        } else {
 468                v = strtol(arg, (char **)&arg, 10);
 469                if (*arg)
 470                        return opterror(opt, "expects a numerical value", 0);
 471                if (v && v < MINIMUM_ABBREV)
 472                        v = MINIMUM_ABBREV;
 473                else if (v > 40)
 474                        v = 40;
 475        }
 476        *(int *)(opt->value) = v;
 477        return 0;
 478}
 479
 480int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
 481                             int unset)
 482{
 483        *(unsigned long *)(opt->value) = approxidate(arg);
 484        return 0;
 485}
 486
 487/*
 488 * This should really be OPTION_FILENAME type as a part of
 489 * parse_options that take prefix to do this while parsing.
 490 */
 491extern const char *parse_options_fix_filename(const char *prefix, const char *file)
 492{
 493        if (!file || !prefix || is_absolute_path(file) || !strcmp("-", file))
 494                return file;
 495        return prefix_filename(prefix, strlen(prefix), file);
 496}
 497