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