Do not notify window-layout-changed if the window is about to be
[tmux-openbsd.git] / options.c
blobfef5637ecf03f87396f7b53e5127ac51f75595f8
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2008 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 <fnmatch.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "tmux.h"
30 * Option handling; each option has a name, type and value and is stored in
31 * a red-black tree.
34 struct options_array_item {
35 u_int index;
36 union options_value value;
37 RB_ENTRY(options_array_item) entry;
39 static int
40 options_array_cmp(struct options_array_item *a1, struct options_array_item *a2)
42 if (a1->index < a2->index)
43 return (-1);
44 if (a1->index > a2->index)
45 return (1);
46 return (0);
48 RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp);
50 struct options_entry {
51 struct options *owner;
53 const char *name;
54 const struct options_table_entry *tableentry;
55 union options_value value;
57 int cached;
58 struct style style;
60 RB_ENTRY(options_entry) entry;
63 struct options {
64 RB_HEAD(options_tree, options_entry) tree;
65 struct options *parent;
68 static struct options_entry *options_add(struct options *, const char *);
69 static void options_remove(struct options_entry *);
71 #define OPTIONS_IS_STRING(o) \
72 ((o)->tableentry == NULL || \
73 (o)->tableentry->type == OPTIONS_TABLE_STRING)
74 #define OPTIONS_IS_NUMBER(o) \
75 ((o)->tableentry != NULL && \
76 ((o)->tableentry->type == OPTIONS_TABLE_NUMBER || \
77 (o)->tableentry->type == OPTIONS_TABLE_KEY || \
78 (o)->tableentry->type == OPTIONS_TABLE_COLOUR || \
79 (o)->tableentry->type == OPTIONS_TABLE_FLAG || \
80 (o)->tableentry->type == OPTIONS_TABLE_CHOICE))
81 #define OPTIONS_IS_COMMAND(o) \
82 ((o)->tableentry != NULL && \
83 (o)->tableentry->type == OPTIONS_TABLE_COMMAND)
85 #define OPTIONS_IS_ARRAY(o) \
86 ((o)->tableentry != NULL && \
87 ((o)->tableentry->flags & OPTIONS_TABLE_IS_ARRAY))
89 static int options_cmp(struct options_entry *, struct options_entry *);
90 RB_GENERATE_STATIC(options_tree, options_entry, entry, options_cmp);
92 static int
93 options_cmp(struct options_entry *lhs, struct options_entry *rhs)
95 return (strcmp(lhs->name, rhs->name));
98 static const char *
99 options_map_name(const char *name)
101 const struct options_name_map *map;
103 for (map = options_other_names; map->from != NULL; map++) {
104 if (strcmp(map->from, name) == 0)
105 return (map->to);
107 return (name);
110 static const struct options_table_entry *
111 options_parent_table_entry(struct options *oo, const char *s)
113 struct options_entry *o;
115 if (oo->parent == NULL)
116 fatalx("no parent options for %s", s);
117 o = options_get(oo->parent, s);
118 if (o == NULL)
119 fatalx("%s not in parent options", s);
120 return (o->tableentry);
123 static void
124 options_value_free(struct options_entry *o, union options_value *ov)
126 if (OPTIONS_IS_STRING(o))
127 free(ov->string);
128 if (OPTIONS_IS_COMMAND(o) && ov->cmdlist != NULL)
129 cmd_list_free(ov->cmdlist);
132 static char *
133 options_value_to_string(struct options_entry *o, union options_value *ov,
134 int numeric)
136 char *s;
138 if (OPTIONS_IS_COMMAND(o))
139 return (cmd_list_print(ov->cmdlist, 0));
140 if (OPTIONS_IS_NUMBER(o)) {
141 switch (o->tableentry->type) {
142 case OPTIONS_TABLE_NUMBER:
143 xasprintf(&s, "%lld", ov->number);
144 break;
145 case OPTIONS_TABLE_KEY:
146 s = xstrdup(key_string_lookup_key(ov->number, 0));
147 break;
148 case OPTIONS_TABLE_COLOUR:
149 s = xstrdup(colour_tostring(ov->number));
150 break;
151 case OPTIONS_TABLE_FLAG:
152 if (numeric)
153 xasprintf(&s, "%lld", ov->number);
154 else
155 s = xstrdup(ov->number ? "on" : "off");
156 break;
157 case OPTIONS_TABLE_CHOICE:
158 s = xstrdup(o->tableentry->choices[ov->number]);
159 break;
160 default:
161 fatalx("not a number option type");
163 return (s);
165 if (OPTIONS_IS_STRING(o))
166 return (xstrdup(ov->string));
167 return (xstrdup(""));
170 struct options *
171 options_create(struct options *parent)
173 struct options *oo;
175 oo = xcalloc(1, sizeof *oo);
176 RB_INIT(&oo->tree);
177 oo->parent = parent;
178 return (oo);
181 void
182 options_free(struct options *oo)
184 struct options_entry *o, *tmp;
186 RB_FOREACH_SAFE(o, options_tree, &oo->tree, tmp)
187 options_remove(o);
188 free(oo);
191 struct options *
192 options_get_parent(struct options *oo)
194 return (oo->parent);
197 void
198 options_set_parent(struct options *oo, struct options *parent)
200 oo->parent = parent;
203 struct options_entry *
204 options_first(struct options *oo)
206 return (RB_MIN(options_tree, &oo->tree));
209 struct options_entry *
210 options_next(struct options_entry *o)
212 return (RB_NEXT(options_tree, &oo->tree, o));
215 struct options_entry *
216 options_get_only(struct options *oo, const char *name)
218 struct options_entry o = { .name = name }, *found;
220 found = RB_FIND(options_tree, &oo->tree, &o);
221 if (found == NULL) {
222 o.name = options_map_name(name);
223 return (RB_FIND(options_tree, &oo->tree, &o));
225 return (found);
228 struct options_entry *
229 options_get(struct options *oo, const char *name)
231 struct options_entry *o;
233 o = options_get_only(oo, name);
234 while (o == NULL) {
235 oo = oo->parent;
236 if (oo == NULL)
237 break;
238 o = options_get_only(oo, name);
240 return (o);
243 struct options_entry *
244 options_empty(struct options *oo, const struct options_table_entry *oe)
246 struct options_entry *o;
248 o = options_add(oo, oe->name);
249 o->tableentry = oe;
251 if (oe->flags & OPTIONS_TABLE_IS_ARRAY)
252 RB_INIT(&o->value.array);
254 return (o);
257 struct options_entry *
258 options_default(struct options *oo, const struct options_table_entry *oe)
260 struct options_entry *o;
261 union options_value *ov;
262 u_int i;
264 o = options_empty(oo, oe);
265 ov = &o->value;
267 if (oe->flags & OPTIONS_TABLE_IS_ARRAY) {
268 if (oe->default_arr == NULL) {
269 options_array_assign(o, oe->default_str, NULL);
270 return (o);
272 for (i = 0; oe->default_arr[i] != NULL; i++)
273 options_array_set(o, i, oe->default_arr[i], 0, NULL);
274 return (o);
277 switch (oe->type) {
278 case OPTIONS_TABLE_STRING:
279 ov->string = xstrdup(oe->default_str);
280 break;
281 default:
282 ov->number = oe->default_num;
283 break;
285 return (o);
288 char *
289 options_default_to_string(const struct options_table_entry *oe)
291 char *s;
293 switch (oe->type) {
294 case OPTIONS_TABLE_STRING:
295 case OPTIONS_TABLE_COMMAND:
296 s = xstrdup(oe->default_str);
297 break;
298 case OPTIONS_TABLE_NUMBER:
299 xasprintf(&s, "%lld", oe->default_num);
300 break;
301 case OPTIONS_TABLE_KEY:
302 s = xstrdup(key_string_lookup_key(oe->default_num, 0));
303 break;
304 case OPTIONS_TABLE_COLOUR:
305 s = xstrdup(colour_tostring(oe->default_num));
306 break;
307 case OPTIONS_TABLE_FLAG:
308 s = xstrdup(oe->default_num ? "on" : "off");
309 break;
310 case OPTIONS_TABLE_CHOICE:
311 s = xstrdup(oe->choices[oe->default_num]);
312 break;
313 default:
314 fatalx("unknown option type");
316 return (s);
319 static struct options_entry *
320 options_add(struct options *oo, const char *name)
322 struct options_entry *o;
324 o = options_get_only(oo, name);
325 if (o != NULL)
326 options_remove(o);
328 o = xcalloc(1, sizeof *o);
329 o->owner = oo;
330 o->name = xstrdup(name);
332 RB_INSERT(options_tree, &oo->tree, o);
333 return (o);
336 static void
337 options_remove(struct options_entry *o)
339 struct options *oo = o->owner;
341 if (OPTIONS_IS_ARRAY(o))
342 options_array_clear(o);
343 else
344 options_value_free(o, &o->value);
345 RB_REMOVE(options_tree, &oo->tree, o);
346 free((void *)o->name);
347 free(o);
350 const char *
351 options_name(struct options_entry *o)
353 return (o->name);
356 struct options *
357 options_owner(struct options_entry *o)
359 return (o->owner);
362 const struct options_table_entry *
363 options_table_entry(struct options_entry *o)
365 return (o->tableentry);
368 static struct options_array_item *
369 options_array_item(struct options_entry *o, u_int idx)
371 struct options_array_item a;
373 a.index = idx;
374 return (RB_FIND(options_array, &o->value.array, &a));
377 static struct options_array_item *
378 options_array_new(struct options_entry *o, u_int idx)
380 struct options_array_item *a;
382 a = xcalloc(1, sizeof *a);
383 a->index = idx;
384 RB_INSERT(options_array, &o->value.array, a);
385 return (a);
388 static void
389 options_array_free(struct options_entry *o, struct options_array_item *a)
391 options_value_free(o, &a->value);
392 RB_REMOVE(options_array, &o->value.array, a);
393 free(a);
396 void
397 options_array_clear(struct options_entry *o)
399 struct options_array_item *a, *a1;
401 if (!OPTIONS_IS_ARRAY(o))
402 return;
404 RB_FOREACH_SAFE(a, options_array, &o->value.array, a1)
405 options_array_free(o, a);
408 union options_value *
409 options_array_get(struct options_entry *o, u_int idx)
411 struct options_array_item *a;
413 if (!OPTIONS_IS_ARRAY(o))
414 return (NULL);
415 a = options_array_item(o, idx);
416 if (a == NULL)
417 return (NULL);
418 return (&a->value);
422 options_array_set(struct options_entry *o, u_int idx, const char *value,
423 int append, char **cause)
425 struct options_array_item *a;
426 char *new;
427 struct cmd_parse_result *pr;
428 long long number;
430 if (!OPTIONS_IS_ARRAY(o)) {
431 if (cause != NULL)
432 *cause = xstrdup("not an array");
433 return (-1);
436 if (value == NULL) {
437 a = options_array_item(o, idx);
438 if (a != NULL)
439 options_array_free(o, a);
440 return (0);
443 if (OPTIONS_IS_COMMAND(o)) {
444 pr = cmd_parse_from_string(value, NULL);
445 switch (pr->status) {
446 case CMD_PARSE_ERROR:
447 if (cause != NULL)
448 *cause = pr->error;
449 else
450 free(pr->error);
451 return (-1);
452 case CMD_PARSE_SUCCESS:
453 break;
456 a = options_array_item(o, idx);
457 if (a == NULL)
458 a = options_array_new(o, idx);
459 else
460 options_value_free(o, &a->value);
461 a->value.cmdlist = pr->cmdlist;
462 return (0);
465 if (OPTIONS_IS_STRING(o)) {
466 a = options_array_item(o, idx);
467 if (a != NULL && append)
468 xasprintf(&new, "%s%s", a->value.string, value);
469 else
470 new = xstrdup(value);
471 if (a == NULL)
472 a = options_array_new(o, idx);
473 else
474 options_value_free(o, &a->value);
475 a->value.string = new;
476 return (0);
479 if (o->tableentry->type == OPTIONS_TABLE_COLOUR) {
480 if ((number = colour_fromstring(value)) == -1) {
481 xasprintf(cause, "bad colour: %s", value);
482 return (-1);
484 a = options_array_item(o, idx);
485 if (a == NULL)
486 a = options_array_new(o, idx);
487 else
488 options_value_free(o, &a->value);
489 a->value.number = number;
490 return (0);
493 if (cause != NULL)
494 *cause = xstrdup("wrong array type");
495 return (-1);
499 options_array_assign(struct options_entry *o, const char *s, char **cause)
501 const char *separator;
502 char *copy, *next, *string;
503 u_int i;
505 separator = o->tableentry->separator;
506 if (separator == NULL)
507 separator = " ,";
508 if (*separator == '\0') {
509 if (*s == '\0')
510 return (0);
511 for (i = 0; i < UINT_MAX; i++) {
512 if (options_array_item(o, i) == NULL)
513 break;
515 return (options_array_set(o, i, s, 0, cause));
518 if (*s == '\0')
519 return (0);
520 copy = string = xstrdup(s);
521 while ((next = strsep(&string, separator)) != NULL) {
522 if (*next == '\0')
523 continue;
524 for (i = 0; i < UINT_MAX; i++) {
525 if (options_array_item(o, i) == NULL)
526 break;
528 if (i == UINT_MAX)
529 break;
530 if (options_array_set(o, i, next, 0, cause) != 0) {
531 free(copy);
532 return (-1);
535 free(copy);
536 return (0);
539 struct options_array_item *
540 options_array_first(struct options_entry *o)
542 if (!OPTIONS_IS_ARRAY(o))
543 return (NULL);
544 return (RB_MIN(options_array, &o->value.array));
547 struct options_array_item *
548 options_array_next(struct options_array_item *a)
550 return (RB_NEXT(options_array, &o->value.array, a));
553 u_int
554 options_array_item_index(struct options_array_item *a)
556 return (a->index);
559 union options_value *
560 options_array_item_value(struct options_array_item *a)
562 return (&a->value);
566 options_is_array(struct options_entry *o)
568 return (OPTIONS_IS_ARRAY(o));
572 options_is_string(struct options_entry *o)
574 return (OPTIONS_IS_STRING(o));
577 char *
578 options_to_string(struct options_entry *o, int idx, int numeric)
580 struct options_array_item *a;
582 if (OPTIONS_IS_ARRAY(o)) {
583 if (idx == -1)
584 return (xstrdup(""));
585 a = options_array_item(o, idx);
586 if (a == NULL)
587 return (xstrdup(""));
588 return (options_value_to_string(o, &a->value, numeric));
590 return (options_value_to_string(o, &o->value, numeric));
593 char *
594 options_parse(const char *name, int *idx)
596 char *copy, *cp, *end;
598 if (*name == '\0')
599 return (NULL);
600 copy = xstrdup(name);
601 if ((cp = strchr(copy, '[')) == NULL) {
602 *idx = -1;
603 return (copy);
605 end = strchr(cp + 1, ']');
606 if (end == NULL || end[1] != '\0' || !isdigit((u_char)end[-1])) {
607 free(copy);
608 return (NULL);
610 if (sscanf(cp, "[%d]", idx) != 1 || *idx < 0) {
611 free(copy);
612 return (NULL);
614 *cp = '\0';
615 return (copy);
618 struct options_entry *
619 options_parse_get(struct options *oo, const char *s, int *idx, int only)
621 struct options_entry *o;
622 char *name;
624 name = options_parse(s, idx);
625 if (name == NULL)
626 return (NULL);
627 if (only)
628 o = options_get_only(oo, name);
629 else
630 o = options_get(oo, name);
631 free(name);
632 return (o);
635 char *
636 options_match(const char *s, int *idx, int *ambiguous)
638 const struct options_table_entry *oe, *found;
639 char *parsed;
640 const char *name;
641 size_t namelen;
643 parsed = options_parse(s, idx);
644 if (parsed == NULL)
645 return (NULL);
646 if (*parsed == '@') {
647 *ambiguous = 0;
648 return (parsed);
651 name = options_map_name(parsed);
652 namelen = strlen(name);
654 found = NULL;
655 for (oe = options_table; oe->name != NULL; oe++) {
656 if (strcmp(oe->name, name) == 0) {
657 found = oe;
658 break;
660 if (strncmp(oe->name, name, namelen) == 0) {
661 if (found != NULL) {
662 *ambiguous = 1;
663 free(parsed);
664 return (NULL);
666 found = oe;
669 free(parsed);
670 if (found == NULL) {
671 *ambiguous = 0;
672 return (NULL);
674 return (xstrdup(found->name));
677 struct options_entry *
678 options_match_get(struct options *oo, const char *s, int *idx, int only,
679 int *ambiguous)
681 char *name;
682 struct options_entry *o;
684 name = options_match(s, idx, ambiguous);
685 if (name == NULL)
686 return (NULL);
687 *ambiguous = 0;
688 if (only)
689 o = options_get_only(oo, name);
690 else
691 o = options_get(oo, name);
692 free(name);
693 return (o);
696 const char *
697 options_get_string(struct options *oo, const char *name)
699 struct options_entry *o;
701 o = options_get(oo, name);
702 if (o == NULL)
703 fatalx("missing option %s", name);
704 if (!OPTIONS_IS_STRING(o))
705 fatalx("option %s is not a string", name);
706 return (o->value.string);
709 long long
710 options_get_number(struct options *oo, const char *name)
712 struct options_entry *o;
714 o = options_get(oo, name);
715 if (o == NULL)
716 fatalx("missing option %s", name);
717 if (!OPTIONS_IS_NUMBER(o))
718 fatalx("option %s is not a number", name);
719 return (o->value.number);
722 struct options_entry *
723 options_set_string(struct options *oo, const char *name, int append,
724 const char *fmt, ...)
726 struct options_entry *o;
727 va_list ap;
728 const char *separator = "";
729 char *s, *value;
731 va_start(ap, fmt);
732 xvasprintf(&s, fmt, ap);
733 va_end(ap);
735 o = options_get_only(oo, name);
736 if (o != NULL && append && OPTIONS_IS_STRING(o)) {
737 if (*name != '@') {
738 separator = o->tableentry->separator;
739 if (separator == NULL)
740 separator = "";
742 xasprintf(&value, "%s%s%s", o->value.string, separator, s);
743 free(s);
744 } else
745 value = s;
746 if (o == NULL && *name == '@')
747 o = options_add(oo, name);
748 else if (o == NULL) {
749 o = options_default(oo, options_parent_table_entry(oo, name));
750 if (o == NULL)
751 return (NULL);
754 if (!OPTIONS_IS_STRING(o))
755 fatalx("option %s is not a string", name);
756 free(o->value.string);
757 o->value.string = value;
758 o->cached = 0;
759 return (o);
762 struct options_entry *
763 options_set_number(struct options *oo, const char *name, long long value)
765 struct options_entry *o;
767 if (*name == '@')
768 fatalx("user option %s must be a string", name);
770 o = options_get_only(oo, name);
771 if (o == NULL) {
772 o = options_default(oo, options_parent_table_entry(oo, name));
773 if (o == NULL)
774 return (NULL);
777 if (!OPTIONS_IS_NUMBER(o))
778 fatalx("option %s is not a number", name);
779 o->value.number = value;
780 return (o);
784 options_scope_from_name(struct args *args, int window,
785 const char *name, struct cmd_find_state *fs, struct options **oo,
786 char **cause)
788 struct session *s = fs->s;
789 struct winlink *wl = fs->wl;
790 struct window_pane *wp = fs->wp;
791 const char *target = args_get(args, 't');
792 const struct options_table_entry *oe;
793 int scope = OPTIONS_TABLE_NONE;
795 if (*name == '@')
796 return (options_scope_from_flags(args, window, fs, oo, cause));
798 for (oe = options_table; oe->name != NULL; oe++) {
799 if (strcmp(oe->name, name) == 0)
800 break;
802 if (oe->name == NULL) {
803 xasprintf(cause, "unknown option: %s", name);
804 return (OPTIONS_TABLE_NONE);
806 switch (oe->scope) {
807 case OPTIONS_TABLE_SERVER:
808 *oo = global_options;
809 scope = OPTIONS_TABLE_SERVER;
810 break;
811 case OPTIONS_TABLE_SESSION:
812 if (args_has(args, 'g')) {
813 *oo = global_s_options;
814 scope = OPTIONS_TABLE_SESSION;
815 } else if (s == NULL && target != NULL)
816 xasprintf(cause, "no such session: %s", target);
817 else if (s == NULL)
818 xasprintf(cause, "no current session");
819 else {
820 *oo = s->options;
821 scope = OPTIONS_TABLE_SESSION;
823 break;
824 case OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE:
825 if (args_has(args, 'p')) {
826 if (wp == NULL && target != NULL)
827 xasprintf(cause, "no such pane: %s", target);
828 else if (wp == NULL)
829 xasprintf(cause, "no current pane");
830 else {
831 *oo = wp->options;
832 scope = OPTIONS_TABLE_PANE;
834 break;
836 /* FALLTHROUGH */
837 case OPTIONS_TABLE_WINDOW:
838 if (args_has(args, 'g')) {
839 *oo = global_w_options;
840 scope = OPTIONS_TABLE_WINDOW;
841 } else if (wl == NULL && target != NULL)
842 xasprintf(cause, "no such window: %s", target);
843 else if (wl == NULL)
844 xasprintf(cause, "no current window");
845 else {
846 *oo = wl->window->options;
847 scope = OPTIONS_TABLE_WINDOW;
849 break;
851 return (scope);
855 options_scope_from_flags(struct args *args, int window,
856 struct cmd_find_state *fs, struct options **oo, char **cause)
858 struct session *s = fs->s;
859 struct winlink *wl = fs->wl;
860 struct window_pane *wp = fs->wp;
861 const char *target = args_get(args, 't');
863 if (args_has(args, 's')) {
864 *oo = global_options;
865 return (OPTIONS_TABLE_SERVER);
868 if (args_has(args, 'p')) {
869 if (wp == NULL) {
870 if (target != NULL)
871 xasprintf(cause, "no such pane: %s", target);
872 else
873 xasprintf(cause, "no current pane");
874 return (OPTIONS_TABLE_NONE);
876 *oo = wp->options;
877 return (OPTIONS_TABLE_PANE);
878 } else if (window || args_has(args, 'w')) {
879 if (args_has(args, 'g')) {
880 *oo = global_w_options;
881 return (OPTIONS_TABLE_WINDOW);
883 if (wl == NULL) {
884 if (target != NULL)
885 xasprintf(cause, "no such window: %s", target);
886 else
887 xasprintf(cause, "no current window");
888 return (OPTIONS_TABLE_NONE);
890 *oo = wl->window->options;
891 return (OPTIONS_TABLE_WINDOW);
892 } else {
893 if (args_has(args, 'g')) {
894 *oo = global_s_options;
895 return (OPTIONS_TABLE_SESSION);
897 if (s == NULL) {
898 if (target != NULL)
899 xasprintf(cause, "no such session: %s", target);
900 else
901 xasprintf(cause, "no current session");
902 return (OPTIONS_TABLE_NONE);
904 *oo = s->options;
905 return (OPTIONS_TABLE_SESSION);
909 struct style *
910 options_string_to_style(struct options *oo, const char *name,
911 struct format_tree *ft)
913 struct options_entry *o;
914 const char *s;
915 char *expanded;
917 o = options_get(oo, name);
918 if (o == NULL || !OPTIONS_IS_STRING(o))
919 return (NULL);
921 if (o->cached)
922 return (&o->style);
923 s = o->value.string;
924 log_debug("%s: %s is '%s'", __func__, name, s);
926 style_set(&o->style, &grid_default_cell);
927 o->cached = (strstr(s, "#{") == NULL);
929 if (ft != NULL && !o->cached) {
930 expanded = format_expand(ft, s);
931 if (style_parse(&o->style, &grid_default_cell, expanded) != 0) {
932 free(expanded);
933 return (NULL);
935 free(expanded);
936 } else {
937 if (style_parse(&o->style, &grid_default_cell, s) != 0)
938 return (NULL);
940 return (&o->style);
943 static int
944 options_from_string_check(const struct options_table_entry *oe,
945 const char *value, char **cause)
947 struct style sy;
949 if (oe == NULL)
950 return (0);
951 if (strcmp(oe->name, "default-shell") == 0 && !checkshell(value)) {
952 xasprintf(cause, "not a suitable shell: %s", value);
953 return (-1);
955 if (oe->pattern != NULL && fnmatch(oe->pattern, value, 0) != 0) {
956 xasprintf(cause, "value is invalid: %s", value);
957 return (-1);
959 if ((oe->flags & OPTIONS_TABLE_IS_STYLE) &&
960 strstr(value, "#{") == NULL &&
961 style_parse(&sy, &grid_default_cell, value) != 0) {
962 xasprintf(cause, "invalid style: %s", value);
963 return (-1);
965 return (0);
968 static int
969 options_from_string_flag(struct options *oo, const char *name,
970 const char *value, char **cause)
972 int flag;
974 if (value == NULL || *value == '\0')
975 flag = !options_get_number(oo, name);
976 else if (strcmp(value, "1") == 0 ||
977 strcasecmp(value, "on") == 0 ||
978 strcasecmp(value, "yes") == 0)
979 flag = 1;
980 else if (strcmp(value, "0") == 0 ||
981 strcasecmp(value, "off") == 0 ||
982 strcasecmp(value, "no") == 0)
983 flag = 0;
984 else {
985 xasprintf(cause, "bad value: %s", value);
986 return (-1);
988 options_set_number(oo, name, flag);
989 return (0);
993 options_find_choice(const struct options_table_entry *oe, const char *value,
994 char **cause)
996 const char **cp;
997 int n = 0, choice = -1;
999 for (cp = oe->choices; *cp != NULL; cp++) {
1000 if (strcmp(*cp, value) == 0)
1001 choice = n;
1002 n++;
1004 if (choice == -1) {
1005 xasprintf(cause, "unknown value: %s", value);
1006 return (-1);
1008 return (choice);
1011 static int
1012 options_from_string_choice(const struct options_table_entry *oe,
1013 struct options *oo, const char *name, const char *value, char **cause)
1015 int choice = -1;
1017 if (value == NULL) {
1018 choice = options_get_number(oo, name);
1019 if (choice < 2)
1020 choice = !choice;
1021 } else {
1022 choice = options_find_choice(oe, value, cause);
1023 if (choice < 0)
1024 return (-1);
1026 options_set_number(oo, name, choice);
1027 return (0);
1031 options_from_string(struct options *oo, const struct options_table_entry *oe,
1032 const char *name, const char *value, int append, char **cause)
1034 enum options_table_type type;
1035 long long number;
1036 const char *errstr, *new;
1037 char *old;
1038 key_code key;
1040 if (oe != NULL) {
1041 if (value == NULL &&
1042 oe->type != OPTIONS_TABLE_FLAG &&
1043 oe->type != OPTIONS_TABLE_CHOICE) {
1044 xasprintf(cause, "empty value");
1045 return (-1);
1047 type = oe->type;
1048 } else {
1049 if (*name != '@') {
1050 xasprintf(cause, "bad option name");
1051 return (-1);
1053 type = OPTIONS_TABLE_STRING;
1056 switch (type) {
1057 case OPTIONS_TABLE_STRING:
1058 old = xstrdup(options_get_string(oo, name));
1059 options_set_string(oo, name, append, "%s", value);
1061 new = options_get_string(oo, name);
1062 if (options_from_string_check(oe, new, cause) != 0) {
1063 options_set_string(oo, name, 0, "%s", old);
1064 free(old);
1065 return (-1);
1067 free(old);
1068 return (0);
1069 case OPTIONS_TABLE_NUMBER:
1070 number = strtonum(value, oe->minimum, oe->maximum, &errstr);
1071 if (errstr != NULL) {
1072 xasprintf(cause, "value is %s: %s", errstr, value);
1073 return (-1);
1075 options_set_number(oo, name, number);
1076 return (0);
1077 case OPTIONS_TABLE_KEY:
1078 key = key_string_lookup_string(value);
1079 if (key == KEYC_UNKNOWN) {
1080 xasprintf(cause, "bad key: %s", value);
1081 return (-1);
1083 options_set_number(oo, name, key);
1084 return (0);
1085 case OPTIONS_TABLE_COLOUR:
1086 if ((number = colour_fromstring(value)) == -1) {
1087 xasprintf(cause, "bad colour: %s", value);
1088 return (-1);
1090 options_set_number(oo, name, number);
1091 return (0);
1092 case OPTIONS_TABLE_FLAG:
1093 return (options_from_string_flag(oo, name, value, cause));
1094 case OPTIONS_TABLE_CHOICE:
1095 return (options_from_string_choice(oe, oo, name, value, cause));
1096 case OPTIONS_TABLE_COMMAND:
1097 break;
1099 return (-1);
1102 void
1103 options_push_changes(const char *name)
1105 struct client *loop;
1106 struct session *s;
1107 struct window *w;
1108 struct window_pane *wp;
1110 log_debug("%s: %s", __func__, name);
1112 if (strcmp(name, "automatic-rename") == 0) {
1113 RB_FOREACH(w, windows, &windows) {
1114 if (w->active == NULL)
1115 continue;
1116 if (options_get_number(w->options, name))
1117 w->active->flags |= PANE_CHANGED;
1120 if (strcmp(name, "cursor-colour") == 0) {
1121 RB_FOREACH(wp, window_pane_tree, &all_window_panes)
1122 window_pane_default_cursor(wp);
1124 if (strcmp(name, "cursor-style") == 0) {
1125 RB_FOREACH(wp, window_pane_tree, &all_window_panes)
1126 window_pane_default_cursor(wp);
1128 if (strcmp(name, "fill-character") == 0) {
1129 RB_FOREACH(w, windows, &windows)
1130 window_set_fill_character(w);
1132 if (strcmp(name, "key-table") == 0) {
1133 TAILQ_FOREACH(loop, &clients, entry)
1134 server_client_set_key_table(loop, NULL);
1136 if (strcmp(name, "user-keys") == 0) {
1137 TAILQ_FOREACH(loop, &clients, entry) {
1138 if (loop->tty.flags & TTY_OPENED)
1139 tty_keys_build(&loop->tty);
1142 if (strcmp(name, "status") == 0 ||
1143 strcmp(name, "status-interval") == 0)
1144 status_timer_start_all();
1145 if (strcmp(name, "monitor-silence") == 0)
1146 alerts_reset_all();
1147 if (strcmp(name, "window-style") == 0 ||
1148 strcmp(name, "window-active-style") == 0) {
1149 RB_FOREACH(wp, window_pane_tree, &all_window_panes)
1150 wp->flags |= PANE_STYLECHANGED;
1152 if (strcmp(name, "pane-colours") == 0) {
1153 RB_FOREACH(wp, window_pane_tree, &all_window_panes)
1154 colour_palette_from_option(&wp->palette, wp->options);
1156 if (strcmp(name, "pane-border-status") == 0) {
1157 RB_FOREACH(w, windows, &windows)
1158 layout_fix_panes(w, NULL);
1160 RB_FOREACH(s, sessions, &sessions)
1161 status_update_cache(s);
1163 recalculate_sizes();
1164 TAILQ_FOREACH(loop, &clients, entry) {
1165 if (loop->session != NULL)
1166 server_redraw_client(loop);
1171 options_remove_or_default(struct options_entry *o, int idx, char **cause)
1173 struct options *oo = o->owner;
1175 if (idx == -1) {
1176 if (o->tableentry != NULL &&
1177 (oo == global_options ||
1178 oo == global_s_options ||
1179 oo == global_w_options))
1180 options_default(oo, o->tableentry);
1181 else
1182 options_remove(o);
1183 } else if (options_array_set(o, idx, NULL, 0, cause) != 0)
1184 return (-1);
1185 return (0);