blob: 359bfa77f39cdebac7df82876b227d1a63975c39 [file] [log] [blame]
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -06001#include <linux/compiler.h>
Arnaldo Carvalho de Melo96395cb2017-04-26 15:49:21 -03002#include <linux/string.h>
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -06003#include <linux/types.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <stdint.h>
7#include <string.h>
8#include <ctype.h>
Josh Poimboeuf901421a2015-12-15 09:39:36 -06009#include "subcmd-util.h"
Ingo Molnar07800602009-04-20 15:00:56 +020010#include "parse-options.h"
Josh Poimboeuf096d3552015-12-15 09:39:35 -060011#include "subcmd-config.h"
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -060012#include "pager.h"
Ingo Molnar07800602009-04-20 15:00:56 +020013
14#define OPT_SHORT 1
15#define OPT_UNSET 2
16
Josh Poimboeuf901421a2015-12-15 09:39:36 -060017char *error_buf;
Namhyung Kim01b19452015-10-25 00:49:26 +090018
Ingo Molnar07800602009-04-20 15:00:56 +020019static int opterror(const struct option *opt, const char *reason, int flags)
20{
21 if (flags & OPT_SHORT)
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -060022 fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
23 else if (flags & OPT_UNSET)
24 fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
25 else
26 fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
27
28 return -1;
29}
30
31static const char *skip_prefix(const char *str, const char *prefix)
32{
33 size_t len = strlen(prefix);
34 return strncmp(str, prefix, len) ? NULL : str + len;
Ingo Molnar07800602009-04-20 15:00:56 +020035}
36
Wang Nan48e1cab2015-12-14 10:39:22 +000037static void optwarning(const struct option *opt, const char *reason, int flags)
38{
39 if (flags & OPT_SHORT)
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -060040 fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
Wang Nan48e1cab2015-12-14 10:39:22 +000041 else if (flags & OPT_UNSET)
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -060042 fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
Wang Nan48e1cab2015-12-14 10:39:22 +000043 else
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -060044 fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
Wang Nan48e1cab2015-12-14 10:39:22 +000045}
46
Ingo Molnar07800602009-04-20 15:00:56 +020047static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
48 int flags, const char **arg)
49{
Wang Nan48e1cab2015-12-14 10:39:22 +000050 const char *res;
51
Ingo Molnar07800602009-04-20 15:00:56 +020052 if (p->opt) {
Wang Nan48e1cab2015-12-14 10:39:22 +000053 res = p->opt;
Ingo Molnar07800602009-04-20 15:00:56 +020054 p->opt = NULL;
Frederic Weisbecker5a4b1812009-07-02 17:58:20 +020055 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
56 **(p->argv + 1) == '-')) {
Wang Nan48e1cab2015-12-14 10:39:22 +000057 res = (const char *)opt->defval;
Ingo Molnar07800602009-04-20 15:00:56 +020058 } else if (p->argc > 1) {
59 p->argc--;
Wang Nan48e1cab2015-12-14 10:39:22 +000060 res = *++p->argv;
Ingo Molnar07800602009-04-20 15:00:56 +020061 } else
62 return opterror(opt, "requires a value", flags);
Wang Nan48e1cab2015-12-14 10:39:22 +000063 if (arg)
64 *arg = res;
Ingo Molnar07800602009-04-20 15:00:56 +020065 return 0;
66}
67
68static int get_value(struct parse_opt_ctx_t *p,
69 const struct option *opt, int flags)
70{
Ingo Molnar233f0b92009-06-03 21:48:40 +020071 const char *s, *arg = NULL;
Ingo Molnar07800602009-04-20 15:00:56 +020072 const int unset = flags & OPT_UNSET;
Wang Nan0c8c2072015-03-13 12:51:54 +000073 int err;
Ingo Molnar07800602009-04-20 15:00:56 +020074
75 if (unset && p->opt)
76 return opterror(opt, "takes no value", flags);
77 if (unset && (opt->flags & PARSE_OPT_NONEG))
78 return opterror(opt, "isn't available", flags);
Namhyung Kimd152d1b2014-10-23 00:15:45 +090079 if (opt->flags & PARSE_OPT_DISABLED)
80 return opterror(opt, "is not usable", flags);
Ingo Molnar07800602009-04-20 15:00:56 +020081
Namhyung Kim42bd71d2014-10-23 00:15:48 +090082 if (opt->flags & PARSE_OPT_EXCLUSIVE) {
Namhyung Kim5594b552015-01-10 19:33:45 +090083 if (p->excl_opt && p->excl_opt != opt) {
Namhyung Kim42bd71d2014-10-23 00:15:48 +090084 char msg[128];
85
86 if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
87 p->excl_opt->long_name == NULL) {
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -060088 snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
89 p->excl_opt->short_name);
Namhyung Kim42bd71d2014-10-23 00:15:48 +090090 } else {
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -060091 snprintf(msg, sizeof(msg), "cannot be used with %s",
92 p->excl_opt->long_name);
Namhyung Kim42bd71d2014-10-23 00:15:48 +090093 }
94 opterror(opt, msg, flags);
95 return -3;
96 }
97 p->excl_opt = opt;
98 }
Ingo Molnar07800602009-04-20 15:00:56 +020099 if (!(flags & OPT_SHORT) && p->opt) {
100 switch (opt->type) {
101 case OPTION_CALLBACK:
102 if (!(opt->flags & PARSE_OPT_NOARG))
103 break;
104 /* FALLTHROUGH */
105 case OPTION_BOOLEAN:
Ian Munsiec0555642010-04-13 18:37:33 +1000106 case OPTION_INCR:
Ingo Molnar07800602009-04-20 15:00:56 +0200107 case OPTION_BIT:
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -0300108 case OPTION_SET_UINT:
Ingo Molnar07800602009-04-20 15:00:56 +0200109 case OPTION_SET_PTR:
110 return opterror(opt, "takes no value", flags);
Ingo Molnar83a09442009-08-15 12:26:57 +0200111 case OPTION_END:
112 case OPTION_ARGUMENT:
113 case OPTION_GROUP:
114 case OPTION_STRING:
115 case OPTION_INTEGER:
Arnaldo Carvalho de Meloc100edb2010-05-17 15:30:00 -0300116 case OPTION_UINTEGER:
Ingo Molnar83a09442009-08-15 12:26:57 +0200117 case OPTION_LONG:
Arnaldo Carvalho de Melo6ba85ce2010-05-17 12:16:48 -0300118 case OPTION_U64:
Ingo Molnar07800602009-04-20 15:00:56 +0200119 default:
120 break;
121 }
122 }
123
Wang Nan48e1cab2015-12-14 10:39:22 +0000124 if (opt->flags & PARSE_OPT_NOBUILD) {
125 char reason[128];
126 bool noarg = false;
127
128 err = snprintf(reason, sizeof(reason),
129 opt->flags & PARSE_OPT_CANSKIP ?
130 "is being ignored because %s " :
131 "is not available because %s",
132 opt->build_opt);
133 reason[sizeof(reason) - 1] = '\0';
134
135 if (err < 0)
136 strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
137 "is being ignored" :
138 "is not available",
139 sizeof(reason));
140
141 if (!(opt->flags & PARSE_OPT_CANSKIP))
142 return opterror(opt, reason, flags);
143
144 err = 0;
145 if (unset)
146 noarg = true;
147 if (opt->flags & PARSE_OPT_NOARG)
148 noarg = true;
149 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
150 noarg = true;
151
152 switch (opt->type) {
153 case OPTION_BOOLEAN:
154 case OPTION_INCR:
155 case OPTION_BIT:
156 case OPTION_SET_UINT:
157 case OPTION_SET_PTR:
158 case OPTION_END:
159 case OPTION_ARGUMENT:
160 case OPTION_GROUP:
161 noarg = true;
162 break;
163 case OPTION_CALLBACK:
164 case OPTION_STRING:
165 case OPTION_INTEGER:
166 case OPTION_UINTEGER:
167 case OPTION_LONG:
168 case OPTION_U64:
169 default:
170 break;
171 }
172
173 if (!noarg)
174 err = get_arg(p, opt, flags, NULL);
175 if (err)
176 return err;
177
178 optwarning(opt, reason, flags);
179 return 0;
180 }
181
Ingo Molnar07800602009-04-20 15:00:56 +0200182 switch (opt->type) {
183 case OPTION_BIT:
184 if (unset)
185 *(int *)opt->value &= ~opt->defval;
186 else
187 *(int *)opt->value |= opt->defval;
188 return 0;
189
190 case OPTION_BOOLEAN:
Ian Munsiec0555642010-04-13 18:37:33 +1000191 *(bool *)opt->value = unset ? false : true;
Adrian Hunter167faf32013-11-18 11:55:56 +0200192 if (opt->set)
193 *(bool *)opt->set = true;
Ian Munsiec0555642010-04-13 18:37:33 +1000194 return 0;
195
196 case OPTION_INCR:
Ingo Molnar07800602009-04-20 15:00:56 +0200197 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
198 return 0;
199
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -0300200 case OPTION_SET_UINT:
201 *(unsigned int *)opt->value = unset ? 0 : opt->defval;
Ingo Molnar07800602009-04-20 15:00:56 +0200202 return 0;
203
204 case OPTION_SET_PTR:
205 *(void **)opt->value = unset ? NULL : (void *)opt->defval;
206 return 0;
207
208 case OPTION_STRING:
Wang Nan0c8c2072015-03-13 12:51:54 +0000209 err = 0;
Ingo Molnar07800602009-04-20 15:00:56 +0200210 if (unset)
211 *(const char **)opt->value = NULL;
212 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
213 *(const char **)opt->value = (const char *)opt->defval;
214 else
Wang Nan0c8c2072015-03-13 12:51:54 +0000215 err = get_arg(p, opt, flags, (const char **)opt->value);
216
Jiri Olsab66fb1d2017-01-03 09:19:54 +0100217 if (opt->set)
218 *(bool *)opt->set = true;
219
Wang Nan0c8c2072015-03-13 12:51:54 +0000220 /* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
221 if (opt->flags & PARSE_OPT_NOEMPTY) {
222 const char *val = *(const char **)opt->value;
223
224 if (!val)
225 return err;
226
227 /* Similar to unset if we are given an empty string. */
228 if (val[0] == '\0') {
229 *(const char **)opt->value = NULL;
230 return 0;
231 }
232 }
233
234 return err;
Ingo Molnar07800602009-04-20 15:00:56 +0200235
236 case OPTION_CALLBACK:
237 if (unset)
238 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
239 if (opt->flags & PARSE_OPT_NOARG)
240 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
241 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
242 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
243 if (get_arg(p, opt, flags, &arg))
244 return -1;
245 return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
246
247 case OPTION_INTEGER:
248 if (unset) {
249 *(int *)opt->value = 0;
250 return 0;
251 }
252 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
253 *(int *)opt->value = opt->defval;
254 return 0;
255 }
256 if (get_arg(p, opt, flags, &arg))
257 return -1;
258 *(int *)opt->value = strtol(arg, (char **)&s, 10);
259 if (*s)
260 return opterror(opt, "expects a numerical value", flags);
261 return 0;
262
Arnaldo Carvalho de Meloc100edb2010-05-17 15:30:00 -0300263 case OPTION_UINTEGER:
264 if (unset) {
265 *(unsigned int *)opt->value = 0;
266 return 0;
267 }
268 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
269 *(unsigned int *)opt->value = opt->defval;
270 return 0;
271 }
272 if (get_arg(p, opt, flags, &arg))
273 return -1;
Arnaldo Carvalho de Melob9889712017-02-14 13:55:40 -0300274 if (arg[0] == '-')
275 return opterror(opt, "expects an unsigned numerical value", flags);
Arnaldo Carvalho de Meloc100edb2010-05-17 15:30:00 -0300276 *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
277 if (*s)
278 return opterror(opt, "expects a numerical value", flags);
279 return 0;
280
Peter Zijlstrae61078a2009-06-03 11:24:33 +0200281 case OPTION_LONG:
282 if (unset) {
283 *(long *)opt->value = 0;
284 return 0;
285 }
286 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
287 *(long *)opt->value = opt->defval;
288 return 0;
289 }
290 if (get_arg(p, opt, flags, &arg))
291 return -1;
292 *(long *)opt->value = strtol(arg, (char **)&s, 10);
293 if (*s)
294 return opterror(opt, "expects a numerical value", flags);
295 return 0;
296
Arnaldo Carvalho de Melo6ba85ce2010-05-17 12:16:48 -0300297 case OPTION_U64:
298 if (unset) {
299 *(u64 *)opt->value = 0;
300 return 0;
301 }
302 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
303 *(u64 *)opt->value = opt->defval;
304 return 0;
305 }
306 if (get_arg(p, opt, flags, &arg))
307 return -1;
Arnaldo Carvalho de Melob9889712017-02-14 13:55:40 -0300308 if (arg[0] == '-')
309 return opterror(opt, "expects an unsigned numerical value", flags);
Arnaldo Carvalho de Melo6ba85ce2010-05-17 12:16:48 -0300310 *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
311 if (*s)
312 return opterror(opt, "expects a numerical value", flags);
313 return 0;
314
Ingo Molnar83a09442009-08-15 12:26:57 +0200315 case OPTION_END:
316 case OPTION_ARGUMENT:
317 case OPTION_GROUP:
Ingo Molnar07800602009-04-20 15:00:56 +0200318 default:
319 die("should not happen, someone must be hit on the forehead");
320 }
321}
322
323static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
324{
Namhyung Kim369a2472016-10-24 12:00:02 +0900325retry:
Ingo Molnar07800602009-04-20 15:00:56 +0200326 for (; options->type != OPTION_END; options++) {
327 if (options->short_name == *p->opt) {
328 p->opt = p->opt[1] ? p->opt + 1 : NULL;
329 return get_value(p, options, OPT_SHORT);
330 }
331 }
Namhyung Kim369a2472016-10-24 12:00:02 +0900332
333 if (options->parent) {
334 options = options->parent;
335 goto retry;
336 }
337
Ingo Molnar07800602009-04-20 15:00:56 +0200338 return -2;
339}
340
341static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
342 const struct option *options)
343{
344 const char *arg_end = strchr(arg, '=');
345 const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
346 int abbrev_flags = 0, ambiguous_flags = 0;
347
348 if (!arg_end)
349 arg_end = arg + strlen(arg);
350
Namhyung Kim369a2472016-10-24 12:00:02 +0900351retry:
Ingo Molnar07800602009-04-20 15:00:56 +0200352 for (; options->type != OPTION_END; options++) {
353 const char *rest;
354 int flags = 0;
355
356 if (!options->long_name)
357 continue;
358
359 rest = skip_prefix(arg, options->long_name);
360 if (options->type == OPTION_ARGUMENT) {
361 if (!rest)
362 continue;
363 if (*rest == '=')
364 return opterror(options, "takes no value", flags);
365 if (*rest)
366 continue;
367 p->out[p->cpidx++] = arg - 2;
368 return 0;
369 }
370 if (!rest) {
Adrian Hunter4bc43792013-11-18 11:55:55 +0200371 if (!prefixcmp(options->long_name, "no-")) {
372 /*
373 * The long name itself starts with "no-", so
374 * accept the option without "no-" so that users
375 * do not have to enter "no-no-" to get the
376 * negation.
377 */
378 rest = skip_prefix(arg, options->long_name + 3);
379 if (rest) {
380 flags |= OPT_UNSET;
381 goto match;
382 }
383 /* Abbreviated case */
384 if (!prefixcmp(options->long_name + 3, arg)) {
385 flags |= OPT_UNSET;
386 goto is_abbreviated;
387 }
388 }
Ingo Molnar07800602009-04-20 15:00:56 +0200389 /* abbreviated? */
390 if (!strncmp(options->long_name, arg, arg_end - arg)) {
391is_abbreviated:
392 if (abbrev_option) {
393 /*
394 * If this is abbreviated, it is
395 * ambiguous. So when there is no
396 * exact match later, we need to
397 * error out.
398 */
399 ambiguous_option = abbrev_option;
400 ambiguous_flags = abbrev_flags;
401 }
402 if (!(flags & OPT_UNSET) && *arg_end)
403 p->opt = arg_end + 1;
404 abbrev_option = options;
405 abbrev_flags = flags;
406 continue;
407 }
408 /* negated and abbreviated very much? */
409 if (!prefixcmp("no-", arg)) {
410 flags |= OPT_UNSET;
411 goto is_abbreviated;
412 }
413 /* negated? */
414 if (strncmp(arg, "no-", 3))
415 continue;
416 flags |= OPT_UNSET;
417 rest = skip_prefix(arg + 3, options->long_name);
418 /* abbreviated and negated? */
419 if (!rest && !prefixcmp(options->long_name, arg + 3))
420 goto is_abbreviated;
421 if (!rest)
422 continue;
423 }
Adrian Hunter4bc43792013-11-18 11:55:55 +0200424match:
Ingo Molnar07800602009-04-20 15:00:56 +0200425 if (*rest) {
426 if (*rest != '=')
427 continue;
428 p->opt = rest + 1;
429 }
430 return get_value(p, options, flags);
431 }
432
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -0600433 if (ambiguous_option) {
434 fprintf(stderr,
435 " Error: Ambiguous option: %s (could be --%s%s or --%s%s)",
436 arg,
437 (ambiguous_flags & OPT_UNSET) ? "no-" : "",
438 ambiguous_option->long_name,
439 (abbrev_flags & OPT_UNSET) ? "no-" : "",
440 abbrev_option->long_name);
441 return -1;
442 }
Ingo Molnar07800602009-04-20 15:00:56 +0200443 if (abbrev_option)
444 return get_value(p, abbrev_option, abbrev_flags);
Namhyung Kim369a2472016-10-24 12:00:02 +0900445
446 if (options->parent) {
447 options = options->parent;
448 goto retry;
449 }
450
Ingo Molnar07800602009-04-20 15:00:56 +0200451 return -2;
452}
453
454static void check_typos(const char *arg, const struct option *options)
455{
456 if (strlen(arg) < 3)
457 return;
458
459 if (!prefixcmp(arg, "no-")) {
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -0600460 fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
Ingo Molnar07800602009-04-20 15:00:56 +0200461 exit(129);
462 }
463
464 for (; options->type != OPTION_END; options++) {
465 if (!options->long_name)
466 continue;
467 if (!prefixcmp(options->long_name, arg)) {
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -0600468 fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
Ingo Molnar07800602009-04-20 15:00:56 +0200469 exit(129);
470 }
471 }
472}
473
Josh Poimboeuf408cf342015-12-13 22:18:12 -0600474static void parse_options_start(struct parse_opt_ctx_t *ctx,
475 int argc, const char **argv, int flags)
Ingo Molnar07800602009-04-20 15:00:56 +0200476{
477 memset(ctx, 0, sizeof(*ctx));
478 ctx->argc = argc - 1;
479 ctx->argv = argv + 1;
480 ctx->out = argv;
481 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
482 ctx->flags = flags;
483 if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
484 (flags & PARSE_OPT_STOP_AT_NON_OPTION))
485 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
486}
487
488static int usage_with_options_internal(const char * const *,
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300489 const struct option *, int,
490 struct parse_opt_ctx_t *);
Ingo Molnar07800602009-04-20 15:00:56 +0200491
Josh Poimboeuf408cf342015-12-13 22:18:12 -0600492static int parse_options_step(struct parse_opt_ctx_t *ctx,
493 const struct option *options,
494 const char * const usagestr[])
Ingo Molnar07800602009-04-20 15:00:56 +0200495{
496 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900497 int excl_short_opt = 1;
498 const char *arg;
Ingo Molnar07800602009-04-20 15:00:56 +0200499
500 /* we must reset ->opt, unknown short option leave it dangling */
501 ctx->opt = NULL;
502
503 for (; ctx->argc; ctx->argc--, ctx->argv++) {
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900504 arg = ctx->argv[0];
Ingo Molnar07800602009-04-20 15:00:56 +0200505 if (*arg != '-' || !arg[1]) {
506 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
507 break;
508 ctx->out[ctx->cpidx++] = ctx->argv[0];
509 continue;
510 }
511
512 if (arg[1] != '-') {
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900513 ctx->opt = ++arg;
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300514 if (internal_help && *ctx->opt == 'h') {
515 return usage_with_options_internal(usagestr, options, 0, ctx);
516 }
Ingo Molnar07800602009-04-20 15:00:56 +0200517 switch (parse_short_opt(ctx, options)) {
518 case -1:
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900519 return parse_options_usage(usagestr, options, arg, 1);
Ingo Molnar07800602009-04-20 15:00:56 +0200520 case -2:
521 goto unknown;
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900522 case -3:
523 goto exclusive;
Ingo Molnar83a09442009-08-15 12:26:57 +0200524 default:
525 break;
Ingo Molnar07800602009-04-20 15:00:56 +0200526 }
527 if (ctx->opt)
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900528 check_typos(arg, options);
Ingo Molnar07800602009-04-20 15:00:56 +0200529 while (ctx->opt) {
530 if (internal_help && *ctx->opt == 'h')
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300531 return usage_with_options_internal(usagestr, options, 0, ctx);
Namhyung Kimac697622013-11-01 16:33:11 +0900532 arg = ctx->opt;
Ingo Molnar07800602009-04-20 15:00:56 +0200533 switch (parse_short_opt(ctx, options)) {
534 case -1:
Namhyung Kimac697622013-11-01 16:33:11 +0900535 return parse_options_usage(usagestr, options, arg, 1);
Ingo Molnar07800602009-04-20 15:00:56 +0200536 case -2:
537 /* fake a short option thing to hide the fact that we may have
538 * started to parse aggregated stuff
539 *
540 * This is leaky, too bad.
541 */
542 ctx->argv[0] = strdup(ctx->opt - 1);
543 *(char *)ctx->argv[0] = '-';
544 goto unknown;
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900545 case -3:
546 goto exclusive;
Ingo Molnar83a09442009-08-15 12:26:57 +0200547 default:
548 break;
Ingo Molnar07800602009-04-20 15:00:56 +0200549 }
550 }
551 continue;
552 }
553
554 if (!arg[2]) { /* "--" */
555 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
556 ctx->argc--;
557 ctx->argv++;
558 }
559 break;
560 }
561
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900562 arg += 2;
563 if (internal_help && !strcmp(arg, "help-all"))
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300564 return usage_with_options_internal(usagestr, options, 1, ctx);
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900565 if (internal_help && !strcmp(arg, "help"))
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300566 return usage_with_options_internal(usagestr, options, 0, ctx);
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900567 if (!strcmp(arg, "list-opts"))
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500568 return PARSE_OPT_LIST_OPTS;
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900569 if (!strcmp(arg, "list-cmds"))
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500570 return PARSE_OPT_LIST_SUBCMDS;
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900571 switch (parse_long_opt(ctx, arg, options)) {
Ingo Molnar07800602009-04-20 15:00:56 +0200572 case -1:
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900573 return parse_options_usage(usagestr, options, arg, 0);
Ingo Molnar07800602009-04-20 15:00:56 +0200574 case -2:
575 goto unknown;
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900576 case -3:
577 excl_short_opt = 0;
578 goto exclusive;
Ingo Molnar83a09442009-08-15 12:26:57 +0200579 default:
580 break;
Ingo Molnar07800602009-04-20 15:00:56 +0200581 }
582 continue;
583unknown:
584 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
585 return PARSE_OPT_UNKNOWN;
586 ctx->out[ctx->cpidx++] = ctx->argv[0];
587 ctx->opt = NULL;
588 }
589 return PARSE_OPT_DONE;
Namhyung Kim42bd71d2014-10-23 00:15:48 +0900590
591exclusive:
592 parse_options_usage(usagestr, options, arg, excl_short_opt);
593 if ((excl_short_opt && ctx->excl_opt->short_name) ||
594 ctx->excl_opt->long_name == NULL) {
595 char opt = ctx->excl_opt->short_name;
596 parse_options_usage(NULL, options, &opt, 1);
597 } else {
598 parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
599 }
600 return PARSE_OPT_HELP;
Ingo Molnar07800602009-04-20 15:00:56 +0200601}
602
Josh Poimboeuf408cf342015-12-13 22:18:12 -0600603static int parse_options_end(struct parse_opt_ctx_t *ctx)
Ingo Molnar07800602009-04-20 15:00:56 +0200604{
605 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
606 ctx->out[ctx->cpidx + ctx->argc] = NULL;
607 return ctx->cpidx + ctx->argc;
608}
609
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500610int parse_options_subcommand(int argc, const char **argv, const struct option *options,
611 const char *const subcommands[], const char *usagestr[], int flags)
Ingo Molnar07800602009-04-20 15:00:56 +0200612{
613 struct parse_opt_ctx_t ctx;
614
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500615 /* build usage string if it's not provided */
616 if (subcommands && !usagestr[0]) {
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600617 char *buf = NULL;
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500618
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600619 astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
620
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500621 for (int i = 0; subcommands[i]; i++) {
622 if (i)
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600623 astrcat(&buf, "|");
624 astrcat(&buf, subcommands[i]);
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500625 }
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600626 astrcat(&buf, "}");
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500627
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600628 usagestr[0] = buf;
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500629 }
630
Ingo Molnar07800602009-04-20 15:00:56 +0200631 parse_options_start(&ctx, argc, argv, flags);
632 switch (parse_options_step(&ctx, options, usagestr)) {
633 case PARSE_OPT_HELP:
634 exit(129);
635 case PARSE_OPT_DONE:
636 break;
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500637 case PARSE_OPT_LIST_OPTS:
Namhyung Kim4d8061f2012-10-03 00:21:34 +0900638 while (options->type != OPTION_END) {
Yunlong Song3ef1e652015-02-27 18:21:30 +0800639 if (options->long_name)
640 printf("--%s ", options->long_name);
Namhyung Kim4d8061f2012-10-03 00:21:34 +0900641 options++;
642 }
Yunlong Songed457522015-02-27 18:21:29 +0800643 putchar('\n');
Namhyung Kim4d8061f2012-10-03 00:21:34 +0900644 exit(130);
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500645 case PARSE_OPT_LIST_SUBCMDS:
Yunlong Song3a030052015-02-13 21:11:52 +0800646 if (subcommands) {
647 for (int i = 0; subcommands[i]; i++)
648 printf("%s ", subcommands[i]);
649 }
Yunlong Songed457522015-02-27 18:21:29 +0800650 putchar('\n');
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500651 exit(130);
Ingo Molnar07800602009-04-20 15:00:56 +0200652 default: /* PARSE_OPT_UNKNOWN */
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600653 if (ctx.argv[0][1] == '-')
654 astrcatf(&error_buf, "unknown option `%s'",
655 ctx.argv[0] + 2);
656 else
657 astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
Ingo Molnar07800602009-04-20 15:00:56 +0200658 usage_with_options(usagestr, options);
659 }
660
661 return parse_options_end(&ctx);
662}
663
Ramkumar Ramachandra09a71b92014-03-03 20:26:36 -0500664int parse_options(int argc, const char **argv, const struct option *options,
665 const char * const usagestr[], int flags)
666{
667 return parse_options_subcommand(argc, argv, options, NULL,
668 (const char **) usagestr, flags);
669}
670
Ingo Molnar07800602009-04-20 15:00:56 +0200671#define USAGE_OPTS_WIDTH 24
672#define USAGE_GAP 2
673
Namhyung Kimac697622013-11-01 16:33:11 +0900674static void print_option_help(const struct option *opts, int full)
675{
676 size_t pos;
677 int pad;
678
679 if (opts->type == OPTION_GROUP) {
680 fputc('\n', stderr);
681 if (*opts->help)
682 fprintf(stderr, "%s\n", opts->help);
683 return;
684 }
685 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
686 return;
Namhyung Kimd152d1b2014-10-23 00:15:45 +0900687 if (opts->flags & PARSE_OPT_DISABLED)
688 return;
Namhyung Kimac697622013-11-01 16:33:11 +0900689
690 pos = fprintf(stderr, " ");
691 if (opts->short_name)
692 pos += fprintf(stderr, "-%c", opts->short_name);
693 else
694 pos += fprintf(stderr, " ");
695
696 if (opts->long_name && opts->short_name)
697 pos += fprintf(stderr, ", ");
698 if (opts->long_name)
699 pos += fprintf(stderr, "--%s", opts->long_name);
700
701 switch (opts->type) {
702 case OPTION_ARGUMENT:
703 break;
704 case OPTION_LONG:
705 case OPTION_U64:
706 case OPTION_INTEGER:
707 case OPTION_UINTEGER:
708 if (opts->flags & PARSE_OPT_OPTARG)
709 if (opts->long_name)
710 pos += fprintf(stderr, "[=<n>]");
711 else
712 pos += fprintf(stderr, "[<n>]");
713 else
714 pos += fprintf(stderr, " <n>");
715 break;
716 case OPTION_CALLBACK:
717 if (opts->flags & PARSE_OPT_NOARG)
718 break;
719 /* FALLTHROUGH */
720 case OPTION_STRING:
721 if (opts->argh) {
722 if (opts->flags & PARSE_OPT_OPTARG)
723 if (opts->long_name)
724 pos += fprintf(stderr, "[=<%s>]", opts->argh);
725 else
726 pos += fprintf(stderr, "[<%s>]", opts->argh);
727 else
728 pos += fprintf(stderr, " <%s>", opts->argh);
729 } else {
730 if (opts->flags & PARSE_OPT_OPTARG)
731 if (opts->long_name)
732 pos += fprintf(stderr, "[=...]");
733 else
734 pos += fprintf(stderr, "[...]");
735 else
736 pos += fprintf(stderr, " ...");
737 }
738 break;
739 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
740 case OPTION_END:
741 case OPTION_GROUP:
742 case OPTION_BIT:
743 case OPTION_BOOLEAN:
744 case OPTION_INCR:
745 case OPTION_SET_UINT:
746 case OPTION_SET_PTR:
747 break;
748 }
749
750 if (pos <= USAGE_OPTS_WIDTH)
751 pad = USAGE_OPTS_WIDTH - pos;
752 else {
753 fputc('\n', stderr);
754 pad = USAGE_OPTS_WIDTH;
755 }
756 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
Wang Nan48e1cab2015-12-14 10:39:22 +0000757 if (opts->flags & PARSE_OPT_NOBUILD)
758 fprintf(stderr, "%*s(not built-in because %s)\n",
759 USAGE_OPTS_WIDTH + USAGE_GAP, "",
760 opts->build_opt);
Namhyung Kimac697622013-11-01 16:33:11 +0900761}
762
Arnaldo Carvalho de Melo869c55b2015-10-23 11:23:28 -0300763static int option__cmp(const void *va, const void *vb)
764{
765 const struct option *a = va, *b = vb;
766 int sa = tolower(a->short_name), sb = tolower(b->short_name), ret;
767
768 if (sa == 0)
769 sa = 'z' + 1;
770 if (sb == 0)
771 sb = 'z' + 1;
772
773 ret = sa - sb;
774
775 if (ret == 0) {
776 const char *la = a->long_name ?: "",
777 *lb = b->long_name ?: "";
778 ret = strcmp(la, lb);
779 }
780
781 return ret;
782}
783
784static struct option *options__order(const struct option *opts)
785{
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -0600786 int nr_opts = 0, len;
Arnaldo Carvalho de Melo869c55b2015-10-23 11:23:28 -0300787 const struct option *o = opts;
788 struct option *ordered;
789
790 for (o = opts; o->type != OPTION_END; o++)
791 ++nr_opts;
792
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -0600793 len = sizeof(*o) * (nr_opts + 1);
794 ordered = malloc(len);
795 if (!ordered)
Arnaldo Carvalho de Melo869c55b2015-10-23 11:23:28 -0300796 goto out;
Josh Poimboeuf2f4ce5e2015-12-15 09:39:38 -0600797 memcpy(ordered, opts, len);
Arnaldo Carvalho de Melo869c55b2015-10-23 11:23:28 -0300798
799 qsort(ordered, nr_opts, sizeof(*o), option__cmp);
800out:
801 return ordered;
802}
803
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300804static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
805{
806 int i;
807
808 for (i = 1; i < ctx->argc; ++i) {
809 const char *arg = ctx->argv[i];
810
Arnaldo Carvalho de Melof4efcce2015-10-27 17:35:58 -0300811 if (arg[0] != '-') {
812 if (arg[1] == '\0') {
813 if (arg[0] == opt->short_name)
814 return true;
815 continue;
816 }
817
818 if (opt->long_name && strcmp(opt->long_name, arg) == 0)
819 return true;
820
821 if (opt->help && strcasestr(opt->help, arg) != NULL)
822 return true;
823
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300824 continue;
Arnaldo Carvalho de Melof4efcce2015-10-27 17:35:58 -0300825 }
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300826
827 if (arg[1] == opt->short_name ||
828 (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
829 return true;
830 }
831
832 return false;
833}
834
Josh Poimboeuf408cf342015-12-13 22:18:12 -0600835static int usage_with_options_internal(const char * const *usagestr,
836 const struct option *opts, int full,
837 struct parse_opt_ctx_t *ctx)
Ingo Molnar07800602009-04-20 15:00:56 +0200838{
Arnaldo Carvalho de Melo869c55b2015-10-23 11:23:28 -0300839 struct option *ordered;
840
Ingo Molnar07800602009-04-20 15:00:56 +0200841 if (!usagestr)
842 return PARSE_OPT_HELP;
843
Namhyung Kim01b19452015-10-25 00:49:26 +0900844 setup_pager();
845
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600846 if (error_buf) {
847 fprintf(stderr, " Error: %s\n", error_buf);
848 zfree(&error_buf);
Namhyung Kim01b19452015-10-25 00:49:26 +0900849 }
850
Yunlong Song3a134ae2015-10-15 15:39:51 +0800851 fprintf(stderr, "\n Usage: %s\n", *usagestr++);
Ingo Molnar07800602009-04-20 15:00:56 +0200852 while (*usagestr && **usagestr)
Ingo Molnar6e6b7542008-04-15 22:39:31 +0200853 fprintf(stderr, " or: %s\n", *usagestr++);
Ingo Molnar07800602009-04-20 15:00:56 +0200854 while (*usagestr) {
855 fprintf(stderr, "%s%s\n",
856 **usagestr ? " " : "",
857 *usagestr);
858 usagestr++;
859 }
860
861 if (opts->type != OPTION_GROUP)
862 fputc('\n', stderr);
863
Arnaldo Carvalho de Melo869c55b2015-10-23 11:23:28 -0300864 ordered = options__order(opts);
865 if (ordered)
866 opts = ordered;
867
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300868 for ( ; opts->type != OPTION_END; opts++) {
869 if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
870 continue;
Namhyung Kimac697622013-11-01 16:33:11 +0900871 print_option_help(opts, full);
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300872 }
Ingo Molnar07800602009-04-20 15:00:56 +0200873
Ingo Molnar07800602009-04-20 15:00:56 +0200874 fputc('\n', stderr);
875
Arnaldo Carvalho de Melo869c55b2015-10-23 11:23:28 -0300876 free(ordered);
877
Ingo Molnar07800602009-04-20 15:00:56 +0200878 return PARSE_OPT_HELP;
879}
880
881void usage_with_options(const char * const *usagestr,
882 const struct option *opts)
883{
Arnaldo Carvalho de Melo161d9042015-10-23 13:27:39 -0300884 usage_with_options_internal(usagestr, opts, 0, NULL);
Ingo Molnar07800602009-04-20 15:00:56 +0200885 exit(129);
886}
887
Namhyung Kimc7118362015-10-25 00:49:27 +0900888void usage_with_options_msg(const char * const *usagestr,
889 const struct option *opts, const char *fmt, ...)
890{
891 va_list ap;
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600892 char *tmp = error_buf;
Namhyung Kimc7118362015-10-25 00:49:27 +0900893
Namhyung Kimc7118362015-10-25 00:49:27 +0900894 va_start(ap, fmt);
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600895 if (vasprintf(&error_buf, fmt, ap) == -1)
896 die("vasprintf failed");
Namhyung Kimc7118362015-10-25 00:49:27 +0900897 va_end(ap);
898
Josh Poimboeuf901421a2015-12-15 09:39:36 -0600899 free(tmp);
900
Namhyung Kimc7118362015-10-25 00:49:27 +0900901 usage_with_options_internal(usagestr, opts, 0, NULL);
902 exit(129);
903}
904
Ingo Molnar07800602009-04-20 15:00:56 +0200905int parse_options_usage(const char * const *usagestr,
Namhyung Kimac697622013-11-01 16:33:11 +0900906 const struct option *opts,
907 const char *optstr, bool short_opt)
Ingo Molnar07800602009-04-20 15:00:56 +0200908{
Namhyung Kimac697622013-11-01 16:33:11 +0900909 if (!usagestr)
Namhyung Kimcc03c542013-11-01 16:33:15 +0900910 goto opt;
Namhyung Kimac697622013-11-01 16:33:11 +0900911
Yunlong Song3a134ae2015-10-15 15:39:51 +0800912 fprintf(stderr, "\n Usage: %s\n", *usagestr++);
Namhyung Kimac697622013-11-01 16:33:11 +0900913 while (*usagestr && **usagestr)
914 fprintf(stderr, " or: %s\n", *usagestr++);
915 while (*usagestr) {
916 fprintf(stderr, "%s%s\n",
917 **usagestr ? " " : "",
918 *usagestr);
919 usagestr++;
920 }
921 fputc('\n', stderr);
922
Namhyung Kimcc03c542013-11-01 16:33:15 +0900923opt:
Namhyung Kimac697622013-11-01 16:33:11 +0900924 for ( ; opts->type != OPTION_END; opts++) {
925 if (short_opt) {
Namhyung Kima5f4a692015-10-25 00:49:24 +0900926 if (opts->short_name == *optstr) {
927 print_option_help(opts, 0);
Namhyung Kimac697622013-11-01 16:33:11 +0900928 break;
Namhyung Kima5f4a692015-10-25 00:49:24 +0900929 }
Namhyung Kimac697622013-11-01 16:33:11 +0900930 continue;
931 }
932
933 if (opts->long_name == NULL)
934 continue;
935
Namhyung Kima5f4a692015-10-25 00:49:24 +0900936 if (!prefixcmp(opts->long_name, optstr))
937 print_option_help(opts, 0);
938 if (!prefixcmp("no-", optstr) &&
939 !prefixcmp(opts->long_name, optstr + 3))
940 print_option_help(opts, 0);
Namhyung Kimac697622013-11-01 16:33:11 +0900941 }
942
Namhyung Kimac697622013-11-01 16:33:11 +0900943 return PARSE_OPT_HELP;
Ingo Molnar07800602009-04-20 15:00:56 +0200944}
945
946
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300947int parse_opt_verbosity_cb(const struct option *opt,
948 const char *arg __maybe_unused,
Ingo Molnar07800602009-04-20 15:00:56 +0200949 int unset)
950{
951 int *target = opt->value;
952
953 if (unset)
954 /* --no-quiet, --no-verbose */
955 *target = 0;
956 else if (opt->short_name == 'v') {
957 if (*target >= 0)
958 (*target)++;
959 else
960 *target = 1;
961 } else {
962 if (*target <= 0)
963 (*target)--;
964 else
965 *target = -1;
966 }
967 return 0;
968}
Namhyung Kimd152d1b2014-10-23 00:15:45 +0900969
Wang Nan48e1cab2015-12-14 10:39:22 +0000970static struct option *
971find_option(struct option *opts, int shortopt, const char *longopt)
Namhyung Kimd152d1b2014-10-23 00:15:45 +0900972{
973 for (; opts->type != OPTION_END; opts++) {
974 if ((shortopt && opts->short_name == shortopt) ||
975 (opts->long_name && longopt &&
Wang Nan48e1cab2015-12-14 10:39:22 +0000976 !strcmp(opts->long_name, longopt)))
977 return opts;
Namhyung Kimd152d1b2014-10-23 00:15:45 +0900978 }
Wang Nan48e1cab2015-12-14 10:39:22 +0000979 return NULL;
980}
981
982void set_option_flag(struct option *opts, int shortopt, const char *longopt,
983 int flag)
984{
985 struct option *opt = find_option(opts, shortopt, longopt);
986
987 if (opt)
988 opt->flags |= flag;
989 return;
990}
991
992void set_option_nobuild(struct option *opts, int shortopt,
993 const char *longopt,
994 const char *build_opt,
995 bool can_skip)
996{
997 struct option *opt = find_option(opts, shortopt, longopt);
998
999 if (!opt)
1000 return;
1001
1002 opt->flags |= PARSE_OPT_NOBUILD;
1003 opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
1004 opt->build_opt = build_opt;
Namhyung Kimd152d1b2014-10-23 00:15:45 +09001005}