X-Git-Url: http://git.efficios.com/?p=argpar.git;a=blobdiff_plain;f=argpar%2Fargpar.c;h=82b561ceaae707002f36754c55e828d35b882206;hp=79a22f565bf99add9bb16b1eda572cd4b525526b;hb=143cec42e14e050571be640cb2dfa5c5e0198d59;hpb=8b95d883334b188d05cb1967980eae628e295d10 diff --git a/argpar/argpar.c b/argpar/argpar.c index 79a22f5..82b561c 100644 --- a/argpar/argpar.c +++ b/argpar/argpar.c @@ -5,7 +5,6 @@ * Copyright (c) 2020-2021 Simon Marchi */ -#include #include #include #include @@ -22,12 +21,15 @@ #define ARGPAR_ZALLOC(_type) ARGPAR_CALLOC(_type, 1) -#define ARGPAR_ASSERT(_cond) assert(_cond) - -#ifdef __MINGW_PRINTF_FORMAT -# define ARGPAR_PRINTF_FORMAT __MINGW_PRINTF_FORMAT +#ifdef NDEBUG +/* + * Force usage of the assertion condition to prevent unused variable warnings + * when `assert()` are disabled by the `NDEBUG` definition. + */ +# define ARGPAR_ASSERT(_cond) ((void) sizeof((void) (_cond), 0)) #else -# define ARGPAR_PRINTF_FORMAT printf +# include +# define ARGPAR_ASSERT(_cond) assert(_cond) #endif /* @@ -41,9 +43,11 @@ struct argpar_iter { * Data provided by the user to argpar_iter_create(); immutable * afterwards. */ - unsigned int argc; - const char * const *argv; - const struct argpar_opt_descr *descrs; + struct { + unsigned int argc; + const char * const *argv; + const struct argpar_opt_descr *descrs; + } user; /* * Index of the argument to process in the next @@ -107,6 +111,9 @@ struct argpar_item_non_opt { /* Parsing error */ struct argpar_error { + /* Error type */ + enum argpar_error_type type; + /* Original argument index */ unsigned int orig_index; @@ -190,6 +197,12 @@ end: return; } +/* + * Creates and returns an option parsing item for the descriptor `descr` + * and having the argument `arg` (copied; may be `NULL`). + * + * Returns `NULL` on memory error. + */ static struct argpar_item_opt *create_opt_item( const struct argpar_opt_descr * const descr, @@ -222,6 +235,13 @@ end: return opt_item; } +/* + * Creates and returns a non-option parsing item for the original + * argument `arg` having the original index `orig_index` and the + * non-option index `non_opt_index`. + * + * Returns `NULL` on memory error. + */ static struct argpar_item_non_opt *create_non_opt_item(const char * const arg, const unsigned int orig_index, @@ -256,6 +276,7 @@ end: */ static int set_error(struct argpar_error ** const error, + enum argpar_error_type type, const char * const unknown_opt_name, const struct argpar_opt_descr * const opt_descr, const bool is_short) @@ -271,9 +292,11 @@ int set_error(struct argpar_error ** const error, goto error; } + (*error)->type = type; + if (unknown_opt_name) { (*error)->unknown_opt_name = ARGPAR_CALLOC(char, - strlen(unknown_opt_name) + 1 + is_short ? 1 : 2); + strlen(unknown_opt_name) + 1 + (is_short ? 1 : 2)); if (!(*error)->unknown_opt_name) { goto error; } @@ -299,6 +322,14 @@ end: return ret; } +ARGPAR_HIDDEN +enum argpar_error_type argpar_error_type( + const struct argpar_error * const error) +{ + ARGPAR_ASSERT(error); + return error->type; +} + ARGPAR_HIDDEN unsigned int argpar_error_orig_index(const struct argpar_error * const error) { @@ -311,6 +342,7 @@ const char *argpar_error_unknown_opt_name( const struct argpar_error * const error) { ARGPAR_ASSERT(error); + ARGPAR_ASSERT(error->type == ARGPAR_ERROR_TYPE_UNKNOWN_OPT); ARGPAR_ASSERT(error->unknown_opt_name); return error->unknown_opt_name; } @@ -320,6 +352,8 @@ const struct argpar_opt_descr *argpar_error_opt_descr( const struct argpar_error * const error, bool * const is_short) { ARGPAR_ASSERT(error); + ARGPAR_ASSERT(error->type == ARGPAR_ERROR_TYPE_MISSING_OPT_ARG || + error->type == ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG); ARGPAR_ASSERT(error->opt_descr); if (is_short) { @@ -338,6 +372,17 @@ void argpar_error_destroy(const struct argpar_error * const error) } } +/* + * Finds and returns the _first_ descriptor having the short option name + * `short_name` or the long option name `long_name` within the option + * descriptors `descrs`. + * + * `short_name` may be `'\0'` to not consider it. + * + * `long_name` may be `NULL` to not consider it. + * + * Returns `NULL` if no descriptor is found. + */ static const struct argpar_opt_descr *find_descr( const struct argpar_opt_descr * const descrs, @@ -361,14 +406,22 @@ end: return !descr->short_name && !descr->long_name ? NULL : descr; } +/* Return type of parse_short_opt_group() and parse_long_opt() */ 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_UNEXPECTED_OPT_ARG = -4, - PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY = -5, + PARSE_ORIG_ARG_OPT_RET_ERROR = -1, + PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY = -2, }; +/* + * Parses the short option group argument `short_opt_group`, starting + * where needed depending on the state of `iter`. + * + * On success, sets `*item`. + * + * On error (except for `PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY`), sets + * `*error`. + */ static enum parse_orig_arg_opt_ret parse_short_opt_group( const char * const short_opt_group, @@ -396,9 +449,10 @@ enum parse_orig_arg_opt_ret parse_short_opt_group( const char unknown_opt_name[] = {*iter->short_opt_group_ch, '\0'}; - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT; + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - if (set_error(error, unknown_opt_name, NULL, true)) { + if (set_error(error, ARGPAR_ERROR_TYPE_UNKNOWN_OPT, + unknown_opt_name, NULL, true)) { ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; } @@ -421,9 +475,10 @@ enum parse_orig_arg_opt_ret parse_short_opt_group( */ if (!opt_arg || (iter->short_opt_group_ch[1] && strlen(opt_arg) == 0)) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG; + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - if (set_error(error, NULL, descr, true)) { + if (set_error(error, ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, + NULL, descr, true)) { ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; } @@ -461,6 +516,14 @@ end: return ret; } +/* + * Parses the long option argument `long_opt_arg`. + * + * On success, sets `*item`. + * + * On error (except for `PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY`), sets + * `*error`. + */ static enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, const char * const next_orig_arg, @@ -509,9 +572,10 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, /* Find corresponding option descriptor */ descr = find_descr(descrs, '\0', long_opt_name); if (!descr) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT; + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - if (set_error(error, long_opt_name, NULL, false)) { + if (set_error(error, ARGPAR_ERROR_TYPE_UNKNOWN_OPT, + long_opt_name, NULL, false)) { ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; } @@ -526,9 +590,10 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, } else { /* `--long-opt arg` style */ if (!next_orig_arg) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG; + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - if (set_error(error, NULL, descr, false)) { + if (set_error(error, ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, + NULL, descr, false)) { ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; } @@ -543,9 +608,10 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, * Unexpected `--opt=arg` style for a long option which * doesn't accept an argument. */ - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG; + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - if (set_error(error, NULL, descr, false)) { + if (set_error(error, ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG, + NULL, descr, false)) { ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; } @@ -574,6 +640,14 @@ end: return ret; } +/* + * Parses the original argument `orig_arg`. + * + * On success, sets `*item`. + * + * On error (except for `PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY`), sets + * `*error`. + */ static enum parse_orig_arg_opt_ret parse_orig_arg_opt(const char * const orig_arg, const char * const next_orig_arg, @@ -610,9 +684,9 @@ struct argpar_iter *argpar_iter_create(const unsigned int argc, goto end; } - iter->argc = argc; - iter->argv = argv; - iter->descrs = descrs; + iter->user.argc = argc; + iter->user.argv = argv; + iter->user.descrs = descrs; iter->tmp_buf.size = 128; iter->tmp_buf.data = ARGPAR_CALLOC(char, iter->tmp_buf.size); if (!iter->tmp_buf.data) { @@ -646,20 +720,21 @@ enum argpar_iter_next_status argpar_iter_next( const char *next_orig_arg; struct argpar_error ** const nc_error = (struct argpar_error **) error; - ARGPAR_ASSERT(iter->i <= iter->argc); + ARGPAR_ASSERT(iter->i <= iter->user.argc); if (error) { *nc_error = NULL; } - if (iter->i == iter->argc) { + if (iter->i == iter->user.argc) { status = ARGPAR_ITER_NEXT_STATUS_END; goto end; } - orig_arg = iter->argv[iter->i]; + orig_arg = iter->user.argv[iter->i]; next_orig_arg = - iter->i < (iter->argc - 1) ? iter->argv[iter->i + 1] : NULL; + iter->i < (iter->user.argc - 1) ? + iter->user.argv[iter->i + 1] : NULL; if (strcmp(orig_arg, "-") == 0 || strcmp(orig_arg, "--") == 0 || orig_arg[0] != '-') { @@ -682,34 +757,18 @@ enum argpar_iter_next_status argpar_iter_next( /* Option argument */ parse_orig_arg_opt_ret = parse_orig_arg_opt(orig_arg, - next_orig_arg, iter->descrs, iter, nc_error, + next_orig_arg, iter->user.descrs, iter, nc_error, (struct argpar_item **) item); switch (parse_orig_arg_opt_ret) { case PARSE_ORIG_ARG_OPT_RET_OK: status = ARGPAR_ITER_NEXT_STATUS_OK; 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_UNEXPECTED_OPT_ARG: + case PARSE_ORIG_ARG_OPT_RET_ERROR: if (error) { ARGPAR_ASSERT(*error); (*nc_error)->orig_index = iter->i; } - - switch (parse_orig_arg_opt_ret) { - case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT: - status = ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT; - break; - 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_UNEXPECTED_OPT_ARG: - status = ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG; - break; - default: - abort(); - } - + status = ARGPAR_ITER_NEXT_STATUS_ERROR; break; case PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY: status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY;