Expand argument to run-shell again.
[tmux-openbsd.git] / arguments.c
blob1555c2f01fb30e24aaa8b1b7ec1459546148c64d
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <vis.h>
26 #include "tmux.h"
29 * Manipulate command arguments.
32 /* List of argument values. */
33 TAILQ_HEAD(args_values, args_value);
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;
43 /* Parsed argument flags and values. */
44 struct args {
45 struct args_tree tree;
46 u_int count;
47 struct args_value *values;
50 /* Prepared command state. */
51 struct args_command_state {
52 struct cmd_list *cmdlist;
53 char *cmd;
54 struct cmd_parse_input pi;
57 static struct args_entry *args_find(struct args *, u_char);
59 static int args_cmp(struct args_entry *, struct args_entry *);
60 RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
62 /* Arguments tree comparison function. */
63 static int
64 args_cmp(struct args_entry *a1, struct args_entry *a2)
66 return (a1->flag - a2->flag);
69 /* Find a flag in the arguments tree. */
70 static struct args_entry *
71 args_find(struct args *args, u_char flag)
73 struct args_entry entry;
75 entry.flag = flag;
76 return (RB_FIND(args_tree, &args->tree, &entry));
79 /* Copy value. */
80 static void
81 args_copy_value(struct args_value *to, struct args_value *from)
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;
97 /* Get value as string. */
98 static const char *
99 args_value_as_string(struct args_value *value)
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);
113 /* Create an empty arguments set. */
114 struct args *
115 args_create(void)
117 struct args *args;
119 args = xcalloc(1, sizeof *args);
120 RB_INIT(&args->tree);
121 return (args);
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)
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;
136 if (count == 0)
137 return (args_create());
139 args = args_create();
140 for (i = 1; i < count; /* nothing */) {
141 value = &values[i];
142 if (value->type != ARGS_STRING)
143 break;
145 string = value->string;
146 if (*string++ != '-' || *string == '\0')
147 break;
148 i++;
149 if (string[0] == '-' && string[1] == '\0')
150 break;
152 for (;;) {
153 flag = *string++;
154 if (flag == '\0')
155 break;
156 if (!isalnum(flag)) {
157 xasprintf(cause, "invalid flag -%c", flag);
158 args_free(args);
159 return (NULL);
161 found = strchr(parse->template, flag);
162 if (found == NULL) {
163 xasprintf(cause, "unknown flag -%c", flag);
164 args_free(args);
165 return (NULL);
167 argument = *++found;
168 if (argument != ':') {
169 log_debug("%s: -%c", __func__, flag);
170 args_set(args, flag, NULL);
171 continue;
173 new = xcalloc(1, sizeof *new);
174 if (*string != '\0') {
175 new->type = ARGS_STRING;
176 new->string = xstrdup(string);
177 } else {
178 if (i == count) {
179 xasprintf(cause,
180 "-%c expects an argument",
181 flag);
182 args_free(args);
183 return (NULL);
185 if (values[i].type != ARGS_STRING) {
186 xasprintf(cause,
187 "-%c argument must be a string",
188 flag);
189 args_free(args);
190 return (NULL);
192 args_copy_value(new, &values[i++]);
194 s = args_value_as_string(new);
195 log_debug("%s: -%c = %s", __func__, flag, s);
196 args_set(args, flag, new);
197 break;
200 log_debug("%s: flags end at %u of %u", __func__, i, count);
201 if (i != count) {
202 for (/* nothing */; i < count; i++) {
203 value = &values[i];
205 s = args_value_as_string(value);
206 log_debug("%s: %u = %s (type %d)", __func__, i, s,
207 value->type);
209 if (parse->cb != NULL) {
210 type = parse->cb(args, args->count, cause);
211 if (type == ARGS_PARSE_INVALID) {
212 args_free(args);
213 return (NULL);
215 } else
216 type = ARGS_PARSE_STRING;
218 args->values = xrecallocarray(args->values,
219 args->count, args->count + 1, sizeof *args->values);
220 new = &args->values[args->count++];
222 switch (type) {
223 case ARGS_PARSE_INVALID:
224 fatalx("unexpected argument type");
225 case ARGS_PARSE_STRING:
226 if (value->type != ARGS_STRING) {
227 xasprintf(cause,
228 "argument %u must be \"string\"",
229 args->count);
230 args_free(args);
231 return (NULL);
233 args_copy_value(new, value);
234 break;
235 case ARGS_PARSE_COMMANDS_OR_STRING:
236 args_copy_value(new, value);
237 break;
238 case ARGS_PARSE_COMMANDS:
239 if (value->type != ARGS_COMMANDS) {
240 xasprintf(cause,
241 "argument %u must be { commands }",
242 args->count);
243 args_free(args);
244 return (NULL);
246 args_copy_value(new, value);
247 break;
252 if (parse->lower != -1 && args->count < (u_int)parse->lower) {
253 xasprintf(cause,
254 "too few arguments (need at least %u)",
255 parse->lower);
256 args_free(args);
257 return (NULL);
259 if (parse->upper != -1 && args->count > (u_int)parse->upper) {
260 xasprintf(cause,
261 "too many arguments (need at most %u)",
262 parse->upper);
263 args_free(args);
264 return (NULL);
266 return (args);
269 /* Copy and expand a value. */
270 static void
271 args_copy_copy_value(struct args_value *to, struct args_value *from, int argc,
272 char **argv)
274 char *s, *expanded;
275 int i;
277 to->type = from->type;
278 switch (from->type) {
279 case ARGS_NONE:
280 break;
281 case ARGS_STRING:
282 expanded = xstrdup(from->string);
283 for (i = 0; i < argc; i++) {
284 s = cmd_template_replace(expanded, argv[i], i + 1);
285 free(expanded);
286 expanded = s;
288 to->string = expanded;
289 break;
290 case ARGS_COMMANDS:
291 to->cmdlist = cmd_list_copy(from->cmdlist, argc, argv);
292 break;
296 /* Copy an arguments set. */
297 struct args *
298 args_copy(struct args *args, int argc, char **argv)
300 struct args *new_args;
301 struct args_entry *entry;
302 struct args_value *value, *new_value;
303 u_int i;
305 cmd_log_argv(argc, argv, "%s", __func__);
307 new_args = args_create();
308 RB_FOREACH(entry, args_tree, &args->tree) {
309 if (TAILQ_EMPTY(&entry->values)) {
310 for (i = 0; i < entry->count; i++)
311 args_set(new_args, entry->flag, NULL);
312 continue;
314 TAILQ_FOREACH(value, &entry->values, entry) {
315 new_value = xcalloc(1, sizeof *new_value);
316 args_copy_copy_value(new_value, value, argc, argv);
317 args_set(new_args, entry->flag, new_value);
320 if (args->count == 0)
321 return (new_args);
322 new_args->count = args->count;
323 new_args->values = xcalloc(args->count, sizeof *new_args->values);
324 for (i = 0; i < args->count; i++) {
325 new_value = &new_args->values[i];
326 args_copy_copy_value(new_value, &args->values[i], argc, argv);
328 return (new_args);
331 /* Free a value. */
332 void
333 args_free_value(struct args_value *value)
335 switch (value->type) {
336 case ARGS_NONE:
337 break;
338 case ARGS_STRING:
339 free(value->string);
340 break;
341 case ARGS_COMMANDS:
342 cmd_list_free(value->cmdlist);
343 break;
345 free(value->cached);
348 /* Free values. */
349 void
350 args_free_values(struct args_value *values, u_int count)
352 u_int i;
354 for (i = 0; i < count; i++)
355 args_free_value(&values[i]);
358 /* Free an arguments set. */
359 void
360 args_free(struct args *args)
362 struct args_entry *entry;
363 struct args_entry *entry1;
364 struct args_value *value;
365 struct args_value *value1;
367 args_free_values(args->values, args->count);
368 free(args->values);
370 RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
371 RB_REMOVE(args_tree, &args->tree, entry);
372 TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
373 TAILQ_REMOVE(&entry->values, value, entry);
374 args_free_value(value);
375 free(value);
377 free(entry);
380 free(args);
383 /* Convert arguments to vector. */
384 void
385 args_to_vector(struct args *args, int *argc, char ***argv)
387 char *s;
388 u_int i;
390 *argc = 0;
391 *argv = NULL;
393 for (i = 0; i < args->count; i++) {
394 switch (args->values[i].type) {
395 case ARGS_NONE:
396 break;
397 case ARGS_STRING:
398 cmd_append_argv(argc, argv, args->values[i].string);
399 break;
400 case ARGS_COMMANDS:
401 s = cmd_list_print(args->values[i].cmdlist, 0);
402 cmd_append_argv(argc, argv, s);
403 free(s);
404 break;
409 /* Convert arguments from vector. */
410 struct args_value *
411 args_from_vector(int argc, char **argv)
413 struct args_value *values;
414 int i;
416 values = xcalloc(argc, sizeof *values);
417 for (i = 0; i < argc; i++) {
418 values[i].type = ARGS_STRING;
419 values[i].string = xstrdup(argv[i]);
421 return (values);
424 /* Add to string. */
425 static void printflike(3, 4)
426 args_print_add(char **buf, size_t *len, const char *fmt, ...)
428 va_list ap;
429 char *s;
430 size_t slen;
432 va_start(ap, fmt);
433 slen = xvasprintf(&s, fmt, ap);
434 va_end(ap);
436 *len += slen;
437 *buf = xrealloc(*buf, *len);
439 strlcat(*buf, s, *len);
440 free(s);
443 /* Add value to string. */
444 static void
445 args_print_add_value(char **buf, size_t *len, struct args_value *value)
447 char *expanded = NULL;
449 if (**buf != '\0')
450 args_print_add(buf, len, " ");
452 switch (value->type) {
453 case ARGS_NONE:
454 break;
455 case ARGS_COMMANDS:
456 expanded = cmd_list_print(value->cmdlist, 0);
457 args_print_add(buf, len, "{ %s }", expanded);
458 break;
459 case ARGS_STRING:
460 expanded = args_escape(value->string);
461 args_print_add(buf, len, "%s", expanded);
462 break;
464 free(expanded);
467 /* Print a set of arguments. */
468 char *
469 args_print(struct args *args)
471 size_t len;
472 char *buf;
473 u_int i, j;
474 struct args_entry *entry;
475 struct args_value *value;
477 len = 1;
478 buf = xcalloc(1, len);
480 /* Process the flags first. */
481 RB_FOREACH(entry, args_tree, &args->tree) {
482 if (!TAILQ_EMPTY(&entry->values))
483 continue;
485 if (*buf == '\0')
486 args_print_add(&buf, &len, "-");
487 for (j = 0; j < entry->count; j++)
488 args_print_add(&buf, &len, "%c", entry->flag);
491 /* Then the flags with arguments. */
492 RB_FOREACH(entry, args_tree, &args->tree) {
493 TAILQ_FOREACH(value, &entry->values, entry) {
494 if (*buf != '\0')
495 args_print_add(&buf, &len, " -%c", entry->flag);
496 else
497 args_print_add(&buf, &len, "-%c", entry->flag);
498 args_print_add_value(&buf, &len, value);
502 /* And finally the argument vector. */
503 for (i = 0; i < args->count; i++)
504 args_print_add_value(&buf, &len, &args->values[i]);
506 return (buf);
509 /* Escape an argument. */
510 char *
511 args_escape(const char *s)
513 static const char dquoted[] = " #';${}%";
514 static const char squoted[] = " \"";
515 char *escaped, *result;
516 int flags, quotes = 0;
518 if (*s == '\0') {
519 xasprintf(&result, "''");
520 return (result);
522 if (s[strcspn(s, dquoted)] != '\0')
523 quotes = '"';
524 else if (s[strcspn(s, squoted)] != '\0')
525 quotes = '\'';
527 if (s[0] != ' ' &&
528 s[1] == '\0' &&
529 (quotes != 0 || s[0] == '~')) {
530 xasprintf(&escaped, "\\%c", s[0]);
531 return (escaped);
534 flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
535 if (quotes == '"')
536 flags |= VIS_DQ;
537 utf8_stravis(&escaped, s, flags);
539 if (quotes == '\'')
540 xasprintf(&result, "'%s'", escaped);
541 else if (quotes == '"') {
542 if (*escaped == '~')
543 xasprintf(&result, "\"\\%s\"", escaped);
544 else
545 xasprintf(&result, "\"%s\"", escaped);
546 } else {
547 if (*escaped == '~')
548 xasprintf(&result, "\\%s", escaped);
549 else
550 result = xstrdup(escaped);
552 free(escaped);
553 return (result);
556 /* Return if an argument is present. */
558 args_has(struct args *args, u_char flag)
560 struct args_entry *entry;
562 entry = args_find(args, flag);
563 if (entry == NULL)
564 return (0);
565 return (entry->count);
568 /* Set argument value in the arguments tree. */
569 void
570 args_set(struct args *args, u_char flag, struct args_value *value)
572 struct args_entry *entry;
574 entry = args_find(args, flag);
575 if (entry == NULL) {
576 entry = xcalloc(1, sizeof *entry);
577 entry->flag = flag;
578 entry->count = 1;
579 TAILQ_INIT(&entry->values);
580 RB_INSERT(args_tree, &args->tree, entry);
581 } else
582 entry->count++;
583 if (value != NULL && value->type != ARGS_NONE)
584 TAILQ_INSERT_TAIL(&entry->values, value, entry);
587 /* Get argument value. Will be NULL if it isn't present. */
588 const char *
589 args_get(struct args *args, u_char flag)
591 struct args_entry *entry;
593 if ((entry = args_find(args, flag)) == NULL)
594 return (NULL);
595 if (TAILQ_EMPTY(&entry->values))
596 return (NULL);
597 return (TAILQ_LAST(&entry->values, args_values)->string);
600 /* Get first argument. */
601 u_char
602 args_first(struct args *args, struct args_entry **entry)
604 *entry = RB_MIN(args_tree, &args->tree);
605 if (*entry == NULL)
606 return (0);
607 return ((*entry)->flag);
610 /* Get next argument. */
611 u_char
612 args_next(struct args_entry **entry)
614 *entry = RB_NEXT(args_tree, &args->tree, *entry);
615 if (*entry == NULL)
616 return (0);
617 return ((*entry)->flag);
620 /* Get argument count. */
621 u_int
622 args_count(struct args *args)
624 return (args->count);
627 /* Get argument values. */
628 struct args_value *
629 args_values(struct args *args)
631 return (args->values);
634 /* Get argument value. */
635 struct args_value *
636 args_value(struct args *args, u_int idx)
638 if (idx >= args->count)
639 return (NULL);
640 return (&args->values[idx]);
643 /* Return argument as string. */
644 const char *
645 args_string(struct args *args, u_int idx)
647 if (idx >= args->count)
648 return (NULL);
649 return (args_value_as_string(&args->values[idx]));
652 /* Make a command now. */
653 struct cmd_list *
654 args_make_commands_now(struct cmd *self, struct cmdq_item *item, u_int idx,
655 int expand)
657 struct args_command_state *state;
658 char *error;
659 struct cmd_list *cmdlist;
661 state = args_make_commands_prepare(self, item, idx, NULL, 0, expand);
662 cmdlist = args_make_commands(state, 0, NULL, &error);
663 if (cmdlist == NULL) {
664 cmdq_error(item, "%s", error);
665 free(error);
667 else
668 cmdlist->references++;
669 args_make_commands_free(state);
670 return (cmdlist);
673 /* Save bits to make a command later. */
674 struct args_command_state *
675 args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
676 const char *default_command, int wait, int expand)
678 struct args *args = cmd_get_args(self);
679 struct cmd_find_state *target = cmdq_get_target(item);
680 struct client *tc = cmdq_get_target_client(item);
681 struct args_value *value;
682 struct args_command_state *state;
683 const char *cmd;
685 state = xcalloc(1, sizeof *state);
687 if (idx < args->count) {
688 value = &args->values[idx];
689 if (value->type == ARGS_COMMANDS) {
690 state->cmdlist = value->cmdlist;
691 state->cmdlist->references++;
692 return (state);
694 cmd = value->string;
695 } else {
696 if (default_command == NULL)
697 fatalx("argument out of range");
698 cmd = default_command;
702 if (expand)
703 state->cmd = format_single_from_target(item, cmd);
704 else
705 state->cmd = xstrdup(cmd);
706 log_debug("%s: %s", __func__, state->cmd);
708 if (wait)
709 state->pi.item = item;
710 cmd_get_source(self, &state->pi.file, &state->pi.line);
711 state->pi.c = tc;
712 if (state->pi.c != NULL)
713 state->pi.c->references++;
714 cmd_find_copy_state(&state->pi.fs, target);
716 return (state);
719 /* Return argument as command. */
720 struct cmd_list *
721 args_make_commands(struct args_command_state *state, int argc, char **argv,
722 char **error)
724 struct cmd_parse_result *pr;
725 char *cmd, *new_cmd;
726 int i;
728 if (state->cmdlist != NULL) {
729 if (argc == 0)
730 return (state->cmdlist);
731 return (cmd_list_copy(state->cmdlist, argc, argv));
734 cmd = xstrdup(state->cmd);
735 for (i = 0; i < argc; i++) {
736 new_cmd = cmd_template_replace(cmd, argv[i], i + 1);
737 log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd);
738 free(cmd);
739 cmd = new_cmd;
741 log_debug("%s: %s", __func__, cmd);
743 pr = cmd_parse_from_string(cmd, &state->pi);
744 free(cmd);
745 switch (pr->status) {
746 case CMD_PARSE_ERROR:
747 *error = pr->error;
748 return (NULL);
749 case CMD_PARSE_SUCCESS:
750 return (pr->cmdlist);
754 /* Free commands state. */
755 void
756 args_make_commands_free(struct args_command_state *state)
758 if (state->cmdlist != NULL)
759 cmd_list_free(state->cmdlist);
760 if (state->pi.c != NULL)
761 server_client_unref(state->pi.c);
762 free(state->cmd);
763 free(state);
766 /* Get prepared command. */
767 char *
768 args_make_commands_get_command(struct args_command_state *state)
770 struct cmd *first;
771 int n;
772 char *s;
774 if (state->cmdlist != NULL) {
775 first = cmd_list_first(state->cmdlist);
776 if (first == NULL)
777 return (xstrdup(""));
778 return (xstrdup(cmd_get_entry(first)->name));
780 n = strcspn(state->cmd, " ,");
781 xasprintf(&s, "%.*s", n, state->cmd);
782 return (s);
785 /* Get first value in argument. */
786 struct args_value *
787 args_first_value(struct args *args, u_char flag)
789 struct args_entry *entry;
791 if ((entry = args_find(args, flag)) == NULL)
792 return (NULL);
793 return (TAILQ_FIRST(&entry->values));
796 /* Get next value in argument. */
797 struct args_value *
798 args_next_value(struct args_value *value)
800 return (TAILQ_NEXT(value, entry));
803 /* Convert an argument value to a number. */
804 long long
805 args_strtonum(struct args *args, u_char flag, long long minval,
806 long long maxval, char **cause)
808 const char *errstr;
809 long long ll;
810 struct args_entry *entry;
811 struct args_value *value;
813 if ((entry = args_find(args, flag)) == NULL) {
814 *cause = xstrdup("missing");
815 return (0);
817 value = TAILQ_LAST(&entry->values, args_values);
819 ll = strtonum(value->string, minval, maxval, &errstr);
820 if (errstr != NULL) {
821 *cause = xstrdup(errstr);
822 return (0);
825 *cause = NULL;
826 return (ll);
829 /* Convert an argument to a number which may be a percentage. */
830 long long
831 args_percentage(struct args *args, u_char flag, long long minval,
832 long long maxval, long long curval, char **cause)
834 const char *value;
835 struct args_entry *entry;
837 if ((entry = args_find(args, flag)) == NULL) {
838 *cause = xstrdup("missing");
839 return (0);
841 value = TAILQ_LAST(&entry->values, args_values)->string;
842 return (args_string_percentage(value, minval, maxval, curval, cause));
845 /* Convert a string to a number which may be a percentage. */
846 long long
847 args_string_percentage(const char *value, long long minval, long long maxval,
848 long long curval, char **cause)
850 const char *errstr;
851 long long ll;
852 size_t valuelen = strlen(value);
853 char *copy;
855 if (value[valuelen - 1] == '%') {
856 copy = xstrdup(value);
857 copy[valuelen - 1] = '\0';
859 ll = strtonum(copy, 0, 100, &errstr);
860 free(copy);
861 if (errstr != NULL) {
862 *cause = xstrdup(errstr);
863 return (0);
865 ll = (curval * ll) / 100;
866 if (ll < minval) {
867 *cause = xstrdup("too small");
868 return (0);
870 if (ll > maxval) {
871 *cause = xstrdup("too large");
872 return (0);
874 } else {
875 ll = strtonum(value, minval, maxval, &errstr);
876 if (errstr != NULL) {
877 *cause = xstrdup(errstr);
878 return (0);
882 *cause = NULL;
883 return (ll);