linux/tools/lib/subcmd/parse-options.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/compiler.h>
   3#include <linux/string.h>
   4#include <linux/types.h>
   5#include <stdio.h>
   6#include <stdlib.h>
   7#include <stdint.h>
   8#include <string.h>
   9#include <ctype.h>
  10#include "subcmd-util.h"
  11#include "parse-options.h"
  12#include "subcmd-config.h"
  13#include "pager.h"
  14
  15#define OPT_SHORT 1
  16#define OPT_UNSET 2
  17
  18char *error_buf;
  19
  20static int opterror(const struct option *opt, const char *reason, int flags)
  21{
  22        if (flags & OPT_SHORT)
  23                fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
  24        else if (flags & OPT_UNSET)
  25                fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
  26        else
  27                fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
  28
  29        return -1;
  30}
  31
  32static const char *skip_prefix(const char *str, const char *prefix)
  33{
  34        size_t len = strlen(prefix);
  35        return strncmp(str, prefix, len) ? NULL : str + len;
  36}
  37
  38static void optwarning(const struct option *opt, const char *reason, int flags)
  39{
  40        if (flags & OPT_SHORT)
  41                fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
  42        else if (flags & OPT_UNSET)
  43                fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
  44        else
  45                fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
  46}
  47
  48static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
  49                   int flags, const char **arg)
  50{
  51        const char *res;
  52
  53        if (p->opt) {
  54                res = p->opt;
  55                p->opt = NULL;
  56        } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
  57                    **(p->argv + 1) == '-')) {
  58                res = (const char *)opt->defval;
  59        } else if (p->argc > 1) {
  60                p->argc--;
  61                res = *++p->argv;
  62        } else
  63                return opterror(opt, "requires a value", flags);
  64        if (arg)
  65                *arg = res;
  66        return 0;
  67}
  68
  69static int get_value(struct parse_opt_ctx_t *p,
  70                     const struct option *opt, int flags)
  71{
  72        const char *s, *arg = NULL;
  73        const int unset = flags & OPT_UNSET;
  74        int err;
  75
  76        if (unset && p->opt)
  77                return opterror(opt, "takes no value", flags);
  78        if (unset && (opt->flags & PARSE_OPT_NONEG))
  79                return opterror(opt, "isn't available", flags);
  80        if (opt->flags & PARSE_OPT_DISABLED)
  81                return opterror(opt, "is not usable", flags);
  82
  83        if (opt->flags & PARSE_OPT_EXCLUSIVE) {
  84                if (p->excl_opt && p->excl_opt != opt) {
  85                        char msg[128];
  86
  87                        if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
  88                            p->excl_opt->long_name == NULL) {
  89                                snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
  90                                         p->excl_opt->short_name);
  91                        } else {
  92                                snprintf(msg, sizeof(msg), "cannot be used with %s",
  93                                         p->excl_opt->long_name);
  94                        }
  95                        opterror(opt, msg, flags);
  96                        return -3;
  97                }
  98                p->excl_opt = opt;
  99        }
 100        if (!(flags & OPT_SHORT) && p->opt) {
 101                switch (opt->type) {
 102                case OPTION_CALLBACK:
 103                        if (!(opt->flags & PARSE_OPT_NOARG))
 104                                break;
 105                        /* FALLTHROUGH */
 106                case OPTION_BOOLEAN:
 107                case OPTION_INCR:
 108                case OPTION_BIT:
 109                case OPTION_SET_UINT:
 110                case OPTION_SET_PTR:
 111                        return opterror(opt, "takes no value", flags);
 112                case OPTION_END:
 113                case OPTION_ARGUMENT:
 114                case OPTION_GROUP:
 115                case OPTION_STRING:
 116                case OPTION_INTEGER:
 117                case OPTION_UINTEGER:
 118                case OPTION_LONG:
 119                case OPTION_U64:
 120                default:
 121                        break;
 122                }
 123        }
 124
 125        if (opt->flags & PARSE_OPT_NOBUILD) {
 126                char reason[128];
 127                bool noarg = false;
 128
 129                err = snprintf(reason, sizeof(reason),
 130                                opt->flags & PARSE_OPT_CANSKIP ?
 131                                        "is being ignored because %s " :
 132                                        "is not available because %s",
 133                                opt->build_opt);
 134                reason[sizeof(reason) - 1] = '\0';
 135
 136                if (err < 0)
 137                        strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
 138                                        "is being ignored" :
 139                                        "is not available",
 140                                        sizeof(reason));
 141
 142                if (!(opt->flags & PARSE_OPT_CANSKIP))
 143                        return opterror(opt, reason, flags);
 144
 145                err = 0;
 146                if (unset)
 147                        noarg = true;
 148                if (opt->flags & PARSE_OPT_NOARG)
 149                        noarg = true;
 150                if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
 151                        noarg = true;
 152
 153                switch (opt->type) {
 154                case OPTION_BOOLEAN:
 155                case OPTION_INCR:
 156                case OPTION_BIT:
 157                case OPTION_SET_UINT:
 158                case OPTION_SET_PTR:
 159                case OPTION_END:
 160                case OPTION_ARGUMENT:
 161                case OPTION_GROUP:
 162                        noarg = true;
 163                        break;
 164                case OPTION_CALLBACK:
 165                case OPTION_STRING:
 166                case OPTION_INTEGER:
 167                case OPTION_UINTEGER:
 168                case OPTION_LONG:
 169                case OPTION_U64:
 170                default:
 171                        break;
 172                }
 173
 174                if (!noarg)
 175                        err = get_arg(p, opt, flags, NULL);
 176                if (err)
 177                        return err;
 178
 179                optwarning(opt, reason, flags);
 180                return 0;
 181        }
 182
 183        switch (opt->type) {
 184        case OPTION_BIT:
 185                if (unset)
 186                        *(int *)opt->value &= ~opt->defval;
 187                else
 188                        *(int *)opt->value |= opt->defval;
 189                return 0;
 190
 191        case OPTION_BOOLEAN:
 192                *(bool *)opt->value = unset ? false : true;
 193                if (opt->set)
 194                        *(bool *)opt->set = true;
 195                return 0;
 196
 197        case OPTION_INCR:
 198                *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
 199                return 0;
 200
 201        case OPTION_SET_UINT:
 202                *(unsigned int *)opt->value = unset ? 0 : opt->defval;
 203                return 0;
 204
 205        case OPTION_SET_PTR:
 206                *(void **)opt->value = unset ? NULL : (void *)opt->defval;
 207                return 0;
 208
 209        case OPTION_STRING:
 210                err = 0;
 211                if (unset)
 212                        *(const char **)opt->value = NULL;
 213                else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
 214                        *(const char **)opt->value = (const char *)opt->defval;
 215                else
 216                        err = get_arg(p, opt, flags, (const char **)opt->value);
 217
 218                if (opt->set)
 219                        *(bool *)opt->set = true;
 220
 221                /* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
 222                if (opt->flags & PARSE_OPT_NOEMPTY) {
 223                        const char *val = *(const char **)opt->value;
 224
 225                        if (!val)
 226                                return err;
 227
 228                        /* Similar to unset if we are given an empty string. */
 229                        if (val[0] == '\0') {
 230                                *(const char **)opt->value = NULL;
 231                                return 0;
 232                        }
 233                }
 234
 235                return err;
 236
 237        case OPTION_CALLBACK:
 238                if (unset)
 239                        return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
 240                if (opt->flags & PARSE_OPT_NOARG)
 241                        return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
 242                if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
 243                        return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
 244                if (get_arg(p, opt, flags, &arg))
 245                        return -1;
 246                return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
 247
 248        case OPTION_INTEGER:
 249                if (unset) {
 250                        *(int *)opt->value = 0;
 251                        return 0;
 252                }
 253                if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
 254                        *(int *)opt->value = opt->defval;
 255                        return 0;
 256                }
 257                if (get_arg(p, opt, flags, &arg))
 258                        return -1;
 259                *(int *)opt->value = strtol(arg, (char **)&s, 10);
 260                if (*s)
 261                        return opterror(opt, "expects a numerical value", flags);
 262                return 0;
 263
 264        case OPTION_UINTEGER:
 265                if (unset) {
 266                        *(unsigned int *)opt->value = 0;
 267                        return 0;
 268                }
 269                if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
 270                        *(unsigned int *)opt->value = opt->defval;
 271                        return 0;
 272                }
 273                if (get_arg(p, opt, flags, &arg))
 274                        return -1;
 275                if (arg[0] == '-')
 276                        return opterror(opt, "expects an unsigned numerical value", flags);
 277                *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
 278                if (*s)
 279                        return opterror(opt, "expects a numerical value", flags);
 280                return 0;
 281
 282        case OPTION_LONG:
 283                if (unset) {
 284                        *(long *)opt->value = 0;
 285                        return 0;
 286                }
 287                if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
 288                        *(long *)opt->value = opt->defval;
 289                        return 0;
 290                }
 291                if (get_arg(p, opt, flags, &arg))
 292                        return -1;
 293                *(long *)opt->value = strtol(arg, (char **)&s, 10);
 294                if (*s)
 295                        return opterror(opt, "expects a numerical value", flags);
 296                return 0;
 297
 298        case OPTION_U64:
 299                if (unset) {
 300                        *(u64 *)opt->value = 0;
 301                        return 0;
 302                }
 303                if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
 304                        *(u64 *)opt->value = opt->defval;
 305                        return 0;
 306                }
 307                if (get_arg(p, opt, flags, &arg))
 308                        return -1;
 309                if (arg[0] == '-')
 310                        return opterror(opt, "expects an unsigned numerical value", flags);
 311                *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
 312                if (*s)
 313                        return opterror(opt, "expects a numerical value", flags);
 314                return 0;
 315
 316        case OPTION_END:
 317        case OPTION_ARGUMENT:
 318        case OPTION_GROUP:
 319        default:
 320                die("should not happen, someone must be hit on the forehead");
 321        }
 322}
 323
 324static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
 325{
 326retry:
 327        for (; options->type != OPTION_END; options++) {
 328                if (options->short_name == *p->opt) {
 329                        p->opt = p->opt[1] ? p->opt + 1 : NULL;
 330                        return get_value(p, options, OPT_SHORT);
 331                }
 332        }
 333
 334        if (options->parent) {
 335                options = options->parent;
 336                goto retry;
 337        }
 338
 339        return -2;
 340}
 341
 342static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
 343                          const struct option *options)
 344{
 345        const char *arg_end = strchr(arg, '=');
 346        const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
 347        int abbrev_flags = 0, ambiguous_flags = 0;
 348
 349        if (!arg_end)
 350                arg_end = arg + strlen(arg);
 351
 352retry:
 353        for (; options->type != OPTION_END; options++) {
 354                const char *rest;
 355                int flags = 0;
 356
 357                if (!options->long_name)
 358                        continue;
 359
 360                rest = skip_prefix(arg, options->long_name);
 361                if (options->type == OPTION_ARGUMENT) {
 362                        if (!rest)
 363                                continue;
 364                        if (*rest == '=')
 365                                return opterror(options, "takes no value", flags);
 366                        if (*rest)
 367                                continue;
 368                        p->out[p->cpidx++] = arg - 2;
 369                        return 0;
 370                }
 371                if (!rest) {
 372                        if (strstarts(options->long_name, "no-")) {
 373                                /*
 374                                 * The long name itself starts with "no-", so
 375                                 * accept the option without "no-" so that users
 376                                 * do not have to enter "no-no-" to get the
 377                                 * negation.
 378                                 */
 379                                rest = skip_prefix(arg, options->long_name + 3);
 380                                if (rest) {
 381                                        flags |= OPT_UNSET;
 382                                        goto match;
 383                                }
 384                                /* Abbreviated case */
 385                                if (strstarts(options->long_name + 3, arg)) {
 386                                        flags |= OPT_UNSET;
 387                                        goto is_abbreviated;
 388                                }
 389                        }
 390                        /* abbreviated? */
 391                        if (!strncmp(options->long_name, arg, arg_end - arg)) {
 392is_abbreviated:
 393                                if (abbrev_option) {
 394                                        /*
 395                                         * If this is abbreviated, it is
 396                                         * ambiguous. So when there is no
 397                                         * exact match later, we need to
 398                                         * error out.
 399                                         */
 400                                        ambiguous_option = abbrev_option;
 401                                        ambiguous_flags = abbrev_flags;
 402                                }
 403                                if (!(flags & OPT_UNSET) && *arg_end)
 404                                        p->opt = arg_end + 1;
 405                                abbrev_option = options;
 406                                abbrev_flags = flags;
 407                                continue;
 408                        }
 409                        /* negated and abbreviated very much? */
 410                        if (strstarts("no-", arg)) {
 411                                flags |= OPT_UNSET;
 412                                goto is_abbreviated;
 413                        }
 414                        /* negated? */
 415                        if (strncmp(arg, "no-", 3))
 416                                continue;
 417                        flags |= OPT_UNSET;
 418                        rest = skip_prefix(arg + 3, options->long_name);
 419                        /* abbreviated and negated? */
 420                        if (!rest && strstarts(options->long_name, arg + 3))
 421                                goto is_abbreviated;
 422                        if (!rest)
 423                                continue;
 424                }
 425match:
 426                if (*rest) {
 427                        if (*rest != '=')
 428                                continue;
 429                        p->opt = rest + 1;
 430                }
 431                return get_value(p, options, flags);
 432        }
 433
 434        if (ambiguous_option) {
 435                 fprintf(stderr,
 436                         " Error: Ambiguous option: %s (could be --%s%s or --%s%s)\n",
 437                         arg,
 438                         (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
 439                         ambiguous_option->long_name,
 440                         (abbrev_flags & OPT_UNSET) ?  "no-" : "",
 441                         abbrev_option->long_name);
 442                 return -1;
 443        }
 444        if (abbrev_option)
 445                return get_value(p, abbrev_option, abbrev_flags);
 446
 447        if (options->parent) {
 448                options = options->parent;
 449                goto retry;
 450        }
 451
 452        return -2;
 453}
 454
 455static void check_typos(const char *arg, const struct option *options)
 456{
 457        if (strlen(arg) < 3)
 458                return;
 459
 460        if (strstarts(arg, "no-")) {
 461                fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
 462                exit(129);
 463        }
 464
 465        for (; options->type != OPTION_END; options++) {
 466                if (!options->long_name)
 467                        continue;
 468                if (strstarts(options->long_name, arg)) {
 469                        fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
 470                        exit(129);
 471                }
 472        }
 473}
 474
 475static void parse_options_start(struct parse_opt_ctx_t *ctx,
 476                                int argc, const char **argv, int flags)
 477{
 478        memset(ctx, 0, sizeof(*ctx));
 479        ctx->argc = argc - 1;
 480        ctx->argv = argv + 1;
 481        ctx->out  = argv;
 482        ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
 483        ctx->flags = flags;
 484        if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
 485            (flags & PARSE_OPT_STOP_AT_NON_OPTION))
 486                die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
 487}
 488
 489static int usage_with_options_internal(const char * const *,
 490                                       const struct option *, int,
 491                                       struct parse_opt_ctx_t *);
 492
 493static int parse_options_step(struct parse_opt_ctx_t *ctx,
 494                              const struct option *options,
 495                              const char * const usagestr[])
 496{
 497        int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
 498        int excl_short_opt = 1;
 499        const char *arg;
 500
 501        /* we must reset ->opt, unknown short option leave it dangling */
 502        ctx->opt = NULL;
 503
 504        for (; ctx->argc; ctx->argc--, ctx->argv++) {
 505                arg = ctx->argv[0];
 506                if (*arg != '-' || !arg[1]) {
 507                        if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
 508                                break;
 509                        ctx->out[ctx->cpidx++] = ctx->argv[0];
 510                        continue;
 511                }
 512
 513                if (arg[1] != '-') {
 514                        ctx->opt = ++arg;
 515                        if (internal_help && *ctx->opt == 'h') {
 516                                return usage_with_options_internal(usagestr, options, 0, ctx);
 517                        }
 518                        switch (parse_short_opt(ctx, options)) {
 519                        case -1:
 520                                return parse_options_usage(usagestr, options, arg, 1);
 521                        case -2:
 522                                goto unknown;
 523                        case -3:
 524                                goto exclusive;
 525                        default:
 526                                break;
 527                        }
 528                        if (ctx->opt)
 529                                check_typos(arg, options);
 530                        while (ctx->opt) {
 531                                if (internal_help && *ctx->opt == 'h')
 532                                        return usage_with_options_internal(usagestr, options, 0, ctx);
 533                                arg = ctx->opt;
 534                                switch (parse_short_opt(ctx, options)) {
 535                                case -1:
 536                                        return parse_options_usage(usagestr, options, arg, 1);
 537                                case -2:
 538                                        /* fake a short option thing to hide the fact that we may have
 539                                         * started to parse aggregated stuff
 540                                         *
 541                                         * This is leaky, too bad.
 542                                         */
 543                                        ctx->argv[0] = strdup(ctx->opt - 1);
 544                                        *(char *)ctx->argv[0] = '-';
 545                                        goto unknown;
 546                                case -3:
 547                                        goto exclusive;
 548                                default:
 549                                        break;
 550                                }
 551                        }
 552                        continue;
 553                }
 554
 555                if (!arg[2]) { /* "--" */
 556                        if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
 557                                ctx->argc--;
 558                                ctx->argv++;
 559                        }
 560                        break;
 561                }
 562
 563                arg += 2;
 564                if (internal_help && !strcmp(arg, "help-all"))
 565                        return usage_with_options_internal(usagestr, options, 1, ctx);
 566                if (internal_help && !strcmp(arg, "help"))
 567                        return usage_with_options_internal(usagestr, options, 0, ctx);
 568                if (!strcmp(arg, "list-opts"))
 569                        return PARSE_OPT_LIST_OPTS;
 570                if (!strcmp(arg, "list-cmds"))
 571                        return PARSE_OPT_LIST_SUBCMDS;
 572                switch (parse_long_opt(ctx, arg, options)) {
 573                case -1:
 574                        return parse_options_usage(usagestr, options, arg, 0);
 575                case -2:
 576                        goto unknown;
 577                case -3:
 578                        excl_short_opt = 0;
 579                        goto exclusive;
 580                default:
 581                        break;
 582                }
 583                continue;
 584unknown:
 585                if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
 586                        return PARSE_OPT_UNKNOWN;
 587                ctx->out[ctx->cpidx++] = ctx->argv[0];
 588                ctx->opt = NULL;
 589        }
 590        return PARSE_OPT_DONE;
 591
 592exclusive:
 593        parse_options_usage(usagestr, options, arg, excl_short_opt);
 594        if ((excl_short_opt && ctx->excl_opt->short_name) ||
 595            ctx->excl_opt->long_name == NULL) {
 596                char opt = ctx->excl_opt->short_name;
 597                parse_options_usage(NULL, options, &opt, 1);
 598        } else {
 599                parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
 600        }
 601        return PARSE_OPT_HELP;
 602}
 603
 604static int parse_options_end(struct parse_opt_ctx_t *ctx)
 605{
 606        memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
 607        ctx->out[ctx->cpidx + ctx->argc] = NULL;
 608        return ctx->cpidx + ctx->argc;
 609}
 610
 611int parse_options_subcommand(int argc, const char **argv, const struct option *options,
 612                        const char *const subcommands[], const char *usagestr[], int flags)
 613{
 614        struct parse_opt_ctx_t ctx;
 615
 616        /* build usage string if it's not provided */
 617        if (subcommands && !usagestr[0]) {
 618                char *buf = NULL;
 619
 620                astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
 621
 622                for (int i = 0; subcommands[i]; i++) {
 623                        if (i)
 624                                astrcat(&buf, "|");
 625                        astrcat(&buf, subcommands[i]);
 626                }
 627                astrcat(&buf, "}");
 628
 629                usagestr[0] = buf;
 630        }
 631
 632        parse_options_start(&ctx, argc, argv, flags);
 633        switch (parse_options_step(&ctx, options, usagestr)) {
 634        case PARSE_OPT_HELP:
 635                exit(129);
 636        case PARSE_OPT_DONE:
 637                break;
 638        case PARSE_OPT_LIST_OPTS:
 639                while (options->type != OPTION_END) {
 640                        if (options->long_name)
 641                                printf("--%s ", options->long_name);
 642                        options++;
 643                }
 644                putchar('\n');
 645                exit(130);
 646        case PARSE_OPT_LIST_SUBCMDS:
 647                if (subcommands) {
 648                        for (int i = 0; subcommands[i]; i++)
 649                                printf("%s ", subcommands[i]);
 650                }
 651                putchar('\n');
 652                exit(130);
 653        default: /* PARSE_OPT_UNKNOWN */
 654                if (ctx.argv[0][1] == '-')
 655                        astrcatf(&error_buf, "unknown option `%s'",
 656                                 ctx.argv[0] + 2);
 657                else
 658                        astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
 659                usage_with_options(usagestr, options);
 660        }
 661
 662        return parse_options_end(&ctx);
 663}
 664
 665int parse_options(int argc, const char **argv, const struct option *options,
 666                  const char * const usagestr[], int flags)
 667{
 668        return parse_options_subcommand(argc, argv, options, NULL,
 669                                        (const char **) usagestr, flags);
 670}
 671
 672#define USAGE_OPTS_WIDTH 24
 673#define USAGE_GAP         2
 674
 675static void print_option_help(const struct option *opts, int full)
 676{
 677        size_t pos;
 678        int pad;
 679
 680        if (opts->type == OPTION_GROUP) {
 681                fputc('\n', stderr);
 682                if (*opts->help)
 683                        fprintf(stderr, "%s\n", opts->help);
 684                return;
 685        }
 686        if (!full && (opts->flags & PARSE_OPT_HIDDEN))
 687                return;
 688        if (opts->flags & PARSE_OPT_DISABLED)
 689                return;
 690
 691        pos = fprintf(stderr, "    ");
 692        if (opts->short_name)
 693                pos += fprintf(stderr, "-%c", opts->short_name);
 694        else
 695                pos += fprintf(stderr, "    ");
 696
 697        if (opts->long_name && opts->short_name)
 698                pos += fprintf(stderr, ", ");
 699        if (opts->long_name)
 700                pos += fprintf(stderr, "--%s", opts->long_name);
 701
 702        switch (opts->type) {
 703        case OPTION_ARGUMENT:
 704                break;
 705        case OPTION_LONG:
 706        case OPTION_U64:
 707        case OPTION_INTEGER:
 708        case OPTION_UINTEGER:
 709                if (opts->flags & PARSE_OPT_OPTARG)
 710                        if (opts->long_name)
 711                                pos += fprintf(stderr, "[=<n>]");
 712                        else
 713                                pos += fprintf(stderr, "[<n>]");
 714                else
 715                        pos += fprintf(stderr, " <n>");
 716                break;
 717        case OPTION_CALLBACK:
 718                if (opts->flags & PARSE_OPT_NOARG)
 719                        break;
 720                /* FALLTHROUGH */
 721        case OPTION_STRING:
 722                if (opts->argh) {
 723                        if (opts->flags & PARSE_OPT_OPTARG)
 724                                if (opts->long_name)
 725                                        pos += fprintf(stderr, "[=<%s>]", opts->argh);
 726                                else
 727                                        pos += fprintf(stderr, "[<%s>]", opts->argh);
 728                        else
 729                                pos += fprintf(stderr, " <%s>", opts->argh);
 730                } else {
 731                        if (opts->flags & PARSE_OPT_OPTARG)
 732                                if (opts->long_name)
 733                                        pos += fprintf(stderr, "[=...]");
 734                                else
 735                                        pos += fprintf(stderr, "[...]");
 736                        else
 737                                pos += fprintf(stderr, " ...");
 738                }
 739                break;
 740        default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
 741        case OPTION_END:
 742        case OPTION_GROUP:
 743        case OPTION_BIT:
 744        case OPTION_BOOLEAN:
 745        case OPTION_INCR:
 746        case OPTION_SET_UINT:
 747        case OPTION_SET_PTR:
 748                break;
 749        }
 750
 751        if (pos <= USAGE_OPTS_WIDTH)
 752                pad = USAGE_OPTS_WIDTH - pos;
 753        else {
 754                fputc('\n', stderr);
 755                pad = USAGE_OPTS_WIDTH;
 756        }
 757        fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
 758        if (opts->flags & PARSE_OPT_NOBUILD)
 759                fprintf(stderr, "%*s(not built-in because %s)\n",
 760                        USAGE_OPTS_WIDTH + USAGE_GAP, "",
 761                        opts->build_opt);
 762}
 763
 764static int option__cmp(const void *va, const void *vb)
 765{
 766        const struct option *a = va, *b = vb;
 767        int sa = tolower(a->short_name), sb = tolower(b->short_name), ret;
 768
 769        if (sa == 0)
 770                sa = 'z' + 1;
 771        if (sb == 0)
 772                sb = 'z' + 1;
 773
 774        ret = sa - sb;
 775
 776        if (ret == 0) {
 777                const char *la = a->long_name ?: "",
 778                           *lb = b->long_name ?: "";
 779                ret = strcmp(la, lb);
 780        }
 781
 782        return ret;
 783}
 784
 785static struct option *options__order(const struct option *opts)
 786{
 787        int nr_opts = 0, len;
 788        const struct option *o = opts;
 789        struct option *ordered;
 790
 791        for (o = opts; o->type != OPTION_END; o++)
 792                ++nr_opts;
 793
 794        len = sizeof(*o) * (nr_opts + 1);
 795        ordered = malloc(len);
 796        if (!ordered)
 797                goto out;
 798        memcpy(ordered, opts, len);
 799
 800        qsort(ordered, nr_opts, sizeof(*o), option__cmp);
 801out:
 802        return ordered;
 803}
 804
 805static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
 806{
 807        int i;
 808
 809        for (i = 1; i < ctx->argc; ++i) {
 810                const char *arg = ctx->argv[i];
 811
 812                if (arg[0] != '-') {
 813                        if (arg[1] == '\0') {
 814                                if (arg[0] == opt->short_name)
 815                                        return true;
 816                                continue;
 817                        }
 818
 819                        if (opt->long_name && strcmp(opt->long_name, arg) == 0)
 820                                return true;
 821
 822                        if (opt->help && strcasestr(opt->help, arg) != NULL)
 823                                return true;
 824
 825                        continue;
 826                }
 827
 828                if (arg[1] == opt->short_name ||
 829                    (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
 830                        return true;
 831        }
 832
 833        return false;
 834}
 835
 836static int usage_with_options_internal(const char * const *usagestr,
 837                                       const struct option *opts, int full,
 838                                       struct parse_opt_ctx_t *ctx)
 839{
 840        struct option *ordered;
 841
 842        if (!usagestr)
 843                return PARSE_OPT_HELP;
 844
 845        setup_pager();
 846
 847        if (error_buf) {
 848                fprintf(stderr, "  Error: %s\n", error_buf);
 849                zfree(&error_buf);
 850        }
 851
 852        fprintf(stderr, "\n Usage: %s\n", *usagestr++);
 853        while (*usagestr && **usagestr)
 854                fprintf(stderr, "    or: %s\n", *usagestr++);
 855        while (*usagestr) {
 856                fprintf(stderr, "%s%s\n",
 857                                **usagestr ? "    " : "",
 858                                *usagestr);
 859                usagestr++;
 860        }
 861
 862        if (opts->type != OPTION_GROUP)
 863                fputc('\n', stderr);
 864
 865        ordered = options__order(opts);
 866        if (ordered)
 867                opts = ordered;
 868
 869        for (  ; opts->type != OPTION_END; opts++) {
 870                if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
 871                        continue;
 872                print_option_help(opts, full);
 873        }
 874
 875        fputc('\n', stderr);
 876
 877        free(ordered);
 878
 879        return PARSE_OPT_HELP;
 880}
 881
 882void usage_with_options(const char * const *usagestr,
 883                        const struct option *opts)
 884{
 885        usage_with_options_internal(usagestr, opts, 0, NULL);
 886        exit(129);
 887}
 888
 889void usage_with_options_msg(const char * const *usagestr,
 890                            const struct option *opts, const char *fmt, ...)
 891{
 892        va_list ap;
 893        char *tmp = error_buf;
 894
 895        va_start(ap, fmt);
 896        if (vasprintf(&error_buf, fmt, ap) == -1)
 897                die("vasprintf failed");
 898        va_end(ap);
 899
 900        free(tmp);
 901
 902        usage_with_options_internal(usagestr, opts, 0, NULL);
 903        exit(129);
 904}
 905
 906int parse_options_usage(const char * const *usagestr,
 907                        const struct option *opts,
 908                        const char *optstr, bool short_opt)
 909{
 910        if (!usagestr)
 911                goto opt;
 912
 913        fprintf(stderr, "\n Usage: %s\n", *usagestr++);
 914        while (*usagestr && **usagestr)
 915                fprintf(stderr, "    or: %s\n", *usagestr++);
 916        while (*usagestr) {
 917                fprintf(stderr, "%s%s\n",
 918                                **usagestr ? "    " : "",
 919                                *usagestr);
 920                usagestr++;
 921        }
 922        fputc('\n', stderr);
 923
 924opt:
 925        for (  ; opts->type != OPTION_END; opts++) {
 926                if (short_opt) {
 927                        if (opts->short_name == *optstr) {
 928                                print_option_help(opts, 0);
 929                                break;
 930                        }
 931                        continue;
 932                }
 933
 934                if (opts->long_name == NULL)
 935                        continue;
 936
 937                if (strstarts(opts->long_name, optstr))
 938                        print_option_help(opts, 0);
 939                if (strstarts("no-", optstr) &&
 940                    strstarts(opts->long_name, optstr + 3))
 941                        print_option_help(opts, 0);
 942        }
 943
 944        return PARSE_OPT_HELP;
 945}
 946
 947
 948int parse_opt_verbosity_cb(const struct option *opt,
 949                           const char *arg __maybe_unused,
 950                           int unset)
 951{
 952        int *target = opt->value;
 953
 954        if (unset)
 955                /* --no-quiet, --no-verbose */
 956                *target = 0;
 957        else if (opt->short_name == 'v') {
 958                if (*target >= 0)
 959                        (*target)++;
 960                else
 961                        *target = 1;
 962        } else {
 963                if (*target <= 0)
 964                        (*target)--;
 965                else
 966                        *target = -1;
 967        }
 968        return 0;
 969}
 970
 971static struct option *
 972find_option(struct option *opts, int shortopt, const char *longopt)
 973{
 974        for (; opts->type != OPTION_END; opts++) {
 975                if ((shortopt && opts->short_name == shortopt) ||
 976                    (opts->long_name && longopt &&
 977                     !strcmp(opts->long_name, longopt)))
 978                        return opts;
 979        }
 980        return NULL;
 981}
 982
 983void set_option_flag(struct option *opts, int shortopt, const char *longopt,
 984                     int flag)
 985{
 986        struct option *opt = find_option(opts, shortopt, longopt);
 987
 988        if (opt)
 989                opt->flags |= flag;
 990        return;
 991}
 992
 993void set_option_nobuild(struct option *opts, int shortopt,
 994                        const char *longopt,
 995                        const char *build_opt,
 996                        bool can_skip)
 997{
 998        struct option *opt = find_option(opts, shortopt, longopt);
 999
1000        if (!opt)
1001                return;
1002
1003        opt->flags |= PARSE_OPT_NOBUILD;
1004        opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
1005        opt->build_opt = build_opt;
1006}
1007