From: Simon Marchi Date: Mon, 18 Mar 2024 18:21:45 +0000 (-0400) Subject: Move argpar to vendor directory X-Git-Url: http://git.lttng.org./?a=commitdiff_plain;h=685e3a1f553cadeaaf7b0366381ed3cf5fbc6b9c;p=lttng-tools.git Move argpar to vendor directory Since this is source copied as-is from another project, I think it belongs to the vendor directory. This will make it so it will be skipped by format-cpp, for instance. Change-Id: I78892f80c4cbb3a2e863567b0021e895c6489402 Signed-off-by: Simon Marchi Signed-off-by: Jérémie Galarneau --- diff --git a/src/bin/lttng/Makefile.am b/src/bin/lttng/Makefile.am index e37183746..ed30ea1ab 100644 --- a/src/bin/lttng/Makefile.am +++ b/src/bin/lttng/Makefile.am @@ -46,5 +46,5 @@ lttng_LDADD = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la \ $(top_builddir)/src/common/libstring-utils.la \ $(top_builddir)/src/common/libfilter.la \ $(top_builddir)/src/common/libargpar-utils.la \ - $(top_builddir)/src/common/libargpar.la \ + $(top_builddir)/src/vendor/argpar/libargpar.la \ $(POPT_LIBS) diff --git a/src/bin/lttng/commands/add_trigger.cpp b/src/bin/lttng/commands/add_trigger.cpp index ad2fd47c1..18e91513b 100644 --- a/src/bin/lttng/commands/add_trigger.cpp +++ b/src/bin/lttng/commands/add_trigger.cpp @@ -9,11 +9,11 @@ #include "../loglevel.hpp" #include "../uprobe.hpp" #include "common/argpar-utils/argpar-utils.hpp" -#include "common/argpar/argpar.h" #include "common/dynamic-array.hpp" #include "common/mi-lttng.hpp" #include "common/string-utils/string-utils.hpp" #include "common/utils.hpp" +#include "vendor/argpar/argpar.h" #include diff --git a/src/bin/lttng/commands/list_triggers.cpp b/src/bin/lttng/commands/list_triggers.cpp index db905bc4f..58262a9e3 100644 --- a/src/bin/lttng/commands/list_triggers.cpp +++ b/src/bin/lttng/commands/list_triggers.cpp @@ -7,10 +7,10 @@ #include "../command.hpp" #include "common/argpar-utils/argpar-utils.hpp" -#include "common/argpar/argpar.h" #include "common/dynamic-array.hpp" #include "common/mi-lttng.hpp" #include "lttng/action/list-internal.hpp" +#include "vendor/argpar/argpar.h" /* For lttng_condition_type_str(). */ #include "lttng/condition/condition-internal.hpp" diff --git a/src/bin/lttng/commands/remove_trigger.cpp b/src/bin/lttng/commands/remove_trigger.cpp index 08d4873f0..81d9a7382 100644 --- a/src/bin/lttng/commands/remove_trigger.cpp +++ b/src/bin/lttng/commands/remove_trigger.cpp @@ -7,8 +7,8 @@ #include "../command.hpp" #include "common/argpar-utils/argpar-utils.hpp" -#include "common/argpar/argpar.h" #include "common/mi-lttng.hpp" +#include "vendor/argpar/argpar.h" #include diff --git a/src/bin/lttng/utils.hpp b/src/bin/lttng/utils.hpp index 7f398397a..15842b8bd 100644 --- a/src/bin/lttng/utils.hpp +++ b/src/bin/lttng/utils.hpp @@ -8,7 +8,6 @@ #ifndef _LTTNG_UTILS_H #define _LTTNG_UTILS_H -#include #include #include #include @@ -16,6 +15,8 @@ #include #include +#include + #include #include #include diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 2516a5042..499ffa9d8 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -19,13 +19,6 @@ noinst_HEADERS = \ utils.hpp -# libargpar -noinst_LTLIBRARIES += libargpar.la -libargpar_la_SOURCES = \ - argpar/argpar.c \ - argpar/argpar.h - - # libargpar-utils noinst_LTLIBRARIES += libargpar-utils.la libargpar_utils_la_SOURCES = \ diff --git a/src/common/argpar-utils/argpar-utils.hpp b/src/common/argpar-utils/argpar-utils.hpp index 4d25b3a70..00a387f57 100644 --- a/src/common/argpar-utils/argpar-utils.hpp +++ b/src/common/argpar-utils/argpar-utils.hpp @@ -8,10 +8,11 @@ #ifndef COMMON_ARGPAR_UTILS_H #define COMMON_ARGPAR_UTILS_H -#include #include #include +#include + #include #ifdef __cplusplus diff --git a/src/common/argpar/argpar.c b/src/common/argpar/argpar.c deleted file mode 100644 index f8280ce14..000000000 --- a/src/common/argpar/argpar.c +++ /dev/null @@ -1,761 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2019-2021 Philippe Proulx - * Copyright (c) 2020-2021 Simon Marchi - */ - -#include "argpar.h" - -#include -#include -#include -#include -#include - -#define ARGPAR_REALLOC(_ptr, _type, _nmemb) ((_type *) realloc(_ptr, (_nmemb) * sizeof(_type))) - -#define ARGPAR_CALLOC(_type, _nmemb) ((_type *) calloc((_nmemb), sizeof(_type))) - -#define ARGPAR_ZALLOC(_type) ARGPAR_CALLOC(_type, 1) - -#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. - * - * 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; -}; - -/* Base parsing item */ -struct argpar_item { - enum argpar_item_type type; -}; - -/* Option parsing item */ -struct argpar_item_opt { - struct argpar_item base; - - /* Corresponding descriptor */ - const struct argpar_opt_descr *descr; - - /* Argument, or `NULL` if none; owned by this */ - char *arg; -}; - -/* 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; -}; - -/* Parsing error */ -struct argpar_error { - /* Error type */ - enum argpar_error_type type; - - /* Original argument index */ - unsigned int orig_index; - - /* Name of unknown option; owned by this */ - char *unknown_opt_name; - - /* Option descriptor */ - const struct argpar_opt_descr *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_ASSERT(item); - return item->type; -} - -ARGPAR_HIDDEN -const struct argpar_opt_descr *argpar_item_opt_descr(const struct argpar_item *const item) -{ - ARGPAR_ASSERT(item); - ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT); - return ((const struct argpar_item_opt *) item)->descr; -} - -ARGPAR_HIDDEN -const char *argpar_item_opt_arg(const struct argpar_item *const item) -{ - ARGPAR_ASSERT(item); - ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT); - return ((const struct argpar_item_opt *) item)->arg; -} - -ARGPAR_HIDDEN -const char *argpar_item_non_opt_arg(const struct argpar_item *const item) -{ - ARGPAR_ASSERT(item); - ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT); - return ((const struct argpar_item_non_opt *) item)->arg; -} - -ARGPAR_HIDDEN -unsigned int argpar_item_non_opt_orig_index(const struct argpar_item *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_HIDDEN -unsigned int argpar_item_non_opt_non_opt_index(const struct argpar_item *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_HIDDEN -void argpar_item_destroy(const struct argpar_item *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; - - free(opt_item->arg); - } - - free((void *) item); - -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, - const char *const arg) -{ - struct argpar_item_opt *opt_item = ARGPAR_ZALLOC(struct argpar_item_opt); - - if (!opt_item) { - goto end; - } - - 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; - } - } - - goto end; - -error: - argpar_item_destroy(&opt_item->base); - opt_item = NULL; - -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, - const unsigned int non_opt_index) -{ - struct argpar_item_non_opt *const non_opt_item = ARGPAR_ZALLOC(struct argpar_item_non_opt); - - 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; - -end: - return non_opt_item; -} - -/* - * If `error` is not `NULL`, sets the error `error` to a new parsing - * error object, setting its `unknown_opt_name`, `opt_descr`, and - * `is_short` members from the parameters. - * - * `unknown_opt_name` is the unknown option name without any `-` or `--` - * prefix: `is_short` controls which type of unknown option it is. - * - * 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) -{ - int ret = 0; - - if (!error) { - goto end; - } - - *error = ARGPAR_ZALLOC(struct argpar_error); - 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)); - if (!(*error)->unknown_opt_name) { - goto error; - } - - if (is_short) { - strcpy((*error)->unknown_opt_name, "-"); - } else { - strcpy((*error)->unknown_opt_name, "--"); - } - - strcat((*error)->unknown_opt_name, unknown_opt_name); - } - - (*error)->opt_descr = opt_descr; - (*error)->is_short = is_short; - goto end; - -error: - argpar_error_destroy(*error); - ret = -1; - -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) -{ - ARGPAR_ASSERT(error); - return error->orig_index; -} - -ARGPAR_HIDDEN -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; -} - -ARGPAR_HIDDEN -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) { - *is_short = error->is_short; - } - - return error->opt_descr; -} - -ARGPAR_HIDDEN -void argpar_error_destroy(const struct argpar_error *const error) -{ - if (error) { - free(error->unknown_opt_name); - free((void *) 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 char short_name, - const char *const long_name) -{ - const struct argpar_opt_descr *descr; - - 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; - } - } - -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 = -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, - 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) -{ - 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; - -error: - ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); - -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, - const struct argpar_opt_descr *const descrs, - struct argpar_iter *const iter, - struct argpar_error **const error, - struct argpar_item **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; - -error: - ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); - -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, - const struct argpar_opt_descr *const descrs, - struct argpar_iter *const iter, - struct argpar_error **const error, - struct argpar_item **const item) -{ - enum parse_orig_arg_opt_ret 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); - } else { - /* Short option */ - 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, - const char *const *const argv, - const struct argpar_opt_descr *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; - } - -end: - return iter; -} - -ARGPAR_HIDDEN -void argpar_iter_destroy(struct argpar_iter *const 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) -{ - 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(); - } - -end: - return status; -} - -ARGPAR_HIDDEN -unsigned int argpar_iter_ingested_orig_args(const struct argpar_iter *const iter) -{ - return iter->i; -} diff --git a/src/common/argpar/argpar.h b/src/common/argpar/argpar.h deleted file mode 100644 index 909da9cb3..000000000 --- a/src/common/argpar/argpar.h +++ /dev/null @@ -1,725 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright (c) 2019-2021 Philippe Proulx - * Copyright (c) 2020-2021 Simon Marchi - */ - -#ifndef ARGPAR_ARGPAR_H -#define ARGPAR_ARGPAR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/*! -@mainpage - -See the \ref api module. - -@addtogroup api argpar API -@{ - -argpar is a library which provides an iterator-based API to parse -command-line arguments. - -The argpar parser supports: - -
    -
  • - Short options without an argument, possibly tied together: - - @code{.unparsed} - -f -auf -n - @endcode - -
  • - Short options with arguments: - - @code{.unparsed} - -b 45 -f/mein/file -xyzhello - @endcode - -
  • - Long options without an argument: - - @code{.unparsed} - --five-guys --burger-king --pizza-hut --subway - @endcode - -
  • - Long options with arguments (two original arguments or a single - one with a = character): - - @code{.unparsed} - --security enable --time=18.56 - @endcode - -
  • - Non-option arguments (anything else, including - - and \--). - - A non-option argument cannot have the form of an option, for example - if you need to pass the exact relative path - \--component. In that case, you would need to pass - ./\--component. There's no generic way to escape - - as of this version. -
