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