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