^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <stdint.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "subcmd-util.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "parse-options.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "subcmd-config.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "pager.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define OPT_SHORT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define OPT_UNSET 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) char *error_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static int opterror(const struct option *opt, const char *reason, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) if (flags & OPT_SHORT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) else if (flags & OPT_UNSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static const char *skip_prefix(const char *str, const char *prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) size_t len = strlen(prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return strncmp(str, prefix, len) ? NULL : str + len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static void optwarning(const struct option *opt, const char *reason, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (flags & OPT_SHORT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) else if (flags & OPT_UNSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int flags, const char **arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) const char *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (p->opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) res = p->opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) p->opt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) **(p->argv + 1) == '-')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) res = (const char *)opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) } else if (p->argc > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) p->argc--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) res = *++p->argv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return opterror(opt, "requires a value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *arg = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static int get_value(struct parse_opt_ctx_t *p,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) const struct option *opt, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) const char *s, *arg = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) const int unset = flags & OPT_UNSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (unset && p->opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return opterror(opt, "takes no value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (unset && (opt->flags & PARSE_OPT_NONEG))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return opterror(opt, "isn't available", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (opt->flags & PARSE_OPT_DISABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return opterror(opt, "is not usable", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (opt->flags & PARSE_OPT_EXCLUSIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (p->excl_opt && p->excl_opt != opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) char msg[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) p->excl_opt->long_name == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) p->excl_opt->short_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) snprintf(msg, sizeof(msg), "cannot be used with %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) p->excl_opt->long_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) opterror(opt, msg, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return -3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) p->excl_opt = opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (!(flags & OPT_SHORT) && p->opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) switch (opt->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) case OPTION_CALLBACK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (!(opt->flags & PARSE_OPT_NOARG))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* FALLTHROUGH */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) case OPTION_BOOLEAN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) case OPTION_INCR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) case OPTION_BIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) case OPTION_SET_UINT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) case OPTION_SET_PTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return opterror(opt, "takes no value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) case OPTION_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) case OPTION_ARGUMENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) case OPTION_GROUP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) case OPTION_STRING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) case OPTION_INTEGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) case OPTION_UINTEGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) case OPTION_LONG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) case OPTION_ULONG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) case OPTION_U64:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (opt->flags & PARSE_OPT_NOBUILD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) char reason[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) bool noarg = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) err = snprintf(reason, sizeof(reason),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) opt->flags & PARSE_OPT_CANSKIP ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) "is being ignored because %s " :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) "is not available because %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) opt->build_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) reason[sizeof(reason) - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) "is being ignored" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) "is not available",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) sizeof(reason));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (!(opt->flags & PARSE_OPT_CANSKIP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return opterror(opt, reason, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (unset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) noarg = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (opt->flags & PARSE_OPT_NOARG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) noarg = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) noarg = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) switch (opt->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) case OPTION_BOOLEAN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) case OPTION_INCR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) case OPTION_BIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) case OPTION_SET_UINT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case OPTION_SET_PTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) case OPTION_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) case OPTION_ARGUMENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) case OPTION_GROUP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) noarg = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) case OPTION_CALLBACK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) case OPTION_STRING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) case OPTION_INTEGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) case OPTION_UINTEGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) case OPTION_LONG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) case OPTION_ULONG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) case OPTION_U64:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (!noarg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) err = get_arg(p, opt, flags, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) optwarning(opt, reason, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) switch (opt->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) case OPTION_BIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (unset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) *(int *)opt->value &= ~opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) *(int *)opt->value |= opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) case OPTION_BOOLEAN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) *(bool *)opt->value = unset ? false : true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (opt->set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) *(bool *)opt->set = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case OPTION_INCR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case OPTION_SET_UINT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) *(unsigned int *)opt->value = unset ? 0 : opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) case OPTION_SET_PTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) *(void **)opt->value = unset ? NULL : (void *)opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) case OPTION_STRING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (unset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) *(const char **)opt->value = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) *(const char **)opt->value = (const char *)opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) err = get_arg(p, opt, flags, (const char **)opt->value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (opt->set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) *(bool *)opt->set = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) /* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (opt->flags & PARSE_OPT_NOEMPTY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) const char *val = *(const char **)opt->value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (!val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /* Similar to unset if we are given an empty string. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (val[0] == '\0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) *(const char **)opt->value = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) case OPTION_CALLBACK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (opt->set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) *(bool *)opt->set = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (unset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (opt->flags & PARSE_OPT_NOARG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (get_arg(p, opt, flags, &arg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) case OPTION_INTEGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (unset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) *(int *)opt->value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) *(int *)opt->value = opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (get_arg(p, opt, flags, &arg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) *(int *)opt->value = strtol(arg, (char **)&s, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (*s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return opterror(opt, "expects a numerical value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) case OPTION_UINTEGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (unset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) *(unsigned int *)opt->value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) *(unsigned int *)opt->value = opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (get_arg(p, opt, flags, &arg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (arg[0] == '-')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return opterror(opt, "expects an unsigned numerical value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (*s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return opterror(opt, "expects a numerical value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) case OPTION_LONG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (unset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) *(long *)opt->value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) *(long *)opt->value = opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (get_arg(p, opt, flags, &arg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) *(long *)opt->value = strtol(arg, (char **)&s, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (*s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) return opterror(opt, "expects a numerical value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) case OPTION_ULONG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (unset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) *(unsigned long *)opt->value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) *(unsigned long *)opt->value = opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (get_arg(p, opt, flags, &arg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) *(unsigned long *)opt->value = strtoul(arg, (char **)&s, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (*s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return opterror(opt, "expects a numerical value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) case OPTION_U64:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (unset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) *(u64 *)opt->value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) *(u64 *)opt->value = opt->defval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (get_arg(p, opt, flags, &arg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (arg[0] == '-')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return opterror(opt, "expects an unsigned numerical value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (*s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return opterror(opt, "expects a numerical value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) case OPTION_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) case OPTION_ARGUMENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) case OPTION_GROUP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) die("should not happen, someone must be hit on the forehead");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) for (; options->type != OPTION_END; options++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (options->short_name == *p->opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) p->opt = p->opt[1] ? p->opt + 1 : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return get_value(p, options, OPT_SHORT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (options->parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) options = options->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) const struct option *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) const char *arg_end = strchr(arg, '=');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) int abbrev_flags = 0, ambiguous_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (!arg_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) arg_end = arg + strlen(arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) for (; options->type != OPTION_END; options++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) const char *rest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) int flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (!options->long_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) rest = skip_prefix(arg, options->long_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (options->type == OPTION_ARGUMENT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (!rest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (*rest == '=')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) return opterror(options, "takes no value", flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (*rest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) p->out[p->cpidx++] = arg - 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (!rest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) if (strstarts(options->long_name, "no-")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * The long name itself starts with "no-", so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * accept the option without "no-" so that users
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * do not have to enter "no-no-" to get the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * negation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) rest = skip_prefix(arg, options->long_name + 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (rest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) flags |= OPT_UNSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) goto match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) /* Abbreviated case */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (strstarts(options->long_name + 3, arg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) flags |= OPT_UNSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) goto is_abbreviated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) /* abbreviated? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (!strncmp(options->long_name, arg, arg_end - arg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) is_abbreviated:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (abbrev_option) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * If this is abbreviated, it is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) * ambiguous. So when there is no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) * exact match later, we need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) * error out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) ambiguous_option = abbrev_option;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) ambiguous_flags = abbrev_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (!(flags & OPT_UNSET) && *arg_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) p->opt = arg_end + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) abbrev_option = options;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) abbrev_flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) /* negated and abbreviated very much? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (strstarts("no-", arg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) flags |= OPT_UNSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) goto is_abbreviated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* negated? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (strncmp(arg, "no-", 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) flags |= OPT_UNSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) rest = skip_prefix(arg + 3, options->long_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) /* abbreviated and negated? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (!rest && strstarts(options->long_name, arg + 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) goto is_abbreviated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) if (!rest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) match:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (*rest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) if (*rest != '=')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) p->opt = rest + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) return get_value(p, options, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (ambiguous_option) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) fprintf(stderr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) " Error: Ambiguous option: %s (could be --%s%s or --%s%s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) arg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) (ambiguous_flags & OPT_UNSET) ? "no-" : "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) ambiguous_option->long_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) (abbrev_flags & OPT_UNSET) ? "no-" : "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) abbrev_option->long_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (abbrev_option)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) return get_value(p, abbrev_option, abbrev_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (options->parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) options = options->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) static void check_typos(const char *arg, const struct option *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (strlen(arg) < 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if (strstarts(arg, "no-")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) exit(129);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) for (; options->type != OPTION_END; options++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) if (!options->long_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (strstarts(options->long_name, arg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) exit(129);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static void parse_options_start(struct parse_opt_ctx_t *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) int argc, const char **argv, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) memset(ctx, 0, sizeof(*ctx));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) ctx->argc = argc - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) ctx->argv = argv + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) ctx->out = argv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) ctx->flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) (flags & PARSE_OPT_STOP_AT_NON_OPTION))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) static int usage_with_options_internal(const char * const *,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) const struct option *, int,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) struct parse_opt_ctx_t *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) static int parse_options_step(struct parse_opt_ctx_t *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) const struct option *options,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) const char * const usagestr[])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) int excl_short_opt = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) const char *arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /* we must reset ->opt, unknown short option leave it dangling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) ctx->opt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) for (; ctx->argc; ctx->argc--, ctx->argv++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) arg = ctx->argv[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (*arg != '-' || !arg[1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) ctx->out[ctx->cpidx++] = ctx->argv[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (arg[1] != '-') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) ctx->opt = ++arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (internal_help && *ctx->opt == 'h') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) return usage_with_options_internal(usagestr, options, 0, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) switch (parse_short_opt(ctx, options)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) return parse_options_usage(usagestr, options, arg, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) case -2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) goto unknown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) case -3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) goto exclusive;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (ctx->opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) check_typos(arg, options);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) while (ctx->opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (internal_help && *ctx->opt == 'h')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) return usage_with_options_internal(usagestr, options, 0, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) arg = ctx->opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) switch (parse_short_opt(ctx, options)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return parse_options_usage(usagestr, options, arg, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) case -2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) /* fake a short option thing to hide the fact that we may have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) * started to parse aggregated stuff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * This is leaky, too bad.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) ctx->argv[0] = strdup(ctx->opt - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) *(char *)ctx->argv[0] = '-';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) goto unknown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) case -3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) goto exclusive;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (!arg[2]) { /* "--" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) ctx->argc--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) ctx->argv++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) arg += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (internal_help && !strcmp(arg, "help-all"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) return usage_with_options_internal(usagestr, options, 1, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (internal_help && !strcmp(arg, "help"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return usage_with_options_internal(usagestr, options, 0, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (!strcmp(arg, "list-opts"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return PARSE_OPT_LIST_OPTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (!strcmp(arg, "list-cmds"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return PARSE_OPT_LIST_SUBCMDS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) switch (parse_long_opt(ctx, arg, options)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) return parse_options_usage(usagestr, options, arg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) case -2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) goto unknown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) case -3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) excl_short_opt = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) goto exclusive;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) unknown:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) return PARSE_OPT_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) ctx->out[ctx->cpidx++] = ctx->argv[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) ctx->opt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return PARSE_OPT_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) exclusive:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) parse_options_usage(usagestr, options, arg, excl_short_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if ((excl_short_opt && ctx->excl_opt->short_name) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) ctx->excl_opt->long_name == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) char opt = ctx->excl_opt->short_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) parse_options_usage(NULL, options, &opt, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) return PARSE_OPT_HELP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) static int parse_options_end(struct parse_opt_ctx_t *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) ctx->out[ctx->cpidx + ctx->argc] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) return ctx->cpidx + ctx->argc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) int parse_options_subcommand(int argc, const char **argv, const struct option *options,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) const char *const subcommands[], const char *usagestr[], int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) struct parse_opt_ctx_t ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* build usage string if it's not provided */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (subcommands && !usagestr[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) char *buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) for (int i = 0; subcommands[i]; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) astrcat(&buf, "|");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) astrcat(&buf, subcommands[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) astrcat(&buf, "}");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) usagestr[0] = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) parse_options_start(&ctx, argc, argv, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) switch (parse_options_step(&ctx, options, usagestr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) case PARSE_OPT_HELP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) exit(129);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) case PARSE_OPT_DONE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) case PARSE_OPT_LIST_OPTS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) while (options->type != OPTION_END) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) if (options->long_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) printf("--%s ", options->long_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) options++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) putchar('\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) exit(130);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) case PARSE_OPT_LIST_SUBCMDS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (subcommands) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) for (int i = 0; subcommands[i]; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) printf("%s ", subcommands[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) putchar('\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) exit(130);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) default: /* PARSE_OPT_UNKNOWN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) if (ctx.argv[0][1] == '-')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) astrcatf(&error_buf, "unknown option `%s'",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) ctx.argv[0] + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) usage_with_options(usagestr, options);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) return parse_options_end(&ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) int parse_options(int argc, const char **argv, const struct option *options,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) const char * const usagestr[], int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) return parse_options_subcommand(argc, argv, options, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) (const char **) usagestr, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) #define USAGE_OPTS_WIDTH 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) #define USAGE_GAP 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) static void print_option_help(const struct option *opts, int full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) size_t pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) int pad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) if (opts->type == OPTION_GROUP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) fputc('\n', stderr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) if (*opts->help)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) fprintf(stderr, "%s\n", opts->help);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if (!full && (opts->flags & PARSE_OPT_HIDDEN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (opts->flags & PARSE_OPT_DISABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) pos = fprintf(stderr, " ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (opts->short_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) pos += fprintf(stderr, "-%c", opts->short_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) pos += fprintf(stderr, " ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (opts->long_name && opts->short_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) pos += fprintf(stderr, ", ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) if (opts->long_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) pos += fprintf(stderr, "--%s", opts->long_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) switch (opts->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) case OPTION_ARGUMENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) case OPTION_LONG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) case OPTION_ULONG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) case OPTION_U64:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) case OPTION_INTEGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) case OPTION_UINTEGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) if (opts->flags & PARSE_OPT_OPTARG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (opts->long_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) pos += fprintf(stderr, "[=<n>]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) pos += fprintf(stderr, "[<n>]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) pos += fprintf(stderr, " <n>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) case OPTION_CALLBACK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) if (opts->flags & PARSE_OPT_NOARG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) /* FALLTHROUGH */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) case OPTION_STRING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (opts->argh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (opts->flags & PARSE_OPT_OPTARG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if (opts->long_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) pos += fprintf(stderr, "[=<%s>]", opts->argh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) pos += fprintf(stderr, "[<%s>]", opts->argh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) pos += fprintf(stderr, " <%s>", opts->argh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) if (opts->flags & PARSE_OPT_OPTARG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if (opts->long_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) pos += fprintf(stderr, "[=...]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) pos += fprintf(stderr, "[...]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) pos += fprintf(stderr, " ...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) case OPTION_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) case OPTION_GROUP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) case OPTION_BIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) case OPTION_BOOLEAN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) case OPTION_INCR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) case OPTION_SET_UINT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) case OPTION_SET_PTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) if (pos <= USAGE_OPTS_WIDTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) pad = USAGE_OPTS_WIDTH - pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) fputc('\n', stderr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) pad = USAGE_OPTS_WIDTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) if (opts->flags & PARSE_OPT_NOBUILD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) fprintf(stderr, "%*s(not built-in because %s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) USAGE_OPTS_WIDTH + USAGE_GAP, "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) opts->build_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) static int option__cmp(const void *va, const void *vb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) const struct option *a = va, *b = vb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) int sa = tolower(a->short_name), sb = tolower(b->short_name), ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) if (sa == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) sa = 'z' + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (sb == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) sb = 'z' + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) ret = sa - sb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) const char *la = a->long_name ?: "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) *lb = b->long_name ?: "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) ret = strcmp(la, lb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) static struct option *options__order(const struct option *opts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) int nr_opts = 0, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) const struct option *o = opts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) struct option *ordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) for (o = opts; o->type != OPTION_END; o++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) ++nr_opts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) len = sizeof(*o) * (nr_opts + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) ordered = malloc(len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) if (!ordered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) memcpy(ordered, opts, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) qsort(ordered, nr_opts, sizeof(*o), option__cmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) return ordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) for (i = 1; i < ctx->argc; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) const char *arg = ctx->argv[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) if (arg[0] != '-') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (arg[1] == '\0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (arg[0] == opt->short_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) if (opt->long_name && strcmp(opt->long_name, arg) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) if (opt->help && strcasestr(opt->help, arg) != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) if (arg[1] == opt->short_name ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) static int usage_with_options_internal(const char * const *usagestr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) const struct option *opts, int full,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) struct parse_opt_ctx_t *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) struct option *ordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (!usagestr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) return PARSE_OPT_HELP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) setup_pager();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) if (error_buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) fprintf(stderr, " Error: %s\n", error_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) zfree(&error_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) fprintf(stderr, "\n Usage: %s\n", *usagestr++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) while (*usagestr && **usagestr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) fprintf(stderr, " or: %s\n", *usagestr++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) while (*usagestr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) fprintf(stderr, "%s%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) **usagestr ? " " : "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) *usagestr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) usagestr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) if (opts->type != OPTION_GROUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) fputc('\n', stderr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) ordered = options__order(opts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) if (ordered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) opts = ordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) for ( ; opts->type != OPTION_END; opts++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) print_option_help(opts, full);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) fputc('\n', stderr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) free(ordered);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) return PARSE_OPT_HELP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) void usage_with_options(const char * const *usagestr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) const struct option *opts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) usage_with_options_internal(usagestr, opts, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) exit(129);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) void usage_with_options_msg(const char * const *usagestr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) const struct option *opts, const char *fmt, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) va_list ap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) char *tmp = error_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) va_start(ap, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) if (vasprintf(&error_buf, fmt, ap) == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) die("vasprintf failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) va_end(ap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) free(tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) usage_with_options_internal(usagestr, opts, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) exit(129);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) int parse_options_usage(const char * const *usagestr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) const struct option *opts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) const char *optstr, bool short_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) if (!usagestr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) goto opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) fprintf(stderr, "\n Usage: %s\n", *usagestr++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) while (*usagestr && **usagestr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) fprintf(stderr, " or: %s\n", *usagestr++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) while (*usagestr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) fprintf(stderr, "%s%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) **usagestr ? " " : "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) *usagestr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) usagestr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) fputc('\n', stderr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) opt:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) for ( ; opts->type != OPTION_END; opts++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) if (short_opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) if (opts->short_name == *optstr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) print_option_help(opts, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) if (opts->long_name == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) if (strstarts(opts->long_name, optstr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) print_option_help(opts, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) if (strstarts("no-", optstr) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) strstarts(opts->long_name, optstr + 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) print_option_help(opts, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) return PARSE_OPT_HELP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) int parse_opt_verbosity_cb(const struct option *opt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) const char *arg __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) int unset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) int *target = opt->value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) if (unset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) /* --no-quiet, --no-verbose */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) *target = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) else if (opt->short_name == 'v') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) if (*target >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) (*target)++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) *target = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) if (*target <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) (*target)--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) *target = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) static struct option *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) find_option(struct option *opts, int shortopt, const char *longopt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) for (; opts->type != OPTION_END; opts++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) if ((shortopt && opts->short_name == shortopt) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) (opts->long_name && longopt &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) !strcmp(opts->long_name, longopt)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) return opts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) void set_option_flag(struct option *opts, int shortopt, const char *longopt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) int flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) struct option *opt = find_option(opts, shortopt, longopt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) if (opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) opt->flags |= flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) void set_option_nobuild(struct option *opts, int shortopt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) const char *longopt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) const char *build_opt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) bool can_skip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) struct option *opt = find_option(opts, shortopt, longopt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) if (!opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) opt->flags |= PARSE_OPT_NOBUILD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) opt->build_opt = build_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) }