Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
16char *error_buf;
17
18static 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
30static 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
36static 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
46static 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
67static 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
322static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
323{
324retry:
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
340static 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
350retry:
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)) {
390is_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 }
423match:
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
453static 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
473static 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
487static int usage_with_options_internal(const char * const *,
488 const struct option *, int,
489 struct parse_opt_ctx_t *);
490
491static 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;
582unknown:
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
590exclusive:
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
602static 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
609int 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
663int 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
673static 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
762static 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
783static 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);
799out:
800 return ordered;
801}
802
803static 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
834static 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
880void 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
887void 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
904int 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
922opt:
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
946int 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
969static struct option *
970find_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
981void 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
991void 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}