aboutsummaryrefslogtreecommitdiff
path: root/src/supplemental/util/options.c
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-02-22 18:48:49 -0800
committerGarrett D'Amore <garrett@damore.org>2018-02-22 18:48:49 -0800
commit1ba0631ca545a69488f4a60e051476fea067a154 (patch)
tree009e8a0cde0b3bed8b61c0af221e9299ce724296 /src/supplemental/util/options.c
parent6a344797283f05ac77e84be0312cf668f7953b6e (diff)
downloadnng-1ba0631ca545a69488f4a60e051476fea067a154.tar.gz
nng-1ba0631ca545a69488f4a60e051476fea067a154.tar.bz2
nng-1ba0631ca545a69488f4a60e051476fea067a154.zip
Add nng_opts_parse() API for handling command line options.
We have implemented this alternative to getopt() so that we can create nngcat. The reason we did not just use getopt() is that getopt() does not understand long options (which nanocat uses, and we want to preserve for compatibility) and getopt() is not available on Windows (and possibly other non-POSIX platforms.) This function handles long and short options, but does not have support for option clustering. It also is threadsafe & reentrant, unlike getopt.
Diffstat (limited to 'src/supplemental/util/options.c')
-rw-r--r--src/supplemental/util/options.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/supplemental/util/options.c b/src/supplemental/util/options.c
new file mode 100644
index 00000000..d8f78deb
--- /dev/null
+++ b/src/supplemental/util/options.c
@@ -0,0 +1,124 @@
+//
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// 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.
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "core/nng_impl.h"
+#include "supplemental/util/options.h"
+
+// Call with optidx set to 1 to start parsing.
+int
+nng_opts_parse(int argc, const char **argv, const nng_optspec *opts, int *val,
+ const char **optarg, int *optidx)
+{
+ const nng_optspec *opt;
+ int matches;
+ bool shortopt;
+ size_t l;
+ const char * arg = argv[*optidx];
+ int i;
+
+ if ((i = *optidx) >= argc) {
+ return (-1);
+ }
+
+ 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;
+ opt = NULL;
+
+ for (int x = 0; opts[x].o_val != 0; x++) {
+
+ if (shortopt) {
+ if (arg[0] == opts[x].o_short) {
+ matches = 1;
+ opt = &opts[x];
+ break;
+ }
+ continue;
+ }
+
+ if ((opts[x].o_name == NULL) ||
+ (strncmp(arg, opts[x].o_name, l) != 0)) {
+ continue;
+ }
+ matches++;
+ opt = &opts[x];
+
+ if (strlen(opts[x].o_name) == l) {
+ // Perfect match.
+ matches = 1;
+ break;
+ }
+ }
+
+ switch (matches) {
+ case 1:
+ // Exact match
+ break;
+ case 0:
+ // No such option
+ return (NNG_EINVAL);
+ break;
+ default:
+ // Ambiguous (not match)
+ return (NNG_EINVAL);
+ break;
+ }
+
+ if (!opt->o_arg) {
+ // No option clustering for short options yet.
+ if (arg[l] != '\0') {
+ return (NNG_EINVAL);
+ }
+ *val = opt->o_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_EINVAL);
+ }
+ *optarg = argv[i];
+ }
+ *optidx = ++i;
+ *val = opt->o_val;
+
+ return (0);
+}