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,
29bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					 const char *opt_name)
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
36bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	if (*opt_name)
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++) {
87bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			if ((opt_end = option_matches(carg+2, lo->name)))
88bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			    break;
89bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		}
90bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (!opt_end)
91bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return '?';
92bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
93bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (longindex)
94bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			*longindex = lo-longopts;
95bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
96bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (*opt_end == '=') {
97bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			if (lo->has_arg)
98bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				optarg = (char *)opt_end+1;
99bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			else
100bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				return '?';
101bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		} else if (lo->has_arg == 1) {
102bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			if (!(optarg = argv[optind]))
103bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				return '?';
104bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			optind++;
105bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		}
106bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
107bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (lo->flag) {
108bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			*lo->flag = lo->val;
109bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return 0;
110bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		} else {
111bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return lo->val;
112bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		}
113bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	}
114bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
115bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
116bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		/* Someone frobbed optind, change to new opt. */
117bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		pvt.optptr = carg + 1;
118bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	}
119bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
120bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	opt = *pvt.optptr++;
121bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac
122bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	if (opt != ':' && (osptr = strchr(optstring, opt))) {
123bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (osptr[1] == ':') {
124bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			if (*pvt.optptr) {
125bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				/* Argument-taking option with attached
126bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				   argument */
127bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				optarg = (char *)pvt.optptr;
128bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				optind++;
129bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			} else {
130bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				/* Argument-taking option with non-attached
131bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				   argument */
1329f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe				if (osptr[2] == ':') {
1339f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe					if (argv[optind + 1]) {
1349f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe						optarg = (char *)argv[optind+1];
1359f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe						optind += 2;
1369f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe					} else {
1379f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe						optarg = NULL;
1389f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe						optind++;
1399f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe					}
1409f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe					return opt;
1419f170691560bacdcd8cef6296d14fc0a8467a9ddJens Axboe				} else if (argv[optind + 1]) {
142bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					optarg = (char *)argv[optind+1];
143bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					optind += 2;
144bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				} else {
145bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					/* Missing argument */
146bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					optind++;
147bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac					return (optstring[0] == ':')
148bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac						? ':' : '?';
149bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				}
150bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			}
151bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return opt;
152bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		} else {
153bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			/* Non-argument-taking option */
154bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			/* pvt.optptr will remember the exact position to
155bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			   resume at */
156bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			if (!*pvt.optptr)
157bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac				optind++;
158bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			return opt;
159bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		}
160bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	} else {
161bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		/* Unknown option */
162bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		optopt = opt;
163bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		if (!*pvt.optptr)
164bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac			optind++;
165bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac		return '?';
166bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac	}
167bf2e821a55d8aa3de1cda7288a0e22883110fdc6Cigy Cyriac}
168