xref: /openbsd-src/usr.bin/tmux/arguments.c (revision 3374c67d44f9b75b98444cbf63020f777792342e)
1 /* $OpenBSD: arguments.c,v 1.57 2022/12/16 08:13:40 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 
41 	int			 flags;
42 #define ARGS_ENTRY_OPTIONAL_VALUE 0x1
43 
44 	RB_ENTRY(args_entry)	 entry;
45 };
46 
47 /* Parsed argument flags and values. */
48 struct args {
49 	struct args_tree	 tree;
50 	u_int			 count;
51 	struct args_value	*values;
52 };
53 
54 /* Prepared command state. */
55 struct args_command_state {
56 	struct cmd_list		*cmdlist;
57 	char			*cmd;
58 	struct cmd_parse_input	 pi;
59 };
60 
61 static struct args_entry	*args_find(struct args *, u_char);
62 
63 static int	args_cmp(struct args_entry *, struct args_entry *);
64 RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
65 
66 /* Arguments tree comparison function. */
67 static int
68 args_cmp(struct args_entry *a1, struct args_entry *a2)
69 {
70 	return (a1->flag - a2->flag);
71 }
72 
73 /* Find a flag in the arguments tree. */
74 static struct args_entry *
75 args_find(struct args *args, u_char flag)
76 {
77 	struct args_entry	entry;
78 
79 	entry.flag = flag;
80 	return (RB_FIND(args_tree, &args->tree, &entry));
81 }
82 
83 /* Copy value. */
84 static void
85 args_copy_value(struct args_value *to, struct args_value *from)
86 {
87 	to->type = from->type;
88 	switch (from->type) {
89 	case ARGS_NONE:
90 		break;
91 	case ARGS_COMMANDS:
92 		to->cmdlist = from->cmdlist;
93 		to->cmdlist->references++;
94 		break;
95 	case ARGS_STRING:
96 		to->string = xstrdup(from->string);
97 		break;
98 	}
99 }
100 
101 /* Get value as string. */
102 static const char *
103 args_value_as_string(struct args_value *value)
104 {
105 	switch (value->type) {
106 	case ARGS_NONE:
107 		return ("");
108 	case ARGS_COMMANDS:
109 		if (value->cached == NULL)
110 			value->cached = cmd_list_print(value->cmdlist, 0);
111 		return (value->cached);
112 	case ARGS_STRING:
113 		return (value->string);
114 	}
115 	fatalx("unexpected argument type");
116 }
117 
118 /* Create an empty arguments set. */
119 struct args *
120 args_create(void)
121 {
122 	struct args	 *args;
123 
124 	args = xcalloc(1, sizeof *args);
125 	RB_INIT(&args->tree);
126 	return (args);
127 }
128 
129 /* Parse a single flag. */
130 static int
131 args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
132     struct args *args, u_int *i, const char *string, int flag,
133     int optional_argument)
134 {
135 	struct args_value	*argument, *new;
136 	const char		*s;
137 
138 	new = xcalloc(1, sizeof *new);
139 	if (*string != '\0') {
140 		new->type = ARGS_STRING;
141 		new->string = xstrdup(string);
142 		goto out;
143 	}
144 
145 	if (*i == count)
146 		argument = NULL;
147 	else {
148 		argument = &values[*i];
149 		if (argument->type != ARGS_STRING) {
150 			xasprintf(cause, "-%c argument must be a string", flag);
151 			return (-1);
152 		}
153 		if (argument->string[0] == '-')
154 			argument = NULL;
155 	}
156 	if (argument == NULL) {
157 		if (optional_argument) {
158 			log_debug("%s: -%c (optional)", __func__, flag);
159 			args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE);
160 			return (0); /* either - or end */
161 		}
162 		xasprintf(cause, "-%c expects an argument", flag);
163 		return (-1);
164 	}
165 	args_copy_value(new, argument);
166 	(*i)++;
167 
168 out:
169 	s = args_value_as_string(new);
170 	log_debug("%s: -%c = %s", __func__, flag, s);
171 	args_set(args, flag, new, 0);
172 	return (0);
173 }
174 
175 /* Parse flags argument. */
176 static int
177 args_parse_flags(const struct args_parse *parse, struct args_value *values,
178     u_int count, char **cause, struct args *args, int *i)
179 {
180 	struct args_value	*value;
181 	u_char			 flag;
182 	const char		*found, *string;
183 	int			 optional_argument;
184 
185 	value = &values[*i];
186 	if (value->type != ARGS_STRING)
187 		return (1);
188 
189 	string = value->string;
190 	log_debug("%s: next %s", __func__, string);
191 	if (*string++ != '-' || *string == '\0')
192 		return (1);
193 	(*i)++;
194 	if (string[0] == '-' && string[1] == '\0')
195 		return (1);
196 
197 	for (;;) {
198 		flag = *string++;
199 		if (flag == '\0')
200 			return (0);
201 		if (flag == '?')
202 			return (-1);
203 		if (!isalnum(flag)) {
204 			xasprintf(cause, "invalid flag -%c", flag);
205 			return (-1);
206 		}
207 
208 		found = strchr(parse->template, flag);
209 		if (found == NULL) {
210 			xasprintf(cause, "unknown flag -%c", flag);
211 			return (-1);
212 		}
213 		if (*++found != ':') {
214 			log_debug("%s: -%c", __func__, flag);
215 			args_set(args, flag, NULL, 0);
216 			continue;
217 		}
218 		optional_argument = (*found == ':');
219 		return (args_parse_flag_argument(values, count, cause, args, i,
220 		    string, flag, optional_argument));
221 	}
222 }
223 
224 /* Parse arguments into a new argument set. */
225 struct args *
226 args_parse(const struct args_parse *parse, struct args_value *values,
227     u_int count, char **cause)
228 {
229 	struct args		*args;
230 	u_int			 i;
231 	enum args_parse_type	 type;
232 	struct args_value	*value, *new;
233 	const char		*s;
234 	int			 stop;
235 
236 	if (count == 0)
237 		return (args_create());
238 
239 	args = args_create();
240 	for (i = 1; i < count; /* nothing */) {
241 		stop = args_parse_flags(parse, values, count, cause, args, &i);
242 		if (stop == -1) {
243 			args_free(args);
244 			return (NULL);
245 		}
246 		if (stop == 1)
247 			break;
248 	}
249 	log_debug("%s: flags end at %u of %u", __func__, i, count);
250 	if (i != count) {
251 		for (/* nothing */; i < count; i++) {
252 			value = &values[i];
253 
254 			s = args_value_as_string(value);
255 			log_debug("%s: %u = %s (type %d)", __func__, i, s,
256 			    value->type);
257 
258 			if (parse->cb != NULL) {
259 				type = parse->cb(args, args->count, cause);
260 				if (type == ARGS_PARSE_INVALID) {
261 					args_free(args);
262 					return (NULL);
263 				}
264 			} else
265 				type = ARGS_PARSE_STRING;
266 
267 			args->values = xrecallocarray(args->values,
268 			    args->count, args->count + 1, sizeof *args->values);
269 			new = &args->values[args->count++];
270 
271 			switch (type) {
272 			case ARGS_PARSE_INVALID:
273 				fatalx("unexpected argument type");
274 			case ARGS_PARSE_STRING:
275 				if (value->type != ARGS_STRING) {
276 					xasprintf(cause,
277 					    "argument %u must be \"string\"",
278 					    args->count);
279 					args_free(args);
280 					return (NULL);
281 				}
282 				args_copy_value(new, value);
283 				break;
284 			case ARGS_PARSE_COMMANDS_OR_STRING:
285 				args_copy_value(new, value);
286 				break;
287 			case ARGS_PARSE_COMMANDS:
288 				if (value->type != ARGS_COMMANDS) {
289 					xasprintf(cause,
290 					    "argument %u must be { commands }",
291 					    args->count);
292 					args_free(args);
293 					return (NULL);
294 				}
295 				args_copy_value(new, value);
296 				break;
297 			}
298 		}
299 	}
300 
301 	if (parse->lower != -1 && args->count < (u_int)parse->lower) {
302 		xasprintf(cause,
303 		    "too few arguments (need at least %u)",
304 		    parse->lower);
305 		args_free(args);
306 		return (NULL);
307 	}
308 	if (parse->upper != -1 && args->count > (u_int)parse->upper) {
309 		xasprintf(cause,
310 		    "too many arguments (need at most %u)",
311 		    parse->upper);
312 		args_free(args);
313 		return (NULL);
314 	}
315 	return (args);
316 }
317 
318 /* Copy and expand a value. */
319 static void
320 args_copy_copy_value(struct args_value *to, struct args_value *from, int argc,
321     char **argv)
322 {
323 	char	*s, *expanded;
324 	int	 i;
325 
326 	to->type = from->type;
327 	switch (from->type) {
328 	case ARGS_NONE:
329 		break;
330 	case ARGS_STRING:
331 		expanded = xstrdup(from->string);
332 		for (i = 0; i < argc; i++) {
333 			s = cmd_template_replace(expanded, argv[i], i + 1);
334 			free(expanded);
335 			expanded = s;
336 		}
337 		to->string = expanded;
338 		break;
339 	case ARGS_COMMANDS:
340 		to->cmdlist = cmd_list_copy(from->cmdlist, argc, argv);
341 		break;
342 	}
343 }
344 
345 /* Copy an arguments set. */
346 struct args *
347 args_copy(struct args *args, int argc, char **argv)
348 {
349 	struct args		*new_args;
350 	struct args_entry	*entry;
351 	struct args_value	*value, *new_value;
352 	u_int			 i;
353 
354 	cmd_log_argv(argc, argv, "%s", __func__);
355 
356 	new_args = args_create();
357 	RB_FOREACH(entry, args_tree, &args->tree) {
358 		if (TAILQ_EMPTY(&entry->values)) {
359 			for (i = 0; i < entry->count; i++)
360 				args_set(new_args, entry->flag, NULL, 0);
361 			continue;
362 		}
363 		TAILQ_FOREACH(value, &entry->values, entry) {
364 			new_value = xcalloc(1, sizeof *new_value);
365 			args_copy_copy_value(new_value, value, argc, argv);
366 			args_set(new_args, entry->flag, new_value, 0);
367 		}
368 	}
369 	if (args->count == 0)
370 		return (new_args);
371 	new_args->count = args->count;
372 	new_args->values = xcalloc(args->count, sizeof *new_args->values);
373 	for (i = 0; i < args->count; i++) {
374 		new_value = &new_args->values[i];
375 		args_copy_copy_value(new_value, &args->values[i], argc, argv);
376 	}
377 	return (new_args);
378 }
379 
380 /* Free a value. */
381 void
382 args_free_value(struct args_value *value)
383 {
384 	switch (value->type) {
385 	case ARGS_NONE:
386 		break;
387 	case ARGS_STRING:
388 		free(value->string);
389 		break;
390 	case ARGS_COMMANDS:
391 		cmd_list_free(value->cmdlist);
392 		break;
393 	}
394 	free(value->cached);
395 }
396 
397 /* Free values. */
398 void
399 args_free_values(struct args_value *values, u_int count)
400 {
401 	u_int	i;
402 
403 	for (i = 0; i < count; i++)
404 		args_free_value(&values[i]);
405 }
406 
407 /* Free an arguments set. */
408 void
409 args_free(struct args *args)
410 {
411 	struct args_entry	*entry;
412 	struct args_entry	*entry1;
413 	struct args_value	*value;
414 	struct args_value	*value1;
415 
416 	args_free_values(args->values, args->count);
417 	free(args->values);
418 
419 	RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
420 		RB_REMOVE(args_tree, &args->tree, entry);
421 		TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
422 			TAILQ_REMOVE(&entry->values, value, entry);
423 			args_free_value(value);
424 			free(value);
425 		}
426 		free(entry);
427 	}
428 
429 	free(args);
430 }
431 
432 /* Convert arguments to vector. */
433 void
434 args_to_vector(struct args *args, int *argc, char ***argv)
435 {
436 	char	*s;
437 	u_int	 i;
438 
439 	*argc = 0;
440 	*argv = NULL;
441 
442 	for (i = 0; i < args->count; i++) {
443 		switch (args->values[i].type) {
444 		case ARGS_NONE:
445 			break;
446 		case ARGS_STRING:
447 			cmd_append_argv(argc, argv, args->values[i].string);
448 			break;
449 		case ARGS_COMMANDS:
450 			s = cmd_list_print(args->values[i].cmdlist, 0);
451 			cmd_append_argv(argc, argv, s);
452 			free(s);
453 			break;
454 		}
455 	}
456 }
457 
458 /* Convert arguments from vector. */
459 struct args_value *
460 args_from_vector(int argc, char **argv)
461 {
462 	struct args_value	*values;
463 	int			 i;
464 
465 	values = xcalloc(argc, sizeof *values);
466 	for (i = 0; i < argc; i++) {
467 		values[i].type = ARGS_STRING;
468 		values[i].string = xstrdup(argv[i]);
469 	}
470 	return (values);
471 }
472 
473 /* Add to string. */
474 static void printflike(3, 4)
475 args_print_add(char **buf, size_t *len, const char *fmt, ...)
476 {
477 	va_list	 ap;
478 	char	*s;
479 	size_t	 slen;
480 
481 	va_start(ap, fmt);
482 	slen = xvasprintf(&s, fmt, ap);
483 	va_end(ap);
484 
485 	*len += slen;
486 	*buf = xrealloc(*buf, *len);
487 
488 	strlcat(*buf, s, *len);
489 	free(s);
490 }
491 
492 /* Add value to string. */
493 static void
494 args_print_add_value(char **buf, size_t *len, struct args_value *value)
495 {
496 	char	*expanded = NULL;
497 
498 	if (**buf != '\0')
499 		args_print_add(buf, len, " ");
500 
501 	switch (value->type) {
502 	case ARGS_NONE:
503 		break;
504 	case ARGS_COMMANDS:
505 		expanded = cmd_list_print(value->cmdlist, 0);
506 		args_print_add(buf, len, "{ %s }", expanded);
507 		break;
508 	case ARGS_STRING:
509 		expanded = args_escape(value->string);
510 		args_print_add(buf, len, "%s", expanded);
511 		break;
512 	}
513 	free(expanded);
514 }
515 
516 /* Print a set of arguments. */
517 char *
518 args_print(struct args *args)
519 {
520 	size_t			 len;
521 	char			*buf;
522 	u_int			 i, j;
523 	struct args_entry	*entry;
524 	struct args_entry	*last = NULL;
525 	struct args_value	*value;
526 
527 	len = 1;
528 	buf = xcalloc(1, len);
529 
530 	/* Process the flags first. */
531 	RB_FOREACH(entry, args_tree, &args->tree) {
532 		if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE)
533 			continue;
534 		if (!TAILQ_EMPTY(&entry->values))
535 			continue;
536 
537 		if (*buf == '\0')
538 			args_print_add(&buf, &len, "-");
539 		for (j = 0; j < entry->count; j++)
540 			args_print_add(&buf, &len, "%c", entry->flag);
541 	}
542 
543 	/* Then the flags with arguments. */
544 	RB_FOREACH(entry, args_tree, &args->tree) {
545 		if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE) {
546 			if (*buf != '\0')
547 				args_print_add(&buf, &len, " -%c", entry->flag);
548 			else
549 				args_print_add(&buf, &len, "-%c", entry->flag);
550 			last = entry;
551 			continue;
552 		}
553 		if (TAILQ_EMPTY(&entry->values))
554 			continue;
555 		TAILQ_FOREACH(value, &entry->values, entry) {
556 			if (*buf != '\0')
557 				args_print_add(&buf, &len, " -%c", entry->flag);
558 			else
559 				args_print_add(&buf, &len, "-%c", entry->flag);
560 			args_print_add_value(&buf, &len, value);
561 		}
562 		last = entry;
563 	}
564 	if (last && (last->flags & ARGS_ENTRY_OPTIONAL_VALUE))
565 		args_print_add(&buf, &len, " --");
566 
567 	/* And finally the argument vector. */
568 	for (i = 0; i < args->count; i++)
569 		args_print_add_value(&buf, &len, &args->values[i]);
570 
571 	return (buf);
572 }
573 
574 /* Escape an argument. */
575 char *
576 args_escape(const char *s)
577 {
578 	static const char	 dquoted[] = " #';${}%";
579 	static const char	 squoted[] = " \"";
580 	char			*escaped, *result;
581 	int			 flags, quotes = 0;
582 
583 	if (*s == '\0') {
584 		xasprintf(&result, "''");
585 		return (result);
586 	}
587 	if (s[strcspn(s, dquoted)] != '\0')
588 		quotes = '"';
589 	else if (s[strcspn(s, squoted)] != '\0')
590 		quotes = '\'';
591 
592 	if (s[0] != ' ' &&
593 	    s[1] == '\0' &&
594 	    (quotes != 0 || s[0] == '~')) {
595 		xasprintf(&escaped, "\\%c", s[0]);
596 		return (escaped);
597 	}
598 
599 	flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
600 	if (quotes == '"')
601 		flags |= VIS_DQ;
602 	utf8_stravis(&escaped, s, flags);
603 
604 	if (quotes == '\'')
605 		xasprintf(&result, "'%s'", escaped);
606 	else if (quotes == '"') {
607 		if (*escaped == '~')
608 			xasprintf(&result, "\"\\%s\"", escaped);
609 		else
610 			xasprintf(&result, "\"%s\"", escaped);
611 	} else {
612 		if (*escaped == '~')
613 			xasprintf(&result, "\\%s", escaped);
614 		else
615 			result = xstrdup(escaped);
616 	}
617 	free(escaped);
618 	return (result);
619 }
620 
621 /* Return if an argument is present. */
622 int
623 args_has(struct args *args, u_char flag)
624 {
625 	struct args_entry	*entry;
626 
627 	entry = args_find(args, flag);
628 	if (entry == NULL)
629 		return (0);
630 	return (entry->count);
631 }
632 
633 /* Set argument value in the arguments tree. */
634 void
635 args_set(struct args *args, u_char flag, struct args_value *value, int flags)
636 {
637 	struct args_entry	*entry;
638 
639 	entry = args_find(args, flag);
640 	if (entry == NULL) {
641 		entry = xcalloc(1, sizeof *entry);
642 		entry->flag = flag;
643 		entry->count = 1;
644 		entry->flags = flags;
645 		TAILQ_INIT(&entry->values);
646 		RB_INSERT(args_tree, &args->tree, entry);
647 	} else
648 		entry->count++;
649 	if (value != NULL && value->type != ARGS_NONE)
650 		TAILQ_INSERT_TAIL(&entry->values, value, entry);
651 }
652 
653 /* Get argument value. Will be NULL if it isn't present. */
654 const char *
655 args_get(struct args *args, u_char flag)
656 {
657 	struct args_entry	*entry;
658 
659 	if ((entry = args_find(args, flag)) == NULL)
660 		return (NULL);
661 	if (TAILQ_EMPTY(&entry->values))
662 		return (NULL);
663 	return (TAILQ_LAST(&entry->values, args_values)->string);
664 }
665 
666 /* Get first argument. */
667 u_char
668 args_first(struct args *args, struct args_entry **entry)
669 {
670 	*entry = RB_MIN(args_tree, &args->tree);
671 	if (*entry == NULL)
672 		return (0);
673 	return ((*entry)->flag);
674 }
675 
676 /* Get next argument. */
677 u_char
678 args_next(struct args_entry **entry)
679 {
680 	*entry = RB_NEXT(args_tree, &args->tree, *entry);
681 	if (*entry == NULL)
682 		return (0);
683 	return ((*entry)->flag);
684 }
685 
686 /* Get argument count. */
687 u_int
688 args_count(struct args *args)
689 {
690 	return (args->count);
691 }
692 
693 /* Get argument values. */
694 struct args_value *
695 args_values(struct args *args)
696 {
697 	return (args->values);
698 }
699 
700 /* Get argument value. */
701 struct args_value *
702 args_value(struct args *args, u_int idx)
703 {
704 	if (idx >= args->count)
705 		return (NULL);
706 	return (&args->values[idx]);
707 }
708 
709 /* Return argument as string. */
710 const char *
711 args_string(struct args *args, u_int idx)
712 {
713 	if (idx >= args->count)
714 		return (NULL);
715 	return (args_value_as_string(&args->values[idx]));
716 }
717 
718 /* Make a command now. */
719 struct cmd_list *
720 args_make_commands_now(struct cmd *self, struct cmdq_item *item, u_int idx,
721     int expand)
722 {
723 	struct args_command_state	*state;
724 	char				*error;
725 	struct cmd_list			*cmdlist;
726 
727 	state = args_make_commands_prepare(self, item, idx, NULL, 0, expand);
728 	cmdlist = args_make_commands(state, 0, NULL, &error);
729 	if (cmdlist == NULL) {
730 		cmdq_error(item, "%s", error);
731 		free(error);
732 	}
733 	else
734 		cmdlist->references++;
735 	args_make_commands_free(state);
736 	return (cmdlist);
737 }
738 
739 /* Save bits to make a command later. */
740 struct args_command_state *
741 args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
742     const char *default_command, int wait, int expand)
743 {
744 	struct args			*args = cmd_get_args(self);
745 	struct cmd_find_state		*target = cmdq_get_target(item);
746 	struct client			*tc = cmdq_get_target_client(item);
747 	struct args_value		*value;
748 	struct args_command_state	*state;
749 	const char			*cmd;
750 
751 	state = xcalloc(1, sizeof *state);
752 
753 	if (idx < args->count) {
754 		value = &args->values[idx];
755 		if (value->type == ARGS_COMMANDS) {
756 			state->cmdlist = value->cmdlist;
757 			state->cmdlist->references++;
758 			return (state);
759 		}
760 		cmd = value->string;
761 	} else {
762 		if (default_command == NULL)
763 			fatalx("argument out of range");
764 		cmd = default_command;
765 	}
766 
767 
768 	if (expand)
769 		state->cmd = format_single_from_target(item, cmd);
770 	else
771 		state->cmd = xstrdup(cmd);
772 	log_debug("%s: %s", __func__, state->cmd);
773 
774 	if (wait)
775 		state->pi.item = item;
776 	cmd_get_source(self, &state->pi.file, &state->pi.line);
777 	state->pi.c = tc;
778 	if (state->pi.c != NULL)
779 		state->pi.c->references++;
780 	cmd_find_copy_state(&state->pi.fs, target);
781 
782 	return (state);
783 }
784 
785 /* Return argument as command. */
786 struct cmd_list *
787 args_make_commands(struct args_command_state *state, int argc, char **argv,
788     char **error)
789 {
790 	struct cmd_parse_result	*pr;
791 	char			*cmd, *new_cmd;
792 	int			 i;
793 
794 	if (state->cmdlist != NULL) {
795 		if (argc == 0)
796 			return (state->cmdlist);
797 		return (cmd_list_copy(state->cmdlist, argc, argv));
798 	}
799 
800 	cmd = xstrdup(state->cmd);
801 	for (i = 0; i < argc; i++) {
802 		new_cmd = cmd_template_replace(cmd, argv[i], i + 1);
803 		log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd);
804 		free(cmd);
805 		cmd = new_cmd;
806 	}
807 	log_debug("%s: %s", __func__, cmd);
808 
809 	pr = cmd_parse_from_string(cmd, &state->pi);
810 	free(cmd);
811 	switch (pr->status) {
812 	case CMD_PARSE_ERROR:
813 		*error = pr->error;
814 		return (NULL);
815 	case CMD_PARSE_SUCCESS:
816 		return (pr->cmdlist);
817 	}
818 	fatalx("invalid parse return state");
819 }
820 
821 /* Free commands state. */
822 void
823 args_make_commands_free(struct args_command_state *state)
824 {
825 	if (state->cmdlist != NULL)
826 		cmd_list_free(state->cmdlist);
827 	if (state->pi.c != NULL)
828 		server_client_unref(state->pi.c);
829 	free(state->cmd);
830 	free(state);
831 }
832 
833 /* Get prepared command. */
834 char *
835 args_make_commands_get_command(struct args_command_state *state)
836 {
837 	struct cmd	*first;
838 	int		 n;
839 	char		*s;
840 
841 	if (state->cmdlist != NULL) {
842 		first = cmd_list_first(state->cmdlist);
843 		if (first == NULL)
844 			return (xstrdup(""));
845 		return (xstrdup(cmd_get_entry(first)->name));
846 	}
847 	n = strcspn(state->cmd, " ,");
848 	xasprintf(&s, "%.*s", n, state->cmd);
849 	return (s);
850 }
851 
852 /* Get first value in argument. */
853 struct args_value *
854 args_first_value(struct args *args, u_char flag)
855 {
856 	struct args_entry	*entry;
857 
858 	if ((entry = args_find(args, flag)) == NULL)
859 		return (NULL);
860 	return (TAILQ_FIRST(&entry->values));
861 }
862 
863 /* Get next value in argument. */
864 struct args_value *
865 args_next_value(struct args_value *value)
866 {
867 	return (TAILQ_NEXT(value, entry));
868 }
869 
870 /* Convert an argument value to a number. */
871 long long
872 args_strtonum(struct args *args, u_char flag, long long minval,
873     long long maxval, char **cause)
874 {
875 	const char		*errstr;
876 	long long		 ll;
877 	struct args_entry	*entry;
878 	struct args_value	*value;
879 
880 	if ((entry = args_find(args, flag)) == NULL) {
881 		*cause = xstrdup("missing");
882 		return (0);
883 	}
884 	value = TAILQ_LAST(&entry->values, args_values);
885 	if (value == NULL ||
886 	    value->type != ARGS_STRING ||
887 	    value->string == NULL) {
888 		*cause = xstrdup("missing");
889 		return (0);
890 	}
891 
892 	ll = strtonum(value->string, minval, maxval, &errstr);
893 	if (errstr != NULL) {
894 		*cause = xstrdup(errstr);
895 		return (0);
896 	}
897 
898 	*cause = NULL;
899 	return (ll);
900 }
901 
902 /* Convert an argument value to a number, and expand formats. */
903 long long
904 args_strtonum_and_expand(struct args *args, u_char flag, long long minval,
905     long long maxval, struct cmdq_item *item, char **cause)
906 {
907 	const char		*errstr;
908 	char			*formatted;
909 	long long		 ll;
910 	struct args_entry	*entry;
911 	struct args_value	*value;
912 
913 	if ((entry = args_find(args, flag)) == NULL) {
914 		*cause = xstrdup("missing");
915 		return (0);
916 	}
917 	value = TAILQ_LAST(&entry->values, args_values);
918 	if (value == NULL ||
919 	    value->type != ARGS_STRING ||
920 	    value->string == NULL) {
921 		*cause = xstrdup("missing");
922 		return (0);
923 	}
924 
925 	formatted = format_single_from_target(item, value->string);
926 	ll = strtonum(formatted, minval, maxval, &errstr);
927 	free(formatted);
928 	if (errstr != NULL) {
929 		*cause = xstrdup(errstr);
930 		return (0);
931 	}
932 
933 	*cause = NULL;
934 	return (ll);
935 }
936 
937 /* Convert an argument to a number which may be a percentage. */
938 long long
939 args_percentage(struct args *args, u_char flag, long long minval,
940     long long maxval, long long curval, char **cause)
941 {
942 	const char		*value;
943 	struct args_entry	*entry;
944 
945 	if ((entry = args_find(args, flag)) == NULL) {
946 		*cause = xstrdup("missing");
947 		return (0);
948 	}
949 	if (TAILQ_EMPTY(&entry->values)) {
950 		*cause = xstrdup("empty");
951 		return (0);
952 	}
953 	value = TAILQ_LAST(&entry->values, args_values)->string;
954 	return (args_string_percentage(value, minval, maxval, curval, cause));
955 }
956 
957 /* Convert a string to a number which may be a percentage. */
958 long long
959 args_string_percentage(const char *value, long long minval, long long maxval,
960     long long curval, char **cause)
961 {
962 	const char	*errstr;
963 	long long	 ll;
964 	size_t		 valuelen = strlen(value);
965 	char		*copy;
966 
967 	if (valuelen == 0) {
968 		*cause = xstrdup("empty");
969 		return (0);
970 	}
971 	if (value[valuelen - 1] == '%') {
972 		copy = xstrdup(value);
973 		copy[valuelen - 1] = '\0';
974 
975 		ll = strtonum(copy, 0, 100, &errstr);
976 		free(copy);
977 		if (errstr != NULL) {
978 			*cause = xstrdup(errstr);
979 			return (0);
980 		}
981 		ll = (curval * ll) / 100;
982 		if (ll < minval) {
983 			*cause = xstrdup("too small");
984 			return (0);
985 		}
986 		if (ll > maxval) {
987 			*cause = xstrdup("too large");
988 			return (0);
989 		}
990 	} else {
991 		ll = strtonum(value, minval, maxval, &errstr);
992 		if (errstr != NULL) {
993 			*cause = xstrdup(errstr);
994 			return (0);
995 		}
996 	}
997 
998 	*cause = NULL;
999 	return (ll);
1000 }
1001 
1002 /*
1003  * Convert an argument to a number which may be a percentage, and expand
1004  * formats.
1005  */
1006 long long
1007 args_percentage_and_expand(struct args *args, u_char flag, long long minval,
1008     long long maxval, long long curval, struct cmdq_item *item, char **cause)
1009 {
1010 	const char		*value;
1011 	struct args_entry	*entry;
1012 
1013 	if ((entry = args_find(args, flag)) == NULL) {
1014 		*cause = xstrdup("missing");
1015 		return (0);
1016 	}
1017 	if (TAILQ_EMPTY(&entry->values)) {
1018 		*cause = xstrdup("empty");
1019 		return (0);
1020 	}
1021 	value = TAILQ_LAST(&entry->values, args_values)->string;
1022 	return (args_string_percentage_and_expand(value, minval, maxval, curval,
1023 		    item, cause));
1024 }
1025 
1026 /*
1027  * Convert a string to a number which may be a percentage, and expand formats.
1028  */
1029 long long
1030 args_string_percentage_and_expand(const char *value, long long minval,
1031     long long maxval, long long curval, struct cmdq_item *item, char **cause)
1032 {
1033 	const char	*errstr;
1034 	long long	 ll;
1035 	size_t		 valuelen = strlen(value);
1036 	char		*copy, *f;
1037 
1038 	if (value[valuelen - 1] == '%') {
1039 		copy = xstrdup(value);
1040 		copy[valuelen - 1] = '\0';
1041 
1042 		f = format_single_from_target(item, copy);
1043 		ll = strtonum(f, 0, 100, &errstr);
1044 		free(f);
1045 		free(copy);
1046 		if (errstr != NULL) {
1047 			*cause = xstrdup(errstr);
1048 			return (0);
1049 		}
1050 		ll = (curval * ll) / 100;
1051 		if (ll < minval) {
1052 			*cause = xstrdup("too small");
1053 			return (0);
1054 		}
1055 		if (ll > maxval) {
1056 			*cause = xstrdup("too large");
1057 			return (0);
1058 		}
1059 	} else {
1060 		f = format_single_from_target(item, value);
1061 		ll = strtonum(f, minval, maxval, &errstr);
1062 		free(f);
1063 		if (errstr != NULL) {
1064 			*cause = xstrdup(errstr);
1065 			return (0);
1066 		}
1067 	}
1068 
1069 	*cause = NULL;
1070 	return (ll);
1071 }
1072