From bd22d0e47d0fb203286b088f048cf1aff1fa93a1 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Mon, 22 Jul 2024 23:14:43 +0200 Subject: Nieuw optieontleedsysteem, en migreer weerklank --- src/util/option.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/util/option.c (limited to 'src/util/option.c') diff --git a/src/util/option.c b/src/util/option.c new file mode 100644 index 0000000..ef7a398 --- /dev/null +++ b/src/util/option.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include "option.h" +#include "util/versie.h" +#include "util/debug.h" + + +/* static void debug_argv(int argc, char **argv) { + fprintf(stderr, "argv: <"); + for (int i = 0; i < argc; i++) { + if (i != 0) fputc(',', stderr); + fprintf(stderr, "'%s'", argv[i]); + } + fprintf(stderr, ">\n"); +} */ + +char** option_parse(int argc, char **argv, const struct option_spec *speclist) { + // fill table of specs + const struct option_spec *spectable[256] = {0}; + for (const struct option_spec *spec = speclist; spec->kind != OPTSPECKIND_END; spec++) { + if (spectable[(uint8_t)spec->optc] != NULL) { + fprintf(stderr, "option_parse: dubbele specs\n"); + abort(); + } + spectable[(uint8_t)spec->optc] = spec; + } + + // parse options + int last_option_index = 0; // index of last option argument, treating '--' as option arg + int npos_before_opts = 0; // number of positional arguments before last_option_index + int opti; + for (opti = 1; opti < argc; opti++) { + if (argv[opti][0] != '-') continue; // skip non-options + + // count an option argument even if it's '--' + npos_before_opts += opti - (last_option_index + 1); + last_option_index = opti; + + if (strcmp(argv[opti], "--") == 0) break; // but don't try to parse '--' + + for (int j = 1; argv[opti][j]; j++) { + const struct option_spec *spec = spectable[(uint8_t)argv[opti][j]]; + if (!spec) { + fprintf(stderr, "%s: Ongeldige optie: -%c\n", argv[0], argv[opti][j]); + exit(1); + } + + switch (spec->kind) { + case OPTSPECKIND_SETBOOL: + *spec->spec_sub.setbool.ptr = true; + break; + + case OPTSPECKIND_CALL: + spec->spec_sub.call.fun(); + break; + + case OPTSPECKIND_CALLP: + spec->spec_sub.callp.fun(spec->spec_sub.callp.data); + break; + + case OPTSPECKIND_HELPUSAGE: + printf(spec->spec_sub.helpusage.usagestr, argv[0]); + exit(0); + + case OPTSPECKIND_VERSION: + drukkedoos_print_versie(stdout, argv[0]); + exit(0); + + case OPTSPECKIND_END: abort(); // unreachable + } + } + } + + DEBUG("last_option_index=%d npos_before_opts=%d\n", last_option_index, npos_before_opts); + + // debug_argv(argc, argv); + + // collect positional arguments that need to be reshuffled + char *posargs[npos_before_opts]; + for (int i = 1, posi = 0; i < last_option_index; i++) { + // don't need to check for '--' here because '--' is an option argument and + // this loop doesn't go beyond it + if (argv[i][0] == '-') continue; + + posargs[posi++] = argv[i]; + } + + // move option arguments to the beginning + int noptargs = 0; + for (int readi = 1; readi <= last_option_index; readi++) { + // no need to check for '--' here + if (argv[readi][0] == '-') { + if (readi > noptargs + 1) argv[noptargs + 1] = argv[readi]; + noptargs++; + } + } + + // debug_argv(argc, argv); + + // write positional arguments after the option arguments + memcpy(argv + 1 + noptargs, posargs, npos_before_opts * sizeof(char*)); + + // debug_argv(argc, argv); + + return argv + 1 + noptargs; +} -- cgit v1.2.3-70-g09d2