parse-options.c (24345B)
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 18char *error_buf; 19 20static 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 32static 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 38static 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 48static 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 69static 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 345static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options) 346{ 347retry: 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 363static 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 373retry: 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)) { 413is_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 } 446match: 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 476static 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 496static 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 510static int usage_with_options_internal(const char * const *, 511 const struct option *, int, 512 struct parse_opt_ctx_t *); 513 514static 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; 605unknown: 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 613exclusive: 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 625static 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 632int 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 686int 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 696static 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 786static 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 807static struct option *options__order(const struct option *opts) 808{ 809 int nr_opts = 0, nr_group = 0, len; 810 const struct option *o = opts; 811 struct option *opt, *ordered, *group; 812 813 for (o = opts; o->type != OPTION_END; o++) 814 ++nr_opts; 815 816 len = sizeof(*o) * (nr_opts + 1); 817 ordered = malloc(len); 818 if (!ordered) 819 goto out; 820 memcpy(ordered, opts, len); 821 822 /* sort each option group individually */ 823 for (opt = group = ordered; opt->type != OPTION_END; opt++) { 824 if (opt->type == OPTION_GROUP) { 825 qsort(group, nr_group, sizeof(*opt), option__cmp); 826 group = opt + 1; 827 nr_group = 0; 828 continue; 829 } 830 nr_group++; 831 } 832 qsort(group, nr_group, sizeof(*opt), option__cmp); 833 834out: 835 return ordered; 836} 837 838static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx) 839{ 840 int i; 841 842 for (i = 1; i < ctx->argc; ++i) { 843 const char *arg = ctx->argv[i]; 844 845 if (arg[0] != '-') { 846 if (arg[1] == '\0') { 847 if (arg[0] == opt->short_name) 848 return true; 849 continue; 850 } 851 852 if (opt->long_name && strcmp(opt->long_name, arg) == 0) 853 return true; 854 855 if (opt->help && strcasestr(opt->help, arg) != NULL) 856 return true; 857 858 continue; 859 } 860 861 if (arg[1] == opt->short_name || 862 (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0)) 863 return true; 864 } 865 866 return false; 867} 868 869static int usage_with_options_internal(const char * const *usagestr, 870 const struct option *opts, int full, 871 struct parse_opt_ctx_t *ctx) 872{ 873 struct option *ordered; 874 875 if (!usagestr) 876 return PARSE_OPT_HELP; 877 878 setup_pager(); 879 880 if (error_buf) { 881 fprintf(stderr, " Error: %s\n", error_buf); 882 zfree(&error_buf); 883 } 884 885 fprintf(stderr, "\n Usage: %s\n", *usagestr++); 886 while (*usagestr && **usagestr) 887 fprintf(stderr, " or: %s\n", *usagestr++); 888 while (*usagestr) { 889 fprintf(stderr, "%s%s\n", 890 **usagestr ? " " : "", 891 *usagestr); 892 usagestr++; 893 } 894 895 if (opts->type != OPTION_GROUP) 896 fputc('\n', stderr); 897 898 ordered = options__order(opts); 899 if (ordered) 900 opts = ordered; 901 902 for ( ; opts->type != OPTION_END; opts++) { 903 if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx)) 904 continue; 905 print_option_help(opts, full); 906 } 907 908 fputc('\n', stderr); 909 910 free(ordered); 911 912 return PARSE_OPT_HELP; 913} 914 915void usage_with_options(const char * const *usagestr, 916 const struct option *opts) 917{ 918 usage_with_options_internal(usagestr, opts, 0, NULL); 919 exit(129); 920} 921 922void usage_with_options_msg(const char * const *usagestr, 923 const struct option *opts, const char *fmt, ...) 924{ 925 va_list ap; 926 char *tmp = error_buf; 927 928 va_start(ap, fmt); 929 if (vasprintf(&error_buf, fmt, ap) == -1) 930 die("vasprintf failed"); 931 va_end(ap); 932 933 free(tmp); 934 935 usage_with_options_internal(usagestr, opts, 0, NULL); 936 exit(129); 937} 938 939int parse_options_usage(const char * const *usagestr, 940 const struct option *opts, 941 const char *optstr, bool short_opt) 942{ 943 if (!usagestr) 944 goto opt; 945 946 fprintf(stderr, "\n Usage: %s\n", *usagestr++); 947 while (*usagestr && **usagestr) 948 fprintf(stderr, " or: %s\n", *usagestr++); 949 while (*usagestr) { 950 fprintf(stderr, "%s%s\n", 951 **usagestr ? " " : "", 952 *usagestr); 953 usagestr++; 954 } 955 fputc('\n', stderr); 956 957opt: 958 for ( ; opts->type != OPTION_END; opts++) { 959 if (short_opt) { 960 if (opts->short_name == *optstr) { 961 print_option_help(opts, 0); 962 break; 963 } 964 continue; 965 } 966 967 if (opts->long_name == NULL) 968 continue; 969 970 if (strstarts(opts->long_name, optstr)) 971 print_option_help(opts, 0); 972 if (strstarts("no-", optstr) && 973 strstarts(opts->long_name, optstr + 3)) 974 print_option_help(opts, 0); 975 } 976 977 return PARSE_OPT_HELP; 978} 979 980 981int parse_opt_verbosity_cb(const struct option *opt, 982 const char *arg __maybe_unused, 983 int unset) 984{ 985 int *target = opt->value; 986 987 if (unset) 988 /* --no-quiet, --no-verbose */ 989 *target = 0; 990 else if (opt->short_name == 'v') { 991 if (*target >= 0) 992 (*target)++; 993 else 994 *target = 1; 995 } else { 996 if (*target <= 0) 997 (*target)--; 998 else 999 *target = -1; 1000 } 1001 return 0; 1002} 1003 1004static struct option * 1005find_option(struct option *opts, int shortopt, const char *longopt) 1006{ 1007 for (; opts->type != OPTION_END; opts++) { 1008 if ((shortopt && opts->short_name == shortopt) || 1009 (opts->long_name && longopt && 1010 !strcmp(opts->long_name, longopt))) 1011 return opts; 1012 } 1013 return NULL; 1014} 1015 1016void set_option_flag(struct option *opts, int shortopt, const char *longopt, 1017 int flag) 1018{ 1019 struct option *opt = find_option(opts, shortopt, longopt); 1020 1021 if (opt) 1022 opt->flags |= flag; 1023 return; 1024} 1025 1026void set_option_nobuild(struct option *opts, int shortopt, 1027 const char *longopt, 1028 const char *build_opt, 1029 bool can_skip) 1030{ 1031 struct option *opt = find_option(opts, shortopt, longopt); 1032 1033 if (!opt) 1034 return; 1035 1036 opt->flags |= PARSE_OPT_NOBUILD; 1037 opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0; 1038 opt->build_opt = build_opt; 1039}