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