summaryrefslogtreecommitdiff
path: root/src/supplemental/util/options.c
blob: 961e0bb27c645e47c845a12caeb663ec1d9cb8fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//
// 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 <nng/nng.h>
#include <nng/supplemental/util/options.h>

#include "core/nng_impl.h"

// Call with optidx set to 1 to start parsing.
int
nng_opts_parse(int argc, char *const *argv, const nng_optspec *opts, int *val,
    char **optarg, int *optidx)
{
	const nng_optspec *opt;
	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;
	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_EAMBIGUOUS);
		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_ENOARG);
		}
		*optarg = argv[i];
	}
	*optidx = ++i;
	*val    = opt->o_val;

	return (0);
}