1bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac/*
2bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac * getopt.c
3bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac *
4bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac * getopt_long(), or at least a common subset thereof:
5bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac *
6bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac * - Option reordering is not supported
7bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac * - -W foo is not supported
8bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac * - First optstring character "-" not supported.
9eb078db384e336c1f2338adfdf8f6594660964d6Jens Axboe *
10eb078db384e336c1f2338adfdf8f6594660964d6Jens Axboe * This file was imported from the klibc library from hpa
11bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac */
12bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
13bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac#include <stdint.h>
14bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac#include <unistd.h>
15bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac#include <string.h>
16eb078db384e336c1f2338adfdf8f6594660964d6Jens Axboe
17eb078db384e336c1f2338adfdf8f6594660964d6Jens Axboe#include "getopt.h"
18bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
195be4c944e83b32c0c6842130df3dc1d46cd6eb1fJens Axboechar *optarg = NULL;
205be4c944e83b32c0c6842130df3dc1d46cd6eb1fJens Axboeint optind = 0, opterr = 0, optopt = 0;
215be4c944e83b32c0c6842130df3dc1d46cd6eb1fJens Axboe
22bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriacstatic struct getopt_private_state {
23bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	const char *optptr;
24bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	const char *last_optstring;
25bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	char *const *last_argv;
26bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac} pvt;
27bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
28bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriacstatic inline const char *option_matches(const char *arg_str,
29eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes					 const char *opt_name, int smatch)
30bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac{
31bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	while (*arg_str != '\0' && *arg_str != '=') {
32bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (*arg_str++ != *opt_name++)
33bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return NULL;
34bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	}
35bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
36eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes	if (*opt_name && !smatch)
37bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		return NULL;
38bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
39bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	return arg_str;
40bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac}
41bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
42bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriacint getopt_long_only(int argc, char *const *argv, const char *optstring,
43bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		const struct option *longopts, int *longindex)
44bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac{
45bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	const char *carg;
46bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	const char *osptr;
47bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	int opt;
48bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
4925c42559e065f5a94a696b7bbefa32426d7b8925Jens Axboe	optarg = NULL;
5025c42559e065f5a94a696b7bbefa32426d7b8925Jens Axboe
51bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	/* getopt() relies on a number of different global state
52bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	   variables, which can make this really confusing if there is
53bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	   more than one use of getopt() in the same program.  This
54bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	   attempts to detect that situation by detecting if the
55bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	   "optstring" or "argv" argument have changed since last time
56bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	   we were called; if so, reinitialize the query state. */
57bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
58bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
59bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	    optind < 1 || optind > argc) {
60bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		/* optind doesn't match the current query */
61bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		pvt.last_optstring = optstring;
62bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		pvt.last_argv = argv;
63bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		optind = 1;
64bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		pvt.optptr = NULL;
65bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	}
66bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
67bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	carg = argv[optind];
68bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
69bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	/* First, eliminate all non-option cases */
70bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
71bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	if (!carg || carg[0] != '-' || !carg[1])
72bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		return -1;
73bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
74bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	if (carg[1] == '-') {
75bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		const struct option *lo;
76bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		const char *opt_end = NULL;
77bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
78bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		optind++;
79bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
80bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		/* Either it's a long option, or it's -- */
81bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (!carg[2]) {
82bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			/* It's -- */
83bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return -1;
84bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		}
85bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
86bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		for (lo = longopts; lo->name; lo++) {
87eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes			opt_end = option_matches(carg+2, lo->name, 0);
88eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes			if (opt_end)
89bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			    break;
90bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		}
91eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		/*
92eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		 * The GNU getopt_long_only() apparently allows a short match,
93eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		 * if it's unique and if we don't have a full match. Let's
94eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		 * do the same here, search and see if there is one (and only
95eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		 * one) short match.
96eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		 */
97eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		if (!opt_end) {
98eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes			const struct option *lo_match = NULL;
99eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes
100eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes			for (lo = longopts; lo->name; lo++) {
101eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes				const char *ret;
102eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes
103eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes				ret = option_matches(carg+2, lo->name, 1);
104eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes				if (!ret)
105eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes					continue;
106eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes				if (!opt_end) {
107eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes					opt_end = ret;
108eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes					lo_match = lo;
109eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes				} else {
110eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes					opt_end = NULL;
111eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes					break;
112eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes				}
113eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes			}
114eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes			if (!opt_end)
115eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes				return '?';
116eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes			lo = lo_match;
117eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		}
118bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
119bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (longindex)
120bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			*longindex = lo-longopts;
121bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
122bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (*opt_end == '=') {
123bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			if (lo->has_arg)
124bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				optarg = (char *)opt_end+1;
125bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			else
126bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				return '?';
127bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		} else if (lo->has_arg == 1) {
128bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			if (!(optarg = argv[optind]))
129bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				return '?';
130bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			optind++;
131bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		}
132bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
133bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (lo->flag) {
134bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			*lo->flag = lo->val;
135bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return 0;
136bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		} else {
137bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return lo->val;
138bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		}
139bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	}
140bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
141bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
142bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		/* Someone frobbed optind, change to new opt. */
143bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		pvt.optptr = carg + 1;
144bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	}
145bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
146bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	opt = *pvt.optptr++;
147bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
148bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	if (opt != ':' && (osptr = strchr(optstring, opt))) {
149bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (osptr[1] == ':') {
150bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			if (*pvt.optptr) {
151bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				/* Argument-taking option with attached
152bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				   argument */
153bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				optarg = (char *)pvt.optptr;
154bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				optind++;
155bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			} else {
156bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				/* Argument-taking option with non-attached
157bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				   argument */
1589f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe				if (osptr[2] == ':') {
1599f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe					if (argv[optind + 1]) {
1609f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe						optarg = (char *)argv[optind+1];
1619f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe						optind += 2;
1629f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe					} else {
1639f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe						optarg = NULL;
1649f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe						optind++;
1659f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe					}
1669f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe					return opt;
1679f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe				} else if (argv[optind + 1]) {
168bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					optarg = (char *)argv[optind+1];
169bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					optind += 2;
170bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				} else {
171bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					/* Missing argument */
172bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					optind++;
173bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					return (optstring[0] == ':')
174bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac						? ':' : '?';
175bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				}
176bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			}
177bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return opt;
178bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		} else {
179bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			/* Non-argument-taking option */
180bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			/* pvt.optptr will remember the exact position to
181bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			   resume at */
182bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			if (!*pvt.optptr)
183bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				optind++;
184bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return opt;
185bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		}
186bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	} else {
187bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		/* Unknown option */
188bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		optopt = opt;
189bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (!*pvt.optptr)
190bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			optind++;
191bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		return '?';
192bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	}
193bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac}
194