cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

parse-options.c (24345B)


      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}