18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __SUBCMD_PARSE_OPTIONS_H
38c2ecf20Sopenharmony_ci#define __SUBCMD_PARSE_OPTIONS_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/kernel.h>
68c2ecf20Sopenharmony_ci#include <stdbool.h>
78c2ecf20Sopenharmony_ci#include <stdint.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#ifndef NORETURN
108c2ecf20Sopenharmony_ci#define NORETURN __attribute__((__noreturn__))
118c2ecf20Sopenharmony_ci#endif
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cienum parse_opt_type {
148c2ecf20Sopenharmony_ci	/* special types */
158c2ecf20Sopenharmony_ci	OPTION_END,
168c2ecf20Sopenharmony_ci	OPTION_ARGUMENT,
178c2ecf20Sopenharmony_ci	OPTION_GROUP,
188c2ecf20Sopenharmony_ci	/* options with no arguments */
198c2ecf20Sopenharmony_ci	OPTION_BIT,
208c2ecf20Sopenharmony_ci	OPTION_BOOLEAN,
218c2ecf20Sopenharmony_ci	OPTION_INCR,
228c2ecf20Sopenharmony_ci	OPTION_SET_UINT,
238c2ecf20Sopenharmony_ci	OPTION_SET_PTR,
248c2ecf20Sopenharmony_ci	/* options with arguments (usually) */
258c2ecf20Sopenharmony_ci	OPTION_STRING,
268c2ecf20Sopenharmony_ci	OPTION_INTEGER,
278c2ecf20Sopenharmony_ci	OPTION_LONG,
288c2ecf20Sopenharmony_ci	OPTION_ULONG,
298c2ecf20Sopenharmony_ci	OPTION_CALLBACK,
308c2ecf20Sopenharmony_ci	OPTION_U64,
318c2ecf20Sopenharmony_ci	OPTION_UINTEGER,
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cienum parse_opt_flags {
358c2ecf20Sopenharmony_ci	PARSE_OPT_KEEP_DASHDASH = 1,
368c2ecf20Sopenharmony_ci	PARSE_OPT_STOP_AT_NON_OPTION = 2,
378c2ecf20Sopenharmony_ci	PARSE_OPT_KEEP_ARGV0 = 4,
388c2ecf20Sopenharmony_ci	PARSE_OPT_KEEP_UNKNOWN = 8,
398c2ecf20Sopenharmony_ci	PARSE_OPT_NO_INTERNAL_HELP = 16,
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cienum parse_opt_option_flags {
438c2ecf20Sopenharmony_ci	PARSE_OPT_OPTARG  = 1,
448c2ecf20Sopenharmony_ci	PARSE_OPT_NOARG   = 2,
458c2ecf20Sopenharmony_ci	PARSE_OPT_NONEG   = 4,
468c2ecf20Sopenharmony_ci	PARSE_OPT_HIDDEN  = 8,
478c2ecf20Sopenharmony_ci	PARSE_OPT_LASTARG_DEFAULT = 16,
488c2ecf20Sopenharmony_ci	PARSE_OPT_DISABLED = 32,
498c2ecf20Sopenharmony_ci	PARSE_OPT_EXCLUSIVE = 64,
508c2ecf20Sopenharmony_ci	PARSE_OPT_NOEMPTY  = 128,
518c2ecf20Sopenharmony_ci	PARSE_OPT_NOBUILD  = 256,
528c2ecf20Sopenharmony_ci	PARSE_OPT_CANSKIP  = 512,
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistruct option;
568c2ecf20Sopenharmony_citypedef int parse_opt_cb(const struct option *, const char *arg, int unset);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/*
598c2ecf20Sopenharmony_ci * `type`::
608c2ecf20Sopenharmony_ci *   holds the type of the option, you must have an OPTION_END last in your
618c2ecf20Sopenharmony_ci *   array.
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * `short_name`::
648c2ecf20Sopenharmony_ci *   the character to use as a short option name, '\0' if none.
658c2ecf20Sopenharmony_ci *
668c2ecf20Sopenharmony_ci * `long_name`::
678c2ecf20Sopenharmony_ci *   the long option name, without the leading dashes, NULL if none.
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * `value`::
708c2ecf20Sopenharmony_ci *   stores pointers to the values to be filled.
718c2ecf20Sopenharmony_ci *
728c2ecf20Sopenharmony_ci * `argh`::
738c2ecf20Sopenharmony_ci *   token to explain the kind of argument this option wants. Keep it
748c2ecf20Sopenharmony_ci *   homogeneous across the repository.
758c2ecf20Sopenharmony_ci *
768c2ecf20Sopenharmony_ci * `help`::
778c2ecf20Sopenharmony_ci *   the short help associated to what the option does.
788c2ecf20Sopenharmony_ci *   Must never be NULL (except for OPTION_END).
798c2ecf20Sopenharmony_ci *   OPTION_GROUP uses this pointer to store the group header.
808c2ecf20Sopenharmony_ci *
818c2ecf20Sopenharmony_ci * `flags`::
828c2ecf20Sopenharmony_ci *   mask of parse_opt_option_flags.
838c2ecf20Sopenharmony_ci *   PARSE_OPT_OPTARG: says that the argument is optional (not for BOOLEANs)
848c2ecf20Sopenharmony_ci *   PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
858c2ecf20Sopenharmony_ci *   PARSE_OPT_NONEG: says that this option cannot be negated
868c2ecf20Sopenharmony_ci *   PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
878c2ecf20Sopenharmony_ci *                    the long one.
888c2ecf20Sopenharmony_ci *
898c2ecf20Sopenharmony_ci * `callback`::
908c2ecf20Sopenharmony_ci *   pointer to the callback to use for OPTION_CALLBACK.
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci * `defval`::
938c2ecf20Sopenharmony_ci *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
948c2ecf20Sopenharmony_ci *   OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
958c2ecf20Sopenharmony_ci *   the value when met.
968c2ecf20Sopenharmony_ci *   CALLBACKS can use it like they want.
978c2ecf20Sopenharmony_ci *
988c2ecf20Sopenharmony_ci * `set`::
998c2ecf20Sopenharmony_ci *   whether an option was set by the user
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_cistruct option {
1028c2ecf20Sopenharmony_ci	enum parse_opt_type type;
1038c2ecf20Sopenharmony_ci	int short_name;
1048c2ecf20Sopenharmony_ci	const char *long_name;
1058c2ecf20Sopenharmony_ci	void *value;
1068c2ecf20Sopenharmony_ci	const char *argh;
1078c2ecf20Sopenharmony_ci	const char *help;
1088c2ecf20Sopenharmony_ci	const char *build_opt;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	int flags;
1118c2ecf20Sopenharmony_ci	parse_opt_cb *callback;
1128c2ecf20Sopenharmony_ci	intptr_t defval;
1138c2ecf20Sopenharmony_ci	bool *set;
1148c2ecf20Sopenharmony_ci	void *data;
1158c2ecf20Sopenharmony_ci	const struct option *parent;
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci#define OPT_END()                   { .type = OPTION_END }
1218c2ecf20Sopenharmony_ci#define OPT_PARENT(p)               { .type = OPTION_END, .parent = (p) }
1228c2ecf20Sopenharmony_ci#define OPT_ARGUMENT(l, h)          { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
1238c2ecf20Sopenharmony_ci#define OPT_GROUP(h)                { .type = OPTION_GROUP, .help = (h) }
1248c2ecf20Sopenharmony_ci#define OPT_BIT(s, l, v, h, b)      { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) }
1258c2ecf20Sopenharmony_ci#define OPT_BOOLEAN(s, l, v, h)     { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) }
1268c2ecf20Sopenharmony_ci#define OPT_BOOLEAN_FLAG(s, l, v, h, f)     { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h), .flags = (f) }
1278c2ecf20Sopenharmony_ci#define OPT_BOOLEAN_SET(s, l, v, os, h) \
1288c2ecf20Sopenharmony_ci	{ .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \
1298c2ecf20Sopenharmony_ci	.value = check_vtype(v, bool *), .help = (h), \
1308c2ecf20Sopenharmony_ci	.set = check_vtype(os, bool *)}
1318c2ecf20Sopenharmony_ci#define OPT_INCR(s, l, v, h)        { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
1328c2ecf20Sopenharmony_ci#define OPT_SET_UINT(s, l, v, h, i)  { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) }
1338c2ecf20Sopenharmony_ci#define OPT_SET_PTR(s, l, v, h, p)  { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
1348c2ecf20Sopenharmony_ci#define OPT_INTEGER(s, l, v, h)     { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
1358c2ecf20Sopenharmony_ci#define OPT_UINTEGER(s, l, v, h)    { .type = OPTION_UINTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h) }
1368c2ecf20Sopenharmony_ci#define OPT_LONG(s, l, v, h)        { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
1378c2ecf20Sopenharmony_ci#define OPT_ULONG(s, l, v, h)        { .type = OPTION_ULONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned long *), .help = (h) }
1388c2ecf20Sopenharmony_ci#define OPT_U64(s, l, v, h)         { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
1398c2ecf20Sopenharmony_ci#define OPT_STRING(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), .argh = (a), .help = (h) }
1408c2ecf20Sopenharmony_ci#define OPT_STRING_OPTARG(s, l, v, a, h, d) \
1418c2ecf20Sopenharmony_ci	{ .type = OPTION_STRING,  .short_name = (s), .long_name = (l), \
1428c2ecf20Sopenharmony_ci	  .value = check_vtype(v, const char **), .argh =(a), .help = (h), \
1438c2ecf20Sopenharmony_ci	  .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d) }
1448c2ecf20Sopenharmony_ci#define OPT_STRING_OPTARG_SET(s, l, v, os, a, h, d) \
1458c2ecf20Sopenharmony_ci	{ .type = OPTION_STRING, .short_name = (s), .long_name = (l), \
1468c2ecf20Sopenharmony_ci	  .value = check_vtype(v, const char **), .argh = (a), .help = (h), \
1478c2ecf20Sopenharmony_ci	  .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d), \
1488c2ecf20Sopenharmony_ci	  .set = check_vtype(os, bool *)}
1498c2ecf20Sopenharmony_ci#define OPT_STRING_NOEMPTY(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), .argh = (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
1508c2ecf20Sopenharmony_ci#define OPT_DATE(s, l, v, h) \
1518c2ecf20Sopenharmony_ci	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
1528c2ecf20Sopenharmony_ci#define OPT_CALLBACK(s, l, v, a, h, f) \
1538c2ecf20Sopenharmony_ci	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f) }
1548c2ecf20Sopenharmony_ci#define OPT_CALLBACK_SET(s, l, v, os, a, h, f) \
1558c2ecf20Sopenharmony_ci	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .set = check_vtype(os, bool *)}
1568c2ecf20Sopenharmony_ci#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
1578c2ecf20Sopenharmony_ci	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
1588c2ecf20Sopenharmony_ci#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
1598c2ecf20Sopenharmony_ci	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
1608c2ecf20Sopenharmony_ci#define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \
1618c2ecf20Sopenharmony_ci	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
1628c2ecf20Sopenharmony_ci	.value = (v), .arg = (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
1638c2ecf20Sopenharmony_ci	.flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
1648c2ecf20Sopenharmony_ci#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
1658c2ecf20Sopenharmony_ci	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
1668c2ecf20Sopenharmony_ci	  .value = (v), .argh = (a), .help = (h), .callback = (f), \
1678c2ecf20Sopenharmony_ci	  .flags = PARSE_OPT_OPTARG, .data = (d) }
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/* parse_options() will filter out the processed options and leave the
1708c2ecf20Sopenharmony_ci * non-option argments in argv[].
1718c2ecf20Sopenharmony_ci * Returns the number of arguments left in argv[].
1728c2ecf20Sopenharmony_ci *
1738c2ecf20Sopenharmony_ci * NOTE: parse_options() and parse_options_subcommand() may call exit() in the
1748c2ecf20Sopenharmony_ci * case of an error (or for 'special' options like --list-cmds or --list-opts).
1758c2ecf20Sopenharmony_ci */
1768c2ecf20Sopenharmony_ciextern int parse_options(int argc, const char **argv,
1778c2ecf20Sopenharmony_ci                         const struct option *options,
1788c2ecf20Sopenharmony_ci                         const char * const usagestr[], int flags);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ciextern int parse_options_subcommand(int argc, const char **argv,
1818c2ecf20Sopenharmony_ci				const struct option *options,
1828c2ecf20Sopenharmony_ci				const char *const subcommands[],
1838c2ecf20Sopenharmony_ci				const char *usagestr[], int flags);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ciextern NORETURN void usage_with_options(const char * const *usagestr,
1868c2ecf20Sopenharmony_ci                                        const struct option *options);
1878c2ecf20Sopenharmony_ciextern NORETURN __attribute__((format(printf,3,4)))
1888c2ecf20Sopenharmony_civoid usage_with_options_msg(const char * const *usagestr,
1898c2ecf20Sopenharmony_ci			    const struct option *options,
1908c2ecf20Sopenharmony_ci			    const char *fmt, ...);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/*----- incremantal advanced APIs -----*/
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cienum {
1958c2ecf20Sopenharmony_ci	PARSE_OPT_HELP = -1,
1968c2ecf20Sopenharmony_ci	PARSE_OPT_DONE,
1978c2ecf20Sopenharmony_ci	PARSE_OPT_LIST_OPTS,
1988c2ecf20Sopenharmony_ci	PARSE_OPT_LIST_SUBCMDS,
1998c2ecf20Sopenharmony_ci	PARSE_OPT_UNKNOWN,
2008c2ecf20Sopenharmony_ci};
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/*
2038c2ecf20Sopenharmony_ci * It's okay for the caller to consume argv/argc in the usual way.
2048c2ecf20Sopenharmony_ci * Other fields of that structure are private to parse-options and should not
2058c2ecf20Sopenharmony_ci * be modified in any way.
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_cistruct parse_opt_ctx_t {
2088c2ecf20Sopenharmony_ci	const char **argv;
2098c2ecf20Sopenharmony_ci	const char **out;
2108c2ecf20Sopenharmony_ci	int argc, cpidx;
2118c2ecf20Sopenharmony_ci	const char *opt;
2128c2ecf20Sopenharmony_ci	const struct option *excl_opt;
2138c2ecf20Sopenharmony_ci	int flags;
2148c2ecf20Sopenharmony_ci};
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ciextern int parse_options_usage(const char * const *usagestr,
2178c2ecf20Sopenharmony_ci			       const struct option *opts,
2188c2ecf20Sopenharmony_ci			       const char *optstr,
2198c2ecf20Sopenharmony_ci			       bool short_opt);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci/*----- some often used options -----*/
2238c2ecf20Sopenharmony_ciextern int parse_opt_abbrev_cb(const struct option *, const char *, int);
2248c2ecf20Sopenharmony_ciextern int parse_opt_approxidate_cb(const struct option *, const char *, int);
2258c2ecf20Sopenharmony_ciextern int parse_opt_verbosity_cb(const struct option *, const char *, int);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci#define OPT__VERBOSE(var)  OPT_BOOLEAN('v', "verbose", (var), "be verbose")
2288c2ecf20Sopenharmony_ci#define OPT__QUIET(var)    OPT_BOOLEAN('q', "quiet",   (var), "be quiet")
2298c2ecf20Sopenharmony_ci#define OPT__VERBOSITY(var) \
2308c2ecf20Sopenharmony_ci	{ OPTION_CALLBACK, 'v', "verbose", (var), NULL, "be more verbose", \
2318c2ecf20Sopenharmony_ci	  PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
2328c2ecf20Sopenharmony_ci	{ OPTION_CALLBACK, 'q', "quiet", (var), NULL, "be more quiet", \
2338c2ecf20Sopenharmony_ci	  PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
2348c2ecf20Sopenharmony_ci#define OPT__DRY_RUN(var)  OPT_BOOLEAN('n', "dry-run", (var), "dry run")
2358c2ecf20Sopenharmony_ci#define OPT__ABBREV(var)  \
2368c2ecf20Sopenharmony_ci	{ OPTION_CALLBACK, 0, "abbrev", (var), "n", \
2378c2ecf20Sopenharmony_ci	  "use <n> digits to display SHA-1s", \
2388c2ecf20Sopenharmony_ci	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ciextern const char *parse_options_fix_filename(const char *prefix, const char *file);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_civoid set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
2438c2ecf20Sopenharmony_civoid set_option_nobuild(struct option *opts, int shortopt, const char *longopt,
2448c2ecf20Sopenharmony_ci			const char *build_opt, bool can_skip);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci#endif /* __SUBCMD_PARSE_OPTIONS_H */
247