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