xref: /kvmtool/util/parse-options.c (revision 98ee79f4333acbe273095d4cfea473f8ee0d3a15)
1*98ee79f4SPrasad Joshi #include <stdio.h>
2*98ee79f4SPrasad Joshi #include <string.h>
3*98ee79f4SPrasad Joshi #include <unistd.h>
4*98ee79f4SPrasad Joshi #include <stdint.h>
5*98ee79f4SPrasad Joshi 
6*98ee79f4SPrasad Joshi #include <stdbool.h>
7*98ee79f4SPrasad Joshi 
8*98ee79f4SPrasad Joshi /* user defined includes */
9*98ee79f4SPrasad Joshi #include <linux/types.h>
10*98ee79f4SPrasad Joshi #include <kvm/util.h>
11*98ee79f4SPrasad Joshi #include <kvm/parse-options.h>
12*98ee79f4SPrasad Joshi #include <kvm/strbuf.h>
13*98ee79f4SPrasad Joshi 
14*98ee79f4SPrasad Joshi #define OPT_SHORT 1
15*98ee79f4SPrasad Joshi #define OPT_UNSET 2
16*98ee79f4SPrasad Joshi 
17*98ee79f4SPrasad Joshi static int opterror(const struct option *opt, const char *reason, int flags)
18*98ee79f4SPrasad Joshi {
19*98ee79f4SPrasad Joshi 	if (flags & OPT_SHORT)
20*98ee79f4SPrasad Joshi 		return error("switch `%c' %s", opt->short_name, reason);
21*98ee79f4SPrasad Joshi 	if (flags & OPT_UNSET)
22*98ee79f4SPrasad Joshi 		return error("option `no-%s' %s", opt->long_name, reason);
23*98ee79f4SPrasad Joshi 	return error("option `%s' %s", opt->long_name, reason);
24*98ee79f4SPrasad Joshi }
25*98ee79f4SPrasad Joshi 
26*98ee79f4SPrasad Joshi static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
27*98ee79f4SPrasad Joshi 		int flags, const char **arg)
28*98ee79f4SPrasad Joshi {
29*98ee79f4SPrasad Joshi 	if (p->opt) {
30*98ee79f4SPrasad Joshi 		*arg = p->opt;
31*98ee79f4SPrasad Joshi 		p->opt = NULL;
32*98ee79f4SPrasad Joshi 	} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
33*98ee79f4SPrasad Joshi 				**(p->argv + 1) == '-')) {
34*98ee79f4SPrasad Joshi 		*arg = (const char *)opt->defval;
35*98ee79f4SPrasad Joshi 	} else if (p->argc > 1) {
36*98ee79f4SPrasad Joshi 		p->argc--;
37*98ee79f4SPrasad Joshi 		*arg = *++p->argv;
38*98ee79f4SPrasad Joshi 	} else
39*98ee79f4SPrasad Joshi 		return opterror(opt, "requires a value", flags);
40*98ee79f4SPrasad Joshi 	return 0;
41*98ee79f4SPrasad Joshi }
42*98ee79f4SPrasad Joshi 
43*98ee79f4SPrasad Joshi static int get_value(struct parse_opt_ctx_t *p,
44*98ee79f4SPrasad Joshi 		const struct option *opt, int flags)
45*98ee79f4SPrasad Joshi {
46*98ee79f4SPrasad Joshi 	const char *s, *arg = NULL;
47*98ee79f4SPrasad Joshi 	const int unset = flags & OPT_UNSET;
48*98ee79f4SPrasad Joshi 
49*98ee79f4SPrasad Joshi 	if (unset && p->opt)
50*98ee79f4SPrasad Joshi 		return opterror(opt, "takes no value", flags);
51*98ee79f4SPrasad Joshi 	if (unset && (opt->flags & PARSE_OPT_NONEG))
52*98ee79f4SPrasad Joshi 		return opterror(opt, "isn't available", flags);
53*98ee79f4SPrasad Joshi 
54*98ee79f4SPrasad Joshi 	if (!(flags & OPT_SHORT) && p->opt) {
55*98ee79f4SPrasad Joshi 		switch (opt->type) {
56*98ee79f4SPrasad Joshi 		case OPTION_CALLBACK:
57*98ee79f4SPrasad Joshi 			if (!(opt->flags & PARSE_OPT_NOARG))
58*98ee79f4SPrasad Joshi 				break;
59*98ee79f4SPrasad Joshi 		/* FALLTHROUGH */
60*98ee79f4SPrasad Joshi 		case OPTION_BOOLEAN:
61*98ee79f4SPrasad Joshi 		case OPTION_INCR:
62*98ee79f4SPrasad Joshi 		case OPTION_BIT:
63*98ee79f4SPrasad Joshi 		case OPTION_SET_UINT:
64*98ee79f4SPrasad Joshi 		case OPTION_SET_PTR:
65*98ee79f4SPrasad Joshi 			return opterror(opt, "takes no value", flags);
66*98ee79f4SPrasad Joshi 		case OPTION_END:
67*98ee79f4SPrasad Joshi 		case OPTION_ARGUMENT:
68*98ee79f4SPrasad Joshi 		case OPTION_GROUP:
69*98ee79f4SPrasad Joshi 		case OPTION_STRING:
70*98ee79f4SPrasad Joshi 		case OPTION_INTEGER:
71*98ee79f4SPrasad Joshi 		case OPTION_UINTEGER:
72*98ee79f4SPrasad Joshi 		case OPTION_LONG:
73*98ee79f4SPrasad Joshi 		case OPTION_U64:
74*98ee79f4SPrasad Joshi 		default:
75*98ee79f4SPrasad Joshi 			break;
76*98ee79f4SPrasad Joshi 		}
77*98ee79f4SPrasad Joshi 	}
78*98ee79f4SPrasad Joshi 
79*98ee79f4SPrasad Joshi 	switch (opt->type) {
80*98ee79f4SPrasad Joshi 	case OPTION_BIT:
81*98ee79f4SPrasad Joshi 		if (unset)
82*98ee79f4SPrasad Joshi 			*(int *)opt->value &= ~opt->defval;
83*98ee79f4SPrasad Joshi 		else
84*98ee79f4SPrasad Joshi 			*(int *)opt->value |= opt->defval;
85*98ee79f4SPrasad Joshi 		return 0;
86*98ee79f4SPrasad Joshi 
87*98ee79f4SPrasad Joshi 	case OPTION_BOOLEAN:
88*98ee79f4SPrasad Joshi 		*(bool *)opt->value = unset ? false : true;
89*98ee79f4SPrasad Joshi 		return 0;
90*98ee79f4SPrasad Joshi 
91*98ee79f4SPrasad Joshi 	case OPTION_INCR:
92*98ee79f4SPrasad Joshi 		*(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
93*98ee79f4SPrasad Joshi 		return 0;
94*98ee79f4SPrasad Joshi 
95*98ee79f4SPrasad Joshi 	case OPTION_SET_UINT:
96*98ee79f4SPrasad Joshi 		*(unsigned int *)opt->value = unset ? 0 : opt->defval;
97*98ee79f4SPrasad Joshi 		return 0;
98*98ee79f4SPrasad Joshi 
99*98ee79f4SPrasad Joshi 	case OPTION_SET_PTR:
100*98ee79f4SPrasad Joshi 		*(void **)opt->value = unset ? NULL : (void *)opt->defval;
101*98ee79f4SPrasad Joshi 		return 0;
102*98ee79f4SPrasad Joshi 
103*98ee79f4SPrasad Joshi 	case OPTION_STRING:
104*98ee79f4SPrasad Joshi 		if (unset)
105*98ee79f4SPrasad Joshi 			*(const char **)opt->value = NULL;
106*98ee79f4SPrasad Joshi 		else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
107*98ee79f4SPrasad Joshi 			*(const char **)opt->value = (const char *)opt->defval;
108*98ee79f4SPrasad Joshi 		else
109*98ee79f4SPrasad Joshi 			return get_arg(p, opt, flags,
110*98ee79f4SPrasad Joshi 					(const char **)opt->value);
111*98ee79f4SPrasad Joshi 		return 0;
112*98ee79f4SPrasad Joshi 
113*98ee79f4SPrasad Joshi 	case OPTION_CALLBACK:
114*98ee79f4SPrasad Joshi 		if (unset)
115*98ee79f4SPrasad Joshi 			return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
116*98ee79f4SPrasad Joshi 		if (opt->flags & PARSE_OPT_NOARG)
117*98ee79f4SPrasad Joshi 			return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
118*98ee79f4SPrasad Joshi 		if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
119*98ee79f4SPrasad Joshi 			return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
120*98ee79f4SPrasad Joshi 		if (get_arg(p, opt, flags, &arg))
121*98ee79f4SPrasad Joshi 			return -1;
122*98ee79f4SPrasad Joshi 		return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
123*98ee79f4SPrasad Joshi 
124*98ee79f4SPrasad Joshi 	case OPTION_INTEGER:
125*98ee79f4SPrasad Joshi 		if (unset) {
126*98ee79f4SPrasad Joshi 			*(int *)opt->value = 0;
127*98ee79f4SPrasad Joshi 			return 0;
128*98ee79f4SPrasad Joshi 		}
129*98ee79f4SPrasad Joshi 		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
130*98ee79f4SPrasad Joshi 			*(int *)opt->value = opt->defval;
131*98ee79f4SPrasad Joshi 			return 0;
132*98ee79f4SPrasad Joshi 		}
133*98ee79f4SPrasad Joshi 		if (get_arg(p, opt, flags, &arg))
134*98ee79f4SPrasad Joshi 			return -1;
135*98ee79f4SPrasad Joshi 		*(int *)opt->value = strtol(arg, (char **)&s, 10);
136*98ee79f4SPrasad Joshi 		if (*s)
137*98ee79f4SPrasad Joshi 			return opterror(opt, "expects a numerical value",
138*98ee79f4SPrasad Joshi 					flags);
139*98ee79f4SPrasad Joshi 		return 0;
140*98ee79f4SPrasad Joshi 
141*98ee79f4SPrasad Joshi 	case OPTION_UINTEGER:
142*98ee79f4SPrasad Joshi 		if (unset) {
143*98ee79f4SPrasad Joshi 			*(unsigned int *)opt->value = 0;
144*98ee79f4SPrasad Joshi 			return 0;
145*98ee79f4SPrasad Joshi 		}
146*98ee79f4SPrasad Joshi 		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
147*98ee79f4SPrasad Joshi 			*(unsigned int *)opt->value = opt->defval;
148*98ee79f4SPrasad Joshi 			return 0;
149*98ee79f4SPrasad Joshi 		}
150*98ee79f4SPrasad Joshi 		if (get_arg(p, opt, flags, &arg))
151*98ee79f4SPrasad Joshi 			return -1;
152*98ee79f4SPrasad Joshi 		*(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
153*98ee79f4SPrasad Joshi 		if (*s)
154*98ee79f4SPrasad Joshi 			return opterror(opt,
155*98ee79f4SPrasad Joshi 					"expects a numerical value", flags);
156*98ee79f4SPrasad Joshi 		return 0;
157*98ee79f4SPrasad Joshi 
158*98ee79f4SPrasad Joshi 	case OPTION_LONG:
159*98ee79f4SPrasad Joshi 		if (unset) {
160*98ee79f4SPrasad Joshi 			*(long *)opt->value = 0;
161*98ee79f4SPrasad Joshi 			return 0;
162*98ee79f4SPrasad Joshi 		}
163*98ee79f4SPrasad Joshi 		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
164*98ee79f4SPrasad Joshi 			*(long *)opt->value = opt->defval;
165*98ee79f4SPrasad Joshi 			return 0;
166*98ee79f4SPrasad Joshi 		}
167*98ee79f4SPrasad Joshi 		if (get_arg(p, opt, flags, &arg))
168*98ee79f4SPrasad Joshi 			return -1;
169*98ee79f4SPrasad Joshi 		*(long *)opt->value = strtol(arg, (char **)&s, 10);
170*98ee79f4SPrasad Joshi 		if (*s)
171*98ee79f4SPrasad Joshi 			return opterror(opt,
172*98ee79f4SPrasad Joshi 					"expects a numerical value", flags);
173*98ee79f4SPrasad Joshi 		return 0;
174*98ee79f4SPrasad Joshi 
175*98ee79f4SPrasad Joshi 	case OPTION_U64:
176*98ee79f4SPrasad Joshi 		if (unset) {
177*98ee79f4SPrasad Joshi 			*(u64 *)opt->value = 0;
178*98ee79f4SPrasad Joshi 			return 0;
179*98ee79f4SPrasad Joshi 		}
180*98ee79f4SPrasad Joshi 		if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
181*98ee79f4SPrasad Joshi 			*(u64 *)opt->value = opt->defval;
182*98ee79f4SPrasad Joshi 			return 0;
183*98ee79f4SPrasad Joshi 		}
184*98ee79f4SPrasad Joshi 		if (get_arg(p, opt, flags, &arg))
185*98ee79f4SPrasad Joshi 			return -1;
186*98ee79f4SPrasad Joshi 		*(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
187*98ee79f4SPrasad Joshi 		if (*s)
188*98ee79f4SPrasad Joshi 			return opterror(opt,
189*98ee79f4SPrasad Joshi 					"expects a numerical value", flags);
190*98ee79f4SPrasad Joshi 		return 0;
191*98ee79f4SPrasad Joshi 
192*98ee79f4SPrasad Joshi 	case OPTION_END:
193*98ee79f4SPrasad Joshi 	case OPTION_ARGUMENT:
194*98ee79f4SPrasad Joshi 	case OPTION_GROUP:
195*98ee79f4SPrasad Joshi 	default:
196*98ee79f4SPrasad Joshi 		die("should not happen, someone must be hit on the forehead");
197*98ee79f4SPrasad Joshi 	}
198*98ee79f4SPrasad Joshi }
199*98ee79f4SPrasad Joshi 
200*98ee79f4SPrasad Joshi #define USAGE_OPTS_WIDTH 24
201*98ee79f4SPrasad Joshi #define USAGE_GAP         2
202*98ee79f4SPrasad Joshi 
203*98ee79f4SPrasad Joshi static int usage_with_options_internal(const char * const *usagestr,
204*98ee79f4SPrasad Joshi 		const struct option *opts, int full)
205*98ee79f4SPrasad Joshi {
206*98ee79f4SPrasad Joshi 	if (!usagestr)
207*98ee79f4SPrasad Joshi 		return PARSE_OPT_HELP;
208*98ee79f4SPrasad Joshi 
209*98ee79f4SPrasad Joshi 	fprintf(stderr, "\n usage: %s\n", *usagestr++);
210*98ee79f4SPrasad Joshi 	while (*usagestr && **usagestr)
211*98ee79f4SPrasad Joshi 		fprintf(stderr, "    or: %s\n", *usagestr++);
212*98ee79f4SPrasad Joshi 	while (*usagestr) {
213*98ee79f4SPrasad Joshi 		fprintf(stderr, "%s%s\n",
214*98ee79f4SPrasad Joshi 				**usagestr ? "    " : "",
215*98ee79f4SPrasad Joshi 				*usagestr);
216*98ee79f4SPrasad Joshi 		usagestr++;
217*98ee79f4SPrasad Joshi 	}
218*98ee79f4SPrasad Joshi 
219*98ee79f4SPrasad Joshi 	if (opts->type != OPTION_GROUP)
220*98ee79f4SPrasad Joshi 		fputc('\n', stderr);
221*98ee79f4SPrasad Joshi 
222*98ee79f4SPrasad Joshi 	for (; opts->type != OPTION_END; opts++) {
223*98ee79f4SPrasad Joshi 		size_t pos;
224*98ee79f4SPrasad Joshi 		int pad;
225*98ee79f4SPrasad Joshi 
226*98ee79f4SPrasad Joshi 		if (opts->type == OPTION_GROUP) {
227*98ee79f4SPrasad Joshi 			fputc('\n', stderr);
228*98ee79f4SPrasad Joshi 			if (*opts->help)
229*98ee79f4SPrasad Joshi 				fprintf(stderr, "%s\n", opts->help);
230*98ee79f4SPrasad Joshi 			continue;
231*98ee79f4SPrasad Joshi 		}
232*98ee79f4SPrasad Joshi 		if (!full && (opts->flags & PARSE_OPT_HIDDEN))
233*98ee79f4SPrasad Joshi 			continue;
234*98ee79f4SPrasad Joshi 
235*98ee79f4SPrasad Joshi 		pos = fprintf(stderr, "    ");
236*98ee79f4SPrasad Joshi 		if (opts->short_name)
237*98ee79f4SPrasad Joshi 			pos += fprintf(stderr, "-%c", opts->short_name);
238*98ee79f4SPrasad Joshi 		else
239*98ee79f4SPrasad Joshi 			pos += fprintf(stderr, "    ");
240*98ee79f4SPrasad Joshi 
241*98ee79f4SPrasad Joshi 		if (opts->long_name && opts->short_name)
242*98ee79f4SPrasad Joshi 			pos += fprintf(stderr, ", ");
243*98ee79f4SPrasad Joshi 		if (opts->long_name)
244*98ee79f4SPrasad Joshi 			pos += fprintf(stderr, "--%s", opts->long_name);
245*98ee79f4SPrasad Joshi 
246*98ee79f4SPrasad Joshi 		switch (opts->type) {
247*98ee79f4SPrasad Joshi 		case OPTION_ARGUMENT:
248*98ee79f4SPrasad Joshi 			break;
249*98ee79f4SPrasad Joshi 		case OPTION_LONG:
250*98ee79f4SPrasad Joshi 		case OPTION_U64:
251*98ee79f4SPrasad Joshi 		case OPTION_INTEGER:
252*98ee79f4SPrasad Joshi 		case OPTION_UINTEGER:
253*98ee79f4SPrasad Joshi 			if (opts->flags & PARSE_OPT_OPTARG)
254*98ee79f4SPrasad Joshi 				if (opts->long_name)
255*98ee79f4SPrasad Joshi 					pos += fprintf(stderr, "[=<n>]");
256*98ee79f4SPrasad Joshi 				else
257*98ee79f4SPrasad Joshi 					pos += fprintf(stderr, "[<n>]");
258*98ee79f4SPrasad Joshi 			else
259*98ee79f4SPrasad Joshi 				pos += fprintf(stderr, " <n>");
260*98ee79f4SPrasad Joshi 			break;
261*98ee79f4SPrasad Joshi 		case OPTION_CALLBACK:
262*98ee79f4SPrasad Joshi 			if (opts->flags & PARSE_OPT_NOARG)
263*98ee79f4SPrasad Joshi 				break;
264*98ee79f4SPrasad Joshi 		/* FALLTHROUGH */
265*98ee79f4SPrasad Joshi 		case OPTION_STRING:
266*98ee79f4SPrasad Joshi 			if (opts->argh) {
267*98ee79f4SPrasad Joshi 				if (opts->flags & PARSE_OPT_OPTARG)
268*98ee79f4SPrasad Joshi 					if (opts->long_name)
269*98ee79f4SPrasad Joshi 						pos += fprintf(stderr, "[=<%s>]", opts->argh);
270*98ee79f4SPrasad Joshi 					else
271*98ee79f4SPrasad Joshi 						pos += fprintf(stderr, "[<%s>]", opts->argh);
272*98ee79f4SPrasad Joshi 				else
273*98ee79f4SPrasad Joshi 					pos += fprintf(stderr, " <%s>", opts->argh);
274*98ee79f4SPrasad Joshi 			} else {
275*98ee79f4SPrasad Joshi 				if (opts->flags & PARSE_OPT_OPTARG)
276*98ee79f4SPrasad Joshi 					if (opts->long_name)
277*98ee79f4SPrasad Joshi 						pos += fprintf(stderr, "[=...]");
278*98ee79f4SPrasad Joshi 					else
279*98ee79f4SPrasad Joshi 						pos += fprintf(stderr, "[...]");
280*98ee79f4SPrasad Joshi 				else
281*98ee79f4SPrasad Joshi 					pos += fprintf(stderr, " ...");
282*98ee79f4SPrasad Joshi 			}
283*98ee79f4SPrasad Joshi 				break;
284*98ee79f4SPrasad Joshi 		default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
285*98ee79f4SPrasad Joshi 		case OPTION_END:
286*98ee79f4SPrasad Joshi 		case OPTION_GROUP:
287*98ee79f4SPrasad Joshi 		case OPTION_BIT:
288*98ee79f4SPrasad Joshi 		case OPTION_BOOLEAN:
289*98ee79f4SPrasad Joshi 		case OPTION_INCR:
290*98ee79f4SPrasad Joshi 		case OPTION_SET_UINT:
291*98ee79f4SPrasad Joshi 		case OPTION_SET_PTR:
292*98ee79f4SPrasad Joshi 			break;
293*98ee79f4SPrasad Joshi 		}
294*98ee79f4SPrasad Joshi 		if (pos <= USAGE_OPTS_WIDTH)
295*98ee79f4SPrasad Joshi 			pad = USAGE_OPTS_WIDTH - pos;
296*98ee79f4SPrasad Joshi 		else {
297*98ee79f4SPrasad Joshi 			fputc('\n', stderr);
298*98ee79f4SPrasad Joshi 			pad = USAGE_OPTS_WIDTH;
299*98ee79f4SPrasad Joshi 		}
300*98ee79f4SPrasad Joshi 		fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
301*98ee79f4SPrasad Joshi 	}
302*98ee79f4SPrasad Joshi 	fputc('\n', stderr);
303*98ee79f4SPrasad Joshi 
304*98ee79f4SPrasad Joshi 	return PARSE_OPT_HELP;
305*98ee79f4SPrasad Joshi }
306*98ee79f4SPrasad Joshi 
307*98ee79f4SPrasad Joshi void usage_with_options(const char * const *usagestr,
308*98ee79f4SPrasad Joshi 		const struct option *opts)
309*98ee79f4SPrasad Joshi {
310*98ee79f4SPrasad Joshi 	usage_with_options_internal(usagestr, opts, 0);
311*98ee79f4SPrasad Joshi 	exit(129);
312*98ee79f4SPrasad Joshi }
313*98ee79f4SPrasad Joshi 
314*98ee79f4SPrasad Joshi static void check_typos(const char *arg, const struct option *options)
315*98ee79f4SPrasad Joshi {
316*98ee79f4SPrasad Joshi 	if (strlen(arg) < 3)
317*98ee79f4SPrasad Joshi 		return;
318*98ee79f4SPrasad Joshi 
319*98ee79f4SPrasad Joshi 	if (!prefixcmp(arg, "no-")) {
320*98ee79f4SPrasad Joshi 		error ("did you mean `--%s` (with two dashes ?)", arg);
321*98ee79f4SPrasad Joshi 		exit(129);
322*98ee79f4SPrasad Joshi 	}
323*98ee79f4SPrasad Joshi 
324*98ee79f4SPrasad Joshi 	for (; options->type != OPTION_END; options++) {
325*98ee79f4SPrasad Joshi 		if (!options->long_name)
326*98ee79f4SPrasad Joshi 			continue;
327*98ee79f4SPrasad Joshi 		if (!prefixcmp(options->long_name, arg)) {
328*98ee79f4SPrasad Joshi 			error ("did you mean `--%s` (with two dashes ?)", arg);
329*98ee79f4SPrasad Joshi 			exit(129);
330*98ee79f4SPrasad Joshi 		}
331*98ee79f4SPrasad Joshi 	}
332*98ee79f4SPrasad Joshi }
333*98ee79f4SPrasad Joshi 
334*98ee79f4SPrasad Joshi static int parse_options_usage(const char * const *usagestr,
335*98ee79f4SPrasad Joshi 		const struct option *opts)
336*98ee79f4SPrasad Joshi {
337*98ee79f4SPrasad Joshi 	return usage_with_options_internal(usagestr, opts, 0);
338*98ee79f4SPrasad Joshi }
339*98ee79f4SPrasad Joshi 
340*98ee79f4SPrasad Joshi static int parse_short_opt(struct parse_opt_ctx_t *p,
341*98ee79f4SPrasad Joshi         const struct option *options)
342*98ee79f4SPrasad Joshi {
343*98ee79f4SPrasad Joshi 	for (; options->type != OPTION_END; options++) {
344*98ee79f4SPrasad Joshi 		if (options->short_name == *p->opt) {
345*98ee79f4SPrasad Joshi 			p->opt = p->opt[1] ? p->opt + 1 : NULL;
346*98ee79f4SPrasad Joshi 			return get_value(p, options, OPT_SHORT);
347*98ee79f4SPrasad Joshi 		}
348*98ee79f4SPrasad Joshi 	}
349*98ee79f4SPrasad Joshi 	return -2;
350*98ee79f4SPrasad Joshi }
351*98ee79f4SPrasad Joshi 
352*98ee79f4SPrasad Joshi static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
353*98ee79f4SPrasad Joshi 		const struct option *options)
354*98ee79f4SPrasad Joshi {
355*98ee79f4SPrasad Joshi 	const char *arg_end = strchr(arg, '=');
356*98ee79f4SPrasad Joshi 	const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
357*98ee79f4SPrasad Joshi 	int abbrev_flags = 0, ambiguous_flags = 0;
358*98ee79f4SPrasad Joshi 
359*98ee79f4SPrasad Joshi 	if (!arg_end)
360*98ee79f4SPrasad Joshi 		arg_end = arg + strlen(arg);
361*98ee79f4SPrasad Joshi 
362*98ee79f4SPrasad Joshi 	for (; options->type != OPTION_END; options++) {
363*98ee79f4SPrasad Joshi 		const char *rest;
364*98ee79f4SPrasad Joshi 		int flags = 0;
365*98ee79f4SPrasad Joshi 
366*98ee79f4SPrasad Joshi 		if (!options->long_name)
367*98ee79f4SPrasad Joshi 			continue;
368*98ee79f4SPrasad Joshi 
369*98ee79f4SPrasad Joshi 		rest = skip_prefix(arg, options->long_name);
370*98ee79f4SPrasad Joshi 		if (options->type == OPTION_ARGUMENT) {
371*98ee79f4SPrasad Joshi 			if (!rest)
372*98ee79f4SPrasad Joshi 				continue;
373*98ee79f4SPrasad Joshi 			if (*rest == '=')
374*98ee79f4SPrasad Joshi 				return opterror(options, "takes no value",
375*98ee79f4SPrasad Joshi 						flags);
376*98ee79f4SPrasad Joshi 			if (*rest)
377*98ee79f4SPrasad Joshi 				continue;
378*98ee79f4SPrasad Joshi 			p->out[p->cpidx++] = arg - 2;
379*98ee79f4SPrasad Joshi 			return 0;
380*98ee79f4SPrasad Joshi 		}
381*98ee79f4SPrasad Joshi 		if (!rest) {
382*98ee79f4SPrasad Joshi 			/* abbreviated? */
383*98ee79f4SPrasad Joshi 			if (!strncmp(options->long_name, arg, arg_end - arg)) {
384*98ee79f4SPrasad Joshi is_abbreviated:
385*98ee79f4SPrasad Joshi 				if (abbrev_option) {
386*98ee79f4SPrasad Joshi 					/*
387*98ee79f4SPrasad Joshi 					 * If this is abbreviated, it is
388*98ee79f4SPrasad Joshi 					 * ambiguous. So when there is no
389*98ee79f4SPrasad Joshi 					 * exact match later, we need to
390*98ee79f4SPrasad Joshi 					 * error out.
391*98ee79f4SPrasad Joshi 					 */
392*98ee79f4SPrasad Joshi 					ambiguous_option = abbrev_option;
393*98ee79f4SPrasad Joshi 					ambiguous_flags = abbrev_flags;
394*98ee79f4SPrasad Joshi 				}
395*98ee79f4SPrasad Joshi 				if (!(flags & OPT_UNSET) && *arg_end)
396*98ee79f4SPrasad Joshi 					p->opt = arg_end + 1;
397*98ee79f4SPrasad Joshi 				abbrev_option = options;
398*98ee79f4SPrasad Joshi 				abbrev_flags = flags;
399*98ee79f4SPrasad Joshi 				continue;
400*98ee79f4SPrasad Joshi 			}
401*98ee79f4SPrasad Joshi 			/* negated and abbreviated very much? */
402*98ee79f4SPrasad Joshi 			if (!prefixcmp("no-", arg)) {
403*98ee79f4SPrasad Joshi 				flags |= OPT_UNSET;
404*98ee79f4SPrasad Joshi 				goto is_abbreviated;
405*98ee79f4SPrasad Joshi 			}
406*98ee79f4SPrasad Joshi 			/* negated? */
407*98ee79f4SPrasad Joshi 			if (strncmp(arg, "no-", 3))
408*98ee79f4SPrasad Joshi 				continue;
409*98ee79f4SPrasad Joshi 			flags |= OPT_UNSET;
410*98ee79f4SPrasad Joshi 			rest = skip_prefix(arg + 3, options->long_name);
411*98ee79f4SPrasad Joshi 			/* abbreviated and negated? */
412*98ee79f4SPrasad Joshi 			if (!rest && !prefixcmp(options->long_name, arg + 3))
413*98ee79f4SPrasad Joshi 				goto is_abbreviated;
414*98ee79f4SPrasad Joshi 			if (!rest)
415*98ee79f4SPrasad Joshi 				continue;
416*98ee79f4SPrasad Joshi 		}
417*98ee79f4SPrasad Joshi 		if (*rest) {
418*98ee79f4SPrasad Joshi 			if (*rest != '=')
419*98ee79f4SPrasad Joshi 				continue;
420*98ee79f4SPrasad Joshi 			p->opt = rest + 1;
421*98ee79f4SPrasad Joshi 		}
422*98ee79f4SPrasad Joshi 		return get_value(p, options, flags);
423*98ee79f4SPrasad Joshi 	}
424*98ee79f4SPrasad Joshi 
425*98ee79f4SPrasad Joshi 	if (ambiguous_option)
426*98ee79f4SPrasad Joshi 		return error("Ambiguous option: %s "
427*98ee79f4SPrasad Joshi 				"(could be --%s%s or --%s%s)",
428*98ee79f4SPrasad Joshi 				arg,
429*98ee79f4SPrasad Joshi 				(ambiguous_flags & OPT_UNSET) ?  "no-" : "",
430*98ee79f4SPrasad Joshi 				ambiguous_option->long_name,
431*98ee79f4SPrasad Joshi 				(abbrev_flags & OPT_UNSET) ?  "no-" : "",
432*98ee79f4SPrasad Joshi 				abbrev_option->long_name);
433*98ee79f4SPrasad Joshi 	if (abbrev_option)
434*98ee79f4SPrasad Joshi 		return get_value(p, abbrev_option, abbrev_flags);
435*98ee79f4SPrasad Joshi 	return -2;
436*98ee79f4SPrasad Joshi }
437*98ee79f4SPrasad Joshi 
438*98ee79f4SPrasad Joshi 
439*98ee79f4SPrasad Joshi static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc,
440*98ee79f4SPrasad Joshi 		const char **argv, int flags)
441*98ee79f4SPrasad Joshi {
442*98ee79f4SPrasad Joshi 	memset(ctx, 0, sizeof(*ctx));
443*98ee79f4SPrasad Joshi 	ctx->argc = argc;
444*98ee79f4SPrasad Joshi 	ctx->argv = argv;
445*98ee79f4SPrasad Joshi 	ctx->out  = argv;
446*98ee79f4SPrasad Joshi 	ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
447*98ee79f4SPrasad Joshi 	ctx->flags = flags;
448*98ee79f4SPrasad Joshi 	if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
449*98ee79f4SPrasad Joshi 			(flags & PARSE_OPT_STOP_AT_NON_OPTION))
450*98ee79f4SPrasad Joshi 		die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
451*98ee79f4SPrasad Joshi }
452*98ee79f4SPrasad Joshi 
453*98ee79f4SPrasad Joshi static int parse_options_end(struct parse_opt_ctx_t *ctx)
454*98ee79f4SPrasad Joshi {
455*98ee79f4SPrasad Joshi 	memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
456*98ee79f4SPrasad Joshi 	ctx->out[ctx->cpidx + ctx->argc] = NULL;
457*98ee79f4SPrasad Joshi 	return ctx->cpidx + ctx->argc;
458*98ee79f4SPrasad Joshi }
459*98ee79f4SPrasad Joshi 
460*98ee79f4SPrasad Joshi 
461*98ee79f4SPrasad Joshi static int parse_options_step(struct parse_opt_ctx_t *ctx,
462*98ee79f4SPrasad Joshi 		const struct option *options, const char * const usagestr[])
463*98ee79f4SPrasad Joshi {
464*98ee79f4SPrasad Joshi 	int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
465*98ee79f4SPrasad Joshi 
466*98ee79f4SPrasad Joshi 	/* we must reset ->opt, unknown short option leave it dangling */
467*98ee79f4SPrasad Joshi 	ctx->opt = NULL;
468*98ee79f4SPrasad Joshi 
469*98ee79f4SPrasad Joshi 	for (; ctx->argc; ctx->argc--, ctx->argv++) {
470*98ee79f4SPrasad Joshi 		const char *arg = ctx->argv[0];
471*98ee79f4SPrasad Joshi 
472*98ee79f4SPrasad Joshi 		if (*arg != '-' || !arg[1]) {
473*98ee79f4SPrasad Joshi 			if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
474*98ee79f4SPrasad Joshi 				break;
475*98ee79f4SPrasad Joshi 			ctx->out[ctx->cpidx++] = ctx->argv[0];
476*98ee79f4SPrasad Joshi 			continue;
477*98ee79f4SPrasad Joshi 		}
478*98ee79f4SPrasad Joshi 
479*98ee79f4SPrasad Joshi 		if (arg[1] != '-') {
480*98ee79f4SPrasad Joshi 			ctx->opt = arg + 1;
481*98ee79f4SPrasad Joshi 			if (internal_help && *ctx->opt == 'h')
482*98ee79f4SPrasad Joshi 				return parse_options_usage(usagestr, options);
483*98ee79f4SPrasad Joshi 			switch (parse_short_opt(ctx, options)) {
484*98ee79f4SPrasad Joshi 			case -1:
485*98ee79f4SPrasad Joshi 				return parse_options_usage(usagestr, options);
486*98ee79f4SPrasad Joshi 			case -2:
487*98ee79f4SPrasad Joshi 				goto unknown;
488*98ee79f4SPrasad Joshi 			default:
489*98ee79f4SPrasad Joshi 				break;
490*98ee79f4SPrasad Joshi 			}
491*98ee79f4SPrasad Joshi 			if (ctx->opt)
492*98ee79f4SPrasad Joshi 				check_typos(arg + 1, options);
493*98ee79f4SPrasad Joshi 			while (ctx->opt) {
494*98ee79f4SPrasad Joshi 				if (internal_help && *ctx->opt == 'h')
495*98ee79f4SPrasad Joshi 					return parse_options_usage(usagestr,
496*98ee79f4SPrasad Joshi 							options);
497*98ee79f4SPrasad Joshi 				switch (parse_short_opt(ctx, options)) {
498*98ee79f4SPrasad Joshi 				case -1:
499*98ee79f4SPrasad Joshi 					return parse_options_usage(usagestr,
500*98ee79f4SPrasad Joshi 							options);
501*98ee79f4SPrasad Joshi 				case -2:
502*98ee79f4SPrasad Joshi 					/* fake a short option thing to hide
503*98ee79f4SPrasad Joshi 					 * the fact that we may have
504*98ee79f4SPrasad Joshi 					 * started to parse aggregated stuff
505*98ee79f4SPrasad Joshi 					 *
506*98ee79f4SPrasad Joshi 					 * This is leaky, too bad.
507*98ee79f4SPrasad Joshi 					 */
508*98ee79f4SPrasad Joshi 					ctx->argv[0] = strdup(ctx->opt - 1);
509*98ee79f4SPrasad Joshi 					*(char *)ctx->argv[0] = '-';
510*98ee79f4SPrasad Joshi 					goto unknown;
511*98ee79f4SPrasad Joshi 				default:
512*98ee79f4SPrasad Joshi 					break;
513*98ee79f4SPrasad Joshi 				}
514*98ee79f4SPrasad Joshi 			}
515*98ee79f4SPrasad Joshi 			continue;
516*98ee79f4SPrasad Joshi 		}
517*98ee79f4SPrasad Joshi 
518*98ee79f4SPrasad Joshi 		if (!arg[2]) { /* "--" */
519*98ee79f4SPrasad Joshi 			if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
520*98ee79f4SPrasad Joshi 				ctx->argc--;
521*98ee79f4SPrasad Joshi 				ctx->argv++;
522*98ee79f4SPrasad Joshi 			}
523*98ee79f4SPrasad Joshi 			break;
524*98ee79f4SPrasad Joshi 		}
525*98ee79f4SPrasad Joshi 
526*98ee79f4SPrasad Joshi 		if (internal_help && !strcmp(arg + 2, "help-all"))
527*98ee79f4SPrasad Joshi 			return usage_with_options_internal(usagestr, options,
528*98ee79f4SPrasad Joshi 					1);
529*98ee79f4SPrasad Joshi 		if (internal_help && !strcmp(arg + 2, "help"))
530*98ee79f4SPrasad Joshi 			return parse_options_usage(usagestr, options);
531*98ee79f4SPrasad Joshi 		switch (parse_long_opt(ctx, arg + 2, options)) {
532*98ee79f4SPrasad Joshi 		case -1:
533*98ee79f4SPrasad Joshi 			return parse_options_usage(usagestr, options);
534*98ee79f4SPrasad Joshi 		case -2:
535*98ee79f4SPrasad Joshi 			goto unknown;
536*98ee79f4SPrasad Joshi 		default:
537*98ee79f4SPrasad Joshi 			break;
538*98ee79f4SPrasad Joshi 		}
539*98ee79f4SPrasad Joshi 		continue;
540*98ee79f4SPrasad Joshi unknown:
541*98ee79f4SPrasad Joshi 		if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
542*98ee79f4SPrasad Joshi 			return PARSE_OPT_UNKNOWN;
543*98ee79f4SPrasad Joshi 		ctx->out[ctx->cpidx++] = ctx->argv[0];
544*98ee79f4SPrasad Joshi 		ctx->opt = NULL;
545*98ee79f4SPrasad Joshi 	}
546*98ee79f4SPrasad Joshi 	return PARSE_OPT_DONE;
547*98ee79f4SPrasad Joshi }
548*98ee79f4SPrasad Joshi 
549*98ee79f4SPrasad Joshi int parse_options(int argc, const char **argv, const struct option *options,
550*98ee79f4SPrasad Joshi 		const char * const usagestr[], int flags)
551*98ee79f4SPrasad Joshi {
552*98ee79f4SPrasad Joshi 	struct parse_opt_ctx_t ctx;
553*98ee79f4SPrasad Joshi 
554*98ee79f4SPrasad Joshi 	parse_options_start(&ctx, argc, argv, flags);
555*98ee79f4SPrasad Joshi 	switch (parse_options_step(&ctx, options, usagestr)) {
556*98ee79f4SPrasad Joshi 	case PARSE_OPT_HELP:
557*98ee79f4SPrasad Joshi 		exit(129);
558*98ee79f4SPrasad Joshi 	case PARSE_OPT_DONE:
559*98ee79f4SPrasad Joshi 		break;
560*98ee79f4SPrasad Joshi 	default: /* PARSE_OPT_UNKNOWN */
561*98ee79f4SPrasad Joshi 		if (ctx.argv[0][1] == '-') {
562*98ee79f4SPrasad Joshi 			error("unknown option `%s'", ctx.argv[0] + 2);
563*98ee79f4SPrasad Joshi 		} else {
564*98ee79f4SPrasad Joshi 			error("unknown switch `%c'", *ctx.opt);
565*98ee79f4SPrasad Joshi 		}
566*98ee79f4SPrasad Joshi 		usage_with_options(usagestr, options);
567*98ee79f4SPrasad Joshi 	}
568*98ee79f4SPrasad Joshi 
569*98ee79f4SPrasad Joshi 	return parse_options_end(&ctx);
570*98ee79f4SPrasad Joshi }
571