author | Olivier Brunel
<jjk@jjacky.com> 2023-04-02 13:02:18 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2023-05-20 18:06:34 UTC |
parent | 4e57787a9cae459fb243a4d5ff7332e19ee72d92 |
src/doc/loadopt.h/loadopt.3.md | +3 | -4 |
src/doc/parseopt.h/parseopt.3.md | +7 | -6 |
src/include/loadopt.h | +2 | -2 |
src/liblimb/include/limb/loadopt.h | +2 | -1 |
src/liblimb/include/limb/parseopt.h | +2 | -1 |
src/liblimb/loadopt.h/loadopt.c | +27 | -31 |
src/liblimb/parseopt.h/parseopt.c | +20 | -21 |
diff --git a/src/doc/loadopt.h/loadopt.3.md b/src/doc/loadopt.h/loadopt.3.md index d17deed..73ee23c 100644 --- a/src/doc/loadopt.h/loadopt.3.md +++ b/src/doc/loadopt.h/loadopt.3.md @@ -10,7 +10,7 @@ loadopt - parse options from command-line and (optionally) configuration file #include <limb/loadopt.h> ```pre hl -int loadopt(int *<em>first</em>, int <em>argc</em>, const char **<em>argv</em>, const struct option *<em>options</em>, +int loadopt(int <em>argc</em>, const char **<em>argv</em>, const struct option *<em>options</em>, const char *<em>file</em>, const char *<em>section</em>, unsigned int <em>flags</em>, struct loadopt *<em>ctx</em>) ``` @@ -23,9 +23,8 @@ After that it ensures any option marked as required has been set, then may check for non-options arguments. The actual parsing of options is done through [parseopt](3), as such many of the -arguments to `loadopt`() are the same as to [parseopt](3), namely `first`, -`argc`, `argv`, `options` and `flags`. Please refer to [parseopt](3) for more -on those. +arguments to `loadopt`() are the same as to [parseopt](3), namely `argc`, +`argv`, `options` and `flags`. Refer to [parseopt](3) for more on those. It is important to note, however, that the member `flags` of *struct option* is relevant here : it allows to define option-specific flags. Specifically, its diff --git a/src/doc/parseopt.h/parseopt.3.md b/src/doc/parseopt.h/parseopt.3.md index 148001a..d684d35 100644 --- a/src/doc/parseopt.h/parseopt.3.md +++ b/src/doc/parseopt.h/parseopt.3.md @@ -10,7 +10,7 @@ parseopt - parse command-line options #include <limb/parseopt.h> ```pre hl -int parseopt(int *<em>first</em>, int <em>argc</em>, const char **<em>argv</em>, const struct option *<em>options</em>, +int parseopt(int <em>argc</em>, const char **<em>argv</em>, const struct option *<em>options</em>, unsigned int <em>flags</em>, struct parseopt *<em>ctx</em>) ``` @@ -23,11 +23,6 @@ on program invocation. The `options` argument is a pointer to the first element of an array defining all possible options. See [[Options]] below for more. -The `first` argument is optional, as therefore can be NULL. If specified, the -value it points to will be set to the index of the first-matching option. This -can notably be useful in the case of abbreviated long options, when more than -one option did match. - The `flags` argument allows to enable certain options, see [[FLAGS]] below. The last argument `ctx` is a semi-opaque structure, that should be initialized @@ -36,6 +31,7 @@ to all zeroes, defined as such : struct parseopt { u16 cur; u16 off; + int idx; const char *arg; }; @@ -43,6 +39,11 @@ When `parseopt`() returns a positive value, i.e. an option was successfully found, its member `arg` points to the option's argument if any, else it is NULL. It is similar to the global `optarg` from [getopt](3). +Additionally its member `idx` is set to the index of said option within +`options`. When an error occurs, it can either be set to -1 or, in the case of +abbreviated long options (and more than one option did match), the +first-matching option. + When `parseopt`() returns -1, its member `cur` is the index in `argv` of the first non-option element. In that way, it is similar to the global `optind` from [getopt](3). diff --git a/src/include/loadopt.h b/src/include/loadopt.h index 07fe3a8..393bf91 100644 --- a/src/include/loadopt.h +++ b/src/include/loadopt.h @@ -26,8 +26,8 @@ enum { LOADOPT_EOF = 1 << 3, }; -void add_optflags(u8 *optflags, u16 idx, u8 val) gccattr_hidden; -u8 get_optflags(const u8 *optflags, u16 idx) gccattr_hidden; +void add_optflags(u8 *optflags, int idx, u8 val) gccattr_hidden; +u8 get_optflags(const u8 *optflags, int idx) gccattr_hidden; int loadopt_handle_noconfig(int idx, const struct option *options, struct loadopt *ctx) gccattr_hidden; diff --git a/src/liblimb/include/limb/loadopt.h b/src/liblimb/include/limb/loadopt.h index 67b139e..0374da3 100644 --- a/src/liblimb/include/limb/loadopt.h +++ b/src/liblimb/include/limb/loadopt.h @@ -34,6 +34,7 @@ struct loadopt { /* struct parseopt */ u16 cur; u16 off; + int idx; const char *arg; /* loadopt */ stralloc sa; @@ -50,7 +51,7 @@ enum { LOADOPT_ID_NOCONFIG = 1, }; -extern int loadopt(int *first, int argc, const char **argv, const struct option *options, +extern int loadopt(int argc, const char **argv, const struct option *options, const char *file, const char *section, unsigned int poflags, struct loadopt *ctx); diff --git a/src/liblimb/include/limb/parseopt.h b/src/liblimb/include/limb/parseopt.h index 9a6b6bb..94a4a05 100644 --- a/src/liblimb/include/limb/parseopt.h +++ b/src/liblimb/include/limb/parseopt.h @@ -42,10 +42,11 @@ struct parseopt { u16 cur; /* public when done : index of first argument in argv */ u16 off; /* public (read-only) */ + int idx; const char *arg; }; -extern int parseopt(int *first, int argc, const char **argv, const struct option *options, +extern int parseopt(int argc, const char **argv, const struct option *options, unsigned int flags, struct parseopt *ctx); #endif /* LIMB_PARSEOPT_H */ diff --git a/src/liblimb/loadopt.h/loadopt.c b/src/liblimb/loadopt.h/loadopt.c index aabbeb5..ce6c143 100644 --- a/src/liblimb/loadopt.h/loadopt.c +++ b/src/liblimb/loadopt.h/loadopt.c @@ -10,7 +10,7 @@ #include "loadopt.h" void -add_optflags(u8 *optflags, u16 idx, u8 val) +add_optflags(u8 *optflags, int idx, u8 val) { if (idx % 2) val <<= 4; @@ -20,7 +20,7 @@ add_optflags(u8 *optflags, u16 idx, u8 val) } u8 -get_optflags(const u8 *optflags, u16 idx) +get_optflags(const u8 *optflags, int idx) { u8 b = optflags[idx / 2]; if (idx % 2) b >>= 4; @@ -28,7 +28,7 @@ get_optflags(const u8 *optflags, u16 idx) } static void -parseopt_warn(int c, int idx, const char **argv, const struct option *options, +parseopt_warn(int c, const char **argv, const struct option *options, const struct parseopt *ctx) { if (c >= 0 || c == PARSEOPT_DONE) @@ -48,8 +48,8 @@ parseopt_warn(int c, int idx, const char **argv, const struct option *options, break; case PARSEOPT_ERR_ARGREQ: { - char buf[2] = { options[idx].shortopt, 0 }; - warn("option --", options[idx].longopt, + char buf[2] = { options[ctx->idx].shortopt, 0 }; + warn("option --", options[ctx->idx].longopt, (*buf) ? "/-" : "", buf, " requires an argument"); } break; @@ -57,19 +57,19 @@ parseopt_warn(int c, int idx, const char **argv, const struct option *options, } static int -loadopt_handle(int c, int first, const char **argv, const struct option *options, +loadopt_handle(int c, const char **argv, const struct option *options, int from_file, struct parseopt *ctx) { - if (!from_file && c >= 0 && options[first].id == LOADOPT_ID_NOCONFIG) - return loadopt_handle_noconfig(first, options, (struct loadopt *) ctx); + if (!from_file && c >= 0 && options[ctx->idx].id == LOADOPT_ID_NOCONFIG) + return loadopt_handle_noconfig(ctx->idx, options, (struct loadopt *) ctx); - if (c == PARSEOPT_ERR_UNKNOWN && first >= 0) { + if (c == PARSEOPT_ERR_UNKNOWN && ctx->idx >= 0) { const char *s = argv[ctx->cur] + ctx->off; size_t l = strlen(s); - adde("did you mean --", options[first].longopt); - while (options[++first].longopt) - if (!strncmp(s, options[first].longopt, l)) - adde(" or --", options[first].longopt); + adde("did you mean --", options[ctx->idx].longopt); + for (int i = ctx->idx + 1; options[i].longopt; ++i) + if (!strncmp(s, options[i].longopt, l)) + adde(" or --", options[i].longopt); err(" ?"); } @@ -77,7 +77,7 @@ loadopt_handle(int c, int first, const char **argv, const struct option *options } int -loadopt(int *first, int argc, const char **argv, const struct option *options, +loadopt(int argc, const char **argv, const struct option *options, const char *file, const char *section, unsigned int poflags, struct loadopt *ctx) { @@ -92,24 +92,21 @@ loadopt(int *first, int argc, const char **argv, const struct option *options, /* init is done, parse options from command line */ nextopt: if (ctx->state == STATE_INIT) { - int c, idx = -1; - c = parseopt(&idx, argc, argv, options, poflags, (struct parseopt *) ctx); + int c; + c = parseopt(argc, argv, options, poflags, (struct parseopt *) ctx); if (c >= 0) - add_optflags(ctx->optflags, idx, OPT_SET); + add_optflags(ctx->optflags, ctx->idx, OPT_SET); else - parseopt_warn(c, idx, argv, options, (struct parseopt *) ctx); + parseopt_warn(c, argv, options, (struct parseopt *) ctx); if (c != PARSEOPT_DONE) { - c = loadopt_handle(c, idx, argv, options, 0, (struct parseopt *) ctx); + c = loadopt_handle(c, argv, options, 0, (struct parseopt *) ctx); if (c == PARSEOPT_DONE) goto nextopt; } - if (c != PARSEOPT_DONE) { - if (first) - *first = idx; + if (c != PARSEOPT_DONE) return c; - } ctx->state = STATE_CMDLINE; } @@ -206,8 +203,8 @@ nextfileopt: struct parseopt po = { 0 }; const char *argv[] = { "", ctx->sa.s + ctx->saoff }; - int c, idx = -1; - c = parseopt(&idx, 2, argv, options, PARSEOPT_IS_LONG | PARSEOPT_STRICT, &po); + int c; + c = parseopt(2, argv, options, PARSEOPT_IS_LONG | PARSEOPT_STRICT, &po); /* seek past the line */ ctx->saoff = o + 1; @@ -215,25 +212,24 @@ nextfileopt: /* ignore already set option, and "argument required" error for * already set option */ if ((c >= 0 || c == PARSEOPT_ERR_ARGREQ) - && (get_optflags(ctx->optflags, idx) & OPT_SET)) { + && (get_optflags(ctx->optflags, po.idx) & OPT_SET)) { goto nextfileopt; } if (c >= 0) - add_optflags(ctx->optflags, idx, OPT_SET); + add_optflags(ctx->optflags, po.idx, OPT_SET); else - parseopt_warn(c, idx, argv, options, &po); + parseopt_warn(c, argv, options, &po); if (c != PARSEOPT_DONE) { - c = loadopt_handle(c, idx, argv, options, 1, &po); + c = loadopt_handle(c, argv, options, 1, &po); if (c == PARSEOPT_DONE) goto nextfileopt; } if (c != PARSEOPT_DONE) { - if (first) - *first = idx; /* adjust returned value */ ctx->arg = po.arg; + ctx->idx = po.idx; ctx->from_file = 1; return c; } diff --git a/src/liblimb/parseopt.h/parseopt.c b/src/liblimb/parseopt.h/parseopt.c index 8f0bb61..d1d843f 100644 --- a/src/liblimb/parseopt.h/parseopt.c +++ b/src/liblimb/parseopt.h/parseopt.c @@ -6,16 +6,16 @@ #include <limb/parseopt.h> int -parseopt(int *first, int argc, const char **argv, const struct option *options, +parseopt(int argc, const char **argv, const struct option *options, unsigned int flags, struct parseopt *ctx) { const char *arg; int is_long, arg_long; - int o; if (!ctx->cur) ctx->cur = 1; + ctx->idx = -1; again: if (ctx->cur == argc) return PARSEOPT_DONE; @@ -63,19 +63,18 @@ again: } if (flags & PARSEOPT_STRICT) { - for (o = 0; options[o].longopt; ++o) - if (end == strlen(options[o].longopt) - && !strncmp(options[o].longopt, arg, end)) + for (ctx->idx = 0; options[ctx->idx].longopt; ++ctx->idx) + if (end == strlen(options[ctx->idx].longopt) + && !strncmp(options[ctx->idx].longopt, arg, end)) break; - if (!options[o].longopt) - o = -1; - } else { - o = byte_get_match_full(first, arg, end, options, - offsetof(struct option, longopt), sizeof(*options)); - } - - if (o < 0) + if (!options[ctx->idx].longopt) { + ctx->idx = -1; + return PARSEOPT_ERR_UNKNOWN; + } + } else if (byte_get_match_full(&ctx->idx, arg, end, options, + offsetof(struct option, longopt), sizeof(*options)) < 0) { return PARSEOPT_ERR_UNKNOWN; + } /* --option-name=value : don't look for optarg on the next arg */ if (end < l) { @@ -83,17 +82,17 @@ again: arg += end; } } else { - for (o = 0; options[o].longopt; ++o) - if (*arg == options[o].shortopt) + for (ctx->idx = 0; options[ctx->idx].longopt; ++ctx->idx) + if (*arg == options[ctx->idx].shortopt) break; - if (!options[o].longopt) + if (!options[ctx->idx].longopt) { + ctx->idx = -1; return PARSEOPT_ERR_UNKNOWN; + } } - if (first) *first = o; - ctx->arg = NULL; - if (options[o].arg == ARG_REQ) { + if (options[ctx->idx].arg == ARG_REQ) { if (arg_long) { ++ctx->cur; if (ctx->cur == argc) @@ -104,7 +103,7 @@ again: return PARSEOPT_ERR_ARGREQ; ctx->arg = arg + 1; } - } else if (options[o].arg == ARG_OPT) { + } else if (options[ctx->idx].arg == ARG_OPT) { if (!arg_long && arg[1]) ctx->arg = arg + 1; } @@ -116,5 +115,5 @@ again: ctx->off = 0; } - return (options[o].id) ? options[o].id : options[o].shortopt; + return (options[ctx->idx].id) ? options[ctx->idx].id : options[ctx->idx].shortopt; }