diff options
Diffstat (limited to 'src/arg.h')
-rw-r--r-- | src/arg.h | 379 |
1 files changed, 0 insertions, 379 deletions
diff --git a/src/arg.h b/src/arg.h deleted file mode 100644 index 2ff6dfc..0000000 --- a/src/arg.h +++ /dev/null @@ -1,379 +0,0 @@ -/*- - * This file is taken, with some parts removed, from libsimple - * - * ISC License - * - * © 2017, 2018, 2021, 2022, 2023, 2024, 2025 Mattias Andrée <m@maandree.se> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - - -/** - * The zeroth command line argument, the name of the process, - * set by the command line parsing macros - */ -extern char *argv0; - - -/** - * Map from a long option to a short option - * - * NB! Long options with optional arguments should - * have to map entries, one where `.long_flag` ends - * with '=' and `.with_arg` is non-zero, and one - * where `.long_flag` does not end with '=' and - * `.with_arg` is zero. These *cannot* have the same - * `.short_flag` - */ -struct longopt { - /** - * The long option, if the value must be attached - * to the flag, this must end with '=' - */ - const char *long_flag; - - /** - * The equivalent short option - * - * The first symbol in the short option - * (normally '-') will be `.long_flag[0]` - */ - char short_flag; - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -#endif - - /** - * Whether the option takes an argument - */ - int with_arg; - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif -}; - - -/** - * `ARGBEGIN {} ARGEND;` creates a switch statement - * instead a loop that parses the command line arguments - * according to the POSIX specification for default - * behaviour (extensions of the behaviour is possible) - * - * This macro requires that the variables `argc` and - * `argv` are defined and that `argv[argc]` is `NULL`, - * `argc` shall be a non-negative `int` that tells - * how many elements (all non-`NULL`) are available in - * `argv`, the list of command line arguments - * - * When parsing stops, `argc` and `argv` are updated - * shuch that all parsed arguments are removed; the - * contents of `argv` will not be modified, rather - * the pointer `argv` will be updated to `&argv[n]` - * where `n` is the number of parsed elements in `argv` - * - * Inside `{}` in `ARGBEGIN {} ARGEND;` there user - * shall specify `case` statements for each recognised - * command line option, and `default` for unrecognised - * option. For example: - * - * ARGBEGIN { - * case 'a': - * // handle -a - * break; - * case 'b': - * // handle -b - * break; - * case ARGNUM: - * // handle -0, -1, -2, ..., -9 - * break; - * default: - * // print usage information for other flags - * usage(); - * } ARGEND; - */ -#define ARGBEGIN ARGBEGIN2(1, 0) - -/** - * `SUBARGBEGIN {} ARGEND;` is similar to - * `ARGBEGIN {} ARGEND;`, however, `argv0` - * is not set to `argv[0]`, instead `argv[0]` - * is handled like any other element in `argv` - */ -#define SUBARGBEGIN ARGBEGIN2(0, 0) - -/** - * Flexible alternative to `ARGBEGIN` - * - * @param WITH_ARGV0 If 0, behave like `SUBARGBEGIN`, - * otherwise, behave like `ARGBEGIN` - * @param KEEP_DASHDASH If and only if 0, "--" is not removed - * `argv` before parsing is stopped when it - * is encountered - */ -#define ARGBEGIN2(WITH_ARGV0, KEEP_DASHDASH)\ - do {\ - char flag_, *lflag_, *arg_;\ - int brk_ = 0, again_;\ - size_t i_, n_;\ - if (WITH_ARGV0) {\ - argv0 = *argv;\ - argv += !!argv0;\ - argc -= !!argv0;\ - }\ - (void) arg_;\ - (void) i_;\ - (void) n_;\ - for (; argv[0] && argv[0][0] && argv[0][1]; argc--, argv++) {\ - lflag_ = argv[0];\ - if (argv[0][0] == '-') {\ - if (argv[0][1] == '-' && !argv[0][2]) {\ - if (!(KEEP_DASHDASH))\ - argv++, argc--;\ - break;\ - }\ - for (argv[0]++; argv[0][0]; argv[0]++) {\ - flag_ = argv[0][0];\ - if (flag_ == '-' && &argv[0][-1] != lflag_)\ - usage();\ - arg_ = argv[0][1] ? &argv[0][1] : argv[1];\ - do {\ - again_ = 0;\ - switch (flag_) { - -/** - * Test multiple long options and go to - * corresponding short option case - * - * If the long option is found (see documentation - * for `struct longopt` for details), the keyword - * `break` is used to break the `case` (or `default`), - * and at the next iteration of the parsing loop, the - * case will be `.short_flag` for the entry where the - * argument matched `.long_flag` and `.with_arg` - * - * @param LONGOPTS:struct longopt * The options, list shall end - * with `NULL` as `.long_flag` - */ -#define ARGMAPLONG(LONGOPTS)\ - for (i_ = 0; (LONGOPTS)[i_].long_flag; i_++) {\ - if (TESTLONG((LONGOPTS)[i_].long_flag, (LONGOPTS)[i_].with_arg)) {\ - flag_ = (LONGOPTS)[i_].short_flag;\ - again_ = 1;\ - break;\ - }\ - }\ - if (again_)\ - break - -/** - * Allows flags to start with another symbol than '-' - * - * Usage example: - * ARGBEGIN { - * case 'a': // handle -a - * break; - * default: - * usage(); - * } ARGALT('+') { - * case 'a': // handle +a - * break; - * default: - * usage(); - * } ARGALT('/') { - * case 'a': // handle /a - * break; - * default: - * usage(); - * } ARGEND; - * - * @param SYMBOL:char The symbol flags should begin with - */ -#define ARGALT(SYMBOL)\ - }\ - } while (again_);\ - if (brk_) {\ - argc -= arg_ == argv[1];\ - argv += arg_ == argv[1];\ - brk_ = 0;\ - break;\ - }\ - }\ - } else if (argv[0][0] == SYMBOL) {\ - if (argv[0][1] == SYMBOL && !argv[0][2])\ - break;\ - for (argv[0]++; argv[0][0]; argv[0]++) {\ - flag_ = argv[0][0];\ - if (flag_ == SYMBOL && &argv[0][-1] != lflag_)\ - usage();\ - arg_ = argv[0][1] ? &argv[0][1] : argv[1];\ - do {\ - again_ = 0;\ - switch (flag_) { - -/** - * Refer to `ARGBEGIN`, `SUBARGBEGIN`, and `ARGBEGIN2` - */ -#define ARGEND\ - }\ - } while (again_);\ - if (brk_) {\ - argc -= arg_ == argv[1];\ - argv += arg_ == argv[1];\ - brk_ = 0;\ - break;\ - }\ - }\ - } else {\ - break;\ - }\ - }\ - } while (0) - - -/** - * `case ARGNUM` creates a switch statement case for each digit - */ -#define ARGNUM '0': case '1': case '2': case '3': case '4':\ - case '5': case '6': case '7': case '8': case '9' - -/** - * Get the flag character, for example in `case 'a'`, - * 'a' is returned - * - * @return :char The option's identifying character - */ -#define FLAG() (flag_) - -/** - * Get the entire argument that is being parsed - * - * Note that an argument can contain multiple options - * and it can contain the last options value but the - * value can also be in the next argument - * - * @return :char * The current command line argument - */ -#define LFLAG() (lflag_) - -/** - * Get the current option's value, if it - * does not have a value, call `usage` - * (which terminates the process) - * - * Using this macro lets the parser knows - * that the option has a value - * - * @return :char * The option's value, never `NULL` - */ -#define ARG() (arg_ ? (brk_ = 1, arg_) : (usage(), NULL)) - -/** - * Get the current option's value, if the option - * does not have a value, `NULL` is returned - * - * Note that the value may appear at the next - * argument (next element in `argv`) which in that - * case is returned - * - * Using this macro lets the parser knows - * that the option has a value - * - * @return :char * The option's value, `NULL` if - * the option does not have a value - */ -#define ARGNULL() (arg_ ? (brk_ = 1, arg_) : NULL) - -/** - * Get the remaining part of the current command - * line argument (element in `argv`) — as well as - * the character that specifies the flag — as the - * value of the argument - * - * Using this macro lets the parser knows - * that the option has a value - * - * Usage example: - * - * char *arg; - * ARGBEGIN { - * case ARGNUM: - * arg = ARGHERE(); - * // `arg` is the number after '-', for example, - * // if the command line contains the argument - * // "-12345", `arg` will be `12345` - * break; - * case 'n': - * arg = &ARGHERE()[1]; - * if (*arg) { - * // flag 'n' has a value (`argv`) - * } else { - * // flag 'n' does not have a value - * } - * default: - * usage(); - * } ARGEND; - * - * @return :char * The option's value include the flag - * character, never `NULL` or "" - */ -#define ARGHERE() (brk_ = 1, argv[0]) - - -/** - * Test if the argument is a specific long option - * - * Example: - * - * ARGBEGIN { - * case 'x': - * handle_dash_x: - * // handle -x - * break; - * case '-': - * if (TESTLONG("--xdev", 0)) - * goto handle_dash_x; - * else - * usage(); - * break; - * default: - * usage(); - * } ARGEND; - * - * @param FLAG:const char * The flag, must end with '=' if the - * value must be attached to the flag, - * must not have side-effects - * @param WARG:int Whether the option takes an argument, - * should not have side-effects - */ -#define TESTLONG(FLG, WARG)\ - ((WARG)\ - ? ((!strncmp(lflag_, (FLG), (n_ = strlen(FLG), n_ -= ((FLG)[n_ - !!n_] == '='))) && lflag_[n_] == '=')\ - ? (lflag_[n_] = '\0',\ - (arg_ = &lflag_[n_ + 1]),\ - (brk_ = 1))\ - : (!strcmp(lflag_, (FLG))\ - ? (argv[1]\ - ? ((arg_ = argv[1]),\ - (brk_ = 1))\ - : (usage(), 0))\ - : 0))\ - : (!strcmp(lflag_, (FLG))\ - ? (brk_ = 1)\ - : 0)) |