#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); 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; }