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 } 1026