From f77e5a5ec7f8b1373eeda0ea56f47137daf40330 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 4 Jan 2025 17:57:28 -0800 Subject: args: Convert nng_opts_parse into a header only library using `nng_args_parse`. The API is identical, except that some names have changed, and this is now a header library in `nng/args.h` - so the core library does not need to carry this code in binaries. Being a header library also means it is not necessary to link against NNG, and it does not include any parts of NNG; it only depends on a standard C99 or C11 environment. --- include/nng/args.h | 163 ++++++++++++++++++++++++++++++++ include/nng/nng.h | 2 - include/nng/supplemental/util/options.h | 50 ---------- 3 files changed, 163 insertions(+), 52 deletions(-) create mode 100644 include/nng/args.h delete mode 100644 include/nng/supplemental/util/options.h (limited to 'include') diff --git a/include/nng/args.h b/include/nng/args.h new file mode 100644 index 00000000..faaa98b2 --- /dev/null +++ b/include/nng/args.h @@ -0,0 +1,163 @@ +// +// Copyright 2025 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +// This is a relatively simple "command line options parsing" library, used to +// parse command line options. We would use getopt(3), but there are +// two problems with getopt(3). First, it isn't available on all +// platforms (especially Win32), and second, it doesn't support long +// options. We *exclusively* support long options. POSIX style +// short option clustering is *NOT* supported. +// +// This is a header library, and it does not depend on anything else in NNG. +// This is by design, please do not add dependencies beyond what is available +// in fairly minimal standard C99 or C11. +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// This is a relatively simple "options parsing" library, used to +// parse command line options. We would use getopt(3), but there are +// two problems with getopt(3). First, it isn't available on all +// platforms (especially Win32), and second, it doesn't support long +// options. We *exclusively* support long options. POSIX style +// short option clustering is *NOT* supported. + +struct nng_arg_spec { + const char *a_name; // Long style name (may be NULL for short only) + int a_short; // Short option (no clustering!) + int a_val; // Value stored on a good parse (>0) + bool a_arg; // Option takes an argument if true +}; + +typedef struct nng_arg_spec nng_arg_spec; + +#define NNG_ARG_END (-1) // no more arguments (not an error) +#define NNG_ARG_INVAL (-2) // an invalid argument/option was given in argv +#define NNG_ARG_AMBIG (-3) // an arg in argv resolves to more than one spec +#define NNG_ARG_MISSING (-4) // a required option argument is missing + +// Call with *optidx set to 1 to start parsing for a standard program, or with +// 0 if parsing arguments without the executable in argv[0]. +// +// The val will store the value of the matched "o_val", optarg will be +// set to match the option string, and optidx will be increment appropriately. +// Returns -1 when the end of options is reached, 0 on success, or +// NNG_EINVAL if the option parse is invalid for any reason. +int +nng_args_parse(int argc, char *const *argv, const nng_arg_spec *specs, + int *val, char **optarg, int *optidx) +{ + const nng_arg_spec *spec; + int matches; + bool shortopt; + size_t l; + char *arg; + int i; + + if ((i = *optidx) >= argc) { + return (-1); + } + arg = argv[*optidx]; + + if (arg[0] != '-') { + return (-1); + } + if (arg[1] == '\0') { + *optidx = i + 1; + return (-1); + } + + if ((arg[0] == '-') && (arg[1] == '-')) { + arg += 2; + shortopt = false; + for (l = 0; arg[l] != '\0'; l++) { + if ((arg[l] == '=') || (arg[l] == ':')) { + break; + } + } + } else { + arg++; + shortopt = true; + l = 1; + } + + matches = 0; + spec = NULL; + + for (int x = 0; specs[x].a_val != 0; x++) { + + if (shortopt) { + if (arg[0] == specs[x].a_short) { + matches = 1; + spec = &specs[x]; + break; + } + continue; + } + + if ((specs[x].a_name == NULL) || + (strncmp(arg, specs[x].a_name, l) != 0)) { + continue; + } + matches++; + spec = &specs[x]; + + if (strlen(specs[x].a_name) == l) { + // Perfect match. + matches = 1; + break; + } + } + + switch (matches) { + case 1: + // Exact match + break; + case 0: + // No such option + return (NNG_ARG_INVAL); + break; + default: + // Ambiguous (not match) + return (NNG_ARG_AMBIG); + break; + } + + if (!spec->a_arg) { + // No option clustering for short options yet. + if (arg[l] != '\0') { + return (NNG_ARG_INVAL); + } + *val = spec->a_val; + *optidx = i + 1; + return (0); + } + + if (arg[l] != '\0') { + if (shortopt) { + *optarg = arg + l; + } else { + *optarg = arg + l + 1; + } + } else { + i++; + if (i >= argc) { + return (NNG_ARG_MISSING); + } + *optarg = argv[i]; + } + *optidx = ++i; + *val = spec->a_val; + + return (0); +} diff --git a/include/nng/nng.h b/include/nng/nng.h index 980e527a..5a9f5dbc 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1059,8 +1059,6 @@ enum nng_errno_enum { NNG_EWRITEONLY = 25, NNG_ECRYPTO = 26, NNG_EPEERAUTH = 27, - NNG_ENOARG = 28, - NNG_EAMBIGUOUS = 29, NNG_EBADTYPE = 30, NNG_ECONNSHUT = 31, NNG_ESTOPPED = 999, diff --git a/include/nng/supplemental/util/options.h b/include/nng/supplemental/util/options.h deleted file mode 100644 index 6d0a3c1a..00000000 --- a/include/nng/supplemental/util/options.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright 2024 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This software is supplied under the terms of the MIT License, a -// copy of which should be located in the distribution where this -// file was obtained (LICENSE.txt). A copy of the license may also be -// found online at https://opensource.org/licenses/MIT. -// - -#ifndef NNG_SUPPLEMENTAL_UTIL_OPTIONS_H -#define NNG_SUPPLEMENTAL_UTIL_OPTIONS_H - -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// This is a relatively simple "options parsing" library, used to -// parse command line options. We would use getopt(3), but there are -// two problems with getopt(3). First, it isn't available on all -// platforms (especially Win32), and second, it doesn't support long -// options. We *exclusively* support long options. POSIX style -// short option clustering is *NOT* supported. - -struct nng_optspec { - const char *o_name; // Long style name (may be NULL for short only) - int o_short; // Short option (no clustering!) - int o_val; // Value stored on a good parse (>0) - bool o_arg; // Option takes an argument if true -}; - -typedef struct nng_optspec nng_optspec; - -// Call with *optidx set to 1 to start parsing for a standard program. -// The val will store the value of the matched "o_val", optarg will be -// set to match the option string, and optidx will be increment appropriately. -// Returns -1 when the end of options is reached, 0 on success, or -// NNG_EINVAL if the option parse is invalid for any reason. -NNG_DECL int nng_opts_parse(int argc, char *const *argv, - const nng_optspec *opts, int *val, char **optarg, int *optidx); - -#ifdef __cplusplus -} -#endif - -#endif // NNG_SUPPLEMENTAL_UTIL_OPTIONS_H -- cgit v1.2.3-70-g09d2