root/tools/lib/subcmd/parse-options.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. opterror
  2. skip_prefix
  3. optwarning
  4. get_arg
  5. get_value
  6. parse_short_opt
  7. parse_long_opt
  8. check_typos
  9. parse_options_start
  10. parse_options_step
  11. parse_options_end
  12. parse_options_subcommand
  13. parse_options
  14. print_option_help
  15. option__cmp
  16. options__order
  17. option__in_argv
  18. usage_with_options_internal
  19. usage_with_options
  20. usage_with_options_msg
  21. parse_options_usage
  22. parse_opt_verbosity_cb
  23. find_option
  24. set_option_flag
  25. set_option_nobuild

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

/* [<][>][^][v][top][bottom][index][help] */