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