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
18char *error_buf;
19
20static 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
32static 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
38static 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
48static 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
69static 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
345static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
346{
347retry:
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
363static 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
373retry:
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)) {
413is_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		}
446match:
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
476static 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
496static 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
510static int usage_with_options_internal(const char * const *,
511				       const struct option *, int,
512				       struct parse_opt_ctx_t *);
513
514static 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;
605unknown:
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
613exclusive:
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
625static 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
632int 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
686int 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
696static 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
786static 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
807static struct option *options__order(const struct option *opts)
808{
809	int nr_opts = 0, nr_group = 0, len;
810	const struct option *o = opts;
811	struct option *opt, *ordered, *group;
812
813	for (o = opts; o->type != OPTION_END; o++)
814		++nr_opts;
815
816	len = sizeof(*o) * (nr_opts + 1);
817	ordered = malloc(len);
818	if (!ordered)
819		goto out;
820	memcpy(ordered, opts, len);
821
822	/* sort each option group individually */
823	for (opt = group = ordered; opt->type != OPTION_END; opt++) {
824		if (opt->type == OPTION_GROUP) {
825			qsort(group, nr_group, sizeof(*opt), option__cmp);
826			group = opt + 1;
827			nr_group = 0;
828			continue;
829		}
830		nr_group++;
831	}
832	qsort(group, nr_group, sizeof(*opt), option__cmp);
833
834out:
835	return ordered;
836}
837
838static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
839{
840	int i;
841
842	for (i = 1; i < ctx->argc; ++i) {
843		const char *arg = ctx->argv[i];
844
845		if (arg[0] != '-') {
846			if (arg[1] == '\0') {
847				if (arg[0] == opt->short_name)
848					return true;
849				continue;
850			}
851
852			if (opt->long_name && strcmp(opt->long_name, arg) == 0)
853				return true;
854
855			if (opt->help && strcasestr(opt->help, arg) != NULL)
856				return true;
857
858			continue;
859		}
860
861		if (arg[1] == opt->short_name ||
862		    (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
863			return true;
864	}
865
866	return false;
867}
868
869static int usage_with_options_internal(const char * const *usagestr,
870				       const struct option *opts, int full,
871				       struct parse_opt_ctx_t *ctx)
872{
873	struct option *ordered;
874
875	if (!usagestr)
876		return PARSE_OPT_HELP;
877
878	setup_pager();
879
880	if (error_buf) {
881		fprintf(stderr, "  Error: %s\n", error_buf);
882		zfree(&error_buf);
883	}
884
885	fprintf(stderr, "\n Usage: %s\n", *usagestr++);
886	while (*usagestr && **usagestr)
887		fprintf(stderr, "    or: %s\n", *usagestr++);
888	while (*usagestr) {
889		fprintf(stderr, "%s%s\n",
890				**usagestr ? "    " : "",
891				*usagestr);
892		usagestr++;
893	}
894
895	if (opts->type != OPTION_GROUP)
896		fputc('\n', stderr);
897
898	ordered = options__order(opts);
899	if (ordered)
900		opts = ordered;
901
902	for (  ; opts->type != OPTION_END; opts++) {
903		if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
904			continue;
905		print_option_help(opts, full);
906	}
907
908	fputc('\n', stderr);
909
910	free(ordered);
911
912	return PARSE_OPT_HELP;
913}
914
915void usage_with_options(const char * const *usagestr,
916			const struct option *opts)
917{
918	usage_with_options_internal(usagestr, opts, 0, NULL);
919	exit(129);
920}
921
922void usage_with_options_msg(const char * const *usagestr,
923			    const struct option *opts, const char *fmt, ...)
924{
925	va_list ap;
926	char *tmp = error_buf;
927
928	va_start(ap, fmt);
929	if (vasprintf(&error_buf, fmt, ap) == -1)
930		die("vasprintf failed");
931	va_end(ap);
932
933	free(tmp);
934
935	usage_with_options_internal(usagestr, opts, 0, NULL);
936	exit(129);
937}
938
939int parse_options_usage(const char * const *usagestr,
940			const struct option *opts,
941			const char *optstr, bool short_opt)
942{
943	if (!usagestr)
944		goto opt;
945
946	fprintf(stderr, "\n Usage: %s\n", *usagestr++);
947	while (*usagestr && **usagestr)
948		fprintf(stderr, "    or: %s\n", *usagestr++);
949	while (*usagestr) {
950		fprintf(stderr, "%s%s\n",
951				**usagestr ? "    " : "",
952				*usagestr);
953		usagestr++;
954	}
955	fputc('\n', stderr);
956
957opt:
958	for (  ; opts->type != OPTION_END; opts++) {
959		if (short_opt) {
960			if (opts->short_name == *optstr) {
961				print_option_help(opts, 0);
962				break;
963			}
964			continue;
965		}
966
967		if (opts->long_name == NULL)
968			continue;
969
970		if (strstarts(opts->long_name, optstr))
971			print_option_help(opts, 0);
972		if (strstarts("no-", optstr) &&
973		    strstarts(opts->long_name, optstr + 3))
974			print_option_help(opts, 0);
975	}
976
977	return PARSE_OPT_HELP;
978}
979
980
981int parse_opt_verbosity_cb(const struct option *opt,
982			   const char *arg __maybe_unused,
983			   int unset)
984{
985	int *target = opt->value;
986
987	if (unset)
988		/* --no-quiet, --no-verbose */
989		*target = 0;
990	else if (opt->short_name == 'v') {
991		if (*target >= 0)
992			(*target)++;
993		else
994			*target = 1;
995	} else {
996		if (*target <= 0)
997			(*target)--;
998		else
999			*target = -1;
1000	}
1001	return 0;
1002}
1003
1004static struct option *
1005find_option(struct option *opts, int shortopt, const char *longopt)
1006{
1007	for (; opts->type != OPTION_END; opts++) {
1008		if ((shortopt && opts->short_name == shortopt) ||
1009		    (opts->long_name && longopt &&
1010		     !strcmp(opts->long_name, longopt)))
1011			return opts;
1012	}
1013	return NULL;
1014}
1015
1016void set_option_flag(struct option *opts, int shortopt, const char *longopt,
1017		     int flag)
1018{
1019	struct option *opt = find_option(opts, shortopt, longopt);
1020
1021	if (opt)
1022		opt->flags |= flag;
1023	return;
1024}
1025
1026void set_option_nobuild(struct option *opts, int shortopt,
1027			const char *longopt,
1028			const char *build_opt,
1029			bool can_skip)
1030{
1031	struct option *opt = find_option(opts, shortopt, longopt);
1032
1033	if (!opt)
1034		return;
1035
1036	opt->flags |= PARSE_OPT_NOBUILD;
1037	opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
1038	opt->build_opt = build_opt;
1039}
1040