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