From d244e4e3cb702dcb87f1c3c1232abd2fc936d8ec Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Sun, 8 Sep 2024 22:02:02 +0200 Subject: OPTION_WITHARG --- src/util/option.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'src/util/option.c') diff --git a/src/util/option.c b/src/util/option.c index 5efcbd7..2ad20d1 100644 --- a/src/util/option.c +++ b/src/util/option.c @@ -25,21 +25,34 @@ char** option_parse(int argc, char **argv, const struct option_spec *speclist) { abort(); } spectable[(uint8_t)spec->optc] = spec; + + if (spec->kind == OPTSPECKIND_WITHARG) { + *spec->spec_sub.witharg.dst = NULL; + } } + // option, option argument, or '--'. + bool *is_option = calloc(argc, 1); + // 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++) { + DEBUG("opti = %d\n", opti); + if (argv[opti][0] != '-') continue; // skip non-options + is_option[opti] = true; + // 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 '--' + bool skip_next_argument = false; + for (int j = 1; argv[opti][j]; j++) { const struct option_spec *spec = spectable[(uint8_t)argv[opti][j]]; if (!spec) { @@ -60,6 +73,27 @@ char** option_parse(int argc, char **argv, const struct option_spec *speclist) { spec->spec_sub.callp.fun(spec->spec_sub.callp.data); break; + case OPTSPECKIND_WITHARG: + if (argv[opti][j+1] != '\0') { + fprintf(stderr, "%s: Optie -%c heeft een argument nodig, maar is niet de laatste op rij\n", argv[0], argv[opti][j]); + exit(1); + } + + if (opti + 1 < argc) { + char **dst = spec->spec_sub.witharg.dst; + if (*dst) free(*dst); // override any previous value + + const size_t arglen = strlen(argv[opti+1]); + *dst = malloc(arglen + 1); + memcpy(*dst, argv[opti+1], arglen + 1); + + skip_next_argument = true; + } else { + fprintf(stderr, "%s: Optie -%c heeft een argument nodig\n", argv[0], argv[opti][j]); + exit(1); + } + break; + case OPTSPECKIND_HELPUSAGE: printf(spec->spec_sub.helpusage.usagestr, argv[0]); exit(0); @@ -71,6 +105,12 @@ char** option_parse(int argc, char **argv, const struct option_spec *speclist) { case OPTSPECKIND_END: abort(); // unreachable } } + + if (skip_next_argument) { + // skip next argument, but mark it as an option + last_option_index = ++opti; + is_option[opti] = true; + } } DEBUG("last_option_index=%d npos_before_opts=%d\n", last_option_index, npos_before_opts); @@ -80,18 +120,13 @@ char** option_parse(int argc, char **argv, const struct option_spec *speclist) { // 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]; + if (!is_option[i]) 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 (is_option[readi]) { if (readi > noptargs + 1) argv[noptargs + 1] = argv[readi]; noptargs++; } @@ -104,5 +139,7 @@ char** option_parse(int argc, char **argv, const struct option_spec *speclist) { // debug_argv(argc, argv); + free(is_option); + return argv + 1 + noptargs; } -- cgit v1.2.3-70-g09d2