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