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