X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=argpar%2Fargpar.c;h=008d10b91a18c01e2b99f9f3b1596ef1f91b4bc0;hb=8a47e37df06099c16733921bf5a4fee599d69338;hp=97acdf2d6223f91f167433aaa8079a35cc02bc06;hpb=64875a48cd0151e30a3029422e19ef16526baebf;p=argpar.git diff --git a/argpar/argpar.c b/argpar/argpar.c index 97acdf2..008d10b 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 /* @@ -44,7 +46,7 @@ struct argpar_iter { struct { unsigned int argc; const char * const *argv; - const struct argpar_opt_descr *descrs; + const argpar_opt_descr_t *descrs; } user; /* @@ -73,23 +75,23 @@ struct argpar_iter { /* Base parsing item */ struct argpar_item { - enum argpar_item_type type; + argpar_item_type_t type; }; /* Option parsing item */ -struct argpar_item_opt { - struct argpar_item base; +typedef struct argpar_item_opt { + argpar_item_t base; /* Corresponding descriptor */ - const struct argpar_opt_descr *descr; + const argpar_opt_descr_t *descr; /* Argument, or `NULL` if none; owned by this */ char *arg; -}; +} argpar_item_opt_t; /* Non-option parsing item */ -struct argpar_item_non_opt { - struct argpar_item base; +typedef struct argpar_item_non_opt { + argpar_item_t base; /* * Complete argument, pointing to one of the entries of the @@ -105,10 +107,13 @@ struct argpar_item_non_opt { /* Index of this argument amongst other non-option arguments */ unsigned int non_opt_index; -}; +} argpar_item_non_opt_t; /* Parsing error */ struct argpar_error { + /* Error type */ + argpar_error_type_t type; + /* Original argument index */ unsigned int orig_index; @@ -116,72 +121,71 @@ struct argpar_error { char *unknown_opt_name; /* Option descriptor */ - const struct argpar_opt_descr *opt_descr; + const argpar_opt_descr_t *opt_descr; /* `true` if a short option caused the error */ bool is_short; }; ARGPAR_HIDDEN -enum argpar_item_type argpar_item_type(const struct argpar_item * const item) +argpar_item_type_t argpar_item_type(const argpar_item_t * const item) { ARGPAR_ASSERT(item); return item->type; } ARGPAR_HIDDEN -const struct argpar_opt_descr *argpar_item_opt_descr( - const struct argpar_item * const item) +const argpar_opt_descr_t *argpar_item_opt_descr( + const argpar_item_t * const item) { ARGPAR_ASSERT(item); ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT); - return ((const struct argpar_item_opt *) item)->descr; + return ((const argpar_item_opt_t *) item)->descr; } ARGPAR_HIDDEN -const char *argpar_item_opt_arg(const struct argpar_item * const item) +const char *argpar_item_opt_arg(const argpar_item_t * const item) { ARGPAR_ASSERT(item); ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT); - return ((const struct argpar_item_opt *) item)->arg; + return ((const argpar_item_opt_t *) item)->arg; } ARGPAR_HIDDEN -const char *argpar_item_non_opt_arg(const struct argpar_item * const item) +const char *argpar_item_non_opt_arg(const argpar_item_t * const item) { ARGPAR_ASSERT(item); ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT); - return ((const struct argpar_item_non_opt *) item)->arg; + return ((const argpar_item_non_opt_t *) item)->arg; } ARGPAR_HIDDEN unsigned int argpar_item_non_opt_orig_index( - const struct argpar_item * const item) + const argpar_item_t * const item) { ARGPAR_ASSERT(item); ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT); - return ((const struct argpar_item_non_opt *) item)->orig_index; + return ((const argpar_item_non_opt_t *) item)->orig_index; } ARGPAR_HIDDEN unsigned int argpar_item_non_opt_non_opt_index( - const struct argpar_item * const item) + const argpar_item_t * const item) { ARGPAR_ASSERT(item); ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT); - return ((const struct argpar_item_non_opt *) item)->non_opt_index; + return ((const argpar_item_non_opt_t *) item)->non_opt_index; } ARGPAR_HIDDEN -void argpar_item_destroy(const struct argpar_item * const item) +void argpar_item_destroy(const argpar_item_t * const item) { if (!item) { goto end; } if (item->type == ARGPAR_ITEM_TYPE_OPT) { - struct argpar_item_opt * const opt_item = - (struct argpar_item_opt *) item; + argpar_item_opt_t * const opt_item = (argpar_item_opt_t *) item; free(opt_item->arg); } @@ -192,13 +196,17 @@ 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, +argpar_item_opt_t *create_opt_item(const argpar_opt_descr_t * const descr, const char * const arg) { - struct argpar_item_opt *opt_item = - ARGPAR_ZALLOC(struct argpar_item_opt); + argpar_item_opt_t *opt_item = ARGPAR_ZALLOC(argpar_item_opt_t); if (!opt_item) { goto end; @@ -224,13 +232,20 @@ 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, +argpar_item_non_opt_t *create_non_opt_item(const char * const arg, const unsigned int orig_index, const unsigned int non_opt_index) { - struct argpar_item_non_opt * const non_opt_item = - ARGPAR_ZALLOC(struct argpar_item_non_opt); + argpar_item_non_opt_t * const non_opt_item = + ARGPAR_ZALLOC(argpar_item_non_opt_t); if (!non_opt_item) { goto end; @@ -257,10 +272,9 @@ end: * error. */ static -int set_error(struct argpar_error ** const error, +int set_error(argpar_error_t ** const error, argpar_error_type_t type, const char * const unknown_opt_name, - const struct argpar_opt_descr * const opt_descr, - const bool is_short) + const argpar_opt_descr_t * const opt_descr, const bool is_short) { int ret = 0; @@ -268,14 +282,16 @@ int set_error(struct argpar_error ** const error, goto end; } - *error = ARGPAR_ZALLOC(struct argpar_error); + *error = ARGPAR_ZALLOC(argpar_error_t); if (!*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; } @@ -302,7 +318,15 @@ end: } ARGPAR_HIDDEN -unsigned int argpar_error_orig_index(const struct argpar_error * const error) +argpar_error_type_t argpar_error_type( + const argpar_error_t * const error) +{ + ARGPAR_ASSERT(error); + return error->type; +} + +ARGPAR_HIDDEN +unsigned int argpar_error_orig_index(const argpar_error_t * const error) { ARGPAR_ASSERT(error); return error->orig_index; @@ -310,18 +334,21 @@ unsigned int argpar_error_orig_index(const struct argpar_error * const error) ARGPAR_HIDDEN const char *argpar_error_unknown_opt_name( - const struct argpar_error * const error) + const argpar_error_t * 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; } ARGPAR_HIDDEN -const struct argpar_opt_descr *argpar_error_opt_descr( - const struct argpar_error * const error, bool * const is_short) +const argpar_opt_descr_t *argpar_error_opt_descr( + const argpar_error_t * 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) { @@ -332,7 +359,7 @@ const struct argpar_opt_descr *argpar_error_opt_descr( } ARGPAR_HIDDEN -void argpar_error_destroy(const struct argpar_error * const error) +void argpar_error_destroy(const argpar_error_t * const error) { if (error) { free(error->unknown_opt_name); @@ -340,12 +367,22 @@ 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, +const argpar_opt_descr_t *find_descr(const argpar_opt_descr_t * const descrs, const char short_name, const char * const long_name) { - const struct argpar_opt_descr *descr; + const argpar_opt_descr_t *descr; for (descr = descrs; descr->short_name || descr->long_name; descr++) { if (short_name && descr->short_name && @@ -363,28 +400,35 @@ end: return !descr->short_name && !descr->long_name ? NULL : descr; } -enum parse_orig_arg_opt_ret { +/* Return type of parse_short_opt_group() and parse_long_opt() */ +typedef 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, +} parse_orig_arg_opt_ret_t; +/* + * 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( +parse_orig_arg_opt_ret_t parse_short_opt_group( const char * const short_opt_group, const char * const next_orig_arg, - const struct argpar_opt_descr * const descrs, - struct argpar_iter * const iter, - struct argpar_error ** const error, - struct argpar_item ** const item) + const argpar_opt_descr_t * const descrs, + argpar_iter_t * const iter, argpar_error_t ** const error, + argpar_item_t ** const item) { - enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK; + parse_orig_arg_opt_ret_t ret = PARSE_ORIG_ARG_OPT_RET_OK; bool used_next_orig_arg = false; const char *opt_arg = NULL; - const struct argpar_opt_descr *descr; - struct argpar_item_opt *opt_item; + const argpar_opt_descr_t *descr; + argpar_item_opt_t *opt_item; ARGPAR_ASSERT(strlen(short_opt_group) != 0); @@ -398,9 +442,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; } @@ -423,9 +468,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; } @@ -463,17 +509,24 @@ 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, +parse_orig_arg_opt_ret_t parse_long_opt(const char * const long_opt_arg, const char * const next_orig_arg, - const struct argpar_opt_descr * const descrs, - struct argpar_iter * const iter, - struct argpar_error ** const error, - struct argpar_item ** const item) + const argpar_opt_descr_t * const descrs, + argpar_iter_t * const iter, argpar_error_t ** const error, + argpar_item_t ** const item) { - 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; + parse_orig_arg_opt_ret_t ret = PARSE_ORIG_ARG_OPT_RET_OK; + const argpar_opt_descr_t *descr; + argpar_item_opt_t *opt_item; bool used_next_orig_arg = false; /* Option's argument, if any */ @@ -511,9 +564,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; } @@ -528,9 +582,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; } @@ -545,9 +600,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; } @@ -576,37 +632,44 @@ 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, +parse_orig_arg_opt_ret_t parse_orig_arg_opt(const char * const orig_arg, const char * const next_orig_arg, - const struct argpar_opt_descr * const descrs, - struct argpar_iter * const iter, - struct argpar_error ** const error, - struct argpar_item ** const item) + const argpar_opt_descr_t * const descrs, + argpar_iter_t * const iter, argpar_error_t ** const error, + argpar_item_t ** const item) { - enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK; + parse_orig_arg_opt_ret_t ret = PARSE_ORIG_ARG_OPT_RET_OK; ARGPAR_ASSERT(orig_arg[0] == '-'); if (orig_arg[1] == '-') { /* Long option */ - ret = parse_long_opt(&orig_arg[2], - next_orig_arg, descrs, iter, error, item); + ret = parse_long_opt(&orig_arg[2], next_orig_arg, descrs, iter, + error, item); } else { /* Short option */ - ret = parse_short_opt_group(&orig_arg[1], - next_orig_arg, descrs, iter, error, item); + ret = parse_short_opt_group(&orig_arg[1], next_orig_arg, descrs, + iter, error, item); } return ret; } ARGPAR_HIDDEN -struct argpar_iter *argpar_iter_create(const unsigned int argc, +argpar_iter_t *argpar_iter_create(const unsigned int argc, const char * const * const argv, - const struct argpar_opt_descr * const descrs) + const argpar_opt_descr_t * const descrs) { - struct argpar_iter *iter = ARGPAR_ZALLOC(struct argpar_iter); + argpar_iter_t *iter = ARGPAR_ZALLOC(argpar_iter_t); if (!iter) { goto end; @@ -628,7 +691,7 @@ end: } ARGPAR_HIDDEN -void argpar_iter_destroy(struct argpar_iter * const iter) +void argpar_iter_destroy(argpar_iter_t * const iter) { if (iter) { free(iter->tmp_buf.data); @@ -637,16 +700,15 @@ void argpar_iter_destroy(struct argpar_iter * const iter) } ARGPAR_HIDDEN -enum argpar_iter_next_status argpar_iter_next( - struct argpar_iter * const iter, - const struct argpar_item ** const item, - const struct argpar_error ** const error) +argpar_iter_next_status_t argpar_iter_next(argpar_iter_t * const iter, + const argpar_item_t ** const item, + const argpar_error_t ** const error) { - enum argpar_iter_next_status status; - enum parse_orig_arg_opt_ret parse_orig_arg_opt_ret; + argpar_iter_next_status_t status; + parse_orig_arg_opt_ret_t parse_orig_arg_opt_ret; const char *orig_arg; const char *next_orig_arg; - struct argpar_error ** const nc_error = (struct argpar_error **) error; + argpar_error_t ** const nc_error = (argpar_error_t **) error; ARGPAR_ASSERT(iter->i <= iter->user.argc); @@ -667,7 +729,7 @@ enum argpar_iter_next_status argpar_iter_next( if (strcmp(orig_arg, "-") == 0 || strcmp(orig_arg, "--") == 0 || orig_arg[0] != '-') { /* Non-option argument */ - const struct argpar_item_non_opt * const non_opt_item = + const argpar_item_non_opt_t * const non_opt_item = create_non_opt_item(orig_arg, iter->i, iter->non_opt_index); @@ -686,33 +748,17 @@ 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->user.descrs, iter, nc_error, - (struct argpar_item **) item); + (argpar_item_t **) 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; @@ -726,8 +772,7 @@ end: } ARGPAR_HIDDEN -unsigned int argpar_iter_ingested_orig_args( - const struct argpar_iter * const iter) +unsigned int argpar_iter_ingested_orig_args(const argpar_iter_t * const iter) { return iter->i; }