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