18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/compiler.h>
38c2ecf20Sopenharmony_ci#include <linux/string.h>
48c2ecf20Sopenharmony_ci#include <linux/types.h>
58c2ecf20Sopenharmony_ci#include <stdio.h>
68c2ecf20Sopenharmony_ci#include <stdlib.h>
78c2ecf20Sopenharmony_ci#include <stdint.h>
88c2ecf20Sopenharmony_ci#include <string.h>
98c2ecf20Sopenharmony_ci#include <ctype.h>
108c2ecf20Sopenharmony_ci#include "subcmd-util.h"
118c2ecf20Sopenharmony_ci#include "parse-options.h"
128c2ecf20Sopenharmony_ci#include "subcmd-config.h"
138c2ecf20Sopenharmony_ci#include "pager.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define OPT_SHORT 1
168c2ecf20Sopenharmony_ci#define OPT_UNSET 2
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cichar *error_buf;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic int opterror(const struct option *opt, const char *reason, int flags)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	if (flags & OPT_SHORT)
238c2ecf20Sopenharmony_ci		fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
248c2ecf20Sopenharmony_ci	else if (flags & OPT_UNSET)
258c2ecf20Sopenharmony_ci		fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
268c2ecf20Sopenharmony_ci	else
278c2ecf20Sopenharmony_ci		fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	return -1;
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic const char *skip_prefix(const char *str, const char *prefix)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	size_t len = strlen(prefix);
358c2ecf20Sopenharmony_ci	return strncmp(str, prefix, len) ? NULL : str + len;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic void optwarning(const struct option *opt, const char *reason, int flags)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	if (flags & OPT_SHORT)
418c2ecf20Sopenharmony_ci		fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
428c2ecf20Sopenharmony_ci	else if (flags & OPT_UNSET)
438c2ecf20Sopenharmony_ci		fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
448c2ecf20Sopenharmony_ci	else
458c2ecf20Sopenharmony_ci		fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
498c2ecf20Sopenharmony_ci		   int flags, const char **arg)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	const char *res;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (p->opt) {
548c2ecf20Sopenharmony_ci		res = p->opt;
558c2ecf20Sopenharmony_ci		p->opt = NULL;
568c2ecf20Sopenharmony_ci	} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
578c2ecf20Sopenharmony_ci		    **(p->argv + 1) == '-')) {
588c2ecf20Sopenharmony_ci		res = (const char *)opt->defval;
598c2ecf20Sopenharmony_ci	} else if (p->argc > 1) {
608c2ecf20Sopenharmony_ci		p->argc--;
618c2ecf20Sopenharmony_ci		res = *++p->argv;
628c2ecf20Sopenharmony_ci	} else
638c2ecf20Sopenharmony_ci		return opterror(opt, "requires a value", flags);
648c2ecf20Sopenharmony_ci	if (arg)
658c2ecf20Sopenharmony_ci		*arg = res;
668c2ecf20Sopenharmony_ci	return 0;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int get_value(struct parse_opt_ctx_t *p,
708c2ecf20Sopenharmony_ci		     const struct option *opt, int flags)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	const char *s, *arg = NULL;
738c2ecf20Sopenharmony_ci	const int unset = flags & OPT_UNSET;
748c2ecf20Sopenharmony_ci	int err;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (unset && p->opt)
778c2ecf20Sopenharmony_ci		return opterror(opt, "takes no value", flags);
788c2ecf20Sopenharmony_ci	if (unset && (opt->flags & PARSE_OPT_NONEG))
798c2ecf20Sopenharmony_ci		return opterror(opt, "isn't available", flags);
808c2ecf20Sopenharmony_ci	if (opt->flags & PARSE_OPT_DISABLED)
818c2ecf20Sopenharmony_ci		return opterror(opt, "is not usable", flags);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (opt->flags & PARSE_OPT_EXCLUSIVE) {
848c2ecf20Sopenharmony_ci		if (p->excl_opt && p->excl_opt != opt) {
858c2ecf20Sopenharmony_ci			char msg[128];
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci			if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
888c2ecf20Sopenharmony_ci			    p->excl_opt->long_name == NULL) {
898c2ecf20Sopenharmony_ci				snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
908c2ecf20Sopenharmony_ci					 p->excl_opt->short_name);
918c2ecf20Sopenharmony_ci			} else {
928c2ecf20Sopenharmony_ci				snprintf(msg, sizeof(msg), "cannot be used with %s",
938c2ecf20Sopenharmony_ci					 p->excl_opt->long_name);
948c2ecf20Sopenharmony_ci			}
958c2ecf20Sopenharmony_ci			opterror(opt, msg, flags);
968c2ecf20Sopenharmony_ci			return -3;
978c2ecf20Sopenharmony_ci		}
988c2ecf20Sopenharmony_ci		p->excl_opt = opt;
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci	if (!(flags & OPT_SHORT) && p->opt) {
1018c2ecf20Sopenharmony_ci		switch (opt->type) {
1028c2ecf20Sopenharmony_ci		case OPTION_CALLBACK:
1038c2ecf20Sopenharmony_ci			if (!(opt->flags & PARSE_OPT_NOARG))
1048c2ecf20Sopenharmony_ci				break;
1058c2ecf20Sopenharmony_ci			/* FALLTHROUGH */
1068c2ecf20Sopenharmony_ci		case OPTION_BOOLEAN:
1078c2ecf20Sopenharmony_ci		case OPTION_INCR:
1088c2ecf20Sopenharmony_ci		case OPTION_BIT:
1098c2ecf20Sopenharmony_ci		case OPTION_SET_UINT:
1108c2ecf20Sopenharmony_ci		case OPTION_SET_PTR:
1118c2ecf20Sopenharmony_ci			return opterror(opt, "takes no value", flags);
1128c2ecf20Sopenharmony_ci		case OPTION_END:
1138c2ecf20Sopenharmony_ci		case OPTION_ARGUMENT:
1148c2ecf20Sopenharmony_ci		case OPTION_GROUP:
1158c2ecf20Sopenharmony_ci		case OPTION_STRING:
1168c2ecf20Sopenharmony_ci		case OPTION_INTEGER:
1178c2ecf20Sopenharmony_ci		case OPTION_UINTEGER:
1188c2ecf20Sopenharmony_ci		case OPTION_LONG:
1198c2ecf20Sopenharmony_ci		case OPTION_ULONG:
1208c2ecf20Sopenharmony_ci		case OPTION_U64:
1218c2ecf20Sopenharmony_ci		default:
1228c2ecf20Sopenharmony_ci			break;
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (opt->flags & PARSE_OPT_NOBUILD) {
1278c2ecf20Sopenharmony_ci		char reason[128];
1288c2ecf20Sopenharmony_ci		bool noarg = false;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		err = snprintf(reason, sizeof(reason),
1318c2ecf20Sopenharmony_ci				opt->flags & PARSE_OPT_CANSKIP ?
1328c2ecf20Sopenharmony_ci					"is being ignored because %s " :
1338c2ecf20Sopenharmony_ci					"is not available because %s",
1348c2ecf20Sopenharmony_ci				opt->build_opt);
1358c2ecf20Sopenharmony_ci		reason[sizeof(reason) - 1] = '\0';
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		if (err < 0)
1388c2ecf20Sopenharmony_ci			strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
1398c2ecf20Sopenharmony_ci					"is being ignored" :
1408c2ecf20Sopenharmony_ci					"is not available",
1418c2ecf20Sopenharmony_ci					sizeof(reason));
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		if (!(opt->flags & PARSE_OPT_CANSKIP))
1448c2ecf20Sopenharmony_ci			return opterror(opt, reason, flags);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci		err = 0;
1478c2ecf20Sopenharmony_ci		if (unset)
1488c2ecf20Sopenharmony_ci			noarg = true;
1498c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_NOARG)
1508c2ecf20Sopenharmony_ci			noarg = true;
1518c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
1528c2ecf20Sopenharmony_ci			noarg = true;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		switch (opt->type) {
1558c2ecf20Sopenharmony_ci		case OPTION_BOOLEAN:
1568c2ecf20Sopenharmony_ci		case OPTION_INCR:
1578c2ecf20Sopenharmony_ci		case OPTION_BIT:
1588c2ecf20Sopenharmony_ci		case OPTION_SET_UINT:
1598c2ecf20Sopenharmony_ci		case OPTION_SET_PTR:
1608c2ecf20Sopenharmony_ci		case OPTION_END:
1618c2ecf20Sopenharmony_ci		case OPTION_ARGUMENT:
1628c2ecf20Sopenharmony_ci		case OPTION_GROUP:
1638c2ecf20Sopenharmony_ci			noarg = true;
1648c2ecf20Sopenharmony_ci			break;
1658c2ecf20Sopenharmony_ci		case OPTION_CALLBACK:
1668c2ecf20Sopenharmony_ci		case OPTION_STRING:
1678c2ecf20Sopenharmony_ci		case OPTION_INTEGER:
1688c2ecf20Sopenharmony_ci		case OPTION_UINTEGER:
1698c2ecf20Sopenharmony_ci		case OPTION_LONG:
1708c2ecf20Sopenharmony_ci		case OPTION_ULONG:
1718c2ecf20Sopenharmony_ci		case OPTION_U64:
1728c2ecf20Sopenharmony_ci		default:
1738c2ecf20Sopenharmony_ci			break;
1748c2ecf20Sopenharmony_ci		}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		if (!noarg)
1778c2ecf20Sopenharmony_ci			err = get_arg(p, opt, flags, NULL);
1788c2ecf20Sopenharmony_ci		if (err)
1798c2ecf20Sopenharmony_ci			return err;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci		optwarning(opt, reason, flags);
1828c2ecf20Sopenharmony_ci		return 0;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	switch (opt->type) {
1868c2ecf20Sopenharmony_ci	case OPTION_BIT:
1878c2ecf20Sopenharmony_ci		if (unset)
1888c2ecf20Sopenharmony_ci			*(int *)opt->value &= ~opt->defval;
1898c2ecf20Sopenharmony_ci		else
1908c2ecf20Sopenharmony_ci			*(int *)opt->value |= opt->defval;
1918c2ecf20Sopenharmony_ci		return 0;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	case OPTION_BOOLEAN:
1948c2ecf20Sopenharmony_ci		*(bool *)opt->value = unset ? false : true;
1958c2ecf20Sopenharmony_ci		if (opt->set)
1968c2ecf20Sopenharmony_ci			*(bool *)opt->set = true;
1978c2ecf20Sopenharmony_ci		return 0;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	case OPTION_INCR:
2008c2ecf20Sopenharmony_ci		*(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
2018c2ecf20Sopenharmony_ci		return 0;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	case OPTION_SET_UINT:
2048c2ecf20Sopenharmony_ci		*(unsigned int *)opt->value = unset ? 0 : opt->defval;
2058c2ecf20Sopenharmony_ci		return 0;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	case OPTION_SET_PTR:
2088c2ecf20Sopenharmony_ci		*(void **)opt->value = unset ? NULL : (void *)opt->defval;
2098c2ecf20Sopenharmony_ci		return 0;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	case OPTION_STRING:
2128c2ecf20Sopenharmony_ci		err = 0;
2138c2ecf20Sopenharmony_ci		if (unset)
2148c2ecf20Sopenharmony_ci			*(const char **)opt->value = NULL;
2158c2ecf20Sopenharmony_ci		else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
2168c2ecf20Sopenharmony_ci			*(const char **)opt->value = (const char *)opt->defval;
2178c2ecf20Sopenharmony_ci		else
2188c2ecf20Sopenharmony_ci			err = get_arg(p, opt, flags, (const char **)opt->value);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci		if (opt->set)
2218c2ecf20Sopenharmony_ci			*(bool *)opt->set = true;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		/* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
2248c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_NOEMPTY) {
2258c2ecf20Sopenharmony_ci			const char *val = *(const char **)opt->value;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci			if (!val)
2288c2ecf20Sopenharmony_ci				return err;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci			/* Similar to unset if we are given an empty string. */
2318c2ecf20Sopenharmony_ci			if (val[0] == '\0') {
2328c2ecf20Sopenharmony_ci				*(const char **)opt->value = NULL;
2338c2ecf20Sopenharmony_ci				return 0;
2348c2ecf20Sopenharmony_ci			}
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		return err;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	case OPTION_CALLBACK:
2408c2ecf20Sopenharmony_ci		if (opt->set)
2418c2ecf20Sopenharmony_ci			*(bool *)opt->set = true;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci		if (unset)
2448c2ecf20Sopenharmony_ci			return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
2458c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_NOARG)
2468c2ecf20Sopenharmony_ci			return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
2478c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
2488c2ecf20Sopenharmony_ci			return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
2498c2ecf20Sopenharmony_ci		if (get_arg(p, opt, flags, &arg))
2508c2ecf20Sopenharmony_ci			return -1;
2518c2ecf20Sopenharmony_ci		return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	case OPTION_INTEGER:
2548c2ecf20Sopenharmony_ci		if (unset) {
2558c2ecf20Sopenharmony_ci			*(int *)opt->value = 0;
2568c2ecf20Sopenharmony_ci			return 0;
2578c2ecf20Sopenharmony_ci		}
2588c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
2598c2ecf20Sopenharmony_ci			*(int *)opt->value = opt->defval;
2608c2ecf20Sopenharmony_ci			return 0;
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci		if (get_arg(p, opt, flags, &arg))
2638c2ecf20Sopenharmony_ci			return -1;
2648c2ecf20Sopenharmony_ci		*(int *)opt->value = strtol(arg, (char **)&s, 10);
2658c2ecf20Sopenharmony_ci		if (*s)
2668c2ecf20Sopenharmony_ci			return opterror(opt, "expects a numerical value", flags);
2678c2ecf20Sopenharmony_ci		return 0;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	case OPTION_UINTEGER:
2708c2ecf20Sopenharmony_ci		if (unset) {
2718c2ecf20Sopenharmony_ci			*(unsigned int *)opt->value = 0;
2728c2ecf20Sopenharmony_ci			return 0;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
2758c2ecf20Sopenharmony_ci			*(unsigned int *)opt->value = opt->defval;
2768c2ecf20Sopenharmony_ci			return 0;
2778c2ecf20Sopenharmony_ci		}
2788c2ecf20Sopenharmony_ci		if (get_arg(p, opt, flags, &arg))
2798c2ecf20Sopenharmony_ci			return -1;
2808c2ecf20Sopenharmony_ci		if (arg[0] == '-')
2818c2ecf20Sopenharmony_ci			return opterror(opt, "expects an unsigned numerical value", flags);
2828c2ecf20Sopenharmony_ci		*(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
2838c2ecf20Sopenharmony_ci		if (*s)
2848c2ecf20Sopenharmony_ci			return opterror(opt, "expects a numerical value", flags);
2858c2ecf20Sopenharmony_ci		return 0;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	case OPTION_LONG:
2888c2ecf20Sopenharmony_ci		if (unset) {
2898c2ecf20Sopenharmony_ci			*(long *)opt->value = 0;
2908c2ecf20Sopenharmony_ci			return 0;
2918c2ecf20Sopenharmony_ci		}
2928c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
2938c2ecf20Sopenharmony_ci			*(long *)opt->value = opt->defval;
2948c2ecf20Sopenharmony_ci			return 0;
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci		if (get_arg(p, opt, flags, &arg))
2978c2ecf20Sopenharmony_ci			return -1;
2988c2ecf20Sopenharmony_ci		*(long *)opt->value = strtol(arg, (char **)&s, 10);
2998c2ecf20Sopenharmony_ci		if (*s)
3008c2ecf20Sopenharmony_ci			return opterror(opt, "expects a numerical value", flags);
3018c2ecf20Sopenharmony_ci		return 0;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	case OPTION_ULONG:
3048c2ecf20Sopenharmony_ci		if (unset) {
3058c2ecf20Sopenharmony_ci			*(unsigned long *)opt->value = 0;
3068c2ecf20Sopenharmony_ci			return 0;
3078c2ecf20Sopenharmony_ci		}
3088c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
3098c2ecf20Sopenharmony_ci			*(unsigned long *)opt->value = opt->defval;
3108c2ecf20Sopenharmony_ci			return 0;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci		if (get_arg(p, opt, flags, &arg))
3138c2ecf20Sopenharmony_ci			return -1;
3148c2ecf20Sopenharmony_ci		*(unsigned long *)opt->value = strtoul(arg, (char **)&s, 10);
3158c2ecf20Sopenharmony_ci		if (*s)
3168c2ecf20Sopenharmony_ci			return opterror(opt, "expects a numerical value", flags);
3178c2ecf20Sopenharmony_ci		return 0;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	case OPTION_U64:
3208c2ecf20Sopenharmony_ci		if (unset) {
3218c2ecf20Sopenharmony_ci			*(u64 *)opt->value = 0;
3228c2ecf20Sopenharmony_ci			return 0;
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
3258c2ecf20Sopenharmony_ci			*(u64 *)opt->value = opt->defval;
3268c2ecf20Sopenharmony_ci			return 0;
3278c2ecf20Sopenharmony_ci		}
3288c2ecf20Sopenharmony_ci		if (get_arg(p, opt, flags, &arg))
3298c2ecf20Sopenharmony_ci			return -1;
3308c2ecf20Sopenharmony_ci		if (arg[0] == '-')
3318c2ecf20Sopenharmony_ci			return opterror(opt, "expects an unsigned numerical value", flags);
3328c2ecf20Sopenharmony_ci		*(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
3338c2ecf20Sopenharmony_ci		if (*s)
3348c2ecf20Sopenharmony_ci			return opterror(opt, "expects a numerical value", flags);
3358c2ecf20Sopenharmony_ci		return 0;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	case OPTION_END:
3388c2ecf20Sopenharmony_ci	case OPTION_ARGUMENT:
3398c2ecf20Sopenharmony_ci	case OPTION_GROUP:
3408c2ecf20Sopenharmony_ci	default:
3418c2ecf20Sopenharmony_ci		die("should not happen, someone must be hit on the forehead");
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ciretry:
3488c2ecf20Sopenharmony_ci	for (; options->type != OPTION_END; options++) {
3498c2ecf20Sopenharmony_ci		if (options->short_name == *p->opt) {
3508c2ecf20Sopenharmony_ci			p->opt = p->opt[1] ? p->opt + 1 : NULL;
3518c2ecf20Sopenharmony_ci			return get_value(p, options, OPT_SHORT);
3528c2ecf20Sopenharmony_ci		}
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (options->parent) {
3568c2ecf20Sopenharmony_ci		options = options->parent;
3578c2ecf20Sopenharmony_ci		goto retry;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	return -2;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
3648c2ecf20Sopenharmony_ci                          const struct option *options)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	const char *arg_end = strchr(arg, '=');
3678c2ecf20Sopenharmony_ci	const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
3688c2ecf20Sopenharmony_ci	int abbrev_flags = 0, ambiguous_flags = 0;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (!arg_end)
3718c2ecf20Sopenharmony_ci		arg_end = arg + strlen(arg);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ciretry:
3748c2ecf20Sopenharmony_ci	for (; options->type != OPTION_END; options++) {
3758c2ecf20Sopenharmony_ci		const char *rest;
3768c2ecf20Sopenharmony_ci		int flags = 0;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci		if (!options->long_name)
3798c2ecf20Sopenharmony_ci			continue;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci		rest = skip_prefix(arg, options->long_name);
3828c2ecf20Sopenharmony_ci		if (options->type == OPTION_ARGUMENT) {
3838c2ecf20Sopenharmony_ci			if (!rest)
3848c2ecf20Sopenharmony_ci				continue;
3858c2ecf20Sopenharmony_ci			if (*rest == '=')
3868c2ecf20Sopenharmony_ci				return opterror(options, "takes no value", flags);
3878c2ecf20Sopenharmony_ci			if (*rest)
3888c2ecf20Sopenharmony_ci				continue;
3898c2ecf20Sopenharmony_ci			p->out[p->cpidx++] = arg - 2;
3908c2ecf20Sopenharmony_ci			return 0;
3918c2ecf20Sopenharmony_ci		}
3928c2ecf20Sopenharmony_ci		if (!rest) {
3938c2ecf20Sopenharmony_ci			if (strstarts(options->long_name, "no-")) {
3948c2ecf20Sopenharmony_ci				/*
3958c2ecf20Sopenharmony_ci				 * The long name itself starts with "no-", so
3968c2ecf20Sopenharmony_ci				 * accept the option without "no-" so that users
3978c2ecf20Sopenharmony_ci				 * do not have to enter "no-no-" to get the
3988c2ecf20Sopenharmony_ci				 * negation.
3998c2ecf20Sopenharmony_ci				 */
4008c2ecf20Sopenharmony_ci				rest = skip_prefix(arg, options->long_name + 3);
4018c2ecf20Sopenharmony_ci				if (rest) {
4028c2ecf20Sopenharmony_ci					flags |= OPT_UNSET;
4038c2ecf20Sopenharmony_ci					goto match;
4048c2ecf20Sopenharmony_ci				}
4058c2ecf20Sopenharmony_ci				/* Abbreviated case */
4068c2ecf20Sopenharmony_ci				if (strstarts(options->long_name + 3, arg)) {
4078c2ecf20Sopenharmony_ci					flags |= OPT_UNSET;
4088c2ecf20Sopenharmony_ci					goto is_abbreviated;
4098c2ecf20Sopenharmony_ci				}
4108c2ecf20Sopenharmony_ci			}
4118c2ecf20Sopenharmony_ci			/* abbreviated? */
4128c2ecf20Sopenharmony_ci			if (!strncmp(options->long_name, arg, arg_end - arg)) {
4138c2ecf20Sopenharmony_ciis_abbreviated:
4148c2ecf20Sopenharmony_ci				if (abbrev_option) {
4158c2ecf20Sopenharmony_ci					/*
4168c2ecf20Sopenharmony_ci					 * If this is abbreviated, it is
4178c2ecf20Sopenharmony_ci					 * ambiguous. So when there is no
4188c2ecf20Sopenharmony_ci					 * exact match later, we need to
4198c2ecf20Sopenharmony_ci					 * error out.
4208c2ecf20Sopenharmony_ci					 */
4218c2ecf20Sopenharmony_ci					ambiguous_option = abbrev_option;
4228c2ecf20Sopenharmony_ci					ambiguous_flags = abbrev_flags;
4238c2ecf20Sopenharmony_ci				}
4248c2ecf20Sopenharmony_ci				if (!(flags & OPT_UNSET) && *arg_end)
4258c2ecf20Sopenharmony_ci					p->opt = arg_end + 1;
4268c2ecf20Sopenharmony_ci				abbrev_option = options;
4278c2ecf20Sopenharmony_ci				abbrev_flags = flags;
4288c2ecf20Sopenharmony_ci				continue;
4298c2ecf20Sopenharmony_ci			}
4308c2ecf20Sopenharmony_ci			/* negated and abbreviated very much? */
4318c2ecf20Sopenharmony_ci			if (strstarts("no-", arg)) {
4328c2ecf20Sopenharmony_ci				flags |= OPT_UNSET;
4338c2ecf20Sopenharmony_ci				goto is_abbreviated;
4348c2ecf20Sopenharmony_ci			}
4358c2ecf20Sopenharmony_ci			/* negated? */
4368c2ecf20Sopenharmony_ci			if (strncmp(arg, "no-", 3))
4378c2ecf20Sopenharmony_ci				continue;
4388c2ecf20Sopenharmony_ci			flags |= OPT_UNSET;
4398c2ecf20Sopenharmony_ci			rest = skip_prefix(arg + 3, options->long_name);
4408c2ecf20Sopenharmony_ci			/* abbreviated and negated? */
4418c2ecf20Sopenharmony_ci			if (!rest && strstarts(options->long_name, arg + 3))
4428c2ecf20Sopenharmony_ci				goto is_abbreviated;
4438c2ecf20Sopenharmony_ci			if (!rest)
4448c2ecf20Sopenharmony_ci				continue;
4458c2ecf20Sopenharmony_ci		}
4468c2ecf20Sopenharmony_cimatch:
4478c2ecf20Sopenharmony_ci		if (*rest) {
4488c2ecf20Sopenharmony_ci			if (*rest != '=')
4498c2ecf20Sopenharmony_ci				continue;
4508c2ecf20Sopenharmony_ci			p->opt = rest + 1;
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci		return get_value(p, options, flags);
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (ambiguous_option) {
4568c2ecf20Sopenharmony_ci		 fprintf(stderr,
4578c2ecf20Sopenharmony_ci			 " Error: Ambiguous option: %s (could be --%s%s or --%s%s)\n",
4588c2ecf20Sopenharmony_ci			 arg,
4598c2ecf20Sopenharmony_ci			 (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
4608c2ecf20Sopenharmony_ci			 ambiguous_option->long_name,
4618c2ecf20Sopenharmony_ci			 (abbrev_flags & OPT_UNSET) ?  "no-" : "",
4628c2ecf20Sopenharmony_ci			 abbrev_option->long_name);
4638c2ecf20Sopenharmony_ci		 return -1;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci	if (abbrev_option)
4668c2ecf20Sopenharmony_ci		return get_value(p, abbrev_option, abbrev_flags);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	if (options->parent) {
4698c2ecf20Sopenharmony_ci		options = options->parent;
4708c2ecf20Sopenharmony_ci		goto retry;
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	return -2;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic void check_typos(const char *arg, const struct option *options)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	if (strlen(arg) < 3)
4798c2ecf20Sopenharmony_ci		return;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (strstarts(arg, "no-")) {
4828c2ecf20Sopenharmony_ci		fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
4838c2ecf20Sopenharmony_ci		exit(129);
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	for (; options->type != OPTION_END; options++) {
4878c2ecf20Sopenharmony_ci		if (!options->long_name)
4888c2ecf20Sopenharmony_ci			continue;
4898c2ecf20Sopenharmony_ci		if (strstarts(options->long_name, arg)) {
4908c2ecf20Sopenharmony_ci			fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
4918c2ecf20Sopenharmony_ci			exit(129);
4928c2ecf20Sopenharmony_ci		}
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic void parse_options_start(struct parse_opt_ctx_t *ctx,
4978c2ecf20Sopenharmony_ci				int argc, const char **argv, int flags)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	memset(ctx, 0, sizeof(*ctx));
5008c2ecf20Sopenharmony_ci	ctx->argc = argc - 1;
5018c2ecf20Sopenharmony_ci	ctx->argv = argv + 1;
5028c2ecf20Sopenharmony_ci	ctx->out  = argv;
5038c2ecf20Sopenharmony_ci	ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
5048c2ecf20Sopenharmony_ci	ctx->flags = flags;
5058c2ecf20Sopenharmony_ci	if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
5068c2ecf20Sopenharmony_ci	    (flags & PARSE_OPT_STOP_AT_NON_OPTION))
5078c2ecf20Sopenharmony_ci		die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int usage_with_options_internal(const char * const *,
5118c2ecf20Sopenharmony_ci				       const struct option *, int,
5128c2ecf20Sopenharmony_ci				       struct parse_opt_ctx_t *);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic int parse_options_step(struct parse_opt_ctx_t *ctx,
5158c2ecf20Sopenharmony_ci			      const struct option *options,
5168c2ecf20Sopenharmony_ci			      const char * const usagestr[])
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
5198c2ecf20Sopenharmony_ci	int excl_short_opt = 1;
5208c2ecf20Sopenharmony_ci	const char *arg;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	/* we must reset ->opt, unknown short option leave it dangling */
5238c2ecf20Sopenharmony_ci	ctx->opt = NULL;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	for (; ctx->argc; ctx->argc--, ctx->argv++) {
5268c2ecf20Sopenharmony_ci		arg = ctx->argv[0];
5278c2ecf20Sopenharmony_ci		if (*arg != '-' || !arg[1]) {
5288c2ecf20Sopenharmony_ci			if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
5298c2ecf20Sopenharmony_ci				break;
5308c2ecf20Sopenharmony_ci			ctx->out[ctx->cpidx++] = ctx->argv[0];
5318c2ecf20Sopenharmony_ci			continue;
5328c2ecf20Sopenharmony_ci		}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci		if (arg[1] != '-') {
5358c2ecf20Sopenharmony_ci			ctx->opt = ++arg;
5368c2ecf20Sopenharmony_ci			if (internal_help && *ctx->opt == 'h') {
5378c2ecf20Sopenharmony_ci				return usage_with_options_internal(usagestr, options, 0, ctx);
5388c2ecf20Sopenharmony_ci			}
5398c2ecf20Sopenharmony_ci			switch (parse_short_opt(ctx, options)) {
5408c2ecf20Sopenharmony_ci			case -1:
5418c2ecf20Sopenharmony_ci				return parse_options_usage(usagestr, options, arg, 1);
5428c2ecf20Sopenharmony_ci			case -2:
5438c2ecf20Sopenharmony_ci				goto unknown;
5448c2ecf20Sopenharmony_ci			case -3:
5458c2ecf20Sopenharmony_ci				goto exclusive;
5468c2ecf20Sopenharmony_ci			default:
5478c2ecf20Sopenharmony_ci				break;
5488c2ecf20Sopenharmony_ci			}
5498c2ecf20Sopenharmony_ci			if (ctx->opt)
5508c2ecf20Sopenharmony_ci				check_typos(arg, options);
5518c2ecf20Sopenharmony_ci			while (ctx->opt) {
5528c2ecf20Sopenharmony_ci				if (internal_help && *ctx->opt == 'h')
5538c2ecf20Sopenharmony_ci					return usage_with_options_internal(usagestr, options, 0, ctx);
5548c2ecf20Sopenharmony_ci				arg = ctx->opt;
5558c2ecf20Sopenharmony_ci				switch (parse_short_opt(ctx, options)) {
5568c2ecf20Sopenharmony_ci				case -1:
5578c2ecf20Sopenharmony_ci					return parse_options_usage(usagestr, options, arg, 1);
5588c2ecf20Sopenharmony_ci				case -2:
5598c2ecf20Sopenharmony_ci					/* fake a short option thing to hide the fact that we may have
5608c2ecf20Sopenharmony_ci					 * started to parse aggregated stuff
5618c2ecf20Sopenharmony_ci					 *
5628c2ecf20Sopenharmony_ci					 * This is leaky, too bad.
5638c2ecf20Sopenharmony_ci					 */
5648c2ecf20Sopenharmony_ci					ctx->argv[0] = strdup(ctx->opt - 1);
5658c2ecf20Sopenharmony_ci					*(char *)ctx->argv[0] = '-';
5668c2ecf20Sopenharmony_ci					goto unknown;
5678c2ecf20Sopenharmony_ci				case -3:
5688c2ecf20Sopenharmony_ci					goto exclusive;
5698c2ecf20Sopenharmony_ci				default:
5708c2ecf20Sopenharmony_ci					break;
5718c2ecf20Sopenharmony_ci				}
5728c2ecf20Sopenharmony_ci			}
5738c2ecf20Sopenharmony_ci			continue;
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		if (!arg[2]) { /* "--" */
5778c2ecf20Sopenharmony_ci			if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
5788c2ecf20Sopenharmony_ci				ctx->argc--;
5798c2ecf20Sopenharmony_ci				ctx->argv++;
5808c2ecf20Sopenharmony_ci			}
5818c2ecf20Sopenharmony_ci			break;
5828c2ecf20Sopenharmony_ci		}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		arg += 2;
5858c2ecf20Sopenharmony_ci		if (internal_help && !strcmp(arg, "help-all"))
5868c2ecf20Sopenharmony_ci			return usage_with_options_internal(usagestr, options, 1, ctx);
5878c2ecf20Sopenharmony_ci		if (internal_help && !strcmp(arg, "help"))
5888c2ecf20Sopenharmony_ci			return usage_with_options_internal(usagestr, options, 0, ctx);
5898c2ecf20Sopenharmony_ci		if (!strcmp(arg, "list-opts"))
5908c2ecf20Sopenharmony_ci			return PARSE_OPT_LIST_OPTS;
5918c2ecf20Sopenharmony_ci		if (!strcmp(arg, "list-cmds"))
5928c2ecf20Sopenharmony_ci			return PARSE_OPT_LIST_SUBCMDS;
5938c2ecf20Sopenharmony_ci		switch (parse_long_opt(ctx, arg, options)) {
5948c2ecf20Sopenharmony_ci		case -1:
5958c2ecf20Sopenharmony_ci			return parse_options_usage(usagestr, options, arg, 0);
5968c2ecf20Sopenharmony_ci		case -2:
5978c2ecf20Sopenharmony_ci			goto unknown;
5988c2ecf20Sopenharmony_ci		case -3:
5998c2ecf20Sopenharmony_ci			excl_short_opt = 0;
6008c2ecf20Sopenharmony_ci			goto exclusive;
6018c2ecf20Sopenharmony_ci		default:
6028c2ecf20Sopenharmony_ci			break;
6038c2ecf20Sopenharmony_ci		}
6048c2ecf20Sopenharmony_ci		continue;
6058c2ecf20Sopenharmony_ciunknown:
6068c2ecf20Sopenharmony_ci		if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
6078c2ecf20Sopenharmony_ci			return PARSE_OPT_UNKNOWN;
6088c2ecf20Sopenharmony_ci		ctx->out[ctx->cpidx++] = ctx->argv[0];
6098c2ecf20Sopenharmony_ci		ctx->opt = NULL;
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci	return PARSE_OPT_DONE;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ciexclusive:
6148c2ecf20Sopenharmony_ci	parse_options_usage(usagestr, options, arg, excl_short_opt);
6158c2ecf20Sopenharmony_ci	if ((excl_short_opt && ctx->excl_opt->short_name) ||
6168c2ecf20Sopenharmony_ci	    ctx->excl_opt->long_name == NULL) {
6178c2ecf20Sopenharmony_ci		char opt = ctx->excl_opt->short_name;
6188c2ecf20Sopenharmony_ci		parse_options_usage(NULL, options, &opt, 1);
6198c2ecf20Sopenharmony_ci	} else {
6208c2ecf20Sopenharmony_ci		parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci	return PARSE_OPT_HELP;
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cistatic int parse_options_end(struct parse_opt_ctx_t *ctx)
6268c2ecf20Sopenharmony_ci{
6278c2ecf20Sopenharmony_ci	memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
6288c2ecf20Sopenharmony_ci	ctx->out[ctx->cpidx + ctx->argc] = NULL;
6298c2ecf20Sopenharmony_ci	return ctx->cpidx + ctx->argc;
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ciint parse_options_subcommand(int argc, const char **argv, const struct option *options,
6338c2ecf20Sopenharmony_ci			const char *const subcommands[], const char *usagestr[], int flags)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct parse_opt_ctx_t ctx;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	/* build usage string if it's not provided */
6388c2ecf20Sopenharmony_ci	if (subcommands && !usagestr[0]) {
6398c2ecf20Sopenharmony_ci		char *buf = NULL;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		for (int i = 0; subcommands[i]; i++) {
6448c2ecf20Sopenharmony_ci			if (i)
6458c2ecf20Sopenharmony_ci				astrcat(&buf, "|");
6468c2ecf20Sopenharmony_ci			astrcat(&buf, subcommands[i]);
6478c2ecf20Sopenharmony_ci		}
6488c2ecf20Sopenharmony_ci		astrcat(&buf, "}");
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci		usagestr[0] = buf;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	parse_options_start(&ctx, argc, argv, flags);
6548c2ecf20Sopenharmony_ci	switch (parse_options_step(&ctx, options, usagestr)) {
6558c2ecf20Sopenharmony_ci	case PARSE_OPT_HELP:
6568c2ecf20Sopenharmony_ci		exit(129);
6578c2ecf20Sopenharmony_ci	case PARSE_OPT_DONE:
6588c2ecf20Sopenharmony_ci		break;
6598c2ecf20Sopenharmony_ci	case PARSE_OPT_LIST_OPTS:
6608c2ecf20Sopenharmony_ci		while (options->type != OPTION_END) {
6618c2ecf20Sopenharmony_ci			if (options->long_name)
6628c2ecf20Sopenharmony_ci				printf("--%s ", options->long_name);
6638c2ecf20Sopenharmony_ci			options++;
6648c2ecf20Sopenharmony_ci		}
6658c2ecf20Sopenharmony_ci		putchar('\n');
6668c2ecf20Sopenharmony_ci		exit(130);
6678c2ecf20Sopenharmony_ci	case PARSE_OPT_LIST_SUBCMDS:
6688c2ecf20Sopenharmony_ci		if (subcommands) {
6698c2ecf20Sopenharmony_ci			for (int i = 0; subcommands[i]; i++)
6708c2ecf20Sopenharmony_ci				printf("%s ", subcommands[i]);
6718c2ecf20Sopenharmony_ci		}
6728c2ecf20Sopenharmony_ci		putchar('\n');
6738c2ecf20Sopenharmony_ci		exit(130);
6748c2ecf20Sopenharmony_ci	default: /* PARSE_OPT_UNKNOWN */
6758c2ecf20Sopenharmony_ci		if (ctx.argv[0][1] == '-')
6768c2ecf20Sopenharmony_ci			astrcatf(&error_buf, "unknown option `%s'",
6778c2ecf20Sopenharmony_ci				 ctx.argv[0] + 2);
6788c2ecf20Sopenharmony_ci		else
6798c2ecf20Sopenharmony_ci			astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
6808c2ecf20Sopenharmony_ci		usage_with_options(usagestr, options);
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	return parse_options_end(&ctx);
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ciint parse_options(int argc, const char **argv, const struct option *options,
6878c2ecf20Sopenharmony_ci		  const char * const usagestr[], int flags)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	return parse_options_subcommand(argc, argv, options, NULL,
6908c2ecf20Sopenharmony_ci					(const char **) usagestr, flags);
6918c2ecf20Sopenharmony_ci}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci#define USAGE_OPTS_WIDTH 24
6948c2ecf20Sopenharmony_ci#define USAGE_GAP         2
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_cistatic void print_option_help(const struct option *opts, int full)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	size_t pos;
6998c2ecf20Sopenharmony_ci	int pad;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	if (opts->type == OPTION_GROUP) {
7028c2ecf20Sopenharmony_ci		fputc('\n', stderr);
7038c2ecf20Sopenharmony_ci		if (*opts->help)
7048c2ecf20Sopenharmony_ci			fprintf(stderr, "%s\n", opts->help);
7058c2ecf20Sopenharmony_ci		return;
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci	if (!full && (opts->flags & PARSE_OPT_HIDDEN))
7088c2ecf20Sopenharmony_ci		return;
7098c2ecf20Sopenharmony_ci	if (opts->flags & PARSE_OPT_DISABLED)
7108c2ecf20Sopenharmony_ci		return;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	pos = fprintf(stderr, "    ");
7138c2ecf20Sopenharmony_ci	if (opts->short_name)
7148c2ecf20Sopenharmony_ci		pos += fprintf(stderr, "-%c", opts->short_name);
7158c2ecf20Sopenharmony_ci	else
7168c2ecf20Sopenharmony_ci		pos += fprintf(stderr, "    ");
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	if (opts->long_name && opts->short_name)
7198c2ecf20Sopenharmony_ci		pos += fprintf(stderr, ", ");
7208c2ecf20Sopenharmony_ci	if (opts->long_name)
7218c2ecf20Sopenharmony_ci		pos += fprintf(stderr, "--%s", opts->long_name);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	switch (opts->type) {
7248c2ecf20Sopenharmony_ci	case OPTION_ARGUMENT:
7258c2ecf20Sopenharmony_ci		break;
7268c2ecf20Sopenharmony_ci	case OPTION_LONG:
7278c2ecf20Sopenharmony_ci	case OPTION_ULONG:
7288c2ecf20Sopenharmony_ci	case OPTION_U64:
7298c2ecf20Sopenharmony_ci	case OPTION_INTEGER:
7308c2ecf20Sopenharmony_ci	case OPTION_UINTEGER:
7318c2ecf20Sopenharmony_ci		if (opts->flags & PARSE_OPT_OPTARG)
7328c2ecf20Sopenharmony_ci			if (opts->long_name)
7338c2ecf20Sopenharmony_ci				pos += fprintf(stderr, "[=<n>]");
7348c2ecf20Sopenharmony_ci			else
7358c2ecf20Sopenharmony_ci				pos += fprintf(stderr, "[<n>]");
7368c2ecf20Sopenharmony_ci		else
7378c2ecf20Sopenharmony_ci			pos += fprintf(stderr, " <n>");
7388c2ecf20Sopenharmony_ci		break;
7398c2ecf20Sopenharmony_ci	case OPTION_CALLBACK:
7408c2ecf20Sopenharmony_ci		if (opts->flags & PARSE_OPT_NOARG)
7418c2ecf20Sopenharmony_ci			break;
7428c2ecf20Sopenharmony_ci		/* FALLTHROUGH */
7438c2ecf20Sopenharmony_ci	case OPTION_STRING:
7448c2ecf20Sopenharmony_ci		if (opts->argh) {
7458c2ecf20Sopenharmony_ci			if (opts->flags & PARSE_OPT_OPTARG)
7468c2ecf20Sopenharmony_ci				if (opts->long_name)
7478c2ecf20Sopenharmony_ci					pos += fprintf(stderr, "[=<%s>]", opts->argh);
7488c2ecf20Sopenharmony_ci				else
7498c2ecf20Sopenharmony_ci					pos += fprintf(stderr, "[<%s>]", opts->argh);
7508c2ecf20Sopenharmony_ci			else
7518c2ecf20Sopenharmony_ci				pos += fprintf(stderr, " <%s>", opts->argh);
7528c2ecf20Sopenharmony_ci		} else {
7538c2ecf20Sopenharmony_ci			if (opts->flags & PARSE_OPT_OPTARG)
7548c2ecf20Sopenharmony_ci				if (opts->long_name)
7558c2ecf20Sopenharmony_ci					pos += fprintf(stderr, "[=...]");
7568c2ecf20Sopenharmony_ci				else
7578c2ecf20Sopenharmony_ci					pos += fprintf(stderr, "[...]");
7588c2ecf20Sopenharmony_ci			else
7598c2ecf20Sopenharmony_ci				pos += fprintf(stderr, " ...");
7608c2ecf20Sopenharmony_ci		}
7618c2ecf20Sopenharmony_ci		break;
7628c2ecf20Sopenharmony_ci	default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
7638c2ecf20Sopenharmony_ci	case OPTION_END:
7648c2ecf20Sopenharmony_ci	case OPTION_GROUP:
7658c2ecf20Sopenharmony_ci	case OPTION_BIT:
7668c2ecf20Sopenharmony_ci	case OPTION_BOOLEAN:
7678c2ecf20Sopenharmony_ci	case OPTION_INCR:
7688c2ecf20Sopenharmony_ci	case OPTION_SET_UINT:
7698c2ecf20Sopenharmony_ci	case OPTION_SET_PTR:
7708c2ecf20Sopenharmony_ci		break;
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	if (pos <= USAGE_OPTS_WIDTH)
7748c2ecf20Sopenharmony_ci		pad = USAGE_OPTS_WIDTH - pos;
7758c2ecf20Sopenharmony_ci	else {
7768c2ecf20Sopenharmony_ci		fputc('\n', stderr);
7778c2ecf20Sopenharmony_ci		pad = USAGE_OPTS_WIDTH;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci	fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
7808c2ecf20Sopenharmony_ci	if (opts->flags & PARSE_OPT_NOBUILD)
7818c2ecf20Sopenharmony_ci		fprintf(stderr, "%*s(not built-in because %s)\n",
7828c2ecf20Sopenharmony_ci			USAGE_OPTS_WIDTH + USAGE_GAP, "",
7838c2ecf20Sopenharmony_ci			opts->build_opt);
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cistatic int option__cmp(const void *va, const void *vb)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	const struct option *a = va, *b = vb;
7898c2ecf20Sopenharmony_ci	int sa = tolower(a->short_name), sb = tolower(b->short_name), ret;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	if (sa == 0)
7928c2ecf20Sopenharmony_ci		sa = 'z' + 1;
7938c2ecf20Sopenharmony_ci	if (sb == 0)
7948c2ecf20Sopenharmony_ci		sb = 'z' + 1;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	ret = sa - sb;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	if (ret == 0) {
7998c2ecf20Sopenharmony_ci		const char *la = a->long_name ?: "",
8008c2ecf20Sopenharmony_ci			   *lb = b->long_name ?: "";
8018c2ecf20Sopenharmony_ci		ret = strcmp(la, lb);
8028c2ecf20Sopenharmony_ci	}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	return ret;
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cistatic struct option *options__order(const struct option *opts)
8088c2ecf20Sopenharmony_ci{
8098c2ecf20Sopenharmony_ci	int nr_opts = 0, len;
8108c2ecf20Sopenharmony_ci	const struct option *o = opts;
8118c2ecf20Sopenharmony_ci	struct option *ordered;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	for (o = opts; o->type != OPTION_END; o++)
8148c2ecf20Sopenharmony_ci		++nr_opts;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	len = sizeof(*o) * (nr_opts + 1);
8178c2ecf20Sopenharmony_ci	ordered = malloc(len);
8188c2ecf20Sopenharmony_ci	if (!ordered)
8198c2ecf20Sopenharmony_ci		goto out;
8208c2ecf20Sopenharmony_ci	memcpy(ordered, opts, len);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	qsort(ordered, nr_opts, sizeof(*o), option__cmp);
8238c2ecf20Sopenharmony_ciout:
8248c2ecf20Sopenharmony_ci	return ordered;
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	int i;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	for (i = 1; i < ctx->argc; ++i) {
8328c2ecf20Sopenharmony_ci		const char *arg = ctx->argv[i];
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci		if (arg[0] != '-') {
8358c2ecf20Sopenharmony_ci			if (arg[1] == '\0') {
8368c2ecf20Sopenharmony_ci				if (arg[0] == opt->short_name)
8378c2ecf20Sopenharmony_ci					return true;
8388c2ecf20Sopenharmony_ci				continue;
8398c2ecf20Sopenharmony_ci			}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci			if (opt->long_name && strcmp(opt->long_name, arg) == 0)
8428c2ecf20Sopenharmony_ci				return true;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci			if (opt->help && strcasestr(opt->help, arg) != NULL)
8458c2ecf20Sopenharmony_ci				return true;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci			continue;
8488c2ecf20Sopenharmony_ci		}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci		if (arg[1] == opt->short_name ||
8518c2ecf20Sopenharmony_ci		    (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
8528c2ecf20Sopenharmony_ci			return true;
8538c2ecf20Sopenharmony_ci	}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	return false;
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic int usage_with_options_internal(const char * const *usagestr,
8598c2ecf20Sopenharmony_ci				       const struct option *opts, int full,
8608c2ecf20Sopenharmony_ci				       struct parse_opt_ctx_t *ctx)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	struct option *ordered;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	if (!usagestr)
8658c2ecf20Sopenharmony_ci		return PARSE_OPT_HELP;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	setup_pager();
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	if (error_buf) {
8708c2ecf20Sopenharmony_ci		fprintf(stderr, "  Error: %s\n", error_buf);
8718c2ecf20Sopenharmony_ci		zfree(&error_buf);
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	fprintf(stderr, "\n Usage: %s\n", *usagestr++);
8758c2ecf20Sopenharmony_ci	while (*usagestr && **usagestr)
8768c2ecf20Sopenharmony_ci		fprintf(stderr, "    or: %s\n", *usagestr++);
8778c2ecf20Sopenharmony_ci	while (*usagestr) {
8788c2ecf20Sopenharmony_ci		fprintf(stderr, "%s%s\n",
8798c2ecf20Sopenharmony_ci				**usagestr ? "    " : "",
8808c2ecf20Sopenharmony_ci				*usagestr);
8818c2ecf20Sopenharmony_ci		usagestr++;
8828c2ecf20Sopenharmony_ci	}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	if (opts->type != OPTION_GROUP)
8858c2ecf20Sopenharmony_ci		fputc('\n', stderr);
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	ordered = options__order(opts);
8888c2ecf20Sopenharmony_ci	if (ordered)
8898c2ecf20Sopenharmony_ci		opts = ordered;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	for (  ; opts->type != OPTION_END; opts++) {
8928c2ecf20Sopenharmony_ci		if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
8938c2ecf20Sopenharmony_ci			continue;
8948c2ecf20Sopenharmony_ci		print_option_help(opts, full);
8958c2ecf20Sopenharmony_ci	}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	fputc('\n', stderr);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	free(ordered);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	return PARSE_OPT_HELP;
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_civoid usage_with_options(const char * const *usagestr,
9058c2ecf20Sopenharmony_ci			const struct option *opts)
9068c2ecf20Sopenharmony_ci{
9078c2ecf20Sopenharmony_ci	usage_with_options_internal(usagestr, opts, 0, NULL);
9088c2ecf20Sopenharmony_ci	exit(129);
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_civoid usage_with_options_msg(const char * const *usagestr,
9128c2ecf20Sopenharmony_ci			    const struct option *opts, const char *fmt, ...)
9138c2ecf20Sopenharmony_ci{
9148c2ecf20Sopenharmony_ci	va_list ap;
9158c2ecf20Sopenharmony_ci	char *tmp = error_buf;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	va_start(ap, fmt);
9188c2ecf20Sopenharmony_ci	if (vasprintf(&error_buf, fmt, ap) == -1)
9198c2ecf20Sopenharmony_ci		die("vasprintf failed");
9208c2ecf20Sopenharmony_ci	va_end(ap);
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	free(tmp);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	usage_with_options_internal(usagestr, opts, 0, NULL);
9258c2ecf20Sopenharmony_ci	exit(129);
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ciint parse_options_usage(const char * const *usagestr,
9298c2ecf20Sopenharmony_ci			const struct option *opts,
9308c2ecf20Sopenharmony_ci			const char *optstr, bool short_opt)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	if (!usagestr)
9338c2ecf20Sopenharmony_ci		goto opt;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	fprintf(stderr, "\n Usage: %s\n", *usagestr++);
9368c2ecf20Sopenharmony_ci	while (*usagestr && **usagestr)
9378c2ecf20Sopenharmony_ci		fprintf(stderr, "    or: %s\n", *usagestr++);
9388c2ecf20Sopenharmony_ci	while (*usagestr) {
9398c2ecf20Sopenharmony_ci		fprintf(stderr, "%s%s\n",
9408c2ecf20Sopenharmony_ci				**usagestr ? "    " : "",
9418c2ecf20Sopenharmony_ci				*usagestr);
9428c2ecf20Sopenharmony_ci		usagestr++;
9438c2ecf20Sopenharmony_ci	}
9448c2ecf20Sopenharmony_ci	fputc('\n', stderr);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ciopt:
9478c2ecf20Sopenharmony_ci	for (  ; opts->type != OPTION_END; opts++) {
9488c2ecf20Sopenharmony_ci		if (short_opt) {
9498c2ecf20Sopenharmony_ci			if (opts->short_name == *optstr) {
9508c2ecf20Sopenharmony_ci				print_option_help(opts, 0);
9518c2ecf20Sopenharmony_ci				break;
9528c2ecf20Sopenharmony_ci			}
9538c2ecf20Sopenharmony_ci			continue;
9548c2ecf20Sopenharmony_ci		}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci		if (opts->long_name == NULL)
9578c2ecf20Sopenharmony_ci			continue;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci		if (strstarts(opts->long_name, optstr))
9608c2ecf20Sopenharmony_ci			print_option_help(opts, 0);
9618c2ecf20Sopenharmony_ci		if (strstarts("no-", optstr) &&
9628c2ecf20Sopenharmony_ci		    strstarts(opts->long_name, optstr + 3))
9638c2ecf20Sopenharmony_ci			print_option_help(opts, 0);
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	return PARSE_OPT_HELP;
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ciint parse_opt_verbosity_cb(const struct option *opt,
9718c2ecf20Sopenharmony_ci			   const char *arg __maybe_unused,
9728c2ecf20Sopenharmony_ci			   int unset)
9738c2ecf20Sopenharmony_ci{
9748c2ecf20Sopenharmony_ci	int *target = opt->value;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	if (unset)
9778c2ecf20Sopenharmony_ci		/* --no-quiet, --no-verbose */
9788c2ecf20Sopenharmony_ci		*target = 0;
9798c2ecf20Sopenharmony_ci	else if (opt->short_name == 'v') {
9808c2ecf20Sopenharmony_ci		if (*target >= 0)
9818c2ecf20Sopenharmony_ci			(*target)++;
9828c2ecf20Sopenharmony_ci		else
9838c2ecf20Sopenharmony_ci			*target = 1;
9848c2ecf20Sopenharmony_ci	} else {
9858c2ecf20Sopenharmony_ci		if (*target <= 0)
9868c2ecf20Sopenharmony_ci			(*target)--;
9878c2ecf20Sopenharmony_ci		else
9888c2ecf20Sopenharmony_ci			*target = -1;
9898c2ecf20Sopenharmony_ci	}
9908c2ecf20Sopenharmony_ci	return 0;
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_cistatic struct option *
9948c2ecf20Sopenharmony_cifind_option(struct option *opts, int shortopt, const char *longopt)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	for (; opts->type != OPTION_END; opts++) {
9978c2ecf20Sopenharmony_ci		if ((shortopt && opts->short_name == shortopt) ||
9988c2ecf20Sopenharmony_ci		    (opts->long_name && longopt &&
9998c2ecf20Sopenharmony_ci		     !strcmp(opts->long_name, longopt)))
10008c2ecf20Sopenharmony_ci			return opts;
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci	return NULL;
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_civoid set_option_flag(struct option *opts, int shortopt, const char *longopt,
10068c2ecf20Sopenharmony_ci		     int flag)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	struct option *opt = find_option(opts, shortopt, longopt);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	if (opt)
10118c2ecf20Sopenharmony_ci		opt->flags |= flag;
10128c2ecf20Sopenharmony_ci	return;
10138c2ecf20Sopenharmony_ci}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_civoid set_option_nobuild(struct option *opts, int shortopt,
10168c2ecf20Sopenharmony_ci			const char *longopt,
10178c2ecf20Sopenharmony_ci			const char *build_opt,
10188c2ecf20Sopenharmony_ci			bool can_skip)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	struct option *opt = find_option(opts, shortopt, longopt);
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	if (!opt)
10238c2ecf20Sopenharmony_ci		return;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	opt->flags |= PARSE_OPT_NOBUILD;
10268c2ecf20Sopenharmony_ci	opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
10278c2ecf20Sopenharmony_ci	opt->build_opt = build_opt;
10288c2ecf20Sopenharmony_ci}
1029