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