Add error enumerators to `enum argpar_iter_parse_next_status`
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 1 Jun 2021 14:13:08 +0000 (10:13 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 4 Jun 2021 17:59:04 +0000 (13:59 -0400)
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 <eeppeliteloop@gmail.com>
Change-Id: I9e8e91dea6066bd2ee935d6ca465569a6fd379aa

argpar/argpar.c
argpar/argpar.h
tests/test_argpar.c

index 72caa49dfd79c1272d47cb3a1279c766444d4abb..0468011374de8b03c4ce4b2e00fc0fa375f500fc 100644 (file)
@@ -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;
index c6f79cf64f6e5ad445464ab7dd1cb02b5c52d9d4..bfcc42241f9fd7d6bb5a88e32d5e5d46774cb00d 100644 (file)
@@ -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,
index e8b362bf3c232cce0ecaa0838807ea733d7d829b..5c4700aa27e8a8ac7afcb5087cb6c24d30951214 100644 (file)
@@ -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);
        }
 }
This page took 0.039992 seconds and 4 git commands to generate.