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