Add a way to force a colour to RGB and a format to display it.
[tmux-openbsd.git] / arguments.c
blob985aadc05f488827c6d0574c63b7ce27160060f1
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 (flag == '?') {
157 args_free(args);
158 return (NULL);
160 if (!isalnum(flag)) {
161 xasprintf(cause, "invalid flag -%c", flag);
162 args_free(args);
163 return (NULL);
165 found = strchr(parse->template, flag);
166 if (found == NULL) {
167 xasprintf(cause, "unknown flag -%c", flag);
168 args_free(args);
169 return (NULL);
171 argument = *++found;
172 if (argument != ':') {
173 log_debug("%s: -%c", __func__, flag);
174 args_set(args, flag, NULL);
175 continue;
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);
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);
196 args_copy_value(new, &values[i++]);
198 s = args_value_as_string(new);
199 log_debug("%s: -%c = %s", __func__, flag, s);
200 args_set(args, flag, new);
201 break;
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];
209 s = args_value_as_string(value);
210 log_debug("%s: %u = %s (type %d)", __func__, i, s,
211 value->type);
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);
219 } else
220 type = ARGS_PARSE_STRING;
222 args->values = xrecallocarray(args->values,
223 args->count, args->count + 1, sizeof *args->values);
224 new = &args->values[args->count++];
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);
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);
250 args_copy_value(new, value);
251 break;
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);
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);
270 return (args);
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)
278 char *s, *expanded;
279 int i;
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;
292 to->string = expanded;
293 break;
294 case ARGS_COMMANDS:
295 to->cmdlist = cmd_list_copy(from->cmdlist, argc, argv);
296 break;
300 /* Copy an arguments set. */
301 struct args *
302 args_copy(struct args *args, int argc, char **argv)
304 struct args *new_args;
305 struct args_entry *entry;
306 struct args_value *value, *new_value;
307 u_int i;
309 cmd_log_argv(argc, argv, "%s", __func__);
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;
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);
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);
332 return (new_args);
335 /* Free a value. */
336 void
337 args_free_value(struct args_value *value)
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;
349 free(value->cached);
352 /* Free values. */
353 void
354 args_free_values(struct args_value *values, u_int count)
356 u_int i;
358 for (i = 0; i < count; i++)
359 args_free_value(&values[i]);
362 /* Free an arguments set. */
363 void
364 args_free(struct args *args)
366 struct args_entry *entry;
367 struct args_entry *entry1;
368 struct args_value *value;
369 struct args_value *value1;
371 args_free_values(args->values, args->count);
372 free(args->values);
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);
381 free(entry);
384 free(args);
387 /* Convert arguments to vector. */
388 void
389 args_to_vector(struct args *args, int *argc, char ***argv)
391 char *s;
392 u_int i;
394 *argc = 0;
395 *argv = NULL;
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;
413 /* Convert arguments from vector. */
414 struct args_value *
415 args_from_vector(int argc, char **argv)
417 struct args_value *values;
418 int i;
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]);
425 return (values);
428 /* Add to string. */
429 static void printflike(3, 4)
430 args_print_add(char **buf, size_t *len, const char *fmt, ...)
432 va_list ap;
433 char *s;
434 size_t slen;
436 va_start(ap, fmt);
437 slen = xvasprintf(&s, fmt, ap);
438 va_end(ap);
440 *len += slen;
441 *buf = xrealloc(*buf, *len);
443 strlcat(*buf, s, *len);
444 free(s);
447 /* Add value to string. */
448 static void
449 args_print_add_value(char **buf, size_t *len, struct args_value *value)
451 char *expanded = NULL;
453 if (**buf != '\0')
454 args_print_add(buf, len, " ");
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;
468 free(expanded);
471 /* Print a set of arguments. */
472 char *
473 args_print(struct args *args)
475 size_t len;
476 char *buf;
477 u_int i, j;
478 struct args_entry *entry;
479 struct args_value *value;
481 len = 1;
482 buf = xcalloc(1, len);
484 /* Process the flags first. */
485 RB_FOREACH(entry, args_tree, &args->tree) {
486 if (!TAILQ_EMPTY(&entry->values))
487 continue;
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);
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);
506 /* And finally the argument vector. */
507 for (i = 0; i < args->count; i++)
508 args_print_add_value(&buf, &len, &args->values[i]);
510 return (buf);
513 /* Escape an argument. */
514 char *
515 args_escape(const char *s)
517 static const char dquoted[] = " #';${}%";
518 static const char squoted[] = " \"";
519 char *escaped, *result;
520 int flags, quotes = 0;
522 if (*s == '\0') {
523 xasprintf(&result, "''");
524 return (result);
526 if (s[strcspn(s, dquoted)] != '\0')
527 quotes = '"';
528 else if (s[strcspn(s, squoted)] != '\0')
529 quotes = '\'';
531 if (s[0] != ' ' &&
532 s[1] == '\0' &&
533 (quotes != 0 || s[0] == '~')) {
534 xasprintf(&escaped, "\\%c", s[0]);
535 return (escaped);
538 flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
539 if (quotes == '"')
540 flags |= VIS_DQ;
541 utf8_stravis(&escaped, s, flags);
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);
556 free(escaped);
557 return (result);
560 /* Return if an argument is present. */
562 args_has(struct args *args, u_char flag)
564 struct args_entry *entry;
566 entry = args_find(args, flag);
567 if (entry == NULL)
568 return (0);
569 return (entry->count);
572 /* Set argument value in the arguments tree. */
573 void
574 args_set(struct args *args, u_char flag, struct args_value *value)
576 struct args_entry *entry;
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);
591 /* Get argument value. Will be NULL if it isn't present. */
592 const char *
593 args_get(struct args *args, u_char flag)
595 struct args_entry *entry;
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);
604 /* Get first argument. */
605 u_char
606 args_first(struct args *args, struct args_entry **entry)
608 *entry = RB_MIN(args_tree, &args->tree);
609 if (*entry == NULL)
610 return (0);
611 return ((*entry)->flag);
614 /* Get next argument. */
615 u_char
616 args_next(struct args_entry **entry)
618 *entry = RB_NEXT(args_tree, &args->tree, *entry);
619 if (*entry == NULL)
620 return (0);
621 return ((*entry)->flag);
624 /* Get argument count. */
625 u_int
626 args_count(struct args *args)
628 return (args->count);
631 /* Get argument values. */
632 struct args_value *
633 args_values(struct args *args)
635 return (args->values);
638 /* Get argument value. */
639 struct args_value *
640 args_value(struct args *args, u_int idx)
642 if (idx >= args->count)
643 return (NULL);
644 return (&args->values[idx]);
647 /* Return argument as string. */
648 const char *
649 args_string(struct args *args, u_int idx)
651 if (idx >= args->count)
652 return (NULL);
653 return (args_value_as_string(&args->values[idx]));
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)
661 struct args_command_state *state;
662 char *error;
663 struct cmd_list *cmdlist;
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);
671 else
672 cmdlist->references++;
673 args_make_commands_free(state);
674 return (cmdlist);
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)
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;
689 state = xcalloc(1, sizeof *state);
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);
698 cmd = value->string;
699 } else {
700 if (default_command == NULL)
701 fatalx("argument out of range");
702 cmd = default_command;
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);
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);
720 return (state);
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)
728 struct cmd_parse_result *pr;
729 char *cmd, *new_cmd;
730 int i;
732 if (state->cmdlist != NULL) {
733 if (argc == 0)
734 return (state->cmdlist);
735 return (cmd_list_copy(state->cmdlist, argc, argv));
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;
745 log_debug("%s: %s", __func__, cmd);
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);
758 /* Free commands state. */
759 void
760 args_make_commands_free(struct args_command_state *state)
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);
770 /* Get prepared command. */
771 char *
772 args_make_commands_get_command(struct args_command_state *state)
774 struct cmd *first;
775 int n;
776 char *s;
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));
784 n = strcspn(state->cmd, " ,");
785 xasprintf(&s, "%.*s", n, state->cmd);
786 return (s);
789 /* Get first value in argument. */
790 struct args_value *
791 args_first_value(struct args *args, u_char flag)
793 struct args_entry *entry;
795 if ((entry = args_find(args, flag)) == NULL)
796 return (NULL);
797 return (TAILQ_FIRST(&entry->values));
800 /* Get next value in argument. */
801 struct args_value *
802 args_next_value(struct args_value *value)
804 return (TAILQ_NEXT(value, entry));
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)
812 const char *errstr;
813 long long ll;
814 struct args_entry *entry;
815 struct args_value *value;
817 if ((entry = args_find(args, flag)) == NULL) {
818 *cause = xstrdup("missing");
819 return (0);
821 value = TAILQ_LAST(&entry->values, args_values);
823 ll = strtonum(value->string, minval, maxval, &errstr);
824 if (errstr != NULL) {
825 *cause = xstrdup(errstr);
826 return (0);
829 *cause = NULL;
830 return (ll);
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)
838 const char *value;
839 struct args_entry *entry;
841 if ((entry = args_find(args, flag)) == NULL) {
842 *cause = xstrdup("missing");
843 return (0);
845 value = TAILQ_LAST(&entry->values, args_values)->string;
846 return (args_string_percentage(value, minval, maxval, curval, cause));
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)
854 const char *errstr;
855 long long ll;
856 size_t valuelen = strlen(value);
857 char *copy;
859 if (value[valuelen - 1] == '%') {
860 copy = xstrdup(value);
861 copy[valuelen - 1] = '\0';
863 ll = strtonum(copy, 0, 100, &errstr);
864 free(copy);
865 if (errstr != NULL) {
866 *cause = xstrdup(errstr);
867 return (0);
869 ll = (curval * ll) / 100;
870 if (ll < minval) {
871 *cause = xstrdup("too small");
872 return (0);
874 if (ll > maxval) {
875 *cause = xstrdup("too large");
876 return (0);
878 } else {
879 ll = strtonum(value, minval, maxval, &errstr);
880 if (errstr != NULL) {
881 *cause = xstrdup(errstr);
882 return (0);
886 *cause = NULL;
887 return (ll);