- -Create a parsing iterator with argpar_iter_create(), then repeatedly -call argpar_iter_next() to access the parsing results (items), until one -of: - -- There are no more arguments. - -- The argument parser encounters an error (for example, an unknown - option). - -- You need to stop. - -argpar_iter_create() accepts duplicate option descriptors in -\p descrs (argpar_iter_next() produces one item for each -instance). - -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. -Each item type has its set of dedicated functions -(\c argpar_item_opt_ and \c argpar_item_non_opt_ prefixes). - -argpar_iter_next() produces the items in the same order that it parses -original arguments, including non-option arguments. This means, for -example, that for: - -@code{.unparsed} ---hello --count=23 /path/to/file -ab --type file -- magie -@endcode - -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). -*/ - -/* - * 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 - -struct argpar_opt_descr; - -/*! -@name Item API -@{ -*/ - -/*! -@brief - Type of a parsing item, as returned by - \link argpar_item_type(const struct argpar_item *) argpar_item_type()\endlink. -*/ -enum argpar_item_type { - /// Option - ARGPAR_ITEM_TYPE_OPT, - - /// Non-option - ARGPAR_ITEM_TYPE_NON_OPT, -}; - -/*! -@struct argpar_item - -@brief - Opaque parsing item type - -argpar_iter_next() sets a pointer to such a type. -*/ -struct argpar_item; - -/*! -@brief - Returns the type of the parsing item \p item. - -@param[in] item - Parsing item of which to get the type. - -@returns - Type of \p 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); - -/*! -@brief - Returns the option descriptor of the option parsing item \p item. - -@param[in] item - Option parsing item of which to get the option descriptor. - -@returns - Option descriptor of \p item. - -@pre - \p item is not \c NULL. -@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); - -/*! -@brief - Returns the argument of the option parsing item \p item, or - \c NULL if none. - -@param[in] item - Option parsing item of which to get the argument. - -@returns - Argument of \p item, or \c NULL if none. - -@pre - \p item is not \c NULL. -@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); - -/*! -@brief - Returns the complete original argument, pointing to one of the - entries of the original arguments (in \p argv, as passed to - argpar_iter_create()), of the non-option parsing item \p item. - -@param[in] item - Non-option parsing item of which to get the complete original - argument. - -@returns - Complete original argument of \p item. - -@pre - \p item is not \c NULL. -@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); - -/*! -@brief - Returns the index, within \em all the original arguments (in - \p argv, as passed to argpar_iter_create()), of the non-option - parsing item \p item. - -For example, with the following command line (all options have no -argument): - -@code{.unparsed} --f -m meow --jus mix --kilo -@endcode - -The original argument index of \c meow is 2 while the original -argument index of \c mix is 4. - -@param[in] item - Non-option parsing item of which to get the original argument index. - -@returns - Original argument index of \p item. - -@pre - \p item is not \c NULL. -@pre - \p item has the type #ARGPAR_ITEM_TYPE_NON_OPT. - -@sa - 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); - -/*! -@brief - Returns the index, within the parsed non-option parsing items, of - the non-option parsing item \p item. - -For example, with the following command line (all options have no -argument): - -@code{.unparsed} --f -m meow --jus mix --kilo -@endcode - -The non-option index of \c meow is 0 while the original -argument index of \c mix is 1. - -@param[in] item - Non-option parsing item of which to get the non-option index. - -@returns - Non-option index of \p item. - -@pre - \p item is not \c NULL. -@pre - \p item has the type #ARGPAR_ITEM_TYPE_NON_OPT. - -@sa - 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); - -/*! -@brief - Destroys the parsing item \p 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); - -/*! -@def ARGPAR_ITEM_DESTROY_AND_RESET(_item) - -@brief - Calls argpar_item_destroy() with \p _item, and then sets \p _item - to \c NULL. - -@param[in] _item - Item to destroy and variable to reset - (const struct argpar_item * type). -*/ -#define ARGPAR_ITEM_DESTROY_AND_RESET(_item) \ - { \ - argpar_item_destroy(_item); \ - ((_item)) = NULL; \ - } - -/// @} - -/*! -@name Error API -@{ -*/ - -/*! -@brief - Parsing error type, as returned by - \link argpar_error_type(const struct argpar_error *) argpar_error_type()\endlink. -*/ -enum argpar_error_type { - /// Unknown option error - ARGPAR_ERROR_TYPE_UNKNOWN_OPT, - - /// Missing option argument error - ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, - - /// Unexpected option argument error - ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG, -}; - -/*! -@struct argpar_error - -@brief - Opaque parsing error type -*/ -struct argpar_error; - -/*! -@brief - Returns the type of the parsing error object \p error. - -@param[in] error - Parsing error of which to get the type. - -@returns - Type of \p 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); - -/*! -@brief - Returns the index of the original argument (in \p argv, as passed to - argpar_iter_create()) for which the parsing error described by - \p error occurred. - -@param[in] error - Parsing error of which to get the original argument index. - -@returns - Original argument index of \p 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); - -/*! -@brief - Returns the name of the unknown option for which the parsing error - described by \p error occurred. - -The returned name includes any - or \-- -prefix. - -With the long option with argument form, for example -\--mireille=deyglun, this function only returns the name -part (\--mireille in the last example). - -@param[in] error - Parsing error of which to get the name of the unknown option. - -@returns - Name of the unknown option of \p error. - -@pre - \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, - is #ARGPAR_ERROR_TYPE_UNKNOWN_OPT. -*/ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -const char *argpar_error_unknown_opt_name(const struct argpar_error *error); - -/*! -@brief - Returns the descriptor of the option for which the parsing error - described by \p error occurred. - -@param[in] error - Parsing error of which to get the option descriptor. -@param[out] is_short - @parblock - If not \c NULL, this function sets \p *is_short to: - - - \c true if the option for which \p error occurred is a short - option. - - - \c false if the option for which \p error occurred is a long - option. - @endparblock - -@returns - Descriptor of the option of \p error. - -@pre - \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, - 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); - -/*! -@brief - Destroys the parsing error \p error. - -@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); - -/// @} - -/*! -@name Iterator API -@{ -*/ - -/*! -@brief - Option descriptor - -argpar_iter_create() accepts an array of instances of such a type, -terminated with #ARGPAR_OPT_DESCR_SENTINEL, as its \p descrs parameter. - -The typical usage is, for example: - -@code -const struct argpar_opt_descr descrs[] = { - { 0, 'd', NULL, false }, - { 1, '\0', "squeeze", true }, - { 2, 'm', "meow", true }, - ARGPAR_OPT_DESCR_SENTINEL, -}; -@endcode -*/ -struct argpar_opt_descr { - /// Numeric ID, to uniquely identify this descriptor - const int id; - - /// Short option character, or '\0' - const char short_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; -}; - -/*! -@brief - Sentinel for an option descriptor array - -The typical usage is, for example: - -@code -const struct argpar_opt_descr descrs[] = { - { 0, 'd', NULL, false }, - { 1, '\0', "squeeze", true }, - { 2, 'm', "meow", true }, - ARGPAR_OPT_DESCR_SENTINEL, -}; -@endcode -*/ -#define ARGPAR_OPT_DESCR_SENTINEL \ - { \ - -1, '\0', NULL, false \ - } - -/*! -@struct argpar_iter - -@brief - Opaque argpar iterator type - -argpar_iter_create() returns a pointer to such a type. -*/ -struct argpar_iter; - -/*! -@brief - Creates and returns an argument parsing iterator to parse the - original arguments \p argv of which the count is \p argc using the - option descriptors \p descrs. - -This function initializes the returned structure, but doesn't actually -start parsing the arguments. - -argpar considers \em all the elements of \p argv, including the first -one, so that you would typically pass (argc - 1) as \p argc -and \&argv[1] as \p argv from what main() -receives, or ignore the parsing item of the first call to -argpar_iter_next(). - -\p *argv and \p *descrs must \em not change for all of: - -- The lifetime of the returned iterator (until you call - argpar_iter_destroy()). - -- The lifetime of any parsing item (until you call - argpar_item_destroy()) which argpar_iter_next() creates from the - returned iterator. - -- The lifetime of any parsing error (until you call - argpar_error_destroy()) which argpar_iter_next() creates from the - returned iterator. - -@param[in] argc - Number of original arguments to parse in \p argv. -@param[in] argv - Original arguments to parse, of which the count is \p argc. -@param[in] descrs - @parblock - Option descriptor array, terminated with #ARGPAR_OPT_DESCR_SENTINEL. - - May contain duplicate entries. - @endparblock - -@returns - New argument parsing iterator, or \c NULL on memory error. - -@pre - \p argc is greater than 0. -@pre - \p argv is not \c NULL. -@pre - The first \p argc elements of \p argv are not \c NULL. -@pre - \p descrs is not \c NULL. - -@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); - -/*! -@brief - Destroys the argument parsing iterator \p iter. - -@param[in] iter - Argument parsing iterator to destroy (may be \c NULL). - -@sa - argpar_iter_create() -- Creates an argument parsing iterator. -*/ -/// @cond hidden_macro -ARGPAR_HIDDEN -/// @endcond -void argpar_iter_destroy(struct argpar_iter *iter); - -/*! -@brief - Return type of argpar_iter_next(). - -Error status enumerators have a negative value. -*/ -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, - - /// Parsing error - ARGPAR_ITER_NEXT_STATUS_ERROR = -1, - - /// Memory error - ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY = -12, -}; - -/*! -@brief - Sets \p *item to the next item of the argument parsing iterator - \p iter and advances \p iter. - -If there are no more original arguments to parse, this function returns -#ARGPAR_ITER_NEXT_STATUS_END. - -@param[in] iter - Argument parsing iterator from which to get the next parsing item. -@param[out] item - @parblock - On success, \p *item is the next parsing item of \p iter. - - Destroy \p *item with argpar_item_destroy(). - @endparblock -@param[out] error - @parblock - When this function returns #ARGPAR_ITER_NEXT_STATUS_ERROR, - if this parameter is not \c NULL, \p *error contains details about - the error. - - Destroy \p *error with argpar_error_destroy(). - @endparblock - -@returns - Status code. - -@pre - \p iter is not \c NULL. -@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); - -/* - * Returns the number of ingested elements from `argv`, as passed to - * argpar_iter_create() to create `*iter`, that were required to produce - * the previously returned items. - */ - -/*! -@brief - Returns the number of ingested original arguments (in - \p argv, as passed to argpar_iter_create() to create \p iter) that - the parser ingested to produce the \em previous parsing items. - -@param[in] iter - Argument parsing iterator of which to get the number of ingested - original arguments. - -@returns - Number of original arguments which \p iter ingested. - -@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); - -/// @} - -/// @} - -#ifdef __cplusplus -} -#endif - -#endif /* ARGPAR_ARGPAR_H */ diff --git a/src/vendor/Makefile.am b/src/vendor/Makefile.am index e8b7a8159..c2626cc16 100644 --- a/src/vendor/Makefile.am +++ b/src/vendor/Makefile.am @@ -3,3 +3,11 @@ SUBDIRS = msgpack EXTRA_DIST = optional.hpp fmt nlohmann + +noinst_LTLIBRARIES = + +# libargpar +noinst_LTLIBRARIES += argpar/libargpar.la +argpar_libargpar_la_SOURCES = \ + argpar/argpar.c \ + argpar/argpar.h diff --git a/src/vendor/argpar/argpar.c b/src/vendor/argpar/argpar.c new file mode 100644 index 000000000..f8280ce14 --- /dev/null +++ b/src/vendor/argpar/argpar.c @@ -0,0 +1,761 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2019-2021 Philippe Proulx + * Copyright (c) 2020-2021 Simon Marchi + */ + +#include "argpar.h" + +#include +#include +#include +#include +#include + +#define ARGPAR_REALLOC(_ptr, _type, _nmemb) ((_type *) realloc(_ptr, (_nmemb) * sizeof(_type))) + +#define ARGPAR_CALLOC(_type, _nmemb) ((_type *) calloc((_nmemb), sizeof(_type))) + +#define ARGPAR_ZALLOC(_type) ARGPAR_CALLOC(_type, 1) + +#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. + * + * 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; +}; + +/* Base parsing item */ +struct argpar_item { + enum argpar_item_type type; +}; + +/* Option parsing item */ +struct argpar_item_opt { + struct argpar_item base; + + /* Corresponding descriptor */ + const struct argpar_opt_descr *descr; + + /* Argument, or `NULL` if none; owned by this */ + char *arg; +}; + +/* 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; +}; + +/* Parsing error */ +struct argpar_error { + /* Error type */ + enum argpar_error_type type; + + /* Original argument index */ + unsigned int orig_index; + + /* Name of unknown option; owned by this */ + char *unknown_opt_name; + + /* Option descriptor */ + const struct argpar_opt_descr *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_ASSERT(item); + return item->type; +} + +ARGPAR_HIDDEN +const struct argpar_opt_descr *argpar_item_opt_descr(const struct argpar_item *const item) +{ + ARGPAR_ASSERT(item); + ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT); + return ((const struct argpar_item_opt *) item)->descr; +} + +ARGPAR_HIDDEN +const char *argpar_item_opt_arg(const struct argpar_item *const item) +{ + ARGPAR_ASSERT(item); + ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT); + return ((const struct argpar_item_opt *) item)->arg; +} + +ARGPAR_HIDDEN +const char *argpar_item_non_opt_arg(const struct argpar_item *const item) +{ + ARGPAR_ASSERT(item); + ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT); + return ((const struct argpar_item_non_opt *) item)->arg; +} + +ARGPAR_HIDDEN +unsigned int argpar_item_non_opt_orig_index(const struct argpar_item *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_HIDDEN +unsigned int argpar_item_non_opt_non_opt_index(const struct argpar_item *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_HIDDEN +void argpar_item_destroy(const struct argpar_item *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; + + free(opt_item->arg); + } + + free((void *) item); + +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, + const char *const arg) +{ + struct argpar_item_opt *opt_item = ARGPAR_ZALLOC(struct argpar_item_opt); + + if (!opt_item) { + goto end; + } + + 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; + } + } + + goto end; + +error: + argpar_item_destroy(&opt_item->base); + opt_item = NULL; + +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, + const unsigned int non_opt_index) +{ + struct argpar_item_non_opt *const non_opt_item = ARGPAR_ZALLOC(struct argpar_item_non_opt); + + 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; + +end: + return non_opt_item; +} + +/* + * If `error` is not `NULL`, sets the error `error` to a new parsing + * error object, setting its `unknown_opt_name`, `opt_descr`, and + * `is_short` members from the parameters. + * + * `unknown_opt_name` is the unknown option name without any `-` or `--` + * prefix: `is_short` controls which type of unknown option it is. + * + * 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) +{ + int ret = 0; + + if (!error) { + goto end; + } + + *error = ARGPAR_ZALLOC(struct argpar_error); + 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)); + if (!(*error)->unknown_opt_name) { + goto error; + } + + if (is_short) { + strcpy((*error)->unknown_opt_name, "-"); + } else { + strcpy((*error)->unknown_opt_name, "--"); + } + + strcat((*error)->unknown_opt_name, unknown_opt_name); + } + + (*error)->opt_descr = opt_descr; + (*error)->is_short = is_short; + goto end; + +error: + argpar_error_destroy(*error); + ret = -1; + +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) +{ + ARGPAR_ASSERT(error); + return error->orig_index; +} + +ARGPAR_HIDDEN +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; +} + +ARGPAR_HIDDEN +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) { + *is_short = error->is_short; + } + + return error->opt_descr; +} + +ARGPAR_HIDDEN +void argpar_error_destroy(const struct argpar_error *const error) +{ + if (error) { + free(error->unknown_opt_name); + free((void *) 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 char short_name, + const char *const long_name) +{ + const struct argpar_opt_descr *descr; + + 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; + } + } + +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 = -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, + 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) +{ + 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; + +error: + ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); + +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, + const struct argpar_opt_descr *const descrs, + struct argpar_iter *const iter, + struct argpar_error **const error, + struct argpar_item **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; + +error: + ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK); + +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, + const struct argpar_opt_descr *const descrs, + struct argpar_iter *const iter, + struct argpar_error **const error, + struct argpar_item **const item) +{ + enum parse_orig_arg_opt_ret 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); + } else { + /* Short option */ + 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, + const char *const *const argv, + const struct argpar_opt_descr *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; + } + +end: + return iter; +} + +ARGPAR_HIDDEN +void argpar_iter_destroy(struct argpar_iter *const 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) +{ + 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(); + } + +end: + return status; +} + +ARGPAR_HIDDEN +unsigned int argpar_iter_ingested_orig_args(const struct argpar_iter *const iter) +{ + return iter->i; +} diff --git a/src/vendor/argpar/argpar.h b/src/vendor/argpar/argpar.h new file mode 100644 index 000000000..909da9cb3 --- /dev/null +++ b/src/vendor/argpar/argpar.h @@ -0,0 +1,725 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2019-2021 Philippe Proulx + * Copyright (c) 2020-2021 Simon Marchi + */ + +#ifndef ARGPAR_ARGPAR_H +#define ARGPAR_ARGPAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/*! +@mainpage + +See the \ref api module. + +@addtogroup api argpar API +@{ + +argpar is a library which provides an iterator-based API to parse +command-line arguments. + +The argpar parser supports: + +
    +
  • + Short options without an argument, possibly tied together: + + @code{.unparsed} + -f -auf -n + @endcode + +
  • + Short options with arguments: + + @code{.unparsed} + -b 45 -f/mein/file -xyzhello + @endcode + +
  • + Long options without an argument: + + @code{.unparsed} + --five-guys --burger-king --pizza-hut --subway + @endcode + +
  • + Long options with arguments (two original arguments or a single + one with a = character): + + @code{.unparsed} + --security enable --time=18.56 + @endcode + +
  • + Non-option arguments (anything else, including + - and \--). + + A non-option argument cannot have the form of an option, for example + if you need to pass the exact relative path + \--component. In that case, you would need to pass + ./\--component. There's no generic way to escape + - as of this version. +
+ +Create a parsing iterator with argpar_iter_create(), then repeatedly +call argpar_iter_next() to access the parsing results (items), until one +of: + +- There are no more arguments. + +- The argument parser encounters an error (for example, an unknown + option). + +- You need to stop. + +argpar_iter_create() accepts duplicate option descriptors in +\p descrs (argpar_iter_next() produces one item for each +instance). + +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. +Each item type has its set of dedicated functions +(\c argpar_item_opt_ and \c argpar_item_non_opt_ prefixes). + +argpar_iter_next() produces the items in the same order that it parses +original arguments, including non-option arguments. This means, for +example, that for: + +@code{.unparsed} +--hello --count=23 /path/to/file -ab --type file -- magie +@endcode + +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). +*/ + +/* + * 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 + +struct argpar_opt_descr; + +/*! +@name Item API +@{ +*/ + +/*! +@brief + Type of a parsing item, as returned by + \link argpar_item_type(const struct argpar_item *) argpar_item_type()\endlink. +*/ +enum argpar_item_type { + /// Option + ARGPAR_ITEM_TYPE_OPT, + + /// Non-option + ARGPAR_ITEM_TYPE_NON_OPT, +}; + +/*! +@struct argpar_item + +@brief + Opaque parsing item type + +argpar_iter_next() sets a pointer to such a type. +*/ +struct argpar_item; + +/*! +@brief + Returns the type of the parsing item \p item. + +@param[in] item + Parsing item of which to get the type. + +@returns + Type of \p 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); + +/*! +@brief + Returns the option descriptor of the option parsing item \p item. + +@param[in] item + Option parsing item of which to get the option descriptor. + +@returns + Option descriptor of \p item. + +@pre + \p item is not \c NULL. +@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); + +/*! +@brief + Returns the argument of the option parsing item \p item, or + \c NULL if none. + +@param[in] item + Option parsing item of which to get the argument. + +@returns + Argument of \p item, or \c NULL if none. + +@pre + \p item is not \c NULL. +@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); + +/*! +@brief + Returns the complete original argument, pointing to one of the + entries of the original arguments (in \p argv, as passed to + argpar_iter_create()), of the non-option parsing item \p item. + +@param[in] item + Non-option parsing item of which to get the complete original + argument. + +@returns + Complete original argument of \p item. + +@pre + \p item is not \c NULL. +@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); + +/*! +@brief + Returns the index, within \em all the original arguments (in + \p argv, as passed to argpar_iter_create()), of the non-option + parsing item \p item. + +For example, with the following command line (all options have no +argument): + +@code{.unparsed} +-f -m meow --jus mix --kilo +@endcode + +The original argument index of \c meow is 2 while the original +argument index of \c mix is 4. + +@param[in] item + Non-option parsing item of which to get the original argument index. + +@returns + Original argument index of \p item. + +@pre + \p item is not \c NULL. +@pre + \p item has the type #ARGPAR_ITEM_TYPE_NON_OPT. + +@sa + 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); + +/*! +@brief + Returns the index, within the parsed non-option parsing items, of + the non-option parsing item \p item. + +For example, with the following command line (all options have no +argument): + +@code{.unparsed} +-f -m meow --jus mix --kilo +@endcode + +The non-option index of \c meow is 0 while the original +argument index of \c mix is 1. + +@param[in] item + Non-option parsing item of which to get the non-option index. + +@returns + Non-option index of \p item. + +@pre + \p item is not \c NULL. +@pre + \p item has the type #ARGPAR_ITEM_TYPE_NON_OPT. + +@sa + 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); + +/*! +@brief + Destroys the parsing item \p 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); + +/*! +@def ARGPAR_ITEM_DESTROY_AND_RESET(_item) + +@brief + Calls argpar_item_destroy() with \p _item, and then sets \p _item + to \c NULL. + +@param[in] _item + Item to destroy and variable to reset + (const struct argpar_item * type). +*/ +#define ARGPAR_ITEM_DESTROY_AND_RESET(_item) \ + { \ + argpar_item_destroy(_item); \ + ((_item)) = NULL; \ + } + +/// @} + +/*! +@name Error API +@{ +*/ + +/*! +@brief + Parsing error type, as returned by + \link argpar_error_type(const struct argpar_error *) argpar_error_type()\endlink. +*/ +enum argpar_error_type { + /// Unknown option error + ARGPAR_ERROR_TYPE_UNKNOWN_OPT, + + /// Missing option argument error + ARGPAR_ERROR_TYPE_MISSING_OPT_ARG, + + /// Unexpected option argument error + ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG, +}; + +/*! +@struct argpar_error + +@brief + Opaque parsing error type +*/ +struct argpar_error; + +/*! +@brief + Returns the type of the parsing error object \p error. + +@param[in] error + Parsing error of which to get the type. + +@returns + Type of \p 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); + +/*! +@brief + Returns the index of the original argument (in \p argv, as passed to + argpar_iter_create()) for which the parsing error described by + \p error occurred. + +@param[in] error + Parsing error of which to get the original argument index. + +@returns + Original argument index of \p 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); + +/*! +@brief + Returns the name of the unknown option for which the parsing error + described by \p error occurred. + +The returned name includes any - or \-- +prefix. + +With the long option with argument form, for example +\--mireille=deyglun, this function only returns the name +part (\--mireille in the last example). + +@param[in] error + Parsing error of which to get the name of the unknown option. + +@returns + Name of the unknown option of \p error. + +@pre + \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, + is #ARGPAR_ERROR_TYPE_UNKNOWN_OPT. +*/ +/// @cond hidden_macro +ARGPAR_HIDDEN +/// @endcond +const char *argpar_error_unknown_opt_name(const struct argpar_error *error); + +/*! +@brief + Returns the descriptor of the option for which the parsing error + described by \p error occurred. + +@param[in] error + Parsing error of which to get the option descriptor. +@param[out] is_short + @parblock + If not \c NULL, this function sets \p *is_short to: + + - \c true if the option for which \p error occurred is a short + option. + + - \c false if the option for which \p error occurred is a long + option. + @endparblock + +@returns + Descriptor of the option of \p error. + +@pre + \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, + 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); + +/*! +@brief + Destroys the parsing error \p error. + +@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); + +/// @} + +/*! +@name Iterator API +@{ +*/ + +/*! +@brief + Option descriptor + +argpar_iter_create() accepts an array of instances of such a type, +terminated with #ARGPAR_OPT_DESCR_SENTINEL, as its \p descrs parameter. + +The typical usage is, for example: + +@code +const struct argpar_opt_descr descrs[] = { + { 0, 'd', NULL, false }, + { 1, '\0', "squeeze", true }, + { 2, 'm', "meow", true }, + ARGPAR_OPT_DESCR_SENTINEL, +}; +@endcode +*/ +struct argpar_opt_descr { + /// Numeric ID, to uniquely identify this descriptor + const int id; + + /// Short option character, or '\0' + const char short_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; +}; + +/*! +@brief + Sentinel for an option descriptor array + +The typical usage is, for example: + +@code +const struct argpar_opt_descr descrs[] = { + { 0, 'd', NULL, false }, + { 1, '\0', "squeeze", true }, + { 2, 'm', "meow", true }, + ARGPAR_OPT_DESCR_SENTINEL, +}; +@endcode +*/ +#define ARGPAR_OPT_DESCR_SENTINEL \ + { \ + -1, '\0', NULL, false \ + } + +/*! +@struct argpar_iter + +@brief + Opaque argpar iterator type + +argpar_iter_create() returns a pointer to such a type. +*/ +struct argpar_iter; + +/*! +@brief + Creates and returns an argument parsing iterator to parse the + original arguments \p argv of which the count is \p argc using the + option descriptors \p descrs. + +This function initializes the returned structure, but doesn't actually +start parsing the arguments. + +argpar considers \em all the elements of \p argv, including the first +one, so that you would typically pass (argc - 1) as \p argc +and \&argv[1] as \p argv from what main() +receives, or ignore the parsing item of the first call to +argpar_iter_next(). + +\p *argv and \p *descrs must \em not change for all of: + +- The lifetime of the returned iterator (until you call + argpar_iter_destroy()). + +- The lifetime of any parsing item (until you call + argpar_item_destroy()) which argpar_iter_next() creates from the + returned iterator. + +- The lifetime of any parsing error (until you call + argpar_error_destroy()) which argpar_iter_next() creates from the + returned iterator. + +@param[in] argc + Number of original arguments to parse in \p argv. +@param[in] argv + Original arguments to parse, of which the count is \p argc. +@param[in] descrs + @parblock + Option descriptor array, terminated with #ARGPAR_OPT_DESCR_SENTINEL. + + May contain duplicate entries. + @endparblock + +@returns + New argument parsing iterator, or \c NULL on memory error. + +@pre + \p argc is greater than 0. +@pre + \p argv is not \c NULL. +@pre + The first \p argc elements of \p argv are not \c NULL. +@pre + \p descrs is not \c NULL. + +@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); + +/*! +@brief + Destroys the argument parsing iterator \p iter. + +@param[in] iter + Argument parsing iterator to destroy (may be \c NULL). + +@sa + argpar_iter_create() -- Creates an argument parsing iterator. +*/ +/// @cond hidden_macro +ARGPAR_HIDDEN +/// @endcond +void argpar_iter_destroy(struct argpar_iter *iter); + +/*! +@brief + Return type of argpar_iter_next(). + +Error status enumerators have a negative value. +*/ +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, + + /// Parsing error + ARGPAR_ITER_NEXT_STATUS_ERROR = -1, + + /// Memory error + ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY = -12, +}; + +/*! +@brief + Sets \p *item to the next item of the argument parsing iterator + \p iter and advances \p iter. + +If there are no more original arguments to parse, this function returns +#ARGPAR_ITER_NEXT_STATUS_END. + +@param[in] iter + Argument parsing iterator from which to get the next parsing item. +@param[out] item + @parblock + On success, \p *item is the next parsing item of \p iter. + + Destroy \p *item with argpar_item_destroy(). + @endparblock +@param[out] error + @parblock + When this function returns #ARGPAR_ITER_NEXT_STATUS_ERROR, + if this parameter is not \c NULL, \p *error contains details about + the error. + + Destroy \p *error with argpar_error_destroy(). + @endparblock + +@returns + Status code. + +@pre + \p iter is not \c NULL. +@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); + +/* + * Returns the number of ingested elements from `argv`, as passed to + * argpar_iter_create() to create `*iter`, that were required to produce + * the previously returned items. + */ + +/*! +@brief + Returns the number of ingested original arguments (in + \p argv, as passed to argpar_iter_create() to create \p iter) that + the parser ingested to produce the \em previous parsing items. + +@param[in] iter + Argument parsing iterator of which to get the number of ingested + original arguments. + +@returns + Number of original arguments which \p iter ingested. + +@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); + +/// @} + +/// @} + +#ifdef __cplusplus +} +#endif + +#endif /* ARGPAR_ARGPAR_H */