parse-options.con commit notes: implement helpers needed for note copying during rewrite (6956f85)
   1#include "git-compat-util.h"
   2#include "parse-options.h"
   3#include "cache.h"
   4#include "commit.h"
   5
   6static int parse_options_usage(const char * const *usagestr,
   7                               const struct option *opts);
   8
   9#define OPT_SHORT 1
  10#define OPT_UNSET 2
  11
  12static int opterror(const struct option *opt, const char *reason, int flags)
  13{
  14        if (flags & OPT_SHORT)
  15                return error("switch `%c' %s", opt->short_name, reason);
  16        if (flags & OPT_UNSET)
  17                return error("option `no-%s' %s", opt->long_name, reason);
  18        return error("option `%s' %s", opt->long_name, reason);
  19}
  20
  21static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
  22                   int flags, const char **arg)
  23{
  24        if (p->opt) {
  25                *arg = p->opt;
  26                p->opt = NULL;
  27        } else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) {
  28                *arg = (const char *)opt->defval;
  29        } else if (p->argc > 1) {
  30                p->argc--;
  31                *arg = *++p->argv;
  32        } else
  33                return opterror(opt, "requires a value", flags);
  34        return 0;
  35}
  36
  37static void fix_filename(const char *prefix, const char **file)
  38{
  39        if (!file || !*file || !prefix || is_absolute_path(*file)
  40            || !strcmp("-", *file))
  41                return;
  42        *file = xstrdup(prefix_filename(prefix, strlen(prefix), *file));
  43}
  44
  45static int get_value(struct parse_opt_ctx_t *p,
  46                     const struct option *opt, int flags)
  47{
  48        const char *s, *arg;
  49        const int unset = flags & OPT_UNSET;
  50        int err;
  51
  52        if (unset && p->opt)
  53                return opterror(opt, "takes no value", flags);
  54        if (unset && (opt->flags & PARSE_OPT_NONEG))
  55                return opterror(opt, "isn't available", flags);
  56
  57        if (!(flags & OPT_SHORT) && p->opt) {
  58                switch (opt->type) {
  59                case OPTION_CALLBACK:
  60                        if (!(opt->flags & PARSE_OPT_NOARG))
  61                                break;
  62                        /* FALLTHROUGH */
  63                case OPTION_BOOLEAN:
  64                case OPTION_BIT:
  65                case OPTION_NEGBIT:
  66                case OPTION_SET_INT:
  67                case OPTION_SET_PTR:
  68                        return opterror(opt, "takes no value", flags);
  69                default:
  70                        break;
  71                }
  72        }
  73
  74        switch (opt->type) {
  75        case OPTION_BIT:
  76                if (unset)
  77                        *(int *)opt->value &= ~opt->defval;
  78                else
  79                        *(int *)opt->value |= opt->defval;
  80                return 0;
  81
  82        case OPTION_NEGBIT:
  83                if (unset)
  84                        *(int *)opt->value |= opt->defval;
  85                else
  86                        *(int *)opt->value &= ~opt->defval;
  87                return 0;
  88
  89        case OPTION_BOOLEAN:
  90                *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
  91                return 0;
  92
  93        case OPTION_SET_INT:
  94                *(int *)opt->value = unset ? 0 : opt->defval;
  95                return 0;
  96
  97        case OPTION_SET_PTR:
  98                *(void **)opt->value = unset ? NULL : (void *)opt->defval;
  99                return 0;
 100
 101        case OPTION_STRING:
 102                if (unset)
 103                        *(const char **)opt->value = NULL;
 104                else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
 105                        *(const char **)opt->value = (const char *)opt->defval;
 106                else
 107                        return get_arg(p, opt, flags, (const char **)opt->value);
 108                return 0;
 109
 110        case OPTION_FILENAME:
 111                err = 0;
 112                if (unset)
 113                        *(const char **)opt->value = NULL;
 114                else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
 115                        *(const char **)opt->value = (const char *)opt->defval;
 116                else
 117                        err = get_arg(p, opt, flags, (const char **)opt->value);
 118
 119                if (!err)
 120                        fix_filename(p->prefix, (const char **)opt->value);
 121                return err;
 122
 123        case OPTION_CALLBACK:
 124                if (unset)
 125                        return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
 126                if (opt->flags & PARSE_OPT_NOARG)
 127                        return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
 128                if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
 129                        return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
 130                if (get_arg(p, opt, flags, &arg))
 131                        return -1;
 132                return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
 133
 134        case OPTION_INTEGER:
 135                if (unset) {
 136                        *(int *)opt->value = 0;
 137                        return 0;
 138                }
 139                if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
 140                        *(int *)opt->value = opt->defval;
 141                        return 0;
 142                }
 143                if (get_arg(p, opt, flags, &arg))
 144                        return -1;
 145                *(int *)opt->value = strtol(arg, (char **)&s, 10);
 146                if (*s)
 147                        return opterror(opt, "expects a numerical value", flags);
 148                return 0;
 149
 150        default:
 151                die("should not happen, someone must be hit on the forehead");
 152        }
 153}
 154
 155static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
 156{
 157        const struct option *numopt = NULL;
 158
 159        for (; options->type != OPTION_END; options++) {
 160                if (options->short_name == *p->opt) {
 161                        p->opt = p->opt[1] ? p->opt + 1 : NULL;
 162                        return get_value(p, options, OPT_SHORT);
 163                }
 164
 165                /*
 166                 * Handle the numerical option later, explicit one-digit
 167                 * options take precedence over it.
 168                 */
 169                if (options->type == OPTION_NUMBER)
 170                        numopt = options;
 171        }
 172        if (numopt && isdigit(*p->opt)) {
 173                size_t len = 1;
 174                char *arg;
 175                int rc;
 176
 177                while (isdigit(p->opt[len]))
 178                        len++;
 179                arg = xmemdupz(p->opt, len);
 180                p->opt = p->opt[len] ? p->opt + len : NULL;
 181                rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0;
 182                free(arg);
 183                return rc;
 184        }
 185        return -2;
 186}
 187
 188static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
 189                          const struct option *options)
 190{
 191        const char *arg_end = strchr(arg, '=');
 192        const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
 193        int abbrev_flags = 0, ambiguous_flags = 0;
 194
 195        if (!arg_end)
 196                arg_end = arg + strlen(arg);
 197
 198        for (; options->type != OPTION_END; options++) {
 199                const char *rest;
 200                int flags = 0;
 201
 202                if (!options->long_name)
 203                        continue;
 204
 205                rest = skip_prefix(arg, options->long_name);
 206                if (options->type == OPTION_ARGUMENT) {
 207                        if (!rest)
 208                                continue;
 209                        if (*rest == '=')
 210                                return opterror(options, "takes no value", flags);
 211                        if (*rest)
 212                                continue;
 213                        p->out[p->cpidx++] = arg - 2;
 214                        return 0;
 215                }
 216                if (!rest) {
 217                        /* abbreviated? */
 218                        if (!strncmp(options->long_name, arg, arg_end - arg)) {
 219is_abbreviated:
 220                                if (abbrev_option) {
 221                                        /*
 222                                         * If this is abbreviated, it is
 223                                         * ambiguous. So when there is no
 224                                         * exact match later, we need to
 225                                         * error out.
 226                                         */
 227                                        ambiguous_option = abbrev_option;
 228                                        ambiguous_flags = abbrev_flags;
 229                                }
 230                                if (!(flags & OPT_UNSET) && *arg_end)
 231                                        p->opt = arg_end + 1;
 232                                abbrev_option = options;
 233                                abbrev_flags = flags;
 234                                continue;
 235                        }
 236                        /* negation allowed? */
 237                        if (options->flags & PARSE_OPT_NONEG)
 238                                continue;
 239                        /* negated and abbreviated very much? */
 240                        if (!prefixcmp("no-", arg)) {
 241                                flags |= OPT_UNSET;
 242                                goto is_abbreviated;
 243                        }
 244                        /* negated? */
 245                        if (strncmp(arg, "no-", 3))
 246                                continue;
 247                        flags |= OPT_UNSET;
 248                        rest = skip_prefix(arg + 3, options->long_name);
 249                        /* abbreviated and negated? */
 250                        if (!rest && !prefixcmp(options->long_name, arg + 3))
 251                                goto is_abbreviated;
 252                        if (!rest)
 253                                continue;
 254                }
 255                if (*rest) {
 256                        if (*rest != '=')
 257                                continue;
 258                        p->opt = rest + 1;
 259                }
 260                return get_value(p, options, flags);
 261        }
 262
 263        if (ambiguous_option)
 264                return error("Ambiguous option: %s "
 265                        "(could be --%s%s or --%s%s)",
 266                        arg,
 267                        (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
 268                        ambiguous_option->long_name,
 269                        (abbrev_flags & OPT_UNSET) ?  "no-" : "",
 270                        abbrev_option->long_name);
 271        if (abbrev_option)
 272                return get_value(p, abbrev_option, abbrev_flags);
 273        return -2;
 274}
 275
 276static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg,
 277                            const struct option *options)
 278{
 279        for (; options->type != OPTION_END; options++) {
 280                if (!(options->flags & PARSE_OPT_NODASH))
 281                        continue;
 282                if ((options->flags & PARSE_OPT_OPTARG) ||
 283                    !(options->flags & PARSE_OPT_NOARG))
 284                        die("BUG: dashless options don't support arguments");
 285                if (!(options->flags & PARSE_OPT_NONEG))
 286                        die("BUG: dashless options don't support negation");
 287                if (options->long_name)
 288                        die("BUG: dashless options can't be long");
 289                if (options->short_name == arg[0] && arg[1] == '\0')
 290                        return get_value(p, options, OPT_SHORT);
 291        }
 292        return -2;
 293}
 294
 295static void check_typos(const char *arg, const struct option *options)
 296{
 297        if (strlen(arg) < 3)
 298                return;
 299
 300        if (!prefixcmp(arg, "no-")) {
 301                error ("did you mean `--%s` (with two dashes ?)", arg);
 302                exit(129);
 303        }
 304
 305        for (; options->type != OPTION_END; options++) {
 306                if (!options->long_name)
 307                        continue;
 308                if (!prefixcmp(options->long_name, arg)) {
 309                        error ("did you mean `--%s` (with two dashes ?)", arg);
 310                        exit(129);
 311                }
 312        }
 313}
 314
 315static void parse_options_check(const struct option *opts)
 316{
 317        int err = 0;
 318
 319        for (; opts->type != OPTION_END; opts++) {
 320                if ((opts->flags & PARSE_OPT_LASTARG_DEFAULT) &&
 321                    (opts->flags & PARSE_OPT_OPTARG)) {
 322                        if (opts->long_name) {
 323                                error("`--%s` uses incompatible flags "
 324                                      "LASTARG_DEFAULT and OPTARG", opts->long_name);
 325                        } else {
 326                                error("`-%c` uses incompatible flags "
 327                                      "LASTARG_DEFAULT and OPTARG", opts->short_name);
 328                        }
 329                        err |= 1;
 330                }
 331        }
 332
 333        if (err)
 334                exit(129);
 335}
 336
 337void parse_options_start(struct parse_opt_ctx_t *ctx,
 338                         int argc, const char **argv, const char *prefix,
 339                         int flags)
 340{
 341        memset(ctx, 0, sizeof(*ctx));
 342        ctx->argc = argc - 1;
 343        ctx->argv = argv + 1;
 344        ctx->out  = argv;
 345        ctx->prefix = prefix;
 346        ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
 347        ctx->flags = flags;
 348        if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
 349            (flags & PARSE_OPT_STOP_AT_NON_OPTION))
 350                die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
 351}
 352
 353static int usage_with_options_internal(const char * const *,
 354                                       const struct option *, int);
 355
 356int parse_options_step(struct parse_opt_ctx_t *ctx,
 357                       const struct option *options,
 358                       const char * const usagestr[])
 359{
 360        int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
 361
 362        parse_options_check(options);
 363
 364        /* we must reset ->opt, unknown short option leave it dangling */
 365        ctx->opt = NULL;
 366
 367        for (; ctx->argc; ctx->argc--, ctx->argv++) {
 368                const char *arg = ctx->argv[0];
 369
 370                if (*arg != '-' || !arg[1]) {
 371                        if (parse_nodash_opt(ctx, arg, options) == 0)
 372                                continue;
 373                        if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
 374                                break;
 375                        ctx->out[ctx->cpidx++] = ctx->argv[0];
 376                        continue;
 377                }
 378
 379                if (arg[1] != '-') {
 380                        ctx->opt = arg + 1;
 381                        if (internal_help && *ctx->opt == 'h')
 382                                return parse_options_usage(usagestr, options);
 383                        switch (parse_short_opt(ctx, options)) {
 384                        case -1:
 385                                return parse_options_usage(usagestr, options);
 386                        case -2:
 387                                goto unknown;
 388                        }
 389                        if (ctx->opt)
 390                                check_typos(arg + 1, options);
 391                        while (ctx->opt) {
 392                                if (internal_help && *ctx->opt == 'h')
 393                                        return parse_options_usage(usagestr, options);
 394                                switch (parse_short_opt(ctx, options)) {
 395                                case -1:
 396                                        return parse_options_usage(usagestr, options);
 397                                case -2:
 398                                        /* fake a short option thing to hide the fact that we may have
 399                                         * started to parse aggregated stuff
 400                                         *
 401                                         * This is leaky, too bad.
 402                                         */
 403                                        ctx->argv[0] = xstrdup(ctx->opt - 1);
 404                                        *(char *)ctx->argv[0] = '-';
 405                                        goto unknown;
 406                                }
 407                        }
 408                        continue;
 409                }
 410
 411                if (!arg[2]) { /* "--" */
 412                        if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
 413                                ctx->argc--;
 414                                ctx->argv++;
 415                        }
 416                        break;
 417                }
 418
 419                if (internal_help && !strcmp(arg + 2, "help-all"))
 420                        return usage_with_options_internal(usagestr, options, 1);
 421                if (internal_help && !strcmp(arg + 2, "help"))
 422                        return parse_options_usage(usagestr, options);
 423                switch (parse_long_opt(ctx, arg + 2, options)) {
 424                case -1:
 425                        return parse_options_usage(usagestr, options);
 426                case -2:
 427                        goto unknown;
 428                }
 429                continue;
 430unknown:
 431                if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
 432                        return PARSE_OPT_UNKNOWN;
 433                ctx->out[ctx->cpidx++] = ctx->argv[0];
 434                ctx->opt = NULL;
 435        }
 436        return PARSE_OPT_DONE;
 437}
 438
 439int parse_options_end(struct parse_opt_ctx_t *ctx)
 440{
 441        memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
 442        ctx->out[ctx->cpidx + ctx->argc] = NULL;
 443        return ctx->cpidx + ctx->argc;
 444}
 445
 446int parse_options(int argc, const char **argv, const char *prefix,
 447                  const struct option *options, const char * const usagestr[],
 448                  int flags)
 449{
 450        struct parse_opt_ctx_t ctx;
 451
 452        parse_options_start(&ctx, argc, argv, prefix, flags);
 453        switch (parse_options_step(&ctx, options, usagestr)) {
 454        case PARSE_OPT_HELP:
 455                exit(129);
 456        case PARSE_OPT_DONE:
 457                break;
 458        default: /* PARSE_OPT_UNKNOWN */
 459                if (ctx.argv[0][1] == '-') {
 460                        error("unknown option `%s'", ctx.argv[0] + 2);
 461                } else {
 462                        error("unknown switch `%c'", *ctx.opt);
 463                }
 464                usage_with_options(usagestr, options);
 465        }
 466
 467        return parse_options_end(&ctx);
 468}
 469
 470static int usage_argh(const struct option *opts)
 471{
 472        const char *s;
 473        int literal = (opts->flags & PARSE_OPT_LITERAL_ARGHELP) || !opts->argh;
 474        if (opts->flags & PARSE_OPT_OPTARG)
 475                if (opts->long_name)
 476                        s = literal ? "[=%s]" : "[=<%s>]";
 477                else
 478                        s = literal ? "[%s]" : "[<%s>]";
 479        else
 480                s = literal ? " %s" : " <%s>";
 481        return fprintf(stderr, s, opts->argh ? opts->argh : "...");
 482}
 483
 484#define USAGE_OPTS_WIDTH 24
 485#define USAGE_GAP         2
 486
 487static int usage_with_options_internal(const char * const *usagestr,
 488                                const struct option *opts, int full)
 489{
 490        if (!usagestr)
 491                return PARSE_OPT_HELP;
 492
 493        fprintf(stderr, "usage: %s\n", *usagestr++);
 494        while (*usagestr && **usagestr)
 495                fprintf(stderr, "   or: %s\n", *usagestr++);
 496        while (*usagestr) {
 497                fprintf(stderr, "%s%s\n",
 498                                **usagestr ? "    " : "",
 499                                *usagestr);
 500                usagestr++;
 501        }
 502
 503        if (opts->type != OPTION_GROUP)
 504                fputc('\n', stderr);
 505
 506        for (; opts->type != OPTION_END; opts++) {
 507                size_t pos;
 508                int pad;
 509
 510                if (opts->type == OPTION_GROUP) {
 511                        fputc('\n', stderr);
 512                        if (*opts->help)
 513                                fprintf(stderr, "%s\n", opts->help);
 514                        continue;
 515                }
 516                if (!full && (opts->flags & PARSE_OPT_HIDDEN))
 517                        continue;
 518
 519                pos = fprintf(stderr, "    ");
 520                if (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) {
 521                        if (opts->flags & PARSE_OPT_NODASH)
 522                                pos += fprintf(stderr, "%c", opts->short_name);
 523                        else
 524                                pos += fprintf(stderr, "-%c", opts->short_name);
 525                }
 526                if (opts->long_name && opts->short_name)
 527                        pos += fprintf(stderr, ", ");
 528                if (opts->long_name)
 529                        pos += fprintf(stderr, "--%s%s",
 530                                (opts->flags & PARSE_OPT_NEGHELP) ?  "no-" : "",
 531                                opts->long_name);
 532                if (opts->type == OPTION_NUMBER)
 533                        pos += fprintf(stderr, "-NUM");
 534
 535                if (!(opts->flags & PARSE_OPT_NOARG))
 536                        pos += usage_argh(opts);
 537
 538                if (pos <= USAGE_OPTS_WIDTH)
 539                        pad = USAGE_OPTS_WIDTH - pos;
 540                else {
 541                        fputc('\n', stderr);
 542                        pad = USAGE_OPTS_WIDTH;
 543                }
 544                fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
 545        }
 546        fputc('\n', stderr);
 547
 548        return PARSE_OPT_HELP;
 549}
 550
 551void usage_with_options(const char * const *usagestr,
 552                        const struct option *opts)
 553{
 554        usage_with_options_internal(usagestr, opts, 0);
 555        exit(129);
 556}
 557
 558void usage_msg_opt(const char *msg,
 559                   const char * const *usagestr,
 560                   const struct option *options)
 561{
 562        fprintf(stderr, "%s\n\n", msg);
 563        usage_with_options(usagestr, options);
 564}
 565
 566static int parse_options_usage(const char * const *usagestr,
 567                               const struct option *opts)
 568{
 569        return usage_with_options_internal(usagestr, opts, 0);
 570}
 571
 572
 573/*----- some often used options -----*/
 574#include "cache.h"
 575
 576int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)
 577{
 578        int v;
 579
 580        if (!arg) {
 581                v = unset ? 0 : DEFAULT_ABBREV;
 582        } else {
 583                v = strtol(arg, (char **)&arg, 10);
 584                if (*arg)
 585                        return opterror(opt, "expects a numerical value", 0);
 586                if (v && v < MINIMUM_ABBREV)
 587                        v = MINIMUM_ABBREV;
 588                else if (v > 40)
 589                        v = 40;
 590        }
 591        *(int *)(opt->value) = v;
 592        return 0;
 593}
 594
 595int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
 596                             int unset)
 597{
 598        *(unsigned long *)(opt->value) = approxidate(arg);
 599        return 0;
 600}
 601
 602int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
 603                           int unset)
 604{
 605        int *target = opt->value;
 606
 607        if (unset)
 608                /* --no-quiet, --no-verbose */
 609                *target = 0;
 610        else if (opt->short_name == 'v') {
 611                if (*target >= 0)
 612                        (*target)++;
 613                else
 614                        *target = 1;
 615        } else {
 616                if (*target <= 0)
 617                        (*target)--;
 618                else
 619                        *target = -1;
 620        }
 621        return 0;
 622}
 623
 624int parse_opt_with_commit(const struct option *opt, const char *arg, int unset)
 625{
 626        unsigned char sha1[20];
 627        struct commit *commit;
 628
 629        if (!arg)
 630                return -1;
 631        if (get_sha1(arg, sha1))
 632                return error("malformed object name %s", arg);
 633        commit = lookup_commit_reference(sha1);
 634        if (!commit)
 635                return error("no such commit %s", arg);
 636        commit_list_insert(commit, opt->value);
 637        return 0;
 638}
 639
 640int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)
 641{
 642        int *target = opt->value;
 643        *target = unset ? 2 : 1;
 644        return 0;
 645}