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