From: Simon Marchi Date: Mon, 9 Sep 2024 16:30:03 +0000 (-0400) Subject: argpar: sync with upstream X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=0915d10bcc40a8ae6c1d400914f1d39f2e0a002d;p=babeltrace.git argpar: sync with upstream Sync with upstream commit a80b22c5f492 ("Add C++ bindings"). Change-Id: I65086a80325907d029a34fde437d52dba5a323c6 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/13252 Tested-by: jenkins Reviewed-by: Philippe Proulx --- diff --git a/src/argpar/argpar.c b/src/argpar/argpar.c index 10f6ee8d..5c3d8faa 100644 --- a/src/argpar/argpar.c +++ b/src/argpar/argpar.c @@ -1,12 +1,9 @@ /* * SPDX-License-Identifier: MIT - * - * Copyright (c) 2019-2021 Philippe Proulx - * Copyright (c) 2020-2021 Simon Marchi + * SPDX-FileCopyrightText: 2019-2024 Philippe Proulx + * SPDX-FileCopyrightText: 2020-2024 Simon Marchi */ -#include -#include #include #include #include @@ -14,15 +11,35 @@ #include "argpar.h" -#define ARGPAR_REALLOC(_ptr, _type, _nmemb) \ - ((_type *) realloc(_ptr, (_nmemb) * sizeof(_type))) +/* + * If argpar is used in some shared library, we don't want said library + * to export its symbols, so mark them as "hidden". + * + * On Windows, symbols are local unless explicitly exported; see + * . + */ +#if defined(_WIN32) || defined(__CYGWIN__) +# define ARGPAR_HIDDEN +#else +# define ARGPAR_HIDDEN __attribute__((visibility("hidden"))) +#endif + +#define ARGPAR_REALLOC(_ptr, _type, _nmemb) ((_type *) realloc(_ptr, (_nmemb) * sizeof(_type))) -#define ARGPAR_CALLOC(_type, _nmemb) \ - ((_type *) calloc((_nmemb), sizeof(_type))) +#define ARGPAR_CALLOC(_type, _nmemb) ((_type *) calloc((_nmemb), sizeof(_type))) #define ARGPAR_ZALLOC(_type) ARGPAR_CALLOC(_type, 1) -#define ARGPAR_ASSERT(_cond) assert(_cond) +#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 +# include +# define ARGPAR_ASSERT(_cond) assert(_cond) +#endif /* * An argpar iterator. @@ -30,163 +47,159 @@ * Such a structure contains the state of an iterator between calls to * argpar_iter_next(). */ -struct argpar_iter { - /* - * Data provided by the user to argpar_iter_create(); immutable - * afterwards. - */ - struct { - unsigned int argc; - const char * const *argv; - const struct argpar_opt_descr *descrs; - } user; - - /* - * Index of the argument to process in the next - * argpar_iter_next() call. - */ - unsigned int i; - - /* Counter of non-option arguments */ - int non_opt_index; - - /* - * Current character within the current short option group: if - * it's not `NULL`, the parser is within a short option group, - * therefore it must resume there in the next argpar_iter_next() - * call. - */ - const char *short_opt_group_ch; - - /* Temporary character buffer which only grows */ - struct { - size_t size; - char *data; - } tmp_buf; +struct argpar_iter +{ + /* + * Data provided by the user to argpar_iter_create(); immutable + * afterwards. + */ + struct + { + unsigned int argc; + const char * const *argv; + const argpar_opt_descr_t *descrs; + } user; + + /* + * Index of the argument to process in the next + * argpar_iter_next() call. + */ + unsigned int i; + + /* Counter of non-option arguments */ + int non_opt_index; + + /* + * Current character within the current short option group: if + * it's not `NULL`, the parser is within a short option group, + * therefore it must resume there in the next argpar_iter_next() + * call. + */ + const char *short_opt_group_ch; + + /* Temporary character buffer which only grows */ + struct + { + size_t size; + char *data; + } tmp_buf; }; /* Base parsing item */ -struct argpar_item { - enum argpar_item_type type; +struct argpar_item +{ + 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; + /* Corresponding descriptor */ + const argpar_opt_descr_t *descr; - /* Argument, or `NULL` if none; owned by this */ - char *arg; -}; + /* 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; - - /* - * Complete argument, pointing to one of the entries of the - * original arguments (`argv`). - */ - const char *arg; - - /* - * Index of this argument amongst all original arguments - * (`argv`). - */ - unsigned int orig_index; - - /* Index of this argument amongst other non-option arguments */ - unsigned int non_opt_index; -}; +typedef struct argpar_item_non_opt +{ + argpar_item_t base; + + /* + * Complete argument, pointing to one of the entries of the + * original arguments (`argv`). + */ + const char *arg; + + /* + * Index of this argument amongst all original arguments + * (`argv`). + */ + unsigned int orig_index; + + /* 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 */ - enum argpar_error_type type; +struct argpar_error +{ + /* Error type */ + argpar_error_type_t type; - /* Original argument index */ - unsigned int orig_index; + /* Original argument index */ + unsigned int orig_index; - /* Name of unknown option; owned by this */ - char *unknown_opt_name; + /* Name of unknown option; owned by this */ + char *unknown_opt_name; - /* Option descriptor */ - const struct argpar_opt_descr *opt_descr; + /* Option descriptor */ + const argpar_opt_descr_t *opt_descr; - /* `true` if a short option caused the error */ - bool is_short; + /* `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_HIDDEN argpar_item_type_t argpar_item_type(const argpar_item_t * const item) { - ARGPAR_ASSERT(item); - return item->type; + ARGPAR_ASSERT(item); + return item->type; } -ARGPAR_HIDDEN -const struct argpar_opt_descr *argpar_item_opt_descr( - const struct argpar_item * const item) +ARGPAR_HIDDEN 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; + ARGPAR_ASSERT(item); + ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT); + return ((const argpar_item_opt_t *) item)->descr; } -ARGPAR_HIDDEN -const char *argpar_item_opt_arg(const struct argpar_item * const item) +ARGPAR_HIDDEN 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; + ARGPAR_ASSERT(item); + ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT); + return ((const argpar_item_opt_t *) item)->arg; } -ARGPAR_HIDDEN -const char *argpar_item_non_opt_arg(const struct argpar_item * const item) +ARGPAR_HIDDEN 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; + ARGPAR_ASSERT(item); + ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT); + 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) +ARGPAR_HIDDEN unsigned int argpar_item_non_opt_orig_index(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; + ARGPAR_ASSERT(item); + ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT); + 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) +ARGPAR_HIDDEN unsigned int argpar_item_non_opt_non_opt_index(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; + ARGPAR_ASSERT(item); + ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT); + return ((const argpar_item_non_opt_t *) item)->non_opt_index; } -ARGPAR_HIDDEN -void argpar_item_destroy(const struct argpar_item * const item) +ARGPAR_HIDDEN void argpar_item_destroy(const argpar_item_t * const item) { - if (!item) { - goto end; - } + if (!item) { + goto end; + } - if (item->type == ARGPAR_ITEM_TYPE_OPT) { - struct argpar_item_opt * const opt_item = - (struct argpar_item_opt *) item; + if (item->type == ARGPAR_ITEM_TYPE_OPT) { + argpar_item_opt_t * const opt_item = (argpar_item_opt_t *) item; - free(opt_item->arg); - } + free(opt_item->arg); + } - free((void *) item); + free((void *) item); end: - return; + return; } /* @@ -195,36 +208,33 @@ end: * * Returns `NULL` on memory error. */ -static -struct argpar_item_opt *create_opt_item( - const struct argpar_opt_descr * const descr, - const char * const arg) +static 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; - } + if (!opt_item) { + goto end; + } - opt_item->base.type = ARGPAR_ITEM_TYPE_OPT; - opt_item->descr = descr; + opt_item->base.type = ARGPAR_ITEM_TYPE_OPT; + opt_item->descr = descr; - if (arg) { - opt_item->arg = strdup(arg); - if (!opt_item->arg) { - goto error; - } - } + if (arg) { + opt_item->arg = strdup(arg); + if (!opt_item->arg) { + goto error; + } + } - goto end; + goto end; error: - argpar_item_destroy(&opt_item->base); - opt_item = NULL; + argpar_item_destroy(&opt_item->base); + opt_item = NULL; end: - return opt_item; + return opt_item; } /* @@ -234,25 +244,23 @@ end: * * Returns `NULL` on memory error. */ -static -struct argpar_item_non_opt *create_non_opt_item(const char * const arg, - const unsigned int orig_index, - const unsigned int non_opt_index) +static 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; - } + if (!non_opt_item) { + goto end; + } - non_opt_item->base.type = ARGPAR_ITEM_TYPE_NON_OPT; - non_opt_item->arg = arg; - non_opt_item->orig_index = orig_index; - non_opt_item->non_opt_index = non_opt_index; + non_opt_item->base.type = ARGPAR_ITEM_TYPE_NON_OPT; + non_opt_item->arg = arg; + non_opt_item->orig_index = orig_index; + non_opt_item->non_opt_index = non_opt_index; end: - return non_opt_item; + return non_opt_item; } /* @@ -266,102 +274,92 @@ end: * Returns 0 on success (including if `error` is `NULL`) or -1 on memory * error. */ -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) +static int set_error(argpar_error_t ** const error, argpar_error_type_t type, + const char * const unknown_opt_name, + const argpar_opt_descr_t * const opt_descr, const bool is_short) { - int ret = 0; + int ret = 0; - if (!error) { - goto end; - } + if (!error) { + goto end; + } - *error = ARGPAR_ZALLOC(struct argpar_error); - if (!*error) { - goto error; - } + *error = ARGPAR_ZALLOC(argpar_error_t); + if (!*error) { + goto error; + } - (*error)->type = type; + (*error)->type = type; - if (unknown_opt_name) { - (*error)->unknown_opt_name = ARGPAR_CALLOC(char, - strlen(unknown_opt_name) + 1 + (is_short ? 1 : 2)); - if (!(*error)->unknown_opt_name) { - goto error; - } + if (unknown_opt_name) { + (*error)->unknown_opt_name = + ARGPAR_CALLOC(char, strlen(unknown_opt_name) + 1 + (is_short ? 1 : 2)); + if (!(*error)->unknown_opt_name) { + goto error; + } - if (is_short) { - strcpy((*error)->unknown_opt_name, "-"); - } else { - strcpy((*error)->unknown_opt_name, "--"); - } + if (is_short) { + strcpy((*error)->unknown_opt_name, "-"); + } else { + strcpy((*error)->unknown_opt_name, "--"); + } - strcat((*error)->unknown_opt_name, unknown_opt_name); - } + strcat((*error)->unknown_opt_name, unknown_opt_name); + } - (*error)->opt_descr = opt_descr; - (*error)->is_short = is_short; - goto end; + (*error)->opt_descr = opt_descr; + (*error)->is_short = is_short; + goto end; error: - argpar_error_destroy(*error); - ret = -1; + argpar_error_destroy(*error); + ret = -1; end: - return ret; + return ret; } -ARGPAR_HIDDEN -enum argpar_error_type argpar_error_type( - const struct argpar_error * const error) +ARGPAR_HIDDEN argpar_error_type_t argpar_error_type(const argpar_error_t * const error) { - ARGPAR_ASSERT(error); - return error->type; + ARGPAR_ASSERT(error); + return error->type; } -ARGPAR_HIDDEN -unsigned int argpar_error_orig_index(const struct argpar_error * const error) +ARGPAR_HIDDEN unsigned int argpar_error_orig_index(const argpar_error_t * const error) { - ARGPAR_ASSERT(error); - return error->orig_index; + ARGPAR_ASSERT(error); + return error->orig_index; } -ARGPAR_HIDDEN -const char *argpar_error_unknown_opt_name( - const struct argpar_error * const error) +ARGPAR_HIDDEN const char *argpar_error_unknown_opt_name(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_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) +ARGPAR_HIDDEN 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); + 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) { - *is_short = error->is_short; - } + if (is_short) { + *is_short = error->is_short; + } - return error->opt_descr; + return error->opt_descr; } -ARGPAR_HIDDEN -void argpar_error_destroy(const struct argpar_error * const error) +ARGPAR_HIDDEN void argpar_error_destroy(const argpar_error_t * const error) { - if (error) { - free(error->unknown_opt_name); - free((void *) error); - } + if (error) { + free(error->unknown_opt_name); + free((void *) error); + } } /* @@ -375,35 +373,32 @@ void argpar_error_destroy(const struct argpar_error * const error) * * Returns `NULL` if no descriptor is found. */ -static -const struct argpar_opt_descr *find_descr( - const struct argpar_opt_descr * const descrs, - const char short_name, const char * const long_name) +static 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 && - short_name == descr->short_name) { - goto end; - } + for (descr = descrs; descr->short_name || descr->long_name; descr++) { + if (short_name && descr->short_name && short_name == descr->short_name) { + goto end; + } - if (long_name && descr->long_name && - strcmp(long_name, descr->long_name) == 0) { - goto end; - } - } + if (long_name && descr->long_name && strcmp(long_name, descr->long_name) == 0) { + goto end; + } + } end: - return !descr->short_name && !descr->long_name ? NULL : descr; + 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 = -1, - PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY = -2, -}; +typedef enum parse_orig_arg_opt_ret +{ + PARSE_ORIG_ARG_OPT_RET_OK, + 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 @@ -414,98 +409,90 @@ enum parse_orig_arg_opt_ret { * 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, - 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) +static parse_orig_arg_opt_ret_t +parse_short_opt_group(const char * const short_opt_group, const char * const next_orig_arg, + 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; - bool used_next_orig_arg = false; - const char *opt_arg = NULL; - const struct argpar_opt_descr *descr; - struct argpar_item_opt *opt_item; - - ARGPAR_ASSERT(strlen(short_opt_group) != 0); - - if (!iter->short_opt_group_ch) { - iter->short_opt_group_ch = short_opt_group; - } - - /* Find corresponding option descriptor */ - descr = find_descr(descrs, *iter->short_opt_group_ch, NULL); - if (!descr) { - const char unknown_opt_name[] = - {*iter->short_opt_group_ch, '\0'}; - - ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - - if (set_error(error, ARGPAR_ERROR_TYPE_UNKNOWN_OPT, - unknown_opt_name, NULL, true)) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; - } - - goto error; - } - - if (descr->with_arg) { - if (iter->short_opt_group_ch[1]) { - /* `-oarg` form */ - opt_arg = &iter->short_opt_group_ch[1]; - } else { - /* `-o arg` form */ - opt_arg = next_orig_arg; - used_next_orig_arg = true; - } - - /* - * We accept `-o ''` (empty option argument), but not - * `-o` alone if an option argument is expected. - */ - if (!opt_arg || (iter->short_opt_group_ch[1] && - strlen(opt_arg) == 0)) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - - if (set_error(error, ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, - NULL, descr, true)) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; - } - - goto error; - } - } - - /* Create and append option argument */ - opt_item = create_opt_item(descr, opt_arg); - if (!opt_item) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; - goto error; - } - - *item = &opt_item->base; - iter->short_opt_group_ch++; - - if (descr->with_arg || !*iter->short_opt_group_ch) { - /* Option has an argument: no more options */ - iter->short_opt_group_ch = NULL; - - if (used_next_orig_arg) { - iter->i += 2; - } else { - iter->i++; - } - } - - goto end; + 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 argpar_opt_descr_t *descr; + argpar_item_opt_t *opt_item; + + ARGPAR_ASSERT(strlen(short_opt_group) != 0); + + if (!iter->short_opt_group_ch) { + iter->short_opt_group_ch = short_opt_group; + } + + /* Find corresponding option descriptor */ + descr = find_descr(descrs, *iter->short_opt_group_ch, NULL); + if (!descr) { + const char unknown_opt_name[] = {*iter->short_opt_group_ch, '\0'}; + + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; + + if (set_error(error, ARGPAR_ERROR_TYPE_UNKNOWN_OPT, unknown_opt_name, NULL, true)) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; + } + + goto error; + } + + if (descr->with_arg) { + if (iter->short_opt_group_ch[1]) { + /* `-oarg` form */ + opt_arg = &iter->short_opt_group_ch[1]; + } else { + /* `-o arg` form */ + opt_arg = next_orig_arg; + used_next_orig_arg = true; + } + + /* + * We accept `-o ''` (empty option argument), but not + * `-o` alone if an option argument is expected. + */ + if (!opt_arg || (iter->short_opt_group_ch[1] && strlen(opt_arg) == 0)) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; + + if (set_error(error, ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, NULL, descr, true)) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; + } + + goto error; + } + } + + /* Create and append option argument */ + opt_item = create_opt_item(descr, opt_arg); + if (!opt_item) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; + goto error; + } + + *item = &opt_item->base; + iter->short_opt_group_ch++; + + if (descr->with_arg || !*iter->short_opt_group_ch) { + /* Option has an argument: no more options */ + iter->short_opt_group_ch = NULL; + + if (used_next_orig_arg) { + iter->i += 2; + } else { + iter->i++; + } + } + + goto end; error: - ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); + ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); end: - return ret; + return ret; } /* @@ -516,120 +503,117 @@ end: * 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, - const struct argpar_opt_descr * const descrs, - struct argpar_iter * const iter, - struct argpar_error ** const error, - struct argpar_item ** const item) +static parse_orig_arg_opt_ret_t +parse_long_opt(const char * const long_opt_arg, const char * const next_orig_arg, + 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; - bool used_next_orig_arg = false; - - /* Option's argument, if any */ - const char *opt_arg = NULL; - - /* Position of first `=`, if any */ - const char *eq_pos; - - /* Option name */ - const char *long_opt_name = long_opt_arg; - - ARGPAR_ASSERT(strlen(long_opt_arg) != 0); - - /* Find the first `=` in original argument */ - eq_pos = strchr(long_opt_arg, '='); - if (eq_pos) { - const size_t long_opt_name_size = eq_pos - long_opt_arg; - - /* Isolate the option name */ - 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(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 */ - descr = find_descr(descrs, '\0', long_opt_name); - if (!descr) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - - if (set_error(error, ARGPAR_ERROR_TYPE_UNKNOWN_OPT, - long_opt_name, NULL, false)) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; - } - - goto error; - } - - /* Find option's argument if any */ - if (descr->with_arg) { - if (eq_pos) { - /* `--long-opt=arg` style */ - opt_arg = eq_pos + 1; - } else { - /* `--long-opt arg` style */ - if (!next_orig_arg) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - - if (set_error(error, ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, - NULL, descr, false)) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; - } - - goto error; - } - - opt_arg = next_orig_arg; - used_next_orig_arg = true; - } - } else if (eq_pos) { - /* - * Unexpected `--opt=arg` style for a long option which - * doesn't accept an argument. - */ - ret = PARSE_ORIG_ARG_OPT_RET_ERROR; - - if (set_error(error, ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG, - NULL, descr, false)) { - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; - } - - goto error; - } - - /* Create and append option argument */ - opt_item = create_opt_item(descr, opt_arg); - if (!opt_item) { - goto error; - } - - if (used_next_orig_arg) { - iter->i += 2; - } else { - iter->i++; - } - - *item = &opt_item->base; - goto end; + 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 */ + const char *opt_arg = NULL; + + /* Position of first `=`, if any */ + const char *eq_pos; + + /* Option name */ + const char *long_opt_name = long_opt_arg; + + ARGPAR_ASSERT(strlen(long_opt_arg) != 0); + + /* Find the first `=` in original argument */ + eq_pos = strchr(long_opt_arg, '='); + if (eq_pos) { + const size_t long_opt_name_size = eq_pos - long_opt_arg; + + /* Isolate the option name */ + while (long_opt_name_size > iter->tmp_buf.size - 1) { + const size_t new_size = iter->tmp_buf.size * 2; + char * const new_data = ARGPAR_REALLOC(iter->tmp_buf.data, char, new_size); + + if (!new_data) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; + goto error; + } + + iter->tmp_buf.size = new_size; + iter->tmp_buf.data = new_data; + } + + 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 */ + descr = find_descr(descrs, '\0', long_opt_name); + if (!descr) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; + + if (set_error(error, ARGPAR_ERROR_TYPE_UNKNOWN_OPT, long_opt_name, NULL, false)) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; + } + + goto error; + } + + /* Find option's argument if any */ + if (descr->with_arg) { + if (eq_pos) { + /* `--long-opt=arg` style */ + opt_arg = eq_pos + 1; + } else { + /* `--long-opt arg` style */ + if (!next_orig_arg) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; + + if (set_error(error, ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, NULL, descr, false)) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; + } + + goto error; + } + + opt_arg = next_orig_arg; + used_next_orig_arg = true; + } + } else if (eq_pos) { + /* + * Unexpected `--opt=arg` style for a long option which + * doesn't accept an argument. + */ + ret = PARSE_ORIG_ARG_OPT_RET_ERROR; + + if (set_error(error, ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG, NULL, descr, false)) { + ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY; + } + + goto error; + } + + /* Create and append option argument */ + opt_item = create_opt_item(descr, opt_arg); + if (!opt_item) { + goto error; + } + + if (used_next_orig_arg) { + iter->i += 2; + } else { + iter->i++; + } + + *item = &opt_item->base; + goto end; error: - ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); + ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); end: - return ret; + return ret; } /* @@ -640,142 +624,126 @@ end: * 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, - const struct argpar_opt_descr * const descrs, - struct argpar_iter * const iter, - struct argpar_error ** const error, - struct argpar_item ** const item) +static parse_orig_arg_opt_ret_t +parse_orig_arg_opt(const char * const orig_arg, const char * const next_orig_arg, + 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] == '-'); + 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); - } else { - /* Short option */ - ret = parse_short_opt_group(&orig_arg[1], - next_orig_arg, descrs, iter, error, item); - } + if (orig_arg[1] == '-') { + /* Long option */ + 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); + } - return ret; + return ret; } -ARGPAR_HIDDEN -struct argpar_iter *argpar_iter_create(const unsigned int argc, - const char * const * const argv, - const struct argpar_opt_descr * const descrs) +ARGPAR_HIDDEN argpar_iter_t *argpar_iter_create(const unsigned int argc, + const char * const * const argv, + const argpar_opt_descr_t * const descrs) { - struct argpar_iter *iter = ARGPAR_ZALLOC(struct argpar_iter); - - if (!iter) { - goto end; - } - - 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) { - argpar_iter_destroy(iter); - iter = NULL; - goto end; - } + argpar_iter_t *iter = ARGPAR_ZALLOC(argpar_iter_t); + + if (!iter) { + goto end; + } + + 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) { + argpar_iter_destroy(iter); + iter = NULL; + goto end; + } end: - return iter; + return iter; } -ARGPAR_HIDDEN -void argpar_iter_destroy(struct argpar_iter * const iter) +ARGPAR_HIDDEN void argpar_iter_destroy(argpar_iter_t * const iter) { - if (iter) { - free(iter->tmp_buf.data); - free(iter); - } + if (iter) { + free(iter->tmp_buf.data); + free(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_HIDDEN 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; - const char *orig_arg; - const char *next_orig_arg; - struct argpar_error ** const nc_error = (struct argpar_error **) error; - - ARGPAR_ASSERT(iter->i <= iter->user.argc); - - if (error) { - *nc_error = NULL; - } - - if (iter->i == iter->user.argc) { - status = ARGPAR_ITER_NEXT_STATUS_END; - goto end; - } - - orig_arg = iter->user.argv[iter->i]; - next_orig_arg = - 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] != '-') { - /* Non-option argument */ - const struct argpar_item_non_opt * const non_opt_item = - create_non_opt_item(orig_arg, iter->i, - iter->non_opt_index); - - if (!non_opt_item) { - status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY; - goto end; - } - - iter->non_opt_index++; - iter->i++; - *item = &non_opt_item->base; - status = ARGPAR_ITER_NEXT_STATUS_OK; - goto end; - } - - /* 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); - 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: - if (error) { - ARGPAR_ASSERT(*error); - (*nc_error)->orig_index = iter->i; - } - status = ARGPAR_ITER_NEXT_STATUS_ERROR; - break; - case PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY: - status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY; - break; - default: - abort(); - } + 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; + argpar_error_t ** const nc_error = (argpar_error_t **) error; + + ARGPAR_ASSERT(iter->i <= iter->user.argc); + + if (error) { + *nc_error = NULL; + } + + if (iter->i == iter->user.argc) { + status = ARGPAR_ITER_NEXT_STATUS_END; + goto end; + } + + orig_arg = iter->user.argv[iter->i]; + next_orig_arg = 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] != '-') { + /* Non-option argument */ + const argpar_item_non_opt_t * const non_opt_item = + create_non_opt_item(orig_arg, iter->i, iter->non_opt_index); + + if (!non_opt_item) { + status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY; + goto end; + } + + iter->non_opt_index++; + iter->i++; + *item = &non_opt_item->base; + status = ARGPAR_ITER_NEXT_STATUS_OK; + goto end; + } + + /* Option argument */ + parse_orig_arg_opt_ret = parse_orig_arg_opt(orig_arg, next_orig_arg, iter->user.descrs, iter, + nc_error, (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: + if (error) { + ARGPAR_ASSERT(*error); + (*nc_error)->orig_index = iter->i; + } + status = ARGPAR_ITER_NEXT_STATUS_ERROR; + break; + case PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY: + status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY; + break; + default: + abort(); + } end: - return status; + return status; } -ARGPAR_HIDDEN -unsigned int argpar_iter_ingested_orig_args( - const struct argpar_iter * const iter) +ARGPAR_HIDDEN unsigned int argpar_iter_ingested_orig_args(const argpar_iter_t * const iter) { - return iter->i; + return iter->i; } diff --git a/src/argpar/argpar.h b/src/argpar/argpar.h index e34b209a..c77f473a 100644 --- a/src/argpar/argpar.h +++ b/src/argpar/argpar.h @@ -1,14 +1,18 @@ /* * SPDX-License-Identifier: MIT - * - * Copyright (c) 2019-2021 Philippe Proulx - * Copyright (c) 2020-2021 Simon Marchi + * SPDX-FileCopyrightText: 2019-2024 Philippe Proulx + * SPDX-FileCopyrightText: 2020-2024 Simon Marchi */ #ifndef ARGPAR_ARGPAR_H #define ARGPAR_ARGPAR_H #include +#include + +#if defined(__cplusplus) +extern "C" { +#endif /*! @mainpage @@ -83,7 +87,7 @@ A parsing item (the result of argpar_iter_next()) has the type #argpar_item. Get the type (option or non-option) of an item with -\link argpar_item_type(const struct argpar_item *) argpar_item_type()\endlink. +\link argpar_item_type(const argpar_item_t *) argpar_item_type()\endlink. Each item type has its set of dedicated functions (\c argpar_item_opt_ and \c argpar_item_non_opt_ prefixes). @@ -97,30 +101,24 @@ example, that for: argpar_iter_next() produces the following items, in this order: --# Option item (\--hello). --# Option item (\--count with argument 23). --# Non-option item (/path/to/file). --# Option item (-a). --# Option item (-b). --# Option item (\--type with argument file). --# Non-option item (\--). --# Non-option item (magie). +-# Option item: \--hello. +-# Option item: \--count with argument 23. +-# Non-option item: /path/to/file. +-# Option item: -a. +-# Option item: -b. +-# Option item: \--type with argument file. +-# Non-option item: \--. +-# Non-option item: magie. */ -/* - * If argpar is used in some shared library, we don't want said library - * to export its symbols, so mark them as "hidden". - * - * On Windows, symbols are local unless explicitly exported; see - * . - */ -#if defined(_WIN32) || defined(__CYGWIN__) -# define ARGPAR_HIDDEN +/* Internal: `noexcept` specifier if C++ ≥ 11 */ +#if defined(__cplusplus) && (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)) +# define ARGPAR_NOEXCEPT noexcept #else -# define ARGPAR_HIDDEN __attribute__((visibility("hidden"))) +# define ARGPAR_NOEXCEPT #endif -struct argpar_opt_descr; +typedef struct argpar_opt_descr argpar_opt_descr_t; /*! @name Item API @@ -130,15 +128,16 @@ struct argpar_opt_descr; /*! @brief Type of a parsing item, as returned by - \link argpar_item_type(const struct argpar_item *) argpar_item_type()\endlink. + \link argpar_item_type(const argpar_item *) argpar_item_type()\endlink. */ -enum argpar_item_type { - /// Option - ARGPAR_ITEM_TYPE_OPT, +typedef enum argpar_item_type +{ + /// Option + ARGPAR_ITEM_TYPE_OPT, - /// Non-option - ARGPAR_ITEM_TYPE_NON_OPT, -}; + /// Non-option + ARGPAR_ITEM_TYPE_NON_OPT, +} argpar_item_type_t; /*! @struct argpar_item @@ -148,7 +147,7 @@ enum argpar_item_type { argpar_iter_next() sets a pointer to such a type. */ -struct argpar_item; +typedef struct argpar_item argpar_item_t; /*! @brief @@ -163,10 +162,7 @@ struct argpar_item; @pre \p item is not \c NULL. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -enum argpar_item_type argpar_item_type(const struct argpar_item *item); +argpar_item_type_t argpar_item_type(const argpar_item_t *item) ARGPAR_NOEXCEPT; /*! @brief @@ -183,11 +179,7 @@ enum argpar_item_type argpar_item_type(const struct argpar_item *item); @pre \p item has the type #ARGPAR_ITEM_TYPE_OPT. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -const struct argpar_opt_descr *argpar_item_opt_descr( - const struct argpar_item *item); +const argpar_opt_descr_t *argpar_item_opt_descr(const argpar_item_t *item) ARGPAR_NOEXCEPT; /*! @brief @@ -205,10 +197,7 @@ const struct argpar_opt_descr *argpar_item_opt_descr( @pre \p item has the type #ARGPAR_ITEM_TYPE_OPT. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -const char *argpar_item_opt_arg(const struct argpar_item *item); +const char *argpar_item_opt_arg(const argpar_item_t *item) ARGPAR_NOEXCEPT; /*! @brief @@ -228,10 +217,7 @@ const char *argpar_item_opt_arg(const struct argpar_item *item); @pre \p item has the type #ARGPAR_ITEM_TYPE_NON_OPT. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -const char *argpar_item_non_opt_arg(const struct argpar_item *item); +const char *argpar_item_non_opt_arg(const argpar_item_t *item) ARGPAR_NOEXCEPT; /*! @brief @@ -243,7 +229,7 @@ For example, with the following command line (all options have no argument): @code{.unparsed} --f -m meow --just mix --kilo +-f -m meow --jus mix --kilo @endcode The original argument index of \c meow is 2 while the original @@ -264,10 +250,7 @@ argument index of \c mix is 4. argpar_item_non_opt_non_opt_index() -- Returns the non-option index of a non-option parsing item. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -unsigned int argpar_item_non_opt_orig_index(const struct argpar_item *item); +unsigned int argpar_item_non_opt_orig_index(const argpar_item_t *item) ARGPAR_NOEXCEPT; /*! @brief @@ -278,7 +261,7 @@ For example, with the following command line (all options have no argument): @code{.unparsed} --f -m meow --just mix --kilo +-f -m meow --jus mix --kilo @endcode The non-option index of \c meow is 0 while the original @@ -299,10 +282,7 @@ argument index of \c mix is 1. argpar_item_non_opt_orig_index() -- Returns the original argument index of a non-option parsing item. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -unsigned int argpar_item_non_opt_non_opt_index(const struct argpar_item *item); +unsigned int argpar_item_non_opt_non_opt_index(const argpar_item_t *item) ARGPAR_NOEXCEPT; /*! @brief @@ -311,10 +291,7 @@ unsigned int argpar_item_non_opt_non_opt_index(const struct argpar_item *item); @param[in] item Parsing item to destroy (may be \c NULL). */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -void argpar_item_destroy(const struct argpar_item *item); +void argpar_item_destroy(const argpar_item_t *item) ARGPAR_NOEXCEPT; /*! @def ARGPAR_ITEM_DESTROY_AND_RESET(_item) @@ -325,13 +302,13 @@ void argpar_item_destroy(const struct argpar_item *item); @param[in] _item Item to destroy and variable to reset - (const struct argpar_item * type). + (const argpar_item_t * type). */ -#define ARGPAR_ITEM_DESTROY_AND_RESET(_item) \ - { \ - argpar_item_destroy(_item); \ - _item = NULL; \ - } +#define ARGPAR_ITEM_DESTROY_AND_RESET(_item) \ + { \ + argpar_item_destroy(_item); \ + (_item) = NULL; \ + } /// @} @@ -343,18 +320,19 @@ void argpar_item_destroy(const struct argpar_item *item); /*! @brief Parsing error type, as returned by - \link argpar_error_type(const struct argpar_error *) argpar_error_type()\endlink. + \link argpar_error_type(const argpar_error_t *) argpar_error_type()\endlink. */ -enum argpar_error_type { - /// Unknown option error - ARGPAR_ERROR_TYPE_UNKNOWN_OPT, +typedef enum argpar_error_type +{ + /// Unknown option error + ARGPAR_ERROR_TYPE_UNKNOWN_OPT, - /// Missing option argument error - ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, + /// Missing option argument error + ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, - /// Unexpected option argument error - ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG, -}; + /// Unexpected option argument error + ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG, +} argpar_error_type_t; /*! @struct argpar_error @@ -362,7 +340,7 @@ enum argpar_error_type { @brief Opaque parsing error type */ -struct argpar_error; +typedef struct argpar_error argpar_error_t; /*! @brief @@ -377,10 +355,7 @@ struct argpar_error; @pre \p error is not \c NULL. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -enum argpar_error_type argpar_error_type(const struct argpar_error *error); +argpar_error_type_t argpar_error_type(const argpar_error_t *error) ARGPAR_NOEXCEPT; /*! @brief @@ -397,10 +372,7 @@ enum argpar_error_type argpar_error_type(const struct argpar_error *error); @pre \p error is not \c NULL. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -unsigned int argpar_error_orig_index(const struct argpar_error *error); +unsigned int argpar_error_orig_index(const argpar_error_t *error) ARGPAR_NOEXCEPT; /*! @brief @@ -424,13 +396,10 @@ part (\--mireille in the last example). \p error is not \c NULL. @pre The type of \p error, as returned by - \link argpar_error_type(const struct argpar_error *) argpar_error_type()\endlink, + \link argpar_error_type(const argpar_error_t *) argpar_error_type()\endlink, is #ARGPAR_ERROR_TYPE_UNKNOWN_OPT. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -const char *argpar_error_unknown_opt_name(const struct argpar_error *error); +const char *argpar_error_unknown_opt_name(const argpar_error_t *error) ARGPAR_NOEXCEPT; /*! @brief @@ -457,15 +426,12 @@ const char *argpar_error_unknown_opt_name(const struct argpar_error *error); \p error is not \c NULL. @pre The type of \p error, as returned by - \link argpar_error_type(const struct argpar_error *) argpar_error_type()\endlink, + \link argpar_error_type(const argpar_error_t *) argpar_error_type()\endlink, is #ARGPAR_ERROR_TYPE_MISSING_OPT_ARG or #ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -const struct argpar_opt_descr *argpar_error_opt_descr( - const struct argpar_error *error, bool *is_short); +const argpar_opt_descr_t *argpar_error_opt_descr(const argpar_error_t *error, + bool *is_short) ARGPAR_NOEXCEPT; /*! @brief @@ -474,10 +440,7 @@ const struct argpar_opt_descr *argpar_error_opt_descr( @param[in] error Parsing error to destroy (may be \c NULL). */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -void argpar_error_destroy(const struct argpar_error *error); +void argpar_error_destroy(const argpar_error_t *error) ARGPAR_NOEXCEPT; /// @} @@ -496,7 +459,7 @@ terminated with #ARGPAR_OPT_DESCR_SENTINEL, as its \p descrs parameter. The typical usage is, for example: @code -const struct argpar_opt_descr descrs[] = { +const argpar_opt_descr_t descrs[] = { { 0, 'd', NULL, false }, { 1, '\0', "squeeze", true }, { 2, 'm', "meow", true }, @@ -504,19 +467,20 @@ const struct argpar_opt_descr descrs[] = { }; @endcode */ -struct argpar_opt_descr { - /// Numeric ID, to uniquely identify this descriptor - const int id; +typedef struct argpar_opt_descr +{ + /// Numeric ID, to uniquely identify this descriptor + const int id; - /// Short option character, or '\0' - const char short_name; + /// Short option character, or '\0' + const char short_name; - /// Long option name (without the \-- prefix), or \c NULL - const char * const long_name; + /// Long option name (without the \-- prefix), or \c NULL + const char * const long_name; - /// \c true if this option has an argument - const bool with_arg; -}; + /// \c true if this option has an argument + const bool with_arg; +} argpar_opt_descr_t; /*! @brief @@ -525,7 +489,7 @@ struct argpar_opt_descr { The typical usage is, for example: @code -const struct argpar_opt_descr descrs[] = { +const argpar_opt_descr_t descrs[] = { { 0, 'd', NULL, false }, { 1, '\0', "squeeze", true }, { 2, 'm', "meow", true }, @@ -533,7 +497,10 @@ const struct argpar_opt_descr descrs[] = { }; @endcode */ -#define ARGPAR_OPT_DESCR_SENTINEL { -1, '\0', NULL, false } +#define ARGPAR_OPT_DESCR_SENTINEL \ + { \ + -1, '\0', NULL, false \ + } /*! @struct argpar_iter @@ -543,7 +510,7 @@ const struct argpar_opt_descr descrs[] = { argpar_iter_create() returns a pointer to such a type. */ -struct argpar_iter; +typedef struct argpar_iter argpar_iter_t; /*! @brief @@ -599,12 +566,8 @@ argpar_iter_next(). @sa argpar_iter_destroy() -- Destroys an argument parsing iterator. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -struct argpar_iter *argpar_iter_create(unsigned int argc, - const char * const *argv, - const struct argpar_opt_descr *descrs); +argpar_iter_t *argpar_iter_create(unsigned int argc, const char * const *argv, + const argpar_opt_descr_t *descrs) ARGPAR_NOEXCEPT; /*! @brief @@ -616,10 +579,7 @@ struct argpar_iter *argpar_iter_create(unsigned int argc, @sa argpar_iter_create() -- Creates an argument parsing iterator. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -void argpar_iter_destroy(struct argpar_iter *iter); +void argpar_iter_destroy(argpar_iter_t *iter) ARGPAR_NOEXCEPT; /*! @brief @@ -627,19 +587,20 @@ void argpar_iter_destroy(struct argpar_iter *iter); Error status enumerators have a negative value. */ -enum argpar_iter_next_status { - /// Success - ARGPAR_ITER_NEXT_STATUS_OK, +typedef enum argpar_iter_next_status +{ + /// Success + ARGPAR_ITER_NEXT_STATUS_OK, - /// End of iteration (no more original arguments to parse) - ARGPAR_ITER_NEXT_STATUS_END, + /// End of iteration (no more original arguments to parse) + ARGPAR_ITER_NEXT_STATUS_END, - /// Parsing error - ARGPAR_ITER_NEXT_STATUS_ERROR = -1, + /// Parsing error + ARGPAR_ITER_NEXT_STATUS_ERROR = -1, - /// Memory error - ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY = -12, -}; + /// Memory error + ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY = -12, +} argpar_iter_next_status_t; /*! @brief @@ -674,12 +635,8 @@ If there are no more original arguments to parse, this function returns @pre \p item is not \c NULL. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -enum argpar_iter_next_status argpar_iter_next( - struct argpar_iter *iter, const struct argpar_item **item, - const struct argpar_error **error); +argpar_iter_next_status_t argpar_iter_next(argpar_iter_t *iter, const argpar_item_t **item, + const argpar_error_t **error) ARGPAR_NOEXCEPT; /* * Returns the number of ingested elements from `argv`, as passed to @@ -703,13 +660,14 @@ enum argpar_iter_next_status argpar_iter_next( @pre \p iter is not \c NULL. */ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -unsigned int argpar_iter_ingested_orig_args(const struct argpar_iter *iter); +unsigned int argpar_iter_ingested_orig_args(const argpar_iter_t *iter) ARGPAR_NOEXCEPT; /// @} /// @} +#if defined(__cplusplus) +} +#endif + #endif /* ARGPAR_ARGPAR_H */ diff --git a/src/argpar/argpar.hpp b/src/argpar/argpar.hpp new file mode 100644 index 00000000..4f36e458 --- /dev/null +++ b/src/argpar/argpar.hpp @@ -0,0 +1,336 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2024 Simon Marchi + */ + +#ifndef ARGPAR_HPP +#define ARGPAR_HPP + +#include +#include +#include + +#include "argpar.h" + +namespace argpar { + +template +class Iter; + +class Error : public std::exception +{ + template + friend class Iter; + +protected: + explicit Error(const argpar_error& error) noexcept : _mError {&error} + + { + } + +public: + unsigned int origIndex() const noexcept + { + return argpar_error_orig_index(_mError.get()); + } + +private: + struct _Deleter final + { + void operator()(const argpar_error *error) + { + argpar_error_destroy(error); + } + }; + +protected: + std::unique_ptr _mError; +}; + +class UnknownOptError final : public Error +{ + template + friend class Iter; + +private: + explicit UnknownOptError(const argpar_error& error) noexcept : Error {error} + { + } + +public: + const char *name() const noexcept + { + return argpar_error_unknown_opt_name(_mError.get()); + } +}; + +class OptArgError; + +class OptArgErrorDescr final +{ + friend class OptArgError; + +private: + explicit OptArgErrorDescr(const argpar_opt_descr_t& descr, const bool isShort) noexcept : + _mDescr {&descr}, _mIsShort {isShort} + { + } + +public: + const argpar_opt_descr_t& descr() const noexcept + { + return *_mDescr; + } + + bool isShort() const noexcept + { + return _mIsShort; + } + +private: + const argpar_opt_descr_t *_mDescr; + bool _mIsShort; +}; + +class OptArgError : public Error +{ +protected: + explicit OptArgError(const argpar_error& error) : Error {error} + { + } + +public: + OptArgErrorDescr descr() const noexcept + { + bool isShort; + auto& descr = *argpar_error_opt_descr(_mError.get(), &isShort); + + return OptArgErrorDescr {descr, isShort}; + } +}; + +class MissingOptArgumentError final : public OptArgError +{ + template + friend class Iter; + +private: + explicit MissingOptArgumentError(const argpar_error& error) noexcept : OptArgError {error} + { + } +}; + +class UnexpectedOptArgumentError final : public OptArgError +{ + template + friend class Iter; + +private: + explicit UnexpectedOptArgumentError(const argpar_error& error) noexcept : OptArgError {error} + { + } +}; + +namespace internal { + +struct ArgparItemDeleter final +{ + void operator()(const argpar_item_t * const item) const noexcept + { + argpar_item_destroy(item); + } +}; + +using ArgparItemUP = std::unique_ptr; + +} /* namespace internal */ + +class OptItemView; +class NonOptItemView; + +class Item +{ + template + friend class Iter; + +public: + enum class Type + { + Opt = ARGPAR_ITEM_TYPE_OPT, + NonOpt = ARGPAR_ITEM_TYPE_NON_OPT, + }; + +protected: + explicit Item(internal::ArgparItemUP item) : _mItem {std::move(item)} + { + } + +public: + bool isOpt() const noexcept + { + return this->type() == Type::Opt; + } + + bool isNonOpt() const noexcept + { + return this->type() == Type::NonOpt; + } + + OptItemView asOpt() const noexcept; + NonOptItemView asNonOpt() const noexcept; + + Type type() const noexcept + { + return static_cast(argpar_item_type(_mItem.get())); + } + +protected: + internal::ArgparItemUP _mItem; +}; + +namespace internal { + +class ItemView +{ +protected: + explicit ItemView(const argpar_item_t& item) : _mItem {&item} + { + } + + const argpar_item_t *_mItem; +}; + +}; // namespace internal + +class OptItemView final : private internal::ItemView +{ + friend class Item; + +private: + explicit OptItemView(const argpar_item_t& item) : internal::ItemView {item} + { + } + +public: + const argpar_opt_descr_t& descr() const noexcept + { + return *argpar_item_opt_descr(_mItem); + } + + const char *arg() const noexcept + { + return argpar_item_opt_arg(_mItem); + } +}; + +inline OptItemView Item::asOpt() const noexcept +{ + return OptItemView {*_mItem}; +} + +class NonOptItemView final : public internal::ItemView +{ + friend class Item; + +private: + explicit NonOptItemView(const argpar_item_t& item) : internal::ItemView {item} + { + } + +public: + const char *arg() const noexcept + { + return argpar_item_non_opt_arg(_mItem); + } + + unsigned int origIndex() const noexcept + { + return argpar_item_non_opt_orig_index(_mItem); + } + + unsigned int nonOptIndex() const noexcept + { + return argpar_item_non_opt_non_opt_index(_mItem); + } +}; + +inline NonOptItemView Item::asNonOpt() const noexcept +{ + return NonOptItemView {*_mItem}; +} + +template +class Iter final +{ + static_assert(std::is_default_constructible::value, + "`OptionalItemT` has a callable default constructor."); + static_assert(std::is_constructible::value, + "`OptionalItemT::OptionalItemT(argpar::Item&&)` is callable."); + +public: + explicit Iter(const unsigned int argc, const char * const * const argv, + const argpar_opt_descr_t * const descrs) : + _mIter {[&] { + if (const auto iter = argpar_iter_create(argc, argv, descrs)) { + return iter; + } + + throw std::bad_alloc {}; + }()} + { + } + + OptionalItemT next() + { + const argpar_item_t *item; + const argpar_error_t *error; + + switch (argpar_iter_next(_mIter.get(), &item, &error)) { + case ARGPAR_ITER_NEXT_STATUS_OK: + return OptionalItemT {Item {internal::ArgparItemUP {item}}}; + + case ARGPAR_ITER_NEXT_STATUS_END: + return OptionalItemT {}; + + case ARGPAR_ITER_NEXT_STATUS_ERROR: + switch (argpar_error_type(error)) { + case ARGPAR_ERROR_TYPE_UNKNOWN_OPT: + throw UnknownOptError {*error}; + + case ARGPAR_ERROR_TYPE_MISSING_OPT_ARG: + throw MissingOptArgumentError {*error}; + + case ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG: + throw UnexpectedOptArgumentError {*error}; + } + + std::abort(); + + case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY: + throw std::bad_alloc {}; + } + + std::abort(); + } + + unsigned int ingestedOrigArgs() const noexcept + { + return argpar_iter_ingested_orig_args(_mIter.get()); + } + +private: + struct _IterDeleter final + { + void operator()(argpar_iter_t * const iter) const noexcept + { + argpar_iter_destroy(iter); + } + }; + + std::unique_ptr _mIter; +}; + +} /* namespace argpar */ + +#endif /* ARGPAR_HPP */