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