From: Philippe Proulx Date: Tue, 1 Jun 2021 16:09:19 +0000 (-0400) Subject: Remove "invalid argument" statuses X-Git-Url: http://git.efficios.com/?p=argpar.git;a=commitdiff_plain;h=d1f7bbdbd28b96b360e815f28697a2f81d699cb4 Remove "invalid argument" statuses This patch removes the only remaining "invalid argument" status, which parse_long_opt() sets when the length of the name of a long option is greater than the size of its temporary buffer. To deal with this, `struct argpar_iter` contains a temporary buffer to contain the long option name in parse_long_opt(). This temporary buffer only grows. `test_argpar.c` contains a new test which exercise the parsers with a 700-character, hipster-themed long option name. Signed-off-by: Philippe Proulx Change-Id: Ia5adcfc2bdd978d81841a19ceea4a02f44559eed --- diff --git a/argpar/argpar.c b/argpar/argpar.c index 58cbc2b..ba57797 100644 --- a/argpar/argpar.c +++ b/argpar/argpar.c @@ -61,6 +61,12 @@ struct argpar_iter { * argpar_iter_next() call. */ const char *short_opt_ch; + + /* Temporary character buffer which only grows */ + struct { + size_t size; + char *data; + } tmp_buf; }; /* Base parsing item */ @@ -400,7 +406,6 @@ enum parse_orig_arg_opt_ret { PARSE_ORIG_ARG_OPT_RET_OK, PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT = -1, PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG = -2, - PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG = -3, PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG = -4, PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY = -5, }; @@ -495,7 +500,6 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, struct argpar_iter * const iter, char ** const error, struct argpar_item ** const item) { - const size_t max_len = 127; enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK; const struct argpar_opt_descr *descr; struct argpar_item_opt *opt_item; @@ -507,9 +511,6 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, /* Position of first `=`, if any */ const char *eq_pos; - /* Buffer holding option name when `long_opt_arg` contains `=` */ - char buf[max_len + 1]; - /* Option name */ const char *long_opt_name = long_opt_arg; @@ -521,16 +522,19 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, const size_t long_opt_name_size = eq_pos - long_opt_arg; /* Isolate the option name */ - if (long_opt_name_size > max_len) { - try_append_string_printf(error, - "Invalid argument `--%s`", long_opt_arg); - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG; - goto error; + while (long_opt_name_size > iter->tmp_buf.size - 1) { + iter->tmp_buf.size *= 2; + iter->tmp_buf.data = ARGPAR_REALLOC(iter->tmp_buf.data, + char, iter->tmp_buf.size); + if (!iter->tmp_buf.data) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; + goto error; + } } - memcpy(buf, long_opt_arg, long_opt_name_size); - buf[long_opt_name_size] = '\0'; - long_opt_name = buf; + memcpy(iter->tmp_buf.data, long_opt_arg, long_opt_name_size); + iter->tmp_buf.data[long_opt_name_size] = '\0'; + long_opt_name = iter->tmp_buf.data; } /* Find corresponding option descriptor */ @@ -650,7 +654,7 @@ struct argpar_iter *argpar_iter_create(const unsigned int argc, const char * const * const argv, const struct argpar_opt_descr * const descrs) { - struct argpar_iter * const iter = ARGPAR_ZALLOC(struct argpar_iter); + struct argpar_iter *iter = ARGPAR_ZALLOC(struct argpar_iter); if (!iter) { goto end; @@ -659,6 +663,13 @@ struct argpar_iter *argpar_iter_create(const unsigned int argc, iter->argc = argc; iter->argv = argv; iter->descrs = descrs; + iter->tmp_buf.size = 128; + iter->tmp_buf.data = ARGPAR_CALLOC(char, iter->tmp_buf.size); + if (!iter->tmp_buf.data) { + argpar_iter_destroy(iter); + iter = NULL; + goto end; + } end: return iter; @@ -667,7 +678,10 @@ end: ARGPAR_HIDDEN void argpar_iter_destroy(struct argpar_iter * const iter) { - free(iter); + if (iter) { + free(iter->tmp_buf.data); + free(iter); + } } ARGPAR_HIDDEN @@ -724,7 +738,6 @@ enum argpar_iter_next_status argpar_iter_next( break; case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT: case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG: - case PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG: case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG: try_prepend_while_parsing_arg_to_error(error, iter->i, orig_arg); @@ -736,9 +749,6 @@ enum argpar_iter_next_status argpar_iter_next( case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG: status = ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG; break; - case PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG: - status = ARGPAR_ITER_NEXT_STATUS_ERROR_INVALID_ARG; - break; case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG: status = ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG; break; @@ -795,7 +805,6 @@ struct argpar_parse_ret argpar_parse(const unsigned int argc, switch (status) { case ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG: - case ARGPAR_ITER_NEXT_STATUS_ERROR_INVALID_ARG: case ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG: case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY: goto error; diff --git a/argpar/argpar.h b/argpar/argpar.h index be71513..0a76315 100644 --- a/argpar/argpar.h +++ b/argpar/argpar.h @@ -313,7 +313,6 @@ enum argpar_iter_next_status { ARGPAR_ITER_NEXT_STATUS_END, ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT, ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG, - ARGPAR_ITER_NEXT_STATUS_ERROR_INVALID_ARG, ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG, ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY, }; @@ -344,9 +343,6 @@ enum argpar_iter_next_status { * `ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG`: * Missing option argument. * - * `ARGPAR_ITER_NEXT_STATUS_ERROR_INVALID_ARG`: - * Invalid argument. - * * `ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG`: * Unexpected option argument. * diff --git a/tests/test_argpar.c b/tests/test_argpar.c index c78b6e8..fee82a9 100644 --- a/tests/test_argpar.c +++ b/tests/test_argpar.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -650,6 +651,34 @@ void succeed_tests(void) "-f --<1,0> -f", descrs, 3); } + + /* Very long name of long option */ + { + const char opt_name[] = + "kale-chips-waistcoat-yr-bicycle-rights-gochujang-" + "woke-tumeric-flexitarian-biodiesel-chillwave-cliche-" + "ethical-cardigan-listicle-pok-pok-sustainable-live-" + "edge-jianbing-gochujang-butcher-disrupt-tattooed-" + "tumeric-prism-photo-booth-vape-kogi-jean-shorts-" + "blog-williamsburg-fingerstache-palo-santo-artisan-" + "affogato-occupy-skateboard-adaptogen-neutra-celiac-" + "put-a-bird-on-it-kombucha-everyday-carry-hot-chicken-" + "craft-beer-subway-tile-tote-bag-disrupt-selvage-" + "raclette-art-party-readymade-paleo-heirloom-trust-" + "fund-small-batch-kinfolk-woke-cardigan-prism-" + "chambray-la-croix-hashtag-unicorn-edison-bulb-tbh-" + "cornhole-cliche-tattooed-green-juice-adaptogen-" + "kitsch-lo-fi-vexillologist-migas-gentrify-" + "viral-raw-denim"; + const struct argpar_opt_descr descrs[] = { + { 0, '\0', opt_name, true }, + ARGPAR_OPT_DESCR_SENTINEL + }; + char cmdline[1024]; + + sprintf(cmdline, "--%s=23", opt_name); + test_succeed(cmdline, cmdline, descrs, 1); + } } /* @@ -880,7 +909,7 @@ void fail_tests(void) int main(void) { - plan_tests(423); + plan_tests(434); succeed_tests(); fail_tests(); return exit_status();