From ee74335c8440803006aeca6b1a427c0cf28b4a98 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Thu, 9 May 2024 03:22:37 +0200 Subject: Rename optparse.h to cli.h --- lib/cli/optparse.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/optparse/optparse.c | 159 ------------------------------------------------ 2 files changed, 159 insertions(+), 159 deletions(-) create mode 100644 lib/cli/optparse.c delete mode 100644 lib/optparse/optparse.c (limited to 'lib') diff --git a/lib/cli/optparse.c b/lib/cli/optparse.c new file mode 100644 index 0000000..ce688cf --- /dev/null +++ b/lib/cli/optparse.c @@ -0,0 +1,159 @@ +#include +#include + +#include "cli.h" +#include "macros.h" +#include "mbstring.h" + +#define CLI_MSG_INVALID "invalid option" +#define CLI_MSG_MISSING "option requires an argument" +#define CLI_MSG_TOOMANY "option takes no arguments" + +#define IS_DASHDASH(s) ((s).len == 2 && (s).p[0] == '-' && (s).p[1] == '-') +#define IS_LONGOPT(s) ((s).len >= 3 && (s).p[0] == '-' && (s).p[1] == '-') +#define IS_SHORTOPT(s) ((s).len >= 2 && (s).p[0] == '-' && (s).p[1] != '-') + +#define error(st, msg, x) \ + _Generic((x), struct u8view: error_s, rune: error_r)((st), (msg), (x)) + +static rune error_r(struct optparser *, const char *, rune); +static rune error_s(struct optparser *, const char *, struct u8view); +static rune shortopt(struct optparser *, const struct cli_option *, size_t); + +rune +optparse(struct optparser *st, const struct cli_option *opts, size_t nopts) +{ + st->errmsg[0] = '\0'; + st->optarg = (struct u8view){}; + + struct u8view opt = {.p = st->_argv[st->optind]}; + if (opt.p == nullptr) + return 0; + opt.len = strlen(opt.p); + + if (IS_DASHDASH(opt)) { + st->optind++; + return 0; + } + if (IS_SHORTOPT(opt)) + return shortopt(st, opts, nopts); + if (!IS_LONGOPT(opt)) + return 0; + + st->_subopt = 0; + st->optind++; + + /* Skip ‘--’ */ + VSHFT(&opt, 2); + + const struct cli_option *o = nullptr; + const char8_t *eq_p = u8chr(opt, '='); + struct u8view opt_no_eq = { + .p = opt.p, + .len = eq_p == nullptr ? opt.len : (size_t)(eq_p - opt.p), + }; + + for (size_t i = 0; i < nopts; i++) { + struct u8view lo = opts[i].longopt; + if (lo.p == nullptr || !u8haspfx(lo, opt_no_eq)) + continue; + if (o != nullptr) + return error(st, CLI_MSG_INVALID, opt_no_eq); + o = opts + i; + } + + if (o == nullptr) + return error(st, CLI_MSG_INVALID, opt_no_eq); + + switch (o->argtype) { + case CLI_NONE: + if (eq_p != nullptr) + return error(st, CLI_MSG_TOOMANY, opt); + break; + case CLI_OPT: + if (eq_p == nullptr) + st->optarg = (struct u8view){}; + else { + ASSUME(opt.len > opt_no_eq.len); + st->optarg = (struct u8view){ + .p = eq_p + 1, + .len = opt.len - opt_no_eq.len + 1, + }; + } + break; + case CLI_REQ: + if (eq_p == nullptr) { + if (st->_argv[st->optind] == nullptr) + return error(st, CLI_MSG_MISSING, opt); + st->optarg.p = st->_argv[st->optind++]; + st->optarg.len = strlen(st->optarg.p); + } else { + ASSUME(opt.len > opt_no_eq.len); + st->optarg = (struct u8view){ + .p = eq_p + 1, + .len = opt.len - opt_no_eq.len + 1, + }; + } + break; + } + + return o->shortopt; +} + +rune +shortopt(struct optparser *st, const struct cli_option *opts, size_t nopts) +{ + rune ch; + const char *opt = st->_argv[st->optind]; + st->_subopt += u8tor(&ch, opt + st->_subopt + 1); + if (ch == '\0') { + st->_subopt = 0; + st->optind++; + return optparse(st, opts, nopts); + } + for (size_t i = 0; i < nopts; i++) { + if (opts[i].shortopt != ch) + continue; + if (opts[i].argtype == CLI_NONE) + goto out; + if (opt[st->_subopt + 1] != '\0') { + st->optarg.p = opt + st->_subopt + 1; + st->optarg.len = strlen(st->optarg.p); + st->_subopt = 0; + st->optind++; + goto out; + } + if (opts[i].argtype == CLI_OPT) { + st->optarg = (struct u8view){}; + goto out; + } + if (st->_argv[st->optind + 1] == nullptr) { + st->optarg = (struct u8view){}; + return error(st, CLI_MSG_MISSING, ch); + } + st->optarg.p = st->_argv[st->optind + 1]; + st->optarg.len = strlen(st->optarg.p); + st->optind += 2; + goto out; + } + return error(st, CLI_MSG_INVALID, ch); +out: + return ch; +} + +rune +error_s(struct optparser *st, const char *msg, struct u8view s) +{ + snprintf(st->errmsg, sizeof(st->errmsg), u8"%s — ‘%.*s’", msg, + SV_PRI_ARGS(s)); + return -1; +} + +rune +error_r(struct optparser *st, const char *msg, rune ch) +{ + char buf[U8_LEN_MAX + 1] = {}; + snprintf(st->errmsg, sizeof(st->errmsg), u8"%s — ‘%.*s’", msg, + rtou8(buf, sizeof(buf), ch), buf); + return -1; +} diff --git a/lib/optparse/optparse.c b/lib/optparse/optparse.c deleted file mode 100644 index 757dd47..0000000 --- a/lib/optparse/optparse.c +++ /dev/null @@ -1,159 +0,0 @@ -#include -#include - -#include "macros.h" -#include "mbstring.h" -#include "optparse.h" - -#define OPT_MSG_INVALID "invalid option" -#define OPT_MSG_MISSING "option requires an argument" -#define OPT_MSG_TOOMANY "option takes no arguments" - -#define IS_DASHDASH(s) ((s).len == 2 && (s).p[0] == '-' && (s).p[1] == '-') -#define IS_LONGOPT(s) ((s).len >= 3 && (s).p[0] == '-' && (s).p[1] == '-') -#define IS_SHORTOPT(s) ((s).len >= 2 && (s).p[0] == '-' && (s).p[1] != '-') - -#define error(st, msg, x) \ - _Generic((x), struct u8view: error_s, rune: error_r)((st), (msg), (x)) - -static rune error_r(struct optparse *, const char *, rune); -static rune error_s(struct optparse *, const char *, struct u8view); -static rune shortopt(struct optparse *, const struct op_option *, size_t); - -rune -optparse(struct optparse *st, const struct op_option *opts, size_t nopts) -{ - st->errmsg[0] = '\0'; - st->optarg = (struct u8view){}; - - struct u8view opt = {.p = st->_argv[st->optind]}; - if (opt.p == nullptr) - return 0; - opt.len = strlen(opt.p); - - if (IS_DASHDASH(opt)) { - st->optind++; - return 0; - } - if (IS_SHORTOPT(opt)) - return shortopt(st, opts, nopts); - if (!IS_LONGOPT(opt)) - return 0; - - st->_subopt = 0; - st->optind++; - - /* Skip ‘--’ */ - VSHFT(&opt, 2); - - const struct op_option *o = nullptr; - const char8_t *eq_p = u8chr(opt, '='); - struct u8view opt_no_eq = { - .p = opt.p, - .len = eq_p == nullptr ? opt.len : (size_t)(eq_p - opt.p), - }; - - for (size_t i = 0; i < nopts; i++) { - struct u8view lo = opts[i].longopt; - if (lo.p == nullptr || !u8haspfx(lo, opt_no_eq)) - continue; - if (o != nullptr) - return error(st, OPT_MSG_INVALID, opt_no_eq); - o = opts + i; - } - - if (o == nullptr) - return error(st, OPT_MSG_INVALID, opt_no_eq); - - switch (o->argtype) { - case OPT_NONE: - if (eq_p != nullptr) - return error(st, OPT_MSG_TOOMANY, opt); - break; - case OPT_OPT: - if (eq_p == nullptr) - st->optarg = (struct u8view){}; - else { - ASSUME(opt.len > opt_no_eq.len); - st->optarg = (struct u8view){ - .p = eq_p + 1, - .len = opt.len - opt_no_eq.len + 1, - }; - } - break; - case OPT_REQ: - if (eq_p == nullptr) { - if (st->_argv[st->optind] == nullptr) - return error(st, OPT_MSG_MISSING, opt); - st->optarg.p = st->_argv[st->optind++]; - st->optarg.len = strlen(st->optarg.p); - } else { - ASSUME(opt.len > opt_no_eq.len); - st->optarg = (struct u8view){ - .p = eq_p + 1, - .len = opt.len - opt_no_eq.len + 1, - }; - } - break; - } - - return o->shortopt; -} - -rune -shortopt(struct optparse *st, const struct op_option *opts, size_t nopts) -{ - rune ch; - const char *opt = st->_argv[st->optind]; - st->_subopt += u8tor(&ch, opt + st->_subopt + 1); - if (ch == '\0') { - st->_subopt = 0; - st->optind++; - return optparse(st, opts, nopts); - } - for (size_t i = 0; i < nopts; i++) { - if (opts[i].shortopt != ch) - continue; - if (opts[i].argtype == OPT_NONE) - goto out; - if (opt[st->_subopt + 1] != '\0') { - st->optarg.p = opt + st->_subopt + 1; - st->optarg.len = strlen(st->optarg.p); - st->_subopt = 0; - st->optind++; - goto out; - } - if (opts[i].argtype == OPT_OPT) { - st->optarg = (struct u8view){}; - goto out; - } - if (st->_argv[st->optind + 1] == nullptr) { - st->optarg = (struct u8view){}; - return error(st, OPT_MSG_MISSING, ch); - } - st->optarg.p = st->_argv[st->optind + 1]; - st->optarg.len = strlen(st->optarg.p); - st->optind += 2; - goto out; - } - return error(st, OPT_MSG_INVALID, ch); -out: - return ch; -} - -rune -error_s(struct optparse *st, const char *msg, struct u8view s) -{ - snprintf(st->errmsg, sizeof(st->errmsg), u8"%s — ‘%.*s’", msg, - SV_PRI_ARGS(s)); - return -1; -} - -rune -error_r(struct optparse *st, const char *msg, rune ch) -{ - char buf[U8_LEN_MAX + 1] = {}; - snprintf(st->errmsg, sizeof(st->errmsg), u8"%s — ‘%.*s’", msg, - rtou8(buf, sizeof(buf), ch), buf); - return -1; -} -- cgit v1.2.3