From: Philippe Proulx Date: Tue, 1 Jun 2021 14:13:08 +0000 (-0400) Subject: Add error enumerators to `enum argpar_iter_parse_next_status` X-Git-Url: http://git.efficios.com/?p=argpar.git;a=commitdiff_plain;h=d4d05805c9634c2ca9ae92950d01196917b6b260 Add error enumerators to `enum argpar_iter_parse_next_status` This patch adds all the possible reasons for a failure of argpar_iter_parse_next() as error enumerators to `enum argpar_iter_parse_next_status`. This will make it possible to convert the `error` parameter of argpar_iter_parse_next() to a rich error, without any formatted error message. In `test_argpar.c`, test_fail() now accepts an expected argpar_iter_parse_next() status which it forwards to test_fail_argpar_iter() which ensures that argpar_iter_parse_next() returns the expected error status. Signed-off-by: Philippe Proulx Change-Id: I9e8e91dea6066bd2ee935d6ca465569a6fd379aa --- diff --git a/argpar/argpar.c b/argpar/argpar.c index 72caa49..0468011 100644 --- a/argpar/argpar.c +++ b/argpar/argpar.c @@ -400,7 +400,7 @@ 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_OPT = -3, + 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, }; @@ -420,7 +420,7 @@ enum parse_orig_arg_opt_ret parse_short_opts(const char * const short_opts, if (strlen(short_opts) == 0) { try_append_string_printf(error, "Invalid argument"); - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_OPT; + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG; goto error; } @@ -519,7 +519,7 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, if (strlen(long_opt_arg) == 0) { try_append_string_printf(error, "Invalid argument"); - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_OPT; + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG; goto error; } @@ -532,7 +532,7 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, 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_OPT; + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG; goto error; } @@ -710,7 +710,7 @@ enum argpar_iter_parse_next_status argpar_iter_parse_next( iter->non_opt_index); if (!non_opt_item) { - status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR; + status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MEMORY; goto end; } @@ -730,17 +730,32 @@ enum argpar_iter_parse_next_status argpar_iter_parse_next( status = ARGPAR_ITER_PARSE_NEXT_STATUS_OK; break; case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT: - try_prepend_while_parsing_arg_to_error(error, iter->i, - orig_arg); - status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT; - break; case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG: - case PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_OPT: + case PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG: case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG: - case PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY: try_prepend_while_parsing_arg_to_error(error, iter->i, orig_arg); - status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR; + + switch (parse_orig_arg_opt_ret) { + case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT: + status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT; + break; + case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG: + status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG; + break; + case PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG: + status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_INVALID_ARG; + break; + case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG: + status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG; + break; + default: + abort(); + } + + break; + case PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY: + status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MEMORY; break; default: abort(); @@ -785,11 +800,13 @@ struct argpar_parse_ret argpar_parse(const unsigned int argc, const enum argpar_iter_parse_next_status status = argpar_iter_parse_next(iter, &item, &parse_ret.error); - if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR) { + switch (status) { + case ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG: + case ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_INVALID_ARG: + case ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG: + case ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MEMORY: goto error; - } else if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_END) { - break; - } else if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) { + case ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT: if (fail_on_unknown_opt) { parse_ret.ingested_orig_args = argpar_iter_get_ingested_orig_args(iter); @@ -798,11 +815,14 @@ struct argpar_parse_ret argpar_parse(const unsigned int argc, free(parse_ret.error); parse_ret.error = NULL; + goto success; + case ARGPAR_ITER_PARSE_NEXT_STATUS_END: + goto success; + default: + ARGPAR_ASSERT(status == ARGPAR_ITER_PARSE_NEXT_STATUS_OK); break; } - ARGPAR_ASSERT(status == ARGPAR_ITER_PARSE_NEXT_STATUS_OK); - if (!push_item(parse_ret.items, item)) { goto error; } @@ -810,6 +830,7 @@ struct argpar_parse_ret argpar_parse(const unsigned int argc, item = NULL; } +success: ARGPAR_ASSERT(!parse_ret.error); parse_ret.ingested_orig_args = argpar_iter_get_ingested_orig_args(iter); goto end; diff --git a/argpar/argpar.h b/argpar/argpar.h index c6f79cf..bfcc422 100644 --- a/argpar/argpar.h +++ b/argpar/argpar.h @@ -307,27 +307,50 @@ enum argpar_iter_parse_next_status { ARGPAR_ITER_PARSE_NEXT_STATUS_OK, ARGPAR_ITER_PARSE_NEXT_STATUS_END, ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT, - ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR, + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG, + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_INVALID_ARG, + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG, + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MEMORY, }; /* * Parses and returns the next item from `iter`. * - * On success, this function sets `*item` to an item which describes the - * next option or non-option argument and returns - * `ARGPAR_ITER_PARSE_NEXT_STATUS_OK`. Destroy `*item` with - * argpar_item_destroy(). + * On success, this function: + * + * * Sets `*item` to a parsing item which describes the next option + * or non-option argument. + * + * Destroy `*item` with argpar_item_destroy(). + * + * * Returns `ARGPAR_ITER_PARSE_NEXT_STATUS_OK`. * * If there are no more items to return, this function returns * `ARGPAR_ITER_PARSE_NEXT_STATUS_END`. * - * On failure (status codes - * `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT` and - * `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR`), this function sets `*error`, - * if not `NULL`, to a descriptive error string. Free `*error` with - * free(). + * On failure, this function: + * + * * Returns one of: + * + * `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT`: + * Unknown option (not found in `descrs` as passed to + * argpar_iter_create() to create `iter`). + * + * `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG`: + * Missing option argument. + * + * `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_INVALID_ARG`: + * Invalid argument. + * + * `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG`: + * Unexpected option argument. + * + * `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MEMORY`: + * Memory error. * - * Create an argument parsing iterator with argpar_iter_create(). + * * Except for the `ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MEMORY` status, + * sets `*error`, if not `NULL`, to a descriptive error string. + * Free `*error` with free(). */ enum argpar_iter_parse_next_status argpar_iter_parse_next( struct argpar_iter *iter, const struct argpar_item **item, diff --git a/tests/test_argpar.c b/tests/test_argpar.c index e8b362b..5c4700a 100644 --- a/tests/test_argpar.c +++ b/tests/test_argpar.c @@ -671,8 +671,9 @@ end: /* * Parses `cmdline` with the iterator API using the option descriptors - * `descrs`, and ensures that argpar_iter_parse_next() fails and that it - * sets an error which is equal to `expected_error`. + * `descrs`, and ensures that argpar_iter_parse_next() fails with status + * `expected_status` and that it sets an error which is equal to + * `expected_error`. * * This function splits `cmdline` on spaces to create an original * argument array. @@ -680,6 +681,7 @@ end: static void test_fail_argpar_iter(const char * const cmdline, const char * const expected_error, + const enum argpar_iter_parse_next_status expected_status, const struct argpar_opt_descr * const descrs) { struct argpar_iter *iter = NULL; @@ -697,10 +699,8 @@ void test_fail_argpar_iter(const char * const cmdline, ARGPAR_ITEM_DESTROY_AND_RESET(item); status = argpar_iter_parse_next(iter, &item, &error); - ok(status == ARGPAR_ITER_PARSE_NEXT_STATUS_OK || - status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR || - status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT, + status == expected_status, "argpar_iter_parse_next() returns the expected status " "(%d) for command line `%s` (call %u)", status, cmdline, i + 1); @@ -754,10 +754,12 @@ void test_fail_argpar_iter(const char * const cmdline, */ static void test_fail(const char * const cmdline, const char * const expected_error, + const enum argpar_iter_parse_next_status expected_iter_next_status, const struct argpar_opt_descr * const descrs) { test_fail_argpar_parse(cmdline, expected_error, descrs); - test_fail_argpar_iter(cmdline, expected_error, descrs); + test_fail_argpar_iter(cmdline, expected_error, + expected_iter_next_status, descrs); } static @@ -773,6 +775,7 @@ void fail_tests(void) test_fail( "--thumb=party --meow", "While parsing argument #2 (`--meow`): Unknown option `--meow`", + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT, descrs); } @@ -786,6 +789,7 @@ void fail_tests(void) test_fail( "--thumb=party -x", "While parsing argument #2 (`-x`): Unknown option `-x`", + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT, descrs); } @@ -799,6 +803,7 @@ void fail_tests(void) test_fail( "--thumb", "While parsing argument #1 (`--thumb`): Missing required argument for option `--thumb`", + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG, descrs); } @@ -812,6 +817,7 @@ void fail_tests(void) test_fail( "-k", "While parsing argument #1 (`-k`): Missing required argument for option `-k`", + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG, descrs); } @@ -827,6 +833,7 @@ void fail_tests(void) test_fail( "-abc", "While parsing argument #1 (`-abc`): Missing required argument for option `-c`", + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_MISSING_OPT_ARG, descrs); } @@ -842,6 +849,7 @@ void fail_tests(void) test_fail( "-ab - -c", "While parsing argument #2 (`-`): Invalid argument", + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_INVALID_ARG, descrs); } @@ -857,6 +865,7 @@ void fail_tests(void) test_fail( "-ab -- -c", "While parsing argument #2 (`--`): Invalid argument", + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_INVALID_ARG, descrs); } @@ -869,6 +878,7 @@ void fail_tests(void) test_fail( "--chevre=fromage", "While parsing argument #1 (`--chevre=fromage`): Unexpected argument for option `--chevre`", + ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG, descrs); } }