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