xref: /openbsd-src/usr.bin/tmux/arguments.c (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
1 /* $OpenBSD: arguments.c,v 1.51 2021/09/09 21:55:03 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <vis.h>
25 
26 #include "tmux.h"
27 
28 /*
29  * Manipulate command arguments.
30  */
31 
32 /* List of argument values. */
33 TAILQ_HEAD(args_values, args_value);
34 
35 /* Single arguments flag. */
36 struct args_entry {
37 	u_char			 flag;
38 	struct args_values	 values;
39 	u_int			 count;
40 	RB_ENTRY(args_entry)	 entry;
41 };
42 
43 /* Parsed argument flags and values. */
44 struct args {
45 	struct args_tree	 tree;
46 	u_int			 count;
47 	struct args_value	*values;
48 };
49 
50 /* Prepared command state. */
51 struct args_command_state {
52 	struct cmd_list		*cmdlist;
53 	char			*cmd;
54 	struct cmd_parse_input	 pi;
55 };
56 
57 static struct args_entry	*args_find(struct args *, u_char);
58 
59 static int	args_cmp(struct args_entry *, struct args_entry *);
60 RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
61 
62 /* Arguments tree comparison function. */
63 static int
64 args_cmp(struct args_entry *a1, struct args_entry *a2)
65 {
66 	return (a1->flag - a2->flag);
67 }
68 
69 /* Find a flag in the arguments tree. */
70 static struct args_entry *
71 args_find(struct args *args, u_char flag)
72 {
73 	struct args_entry	entry;
74 
75 	entry.flag = flag;
76 	return (RB_FIND(args_tree, &args->tree, &entry));
77 }
78 
79 /* Copy value. */
80 static void
81 args_copy_value(struct args_value *to, struct args_value *from)
82 {
83 	to->type = from->type;
84 	switch (from->type) {
85 	case ARGS_NONE:
86 		break;
87 	case ARGS_COMMANDS:
88 		to->cmdlist = from->cmdlist;
89 		to->cmdlist->references++;
90 		break;
91 	case ARGS_STRING:
92 		to->string = xstrdup(from->string);
93 		break;
94 	}
95 }
96 
97 /* Get value as string. */
98 static const char *
99 args_value_as_string(struct args_value *value)
100 {
101 	switch (value->type) {
102 	case ARGS_NONE:
103 		return ("");
104 	case ARGS_COMMANDS:
105 		if (value->cached == NULL)
106 			value->cached = cmd_list_print(value->cmdlist, 0);
107 		return (value->cached);
108 	case ARGS_STRING:
109 		return (value->string);
110 	}
111 }
112 
113 /* Create an empty arguments set. */
114 struct args *
115 args_create(void)
116 {
117 	struct args	 *args;
118 
119 	args = xcalloc(1, sizeof *args);
120 	RB_INIT(&args->tree);
121 	return (args);
122 }
123 
124 /* Parse arguments into a new argument set. */
125 struct args *
126 args_parse(const struct args_parse *parse, struct args_value *values,
127     u_int count, char **cause)
128 {
129 	struct args		*args;
130 	u_int			 i;
131 	enum args_parse_type	 type;
132 	struct args_value	*value, *new;
133 	u_char			 flag, argument;
134 	const char		*found, *string, *s;
135 
136 	if (count == 0)
137 		return (args_create());
138 
139 	args = args_create();
140 	for (i = 1; i < count; /* nothing */) {
141 		value = &values[i];
142 		if (value->type != ARGS_STRING)
143 			break;
144 
145 		string = value->string;
146 		if (*string++ != '-' || *string == '\0')
147 			break;
148 		i++;
149 		if (string[0] == '-' && string[1] == '\0')
150 			break;
151 
152 		for (;;) {
153 			flag = *string++;
154 			if (flag == '\0')
155 				break;
156 			if (flag == '?') {
157 				args_free(args);
158 				return (NULL);
159 			}
160 			if (!isalnum(flag)) {
161 				xasprintf(cause, "invalid flag -%c", flag);
162 				args_free(args);
163 				return (NULL);
164 			}
165 			found = strchr(parse->template, flag);
166 			if (found == NULL) {
167 				xasprintf(cause, "unknown flag -%c", flag);
168 				args_free(args);
169 				return (NULL);
170 			}
171 			argument = *++found;
172 			if (argument != ':') {
173 				log_debug("%s: -%c", __func__, flag);
174 				args_set(args, flag, NULL);
175 				continue;
176 			}
177 			new = xcalloc(1, sizeof *new);
178 			if (*string != '\0') {
179 				new->type = ARGS_STRING;
180 				new->string = xstrdup(string);
181 			} else {
182 				if (i == count) {
183 					xasprintf(cause,
184 					    "-%c expects an argument",
185 					    flag);
186 					args_free(args);
187 					return (NULL);
188 				}
189 				if (values[i].type != ARGS_STRING) {
190 					xasprintf(cause,
191 					    "-%c argument must be a string",
192 					    flag);
193 					args_free(args);
194 					return (NULL);
195 				}
196 				args_copy_value(new, &values[i++]);
197 			}
198 			s = args_value_as_string(new);
199 			log_debug("%s: -%c = %s", __func__, flag, s);
200 			args_set(args, flag, new);
201 			break;
202 		}
203 	}
204 	log_debug("%s: flags end at %u of %u", __func__, i, count);
205 	if (i != count) {
206 		for (/* nothing */; i < count; i++) {
207 			value = &values[i];
208 
209 			s = args_value_as_string(value);
210 			log_debug("%s: %u = %s (type %d)", __func__, i, s,
211 			    value->type);
212 
213 			if (parse->cb != NULL) {
214 				type = parse->cb(args, args->count, cause);
215 				if (type == ARGS_PARSE_INVALID) {
216 					args_free(args);
217 					return (NULL);
218 				}
219 			} else
220 				type = ARGS_PARSE_STRING;
221 
222 			args->values = xrecallocarray(args->values,
223 			    args->count, args->count + 1, sizeof *args->values);
224 			new = &args->values[args->count++];
225 
226 			switch (type) {
227 			case ARGS_PARSE_INVALID:
228 				fatalx("unexpected argument type");
229 			case ARGS_PARSE_STRING:
230 				if (value->type != ARGS_STRING) {
231 					xasprintf(cause,
232 					    "argument %u must be \"string\"",
233 					    args->count);
234 					args_free(args);
235 					return (NULL);
236 				}
237 				args_copy_value(new, value);
238 				break;
239 			case ARGS_PARSE_COMMANDS_OR_STRING:
240 				args_copy_value(new, value);
241 				break;
242 			case ARGS_PARSE_COMMANDS:
243 				if (value->type != ARGS_COMMANDS) {
244 					xasprintf(cause,
245 					    "argument %u must be { commands }",
246 					    args->count);
247 					args_free(args);
248 					return (NULL);
249 				}
250 				args_copy_value(new, value);
251 				break;
252 			}
253 		}
254 	}
255 
256 	if (parse->lower != -1 && args->count < (u_int)parse->lower) {
257 		xasprintf(cause,
258 		    "too few arguments (need at least %u)",
259 		    parse->lower);
260 		args_free(args);
261 		return (NULL);
262 	}
263 	if (parse->upper != -1 && args->count > (u_int)parse->upper) {
264 		xasprintf(cause,
265 		    "too many arguments (need at most %u)",
266 		    parse->upper);
267 		args_free(args);
268 		return (NULL);
269 	}
270 	return (args);
271 }
272 
273 /* Copy and expand a value. */
274 static void
275 args_copy_copy_value(struct args_value *to, struct args_value *from, int argc,
276     char **argv)
277 {
278 	char	*s, *expanded;
279 	int	 i;
280 
281 	to->type = from->type;
282 	switch (from->type) {
283 	case ARGS_NONE:
284 		break;
285 	case ARGS_STRING:
286 		expanded = xstrdup(from->string);
287 		for (i = 0; i < argc; i++) {
288 			s = cmd_template_replace(expanded, argv[i], i + 1);
289 			free(expanded);
290 			expanded = s;
291 		}
292 		to->string = expanded;
293 		break;
294 	case ARGS_COMMANDS:
295 		to->cmdlist = cmd_list_copy(from->cmdlist, argc, argv);
296 		break;
297 	}
298 }
299 
300 /* Copy an arguments set. */
301 struct args *
302 args_copy(struct args *args, int argc, char **argv)
303 {
304 	struct args		*new_args;
305 	struct args_entry	*entry;
306 	struct args_value	*value, *new_value;
307 	u_int			 i;
308 
309 	cmd_log_argv(argc, argv, "%s", __func__);
310 
311 	new_args = args_create();
312 	RB_FOREACH(entry, args_tree, &args->tree) {
313 		if (TAILQ_EMPTY(&entry->values)) {
314 			for (i = 0; i < entry->count; i++)
315 				args_set(new_args, entry->flag, NULL);
316 			continue;
317 		}
318 		TAILQ_FOREACH(value, &entry->values, entry) {
319 			new_value = xcalloc(1, sizeof *new_value);
320 			args_copy_copy_value(new_value, value, argc, argv);
321 			args_set(new_args, entry->flag, new_value);
322 		}
323 	}
324 	if (args->count == 0)
325 		return (new_args);
326 	new_args->count = args->count;
327 	new_args->values = xcalloc(args->count, sizeof *new_args->values);
328 	for (i = 0; i < args->count; i++) {
329 		new_value = &new_args->values[i];
330 		args_copy_copy_value(new_value, &args->values[i], argc, argv);
331 	}
332 	return (new_args);
333 }
334 
335 /* Free a value. */
336 void
337 args_free_value(struct args_value *value)
338 {
339 	switch (value->type) {
340 	case ARGS_NONE:
341 		break;
342 	case ARGS_STRING:
343 		free(value->string);
344 		break;
345 	case ARGS_COMMANDS:
346 		cmd_list_free(value->cmdlist);
347 		break;
348 	}
349 	free(value->cached);
350 }
351 
352 /* Free values. */
353 void
354 args_free_values(struct args_value *values, u_int count)
355 {
356 	u_int	i;
357 
358 	for (i = 0; i < count; i++)
359 		args_free_value(&values[i]);
360 }
361 
362 /* Free an arguments set. */
363 void
364 args_free(struct args *args)
365 {
366 	struct args_entry	*entry;
367 	struct args_entry	*entry1;
368 	struct args_value	*value;
369 	struct args_value	*value1;
370 
371 	args_free_values(args->values, args->count);
372 	free(args->values);
373 
374 	RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
375 		RB_REMOVE(args_tree, &args->tree, entry);
376 		TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
377 			TAILQ_REMOVE(&entry->values, value, entry);
378 			args_free_value(value);
379 			free(value);
380 		}
381 		free(entry);
382 	}
383 
384 	free(args);
385 }
386 
387 /* Convert arguments to vector. */
388 void
389 args_to_vector(struct args *args, int *argc, char ***argv)
390 {
391 	char	*s;
392 	u_int	 i;
393 
394 	*argc = 0;
395 	*argv = NULL;
396 
397 	for (i = 0; i < args->count; i++) {
398 		switch (args->values[i].type) {
399 		case ARGS_NONE:
400 			break;
401 		case ARGS_STRING:
402 			cmd_append_argv(argc, argv, args->values[i].string);
403 			break;
404 		case ARGS_COMMANDS:
405 			s = cmd_list_print(args->values[i].cmdlist, 0);
406 			cmd_append_argv(argc, argv, s);
407 			free(s);
408 			break;
409 		}
410 	}
411 }
412 
413 /* Convert arguments from vector. */
414 struct args_value *
415 args_from_vector(int argc, char **argv)
416 {
417 	struct args_value	*values;
418 	int			 i;
419 
420 	values = xcalloc(argc, sizeof *values);
421 	for (i = 0; i < argc; i++) {
422 		values[i].type = ARGS_STRING;
423 		values[i].string = xstrdup(argv[i]);
424 	}
425 	return (values);
426 }
427 
428 /* Add to string. */
429 static void printflike(3, 4)
430 args_print_add(char **buf, size_t *len, const char *fmt, ...)
431 {
432 	va_list	 ap;
433 	char	*s;
434 	size_t	 slen;
435 
436 	va_start(ap, fmt);
437 	slen = xvasprintf(&s, fmt, ap);
438 	va_end(ap);
439 
440 	*len += slen;
441 	*buf = xrealloc(*buf, *len);
442 
443 	strlcat(*buf, s, *len);
444 	free(s);
445 }
446 
447 /* Add value to string. */
448 static void
449 args_print_add_value(char **buf, size_t *len, struct args_value *value)
450 {
451 	char	*expanded = NULL;
452 
453 	if (**buf != '\0')
454 		args_print_add(buf, len, " ");
455 
456 	switch (value->type) {
457 	case ARGS_NONE:
458 		break;
459 	case ARGS_COMMANDS:
460 		expanded = cmd_list_print(value->cmdlist, 0);
461 		args_print_add(buf, len, "{ %s }", expanded);
462 		break;
463 	case ARGS_STRING:
464 		expanded = args_escape(value->string);
465 		args_print_add(buf, len, "%s", expanded);
466 		break;
467 	}
468 	free(expanded);
469 }
470 
471 /* Print a set of arguments. */
472 char *
473 args_print(struct args *args)
474 {
475 	size_t			 len;
476 	char			*buf;
477 	u_int			 i, j;
478 	struct args_entry	*entry;
479 	struct args_value	*value;
480 
481 	len = 1;
482 	buf = xcalloc(1, len);
483 
484 	/* Process the flags first. */
485 	RB_FOREACH(entry, args_tree, &args->tree) {
486 		if (!TAILQ_EMPTY(&entry->values))
487 			continue;
488 
489 		if (*buf == '\0')
490 			args_print_add(&buf, &len, "-");
491 		for (j = 0; j < entry->count; j++)
492 			args_print_add(&buf, &len, "%c", entry->flag);
493 	}
494 
495 	/* Then the flags with arguments. */
496 	RB_FOREACH(entry, args_tree, &args->tree) {
497 		TAILQ_FOREACH(value, &entry->values, entry) {
498 			if (*buf != '\0')
499 				args_print_add(&buf, &len, " -%c", entry->flag);
500 			else
501 				args_print_add(&buf, &len, "-%c", entry->flag);
502 			args_print_add_value(&buf, &len, value);
503 		}
504 	}
505 
506 	/* And finally the argument vector. */
507 	for (i = 0; i < args->count; i++)
508 		args_print_add_value(&buf, &len, &args->values[i]);
509 
510 	return (buf);
511 }
512 
513 /* Escape an argument. */
514 char *
515 args_escape(const char *s)
516 {
517 	static const char	 dquoted[] = " #';${}%";
518 	static const char	 squoted[] = " \"";
519 	char			*escaped, *result;
520 	int			 flags, quotes = 0;
521 
522 	if (*s == '\0') {
523 		xasprintf(&result, "''");
524 		return (result);
525 	}
526 	if (s[strcspn(s, dquoted)] != '\0')
527 		quotes = '"';
528 	else if (s[strcspn(s, squoted)] != '\0')
529 		quotes = '\'';
530 
531 	if (s[0] != ' ' &&
532 	    s[1] == '\0' &&
533 	    (quotes != 0 || s[0] == '~')) {
534 		xasprintf(&escaped, "\\%c", s[0]);
535 		return (escaped);
536 	}
537 
538 	flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
539 	if (quotes == '"')
540 		flags |= VIS_DQ;
541 	utf8_stravis(&escaped, s, flags);
542 
543 	if (quotes == '\'')
544 		xasprintf(&result, "'%s'", escaped);
545 	else if (quotes == '"') {
546 		if (*escaped == '~')
547 			xasprintf(&result, "\"\\%s\"", escaped);
548 		else
549 			xasprintf(&result, "\"%s\"", escaped);
550 	} else {
551 		if (*escaped == '~')
552 			xasprintf(&result, "\\%s", escaped);
553 		else
554 			result = xstrdup(escaped);
555 	}
556 	free(escaped);
557 	return (result);
558 }
559 
560 /* Return if an argument is present. */
561 int
562 args_has(struct args *args, u_char flag)
563 {
564 	struct args_entry	*entry;
565 
566 	entry = args_find(args, flag);
567 	if (entry == NULL)
568 		return (0);
569 	return (entry->count);
570 }
571 
572 /* Set argument value in the arguments tree. */
573 void
574 args_set(struct args *args, u_char flag, struct args_value *value)
575 {
576 	struct args_entry	*entry;
577 
578 	entry = args_find(args, flag);
579 	if (entry == NULL) {
580 		entry = xcalloc(1, sizeof *entry);
581 		entry->flag = flag;
582 		entry->count = 1;
583 		TAILQ_INIT(&entry->values);
584 		RB_INSERT(args_tree, &args->tree, entry);
585 	} else
586 		entry->count++;
587 	if (value != NULL && value->type != ARGS_NONE)
588 		TAILQ_INSERT_TAIL(&entry->values, value, entry);
589 }
590 
591 /* Get argument value. Will be NULL if it isn't present. */
592 const char *
593 args_get(struct args *args, u_char flag)
594 {
595 	struct args_entry	*entry;
596 
597 	if ((entry = args_find(args, flag)) == NULL)
598 		return (NULL);
599 	if (TAILQ_EMPTY(&entry->values))
600 		return (NULL);
601 	return (TAILQ_LAST(&entry->values, args_values)->string);
602 }
603 
604 /* Get first argument. */
605 u_char
606 args_first(struct args *args, struct args_entry **entry)
607 {
608 	*entry = RB_MIN(args_tree, &args->tree);
609 	if (*entry == NULL)
610 		return (0);
611 	return ((*entry)->flag);
612 }
613 
614 /* Get next argument. */
615 u_char
616 args_next(struct args_entry **entry)
617 {
618 	*entry = RB_NEXT(args_tree, &args->tree, *entry);
619 	if (*entry == NULL)
620 		return (0);
621 	return ((*entry)->flag);
622 }
623 
624 /* Get argument count. */
625 u_int
626 args_count(struct args *args)
627 {
628 	return (args->count);
629 }
630 
631 /* Get argument values. */
632 struct args_value *
633 args_values(struct args *args)
634 {
635 	return (args->values);
636 }
637 
638 /* Get argument value. */
639 struct args_value *
640 args_value(struct args *args, u_int idx)
641 {
642 	if (idx >= args->count)
643 		return (NULL);
644 	return (&args->values[idx]);
645 }
646 
647 /* Return argument as string. */
648 const char *
649 args_string(struct args *args, u_int idx)
650 {
651 	if (idx >= args->count)
652 		return (NULL);
653 	return (args_value_as_string(&args->values[idx]));
654 }
655 
656 /* Make a command now. */
657 struct cmd_list *
658 args_make_commands_now(struct cmd *self, struct cmdq_item *item, u_int idx,
659     int expand)
660 {
661 	struct args_command_state	*state;
662 	char				*error;
663 	struct cmd_list			*cmdlist;
664 
665 	state = args_make_commands_prepare(self, item, idx, NULL, 0, expand);
666 	cmdlist = args_make_commands(state, 0, NULL, &error);
667 	if (cmdlist == NULL) {
668 		cmdq_error(item, "%s", error);
669 		free(error);
670 	}
671 	else
672 		cmdlist->references++;
673 	args_make_commands_free(state);
674 	return (cmdlist);
675 }
676 
677 /* Save bits to make a command later. */
678 struct args_command_state *
679 args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
680     const char *default_command, int wait, int expand)
681 {
682 	struct args			*args = cmd_get_args(self);
683 	struct cmd_find_state		*target = cmdq_get_target(item);
684 	struct client			*tc = cmdq_get_target_client(item);
685 	struct args_value		*value;
686 	struct args_command_state	*state;
687 	const char			*cmd;
688 
689 	state = xcalloc(1, sizeof *state);
690 
691 	if (idx < args->count) {
692 		value = &args->values[idx];
693 		if (value->type == ARGS_COMMANDS) {
694 			state->cmdlist = value->cmdlist;
695 			state->cmdlist->references++;
696 			return (state);
697 		}
698 		cmd = value->string;
699 	} else {
700 		if (default_command == NULL)
701 			fatalx("argument out of range");
702 		cmd = default_command;
703 	}
704 
705 
706 	if (expand)
707 		state->cmd = format_single_from_target(item, cmd);
708 	else
709 		state->cmd = xstrdup(cmd);
710 	log_debug("%s: %s", __func__, state->cmd);
711 
712 	if (wait)
713 		state->pi.item = item;
714 	cmd_get_source(self, &state->pi.file, &state->pi.line);
715 	state->pi.c = tc;
716 	if (state->pi.c != NULL)
717 		state->pi.c->references++;
718 	cmd_find_copy_state(&state->pi.fs, target);
719 
720 	return (state);
721 }
722 
723 /* Return argument as command. */
724 struct cmd_list *
725 args_make_commands(struct args_command_state *state, int argc, char **argv,
726     char **error)
727 {
728 	struct cmd_parse_result	*pr;
729 	char			*cmd, *new_cmd;
730 	int			 i;
731 
732 	if (state->cmdlist != NULL) {
733 		if (argc == 0)
734 			return (state->cmdlist);
735 		return (cmd_list_copy(state->cmdlist, argc, argv));
736 	}
737 
738 	cmd = xstrdup(state->cmd);
739 	for (i = 0; i < argc; i++) {
740 		new_cmd = cmd_template_replace(cmd, argv[i], i + 1);
741 		log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd);
742 		free(cmd);
743 		cmd = new_cmd;
744 	}
745 	log_debug("%s: %s", __func__, cmd);
746 
747 	pr = cmd_parse_from_string(cmd, &state->pi);
748 	free(cmd);
749 	switch (pr->status) {
750 	case CMD_PARSE_ERROR:
751 		*error = pr->error;
752 		return (NULL);
753 	case CMD_PARSE_SUCCESS:
754 		return (pr->cmdlist);
755 	}
756 }
757 
758 /* Free commands state. */
759 void
760 args_make_commands_free(struct args_command_state *state)
761 {
762 	if (state->cmdlist != NULL)
763 		cmd_list_free(state->cmdlist);
764 	if (state->pi.c != NULL)
765 		server_client_unref(state->pi.c);
766 	free(state->cmd);
767 	free(state);
768 }
769 
770 /* Get prepared command. */
771 char *
772 args_make_commands_get_command(struct args_command_state *state)
773 {
774 	struct cmd	*first;
775 	int		 n;
776 	char		*s;
777 
778 	if (state->cmdlist != NULL) {
779 		first = cmd_list_first(state->cmdlist);
780 		if (first == NULL)
781 			return (xstrdup(""));
782 		return (xstrdup(cmd_get_entry(first)->name));
783 	}
784 	n = strcspn(state->cmd, " ,");
785 	xasprintf(&s, "%.*s", n, state->cmd);
786 	return (s);
787 }
788 
789 /* Get first value in argument. */
790 struct args_value *
791 args_first_value(struct args *args, u_char flag)
792 {
793 	struct args_entry	*entry;
794 
795 	if ((entry = args_find(args, flag)) == NULL)
796 		return (NULL);
797 	return (TAILQ_FIRST(&entry->values));
798 }
799 
800 /* Get next value in argument. */
801 struct args_value *
802 args_next_value(struct args_value *value)
803 {
804 	return (TAILQ_NEXT(value, entry));
805 }
806 
807 /* Convert an argument value to a number. */
808 long long
809 args_strtonum(struct args *args, u_char flag, long long minval,
810     long long maxval, char **cause)
811 {
812 	const char		*errstr;
813 	long long		 ll;
814 	struct args_entry	*entry;
815 	struct args_value	*value;
816 
817 	if ((entry = args_find(args, flag)) == NULL) {
818 		*cause = xstrdup("missing");
819 		return (0);
820 	}
821 	value = TAILQ_LAST(&entry->values, args_values);
822 
823 	ll = strtonum(value->string, minval, maxval, &errstr);
824 	if (errstr != NULL) {
825 		*cause = xstrdup(errstr);
826 		return (0);
827 	}
828 
829 	*cause = NULL;
830 	return (ll);
831 }
832 
833 /* Convert an argument to a number which may be a percentage. */
834 long long
835 args_percentage(struct args *args, u_char flag, long long minval,
836     long long maxval, long long curval, char **cause)
837 {
838 	const char		*value;
839 	struct args_entry	*entry;
840 
841 	if ((entry = args_find(args, flag)) == NULL) {
842 		*cause = xstrdup("missing");
843 		return (0);
844 	}
845 	value = TAILQ_LAST(&entry->values, args_values)->string;
846 	return (args_string_percentage(value, minval, maxval, curval, cause));
847 }
848 
849 /* Convert a string to a number which may be a percentage. */
850 long long
851 args_string_percentage(const char *value, long long minval, long long maxval,
852     long long curval, char **cause)
853 {
854 	const char	*errstr;
855 	long long	 ll;
856 	size_t		 valuelen = strlen(value);
857 	char		*copy;
858 
859 	if (value[valuelen - 1] == '%') {
860 		copy = xstrdup(value);
861 		copy[valuelen - 1] = '\0';
862 
863 		ll = strtonum(copy, 0, 100, &errstr);
864 		free(copy);
865 		if (errstr != NULL) {
866 			*cause = xstrdup(errstr);
867 			return (0);
868 		}
869 		ll = (curval * ll) / 100;
870 		if (ll < minval) {
871 			*cause = xstrdup("too small");
872 			return (0);
873 		}
874 		if (ll > maxval) {
875 			*cause = xstrdup("too large");
876 			return (0);
877 		}
878 	} else {
879 		ll = strtonum(value, minval, maxval, &errstr);
880 		if (errstr != NULL) {
881 			*cause = xstrdup(errstr);
882 			return (0);
883 		}
884 	}
885 
886 	*cause = NULL;
887 	return (ll);
888 }
889