diff options
| author | Tyge Løvset <[email protected]> | 2021-11-10 08:22:36 +0100 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2021-11-10 08:22:36 +0100 |
| commit | 888a3ac3c43b49a9fdd1f5e29dcb6b4cdbf3b262 (patch) | |
| tree | 8e22f017dd5a97aac6ec893b4f457e0436fe29af | |
| parent | bc69c8f5edee0bf17685ed78c5b3637552ca19af (diff) | |
| download | STC-modified-888a3ac3c43b49a9fdd1f5e29dcb6b4cdbf3b262.tar.gz STC-modified-888a3ac3c43b49a9fdd1f5e29dcb6b4cdbf3b262.zip | |
Added back coption.h
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | benchmarks/misc/string_bench.c | 18 | ||||
| -rw-r--r-- | docs/coption_api.md | 26 | ||||
| -rw-r--r-- | include/stc/coption.h | 180 |
4 files changed, 205 insertions, 22 deletions
@@ -40,8 +40,9 @@ which by the compiler is seen as different code because of macro name substituti - [***cvec*** - **std::vector** alike type](docs/cvec_api.md) Others: -- [***crandom*** - A novel very fast *PRNG* named **stc64**](docs/crandom_api.md) - [***ccommon*** - Some handy macros and general definitions](docs/ccommon_api.md) +- [***crandom*** - A novel very fast *PRNG* named **stc64**](docs/crandom_api.md) +- [***coption*** - Command line options scanner](docs/coption_api.md) Highlights ---------- diff --git a/benchmarks/misc/string_bench.c b/benchmarks/misc/string_bench.c index 8e639aa2..28777e8d 100644 --- a/benchmarks/misc/string_bench.c +++ b/benchmarks/misc/string_bench.c @@ -33,6 +33,8 @@ void initShortStringVec(cvec_str* vs) size_t lengths = 0;
c_foreach (i, cvec_str, *vs)
{
+ cstr_append_s(i.ref, *i.ref);
+ cstr_append_s(i.ref, *i.ref);
lengths += cstr_size(*i.ref);
}
printf("avg len: %f\n", (float)lengths / cvec_str_size(*vs));
@@ -44,17 +46,17 @@ void initLongStringVec(cvec_str* vs) *vs = read_file("names.txt");
cstr* s = vs->data;
size_t lengths = 0;
- cstr_append(s, s[1].str);
- cstr_append(s, s[2].str);
- cstr_append(s, s[3].str);
+ cstr_append_s(s, s[1]);
+ cstr_append_s(s, s[2]);
+ cstr_append_s(s, s[3]);
for (int i=1; i < cvec_str_size(*vs); ++i)
{
cstr* t = vs->data + i;
- cstr_append(t, t->str);
- cstr_append(t, t->str);
- cstr_append(t, s->str);
- cstr_append(t, t->str);
- cstr_append(t, t->str);
+ cstr_append_s(t, *t);
+ cstr_append_s(t, *t);
+ cstr_append_s(t, *s);
+ cstr_append_s(t, *t);
+ cstr_append_s(t, *t);
lengths += cstr_size(*t);
}
printf("avg len: %f\n", (float)lengths / cvec_str_size(*vs));
diff --git a/docs/coption_api.md b/docs/coption_api.md index f7c870bc..7a62ddea 100644 --- a/docs/coption_api.md +++ b/docs/coption_api.md @@ -8,15 +8,15 @@ See [getopt_long](https://www.freebsd.org/cgi/man.cgi?getopt_long(3)) for a simi ```c enum { - copt_no_argument = 0, - copt_required_argument = 1, - copt_optional_argument = 2 + coption_no_argument = 0, + coption_required_argument = 1, + coption_optional_argument = 2 }; typedef struct { int ind; /* equivalent to posix optind */ int opt; /* equivalent to posix optopt */ const char *arg; /* equivalent to posix optarg */ - const char *faulty; /* points to the faulty option, if any */ + const char *badopt; /* points to the bad option, if any */ int longindex; /* index of long option; or -1 if short */ ... } coption; @@ -46,13 +46,13 @@ int coption_get(coption *opt, int argc, char *argv[], int main(int argc, char *argv[]) { static coption_long long_options[] = { - {"verbose", copt_no_argument, 'V'}, - {"help", copt_no_argument, 'H'}, - {"add", copt_no_argument, 'a'}, - {"append", copt_no_argument, 'b'}, - {"delete", copt_required_argument, 'd'}, - {"create", copt_required_argument, 'c'}, - {"file", copt_required_argument, 'f'}, + {"verbose", coption_no_argument, 'V'}, + {"help", coption_no_argument, 'H'}, + {"add", coption_no_argument, 'a'}, + {"append", coption_no_argument, 'b'}, + {"delete", coption_required_argument, 'd'}, + {"create", coption_required_argument, 'c'}, + {"file", coption_required_argument, 'f'}, {NULL} }; coption opt = coption_init(); @@ -70,10 +70,10 @@ int main(int argc, char *argv[]) { printf("filename: %s\n", opt.arg); break; case ':': - printf("option %s needs a value\n", opt.faulty); + printf("option %s needs a value\n", opt.badopt); break; case '?': - printf("unknown option: %s\n", opt.faulty); + printf("unknown option: %s\n", opt.badopt); break; } } diff --git a/include/stc/coption.h b/include/stc/coption.h new file mode 100644 index 00000000..c542867b --- /dev/null +++ b/include/stc/coption.h @@ -0,0 +1,180 @@ +/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/*
+Inspired by https://attractivechaos.wordpress.com/2018/08/31/a-survey-of-argument-parsing-libraries-in-c-c
+Fixed major bugs with optional arguments (both long and short).
+Added arg->badopt output field, more consistent API.
+
+coption_get() is similar to GNU's getopt_long(). Each call parses one option and
+returns the option name. opt->arg points to the option argument if present.
+The function returns -1 when all command-line arguments are parsed. In this case,
+opt->ind is the index of the first non-option argument.
+
+#include <stdio.h>
+#include <stc/coption.h>
+
+int main(int argc, char *argv[])
+{
+ coption_long longopts[] = {
+ {"foo", coption_no_argument, 'f'},
+ {"bar", coption_required_argument, 'b'},
+ {"opt", coption_optional_argument, 'o'},
+ {0}
+ };
+ const char* optstr = "xy:z::123";
+ printf("program -x -y ARG -z [ARG] -1 -2 -3 --foo --bar ARG --opt [ARG] [ARGUMENTS]\n");
+ int c;
+ coption opt = coption_init();
+ while ((c = coption_get(&opt, argc, argv, optstr, longopts)) != -1) {
+ switch (c) {
+ case '?': printf("error: unknown option: %s\n", opt.badopt); break;
+ case ':': printf("error: missing argument for %s\n", opt.badopt); break;
+ default: printf("option: %c [%s]\n", opt.opt, opt.arg ? opt.arg : ""); break;
+ }
+ }
+ printf("\nNon-option arguments:");
+ for (int i = opt.ind; i < argc; ++i)
+ printf(" %s", argv[i]);
+ putchar('\n');
+ return 0;
+}
+*/
+#ifndef COPTION_H_INCLUDED
+#define COPTION_H_INCLUDED
+
+#include <string.h>
+#include <stdbool.h>
+
+enum {
+ coption_no_argument = 0,
+ coption_required_argument = 1,
+ coption_optional_argument = 2
+};
+typedef struct {
+ int ind; /* equivalent to optind */
+ int opt; /* equivalent to optopt */
+ const char *arg; /* equivalent to optarg */
+ const char *badopt; /* points to the bad option */
+ int longindex; /* idx of long option; or -1 if short */
+ int _i, _pos, _nargs;
+ char _badopt[4];
+} coption;
+
+typedef struct {
+ const char *name;
+ int has_arg;
+ int val;
+} coption_long;
+
+static inline coption coption_init(void) {
+ coption opt = {1, 0, NULL, NULL, -1, 1, 0, 0, {'-', '?', '\0'}};
+ return opt;
+}
+
+/* move argv[j] over n elements to the left */
+static void coption_permute_(char *argv[], int j, int n) {
+ int k;
+ char *p = argv[j];
+ for (k = 0; k < n; ++k)
+ argv[j - k] = argv[j - k - 1];
+ argv[j - k] = p;
+}
+
+/* @param opt output; must be initialized to coption_init() on first call
+ * @return ASCII val for a short option; longopt.val for a long option;
+ * -1 if argv[] is fully processed; '?' for an unknown option or
+ * an ambiguous long option; ':' if an option argument is missing
+ */
+static int coption_get(coption *opt, int argc, char *argv[],
+ const char *shortopts, const coption_long *longopts) {
+ int optc = -1, i0, j, posixly_correct = (shortopts[0] == '+');
+ if (!posixly_correct) {
+ while (opt->_i < argc && (argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0'))
+ ++opt->_i, ++opt->_nargs;
+ }
+ opt->arg = 0, opt->longindex = -1, i0 = opt->_i;
+ if (opt->_i >= argc || argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0') {
+ opt->ind = opt->_i - opt->_nargs;
+ return -1;
+ }
+ if (argv[opt->_i][0] == '-' && argv[opt->_i][1] == '-') { /* "--" or a long option */
+ if (argv[opt->_i][2] == '\0') { /* a bare "--" */
+ coption_permute_(argv, opt->_i, opt->_nargs);
+ ++opt->_i, opt->ind = opt->_i - opt->_nargs;
+ return -1;
+ }
+ opt->opt = 0, optc = '?', opt->_pos = -1;
+ if (longopts) { /* parse long options */
+ int k, n_exact = 0, n_partial = 0;
+ const coption_long *o = 0, *o_exact = 0, *o_partial = 0;
+ for (j = 2; argv[opt->_i][j] != '\0' && argv[opt->_i][j] != '='; ++j) {} /* find the end of the option name */
+ for (k = 0; longopts[k].name != 0; ++k)
+ if (strncmp(&argv[opt->_i][2], longopts[k].name, j - 2) == 0) {
+ if (longopts[k].name[j - 2] == 0) ++n_exact, o_exact = &longopts[k];
+ else ++n_partial, o_partial = &longopts[k];
+ }
+ opt->badopt = argv[opt->_i];
+ if (n_exact > 1 || (n_exact == 0 && n_partial > 1)) return '?';
+ o = n_exact == 1? o_exact : n_partial == 1? o_partial : 0;
+ if (o) {
+ opt->opt = optc = o->val, opt->longindex = o - longopts;
+ if (o->has_arg != coption_no_argument) {
+ if (argv[opt->_i][j] == '=')
+ opt->arg = &argv[opt->_i][j + 1];
+ else if (argv[opt->_i][j] == '\0' && opt->_i < argc - 1 && (o->has_arg == coption_required_argument ||
+ argv[opt->_i + 1][0] != '-'))
+ opt->arg = argv[++opt->_i];
+ else if (o->has_arg == coption_required_argument)
+ optc = ':'; /* missing option argument */
+ }
+ }
+ }
+ } else { /* a short option */
+ const char *p;
+ if (opt->_pos == 0) opt->_pos = 1;
+ optc = opt->opt = argv[opt->_i][opt->_pos++];
+ opt->_badopt[1] = optc, opt->badopt = opt->_badopt;
+ p = strchr((char *) shortopts, optc);
+ if (p == 0) {
+ optc = '?'; /* unknown option */
+ } else if (p[1] == ':') {
+ if (argv[opt->_i][opt->_pos] != '\0')
+ opt->arg = &argv[opt->_i][opt->_pos];
+ else if (opt->_i < argc - 1 && (p[2] != ':' || argv[opt->_i + 1][0] != '-'))
+ opt->arg = argv[++opt->_i];
+ else if (p[2] != ':')
+ optc = ':';
+ opt->_pos = -1;
+ }
+ }
+ if (opt->_pos < 0 || argv[opt->_i][opt->_pos] == 0) {
+ ++opt->_i, opt->_pos = 0;
+ if (opt->_nargs > 0) /* permute */
+ for (j = i0; j < opt->_i; ++j)
+ coption_permute_(argv, j, opt->_nargs);
+ }
+ opt->ind = opt->_i - opt->_nargs;
+ return optc;
+}
+
+#endif
\ No newline at end of file |
