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