1 /* $OpenBSD$ */
2
3 /*
4 * Copyright (c) 2008 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 <fnmatch.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "tmux.h"
28
29 /*
30 * Option handling; each option has a name, type and value and is stored in
31 * a red-black tree.
32 */
33
34 struct options_array_item {
35 u_int index;
36 union options_value value;
37 RB_ENTRY(options_array_item) entry;
38 };
39 static int
options_array_cmp(struct options_array_item * a1,struct options_array_item * a2)40 options_array_cmp(struct options_array_item *a1, struct options_array_item *a2)
41 {
42 if (a1->index < a2->index)
43 return (-1);
44 if (a1->index > a2->index)
45 return (1);
46 return (0);
47 }
48 RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp);
49
50 struct options_entry {
51 struct options *owner;
52
53 const char *name;
54 const struct options_table_entry *tableentry;
55 union options_value value;
56
57 int cached;
58 struct style style;
59
60 RB_ENTRY(options_entry) entry;
61 };
62
63 struct options {
64 RB_HEAD(options_tree, options_entry) tree;
65 struct options *parent;
66 };
67
68 static struct options_entry *options_add(struct options *, const char *);
69 static void options_remove(struct options_entry *);
70
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)
84
85 #define OPTIONS_IS_ARRAY(o) \
86 ((o)->tableentry != NULL && \
87 ((o)->tableentry->flags & OPTIONS_TABLE_IS_ARRAY))
88
89 static int options_cmp(struct options_entry *, struct options_entry *);
90 RB_GENERATE_STATIC(options_tree, options_entry, entry, options_cmp);
91
92 static int
options_cmp(struct options_entry * lhs,struct options_entry * rhs)93 options_cmp(struct options_entry *lhs, struct options_entry *rhs)
94 {
95 return (strcmp(lhs->name, rhs->name));
96 }
97
98 static const char *
options_map_name(const char * name)99 options_map_name(const char *name)
100 {
101 const struct options_name_map *map;
102
103 for (map = options_other_names; map->from != NULL; map++) {
104 if (strcmp(map->from, name) == 0)
105 return (map->to);
106 }
107 return (name);
108 }
109
110 static const struct options_table_entry *
options_parent_table_entry(struct options * oo,const char * s)111 options_parent_table_entry(struct options *oo, const char *s)
112 {
113 struct options_entry *o;
114
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);
121 }
122
123 static void
options_value_free(struct options_entry * o,union options_value * ov)124 options_value_free(struct options_entry *o, union options_value *ov)
125 {
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);
130 }
131
132 static char *
options_value_to_string(struct options_entry * o,union options_value * ov,int numeric)133 options_value_to_string(struct options_entry *o, union options_value *ov,
134 int numeric)
135 {
136 char *s;
137
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");
162 }
163 return (s);
164 }
165 if (OPTIONS_IS_STRING(o))
166 return (xstrdup(ov->string));
167 return (xstrdup(""));
168 }
169
170 struct options *
options_create(struct options * parent)171 options_create(struct options *parent)
172 {
173 struct options *oo;
174
175 oo = xcalloc(1, sizeof *oo);
176 RB_INIT(&oo->tree);
177 oo->parent = parent;
178 return (oo);
179 }
180
181 void
options_free(struct options * oo)182 options_free(struct options *oo)
183 {
184 struct options_entry *o, *tmp;
185
186 RB_FOREACH_SAFE(o, options_tree, &oo->tree, tmp)
187 options_remove(o);
188 free(oo);
189 }
190
191 struct options *
options_get_parent(struct options * oo)192 options_get_parent(struct options *oo)
193 {
194 return (oo->parent);
195 }
196
197 void
options_set_parent(struct options * oo,struct options * parent)198 options_set_parent(struct options *oo, struct options *parent)
199 {
200 oo->parent = parent;
201 }
202
203 struct options_entry *
options_first(struct options * oo)204 options_first(struct options *oo)
205 {
206 return (RB_MIN(options_tree, &oo->tree));
207 }
208
209 struct options_entry *
options_next(struct options_entry * o)210 options_next(struct options_entry *o)
211 {
212 return (RB_NEXT(options_tree, &oo->tree, o));
213 }
214
215 struct options_entry *
options_get_only(struct options * oo,const char * name)216 options_get_only(struct options *oo, const char *name)
217 {
218 struct options_entry o = { .name = name }, *found;
219
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));
224 }
225 return (found);
226 }
227
228 struct options_entry *
options_get(struct options * oo,const char * name)229 options_get(struct options *oo, const char *name)
230 {
231 struct options_entry *o;
232
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);
239 }
240 return (o);
241 }
242
243 struct options_entry *
options_empty(struct options * oo,const struct options_table_entry * oe)244 options_empty(struct options *oo, const struct options_table_entry *oe)
245 {
246 struct options_entry *o;
247
248 o = options_add(oo, oe->name);
249 o->tableentry = oe;
250
251 if (oe->flags & OPTIONS_TABLE_IS_ARRAY)
252 RB_INIT(&o->value.array);
253
254 return (o);
255 }
256
257 struct options_entry *
options_default(struct options * oo,const struct options_table_entry * oe)258 options_default(struct options *oo, const struct options_table_entry *oe)
259 {
260 struct options_entry *o;
261 union options_value *ov;
262 u_int i;
263
264 o = options_empty(oo, oe);
265 ov = &o->value;
266
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);
271 }
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);
275 }
276
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;
284 }
285 return (o);
286 }
287
288 char *
options_default_to_string(const struct options_table_entry * oe)289 options_default_to_string(const struct options_table_entry *oe)
290 {
291 char *s;
292
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");
315 }
316 return (s);
317 }
318
319 static struct options_entry *
options_add(struct options * oo,const char * name)320 options_add(struct options *oo, const char *name)
321 {
322 struct options_entry *o;
323
324 o = options_get_only(oo, name);
325 if (o != NULL)
326 options_remove(o);
327
328 o = xcalloc(1, sizeof *o);
329 o->owner = oo;
330 o->name = xstrdup(name);
331
332 RB_INSERT(options_tree, &oo->tree, o);
333 return (o);
334 }
335
336 static void
options_remove(struct options_entry * o)337 options_remove(struct options_entry *o)
338 {
339 struct options *oo = o->owner;
340
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);
348 }
349
350 const char *
options_name(struct options_entry * o)351 options_name(struct options_entry *o)
352 {
353 return (o->name);
354 }
355
356 struct options *
options_owner(struct options_entry * o)357 options_owner(struct options_entry *o)
358 {
359 return (o->owner);
360 }
361
362 const struct options_table_entry *
options_table_entry(struct options_entry * o)363 options_table_entry(struct options_entry *o)
364 {
365 return (o->tableentry);
366 }
367
368 static struct options_array_item *
options_array_item(struct options_entry * o,u_int idx)369 options_array_item(struct options_entry *o, u_int idx)
370 {
371 struct options_array_item a;
372
373 a.index = idx;
374 return (RB_FIND(options_array, &o->value.array, &a));
375 }
376
377 static struct options_array_item *
options_array_new(struct options_entry * o,u_int idx)378 options_array_new(struct options_entry *o, u_int idx)
379 {
380 struct options_array_item *a;
381
382 a = xcalloc(1, sizeof *a);
383 a->index = idx;
384 RB_INSERT(options_array, &o->value.array, a);
385 return (a);
386 }
387
388 static void
options_array_free(struct options_entry * o,struct options_array_item * a)389 options_array_free(struct options_entry *o, struct options_array_item *a)
390 {
391 options_value_free(o, &a->value);
392 RB_REMOVE(options_array, &o->value.array, a);
393 free(a);
394 }
395
396 void
options_array_clear(struct options_entry * o)397 options_array_clear(struct options_entry *o)
398 {
399 struct options_array_item *a, *a1;
400
401 if (!OPTIONS_IS_ARRAY(o))
402 return;
403
404 RB_FOREACH_SAFE(a, options_array, &o->value.array, a1)
405 options_array_free(o, a);
406 }
407
408 union options_value *
options_array_get(struct options_entry * o,u_int idx)409 options_array_get(struct options_entry *o, u_int idx)
410 {
411 struct options_array_item *a;
412
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);
419 }
420
421 int
options_array_set(struct options_entry * o,u_int idx,const char * value,int append,char ** cause)422 options_array_set(struct options_entry *o, u_int idx, const char *value,
423 int append, char **cause)
424 {
425 struct options_array_item *a;
426 char *new;
427 struct cmd_parse_result *pr;
428
429 if (!OPTIONS_IS_ARRAY(o)) {
430 if (cause != NULL)
431 *cause = xstrdup("not an array");
432 return (-1);
433 }
434
435 if (value == NULL) {
436 a = options_array_item(o, idx);
437 if (a != NULL)
438 options_array_free(o, a);
439 return (0);
440 }
441
442 if (OPTIONS_IS_COMMAND(o)) {
443 pr = cmd_parse_from_string(value, NULL);
444 switch (pr->status) {
445 case CMD_PARSE_EMPTY:
446 if (cause != NULL)
447 *cause = xstrdup("empty command");
448 return (-1);
449 case CMD_PARSE_ERROR:
450 if (cause != NULL)
451 *cause = pr->error;
452 else
453 free(pr->error);
454 return (-1);
455 case CMD_PARSE_SUCCESS:
456 break;
457 }
458
459 a = options_array_item(o, idx);
460 if (a == NULL)
461 a = options_array_new(o, idx);
462 else
463 options_value_free(o, &a->value);
464 a->value.cmdlist = pr->cmdlist;
465 return (0);
466 }
467
468 if (OPTIONS_IS_STRING(o)) {
469 a = options_array_item(o, idx);
470 if (a != NULL && append)
471 xasprintf(&new, "%s%s", a->value.string, value);
472 else
473 new = xstrdup(value);
474 if (a == NULL)
475 a = options_array_new(o, idx);
476 else
477 options_value_free(o, &a->value);
478 a->value.string = new;
479 return (0);
480 }
481
482 if (cause != NULL)
483 *cause = xstrdup("wrong array type");
484 return (-1);
485 }
486
487 int
options_array_assign(struct options_entry * o,const char * s,char ** cause)488 options_array_assign(struct options_entry *o, const char *s, char **cause)
489 {
490 const char *separator;
491 char *copy, *next, *string;
492 u_int i;
493
494 separator = o->tableentry->separator;
495 if (separator == NULL)
496 separator = " ,";
497 if (*separator == '\0') {
498 if (*s == '\0')
499 return (0);
500 for (i = 0; i < UINT_MAX; i++) {
501 if (options_array_item(o, i) == NULL)
502 break;
503 }
504 return (options_array_set(o, i, s, 0, cause));
505 }
506
507 if (*s == '\0')
508 return (0);
509 copy = string = xstrdup(s);
510 while ((next = strsep(&string, separator)) != NULL) {
511 if (*next == '\0')
512 continue;
513 for (i = 0; i < UINT_MAX; i++) {
514 if (options_array_item(o, i) == NULL)
515 break;
516 }
517 if (i == UINT_MAX)
518 break;
519 if (options_array_set(o, i, next, 0, cause) != 0) {
520 free(copy);
521 return (-1);
522 }
523 }
524 free(copy);
525 return (0);
526 }
527
528 struct options_array_item *
options_array_first(struct options_entry * o)529 options_array_first(struct options_entry *o)
530 {
531 if (!OPTIONS_IS_ARRAY(o))
532 return (NULL);
533 return (RB_MIN(options_array, &o->value.array));
534 }
535
536 struct options_array_item *
options_array_next(struct options_array_item * a)537 options_array_next(struct options_array_item *a)
538 {
539 return (RB_NEXT(options_array, &o->value.array, a));
540 }
541
542 u_int
options_array_item_index(struct options_array_item * a)543 options_array_item_index(struct options_array_item *a)
544 {
545 return (a->index);
546 }
547
548 union options_value *
options_array_item_value(struct options_array_item * a)549 options_array_item_value(struct options_array_item *a)
550 {
551 return (&a->value);
552 }
553
554 int
options_is_array(struct options_entry * o)555 options_is_array(struct options_entry *o)
556 {
557 return (OPTIONS_IS_ARRAY(o));
558 }
559
560 int
options_is_string(struct options_entry * o)561 options_is_string(struct options_entry *o)
562 {
563 return (OPTIONS_IS_STRING(o));
564 }
565
566 char *
options_to_string(struct options_entry * o,int idx,int numeric)567 options_to_string(struct options_entry *o, int idx, int numeric)
568 {
569 struct options_array_item *a;
570
571 if (OPTIONS_IS_ARRAY(o)) {
572 if (idx == -1)
573 return (xstrdup(""));
574 a = options_array_item(o, idx);
575 if (a == NULL)
576 return (xstrdup(""));
577 return (options_value_to_string(o, &a->value, numeric));
578 }
579 return (options_value_to_string(o, &o->value, numeric));
580 }
581
582 char *
options_parse(const char * name,int * idx)583 options_parse(const char *name, int *idx)
584 {
585 char *copy, *cp, *end;
586
587 if (*name == '\0')
588 return (NULL);
589 copy = xstrdup(name);
590 if ((cp = strchr(copy, '[')) == NULL) {
591 *idx = -1;
592 return (copy);
593 }
594 end = strchr(cp + 1, ']');
595 if (end == NULL || end[1] != '\0' || !isdigit((u_char)end[-1])) {
596 free(copy);
597 return (NULL);
598 }
599 if (sscanf(cp, "[%d]", idx) != 1 || *idx < 0) {
600 free(copy);
601 return (NULL);
602 }
603 *cp = '\0';
604 return (copy);
605 }
606
607 struct options_entry *
options_parse_get(struct options * oo,const char * s,int * idx,int only)608 options_parse_get(struct options *oo, const char *s, int *idx, int only)
609 {
610 struct options_entry *o;
611 char *name;
612
613 name = options_parse(s, idx);
614 if (name == NULL)
615 return (NULL);
616 if (only)
617 o = options_get_only(oo, name);
618 else
619 o = options_get(oo, name);
620 free(name);
621 return (o);
622 }
623
624 char *
options_match(const char * s,int * idx,int * ambiguous)625 options_match(const char *s, int *idx, int *ambiguous)
626 {
627 const struct options_table_entry *oe, *found;
628 char *parsed;
629 const char *name;
630 size_t namelen;
631
632 parsed = options_parse(s, idx);
633 if (parsed == NULL)
634 return (NULL);
635 if (*parsed == '@') {
636 *ambiguous = 0;
637 return (parsed);
638 }
639
640 name = options_map_name(parsed);
641 namelen = strlen(name);
642
643 found = NULL;
644 for (oe = options_table; oe->name != NULL; oe++) {
645 if (strcmp(oe->name, name) == 0) {
646 found = oe;
647 break;
648 }
649 if (strncmp(oe->name, name, namelen) == 0) {
650 if (found != NULL) {
651 *ambiguous = 1;
652 free(parsed);
653 return (NULL);
654 }
655 found = oe;
656 }
657 }
658 free(parsed);
659 if (found == NULL) {
660 *ambiguous = 0;
661 return (NULL);
662 }
663 return (xstrdup(found->name));
664 }
665
666 struct options_entry *
options_match_get(struct options * oo,const char * s,int * idx,int only,int * ambiguous)667 options_match_get(struct options *oo, const char *s, int *idx, int only,
668 int *ambiguous)
669 {
670 char *name;
671 struct options_entry *o;
672
673 name = options_match(s, idx, ambiguous);
674 if (name == NULL)
675 return (NULL);
676 *ambiguous = 0;
677 if (only)
678 o = options_get_only(oo, name);
679 else
680 o = options_get(oo, name);
681 free(name);
682 return (o);
683 }
684
685 const char *
options_get_string(struct options * oo,const char * name)686 options_get_string(struct options *oo, const char *name)
687 {
688 struct options_entry *o;
689
690 o = options_get(oo, name);
691 if (o == NULL)
692 fatalx("missing option %s", name);
693 if (!OPTIONS_IS_STRING(o))
694 fatalx("option %s is not a string", name);
695 return (o->value.string);
696 }
697
698 long long
options_get_number(struct options * oo,const char * name)699 options_get_number(struct options *oo, const char *name)
700 {
701 struct options_entry *o;
702
703 o = options_get(oo, name);
704 if (o == NULL)
705 fatalx("missing option %s", name);
706 if (!OPTIONS_IS_NUMBER(o))
707 fatalx("option %s is not a number", name);
708 return (o->value.number);
709 }
710
711 struct options_entry *
options_set_string(struct options * oo,const char * name,int append,const char * fmt,...)712 options_set_string(struct options *oo, const char *name, int append,
713 const char *fmt, ...)
714 {
715 struct options_entry *o;
716 va_list ap;
717 const char *separator = "";
718 char *s, *value;
719
720 va_start(ap, fmt);
721 xvasprintf(&s, fmt, ap);
722 va_end(ap);
723
724 o = options_get_only(oo, name);
725 if (o != NULL && append && OPTIONS_IS_STRING(o)) {
726 if (*name != '@') {
727 separator = o->tableentry->separator;
728 if (separator == NULL)
729 separator = "";
730 }
731 xasprintf(&value, "%s%s%s", o->value.string, separator, s);
732 free(s);
733 } else
734 value = s;
735 if (o == NULL && *name == '@')
736 o = options_add(oo, name);
737 else if (o == NULL) {
738 o = options_default(oo, options_parent_table_entry(oo, name));
739 if (o == NULL)
740 return (NULL);
741 }
742
743 if (!OPTIONS_IS_STRING(o))
744 fatalx("option %s is not a string", name);
745 free(o->value.string);
746 o->value.string = value;
747 o->cached = 0;
748 return (o);
749 }
750
751 struct options_entry *
options_set_number(struct options * oo,const char * name,long long value)752 options_set_number(struct options *oo, const char *name, long long value)
753 {
754 struct options_entry *o;
755
756 if (*name == '@')
757 fatalx("user option %s must be a string", name);
758
759 o = options_get_only(oo, name);
760 if (o == NULL) {
761 o = options_default(oo, options_parent_table_entry(oo, name));
762 if (o == NULL)
763 return (NULL);
764 }
765
766 if (!OPTIONS_IS_NUMBER(o))
767 fatalx("option %s is not a number", name);
768 o->value.number = value;
769 return (o);
770 }
771
772 int
options_scope_from_name(struct args * args,int window,const char * name,struct cmd_find_state * fs,struct options ** oo,char ** cause)773 options_scope_from_name(struct args *args, int window,
774 const char *name, struct cmd_find_state *fs, struct options **oo,
775 char **cause)
776 {
777 struct session *s = fs->s;
778 struct winlink *wl = fs->wl;
779 struct window_pane *wp = fs->wp;
780 const char *target = args_get(args, 't');
781 const struct options_table_entry *oe;
782 int scope = OPTIONS_TABLE_NONE;
783
784 if (*name == '@')
785 return (options_scope_from_flags(args, window, fs, oo, cause));
786
787 for (oe = options_table; oe->name != NULL; oe++) {
788 if (strcmp(oe->name, name) == 0)
789 break;
790 }
791 if (oe->name == NULL) {
792 xasprintf(cause, "unknown option: %s", name);
793 return (OPTIONS_TABLE_NONE);
794 }
795 switch (oe->scope) {
796 case OPTIONS_TABLE_SERVER:
797 *oo = global_options;
798 scope = OPTIONS_TABLE_SERVER;
799 break;
800 case OPTIONS_TABLE_SESSION:
801 if (args_has(args, 'g')) {
802 *oo = global_s_options;
803 scope = OPTIONS_TABLE_SESSION;
804 } else if (s == NULL && target != NULL)
805 xasprintf(cause, "no such session: %s", target);
806 else if (s == NULL)
807 xasprintf(cause, "no current session");
808 else {
809 *oo = s->options;
810 scope = OPTIONS_TABLE_SESSION;
811 }
812 break;
813 case OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE:
814 if (args_has(args, 'p')) {
815 if (wp == NULL && target != NULL)
816 xasprintf(cause, "no such pane: %s", target);
817 else if (wp == NULL)
818 xasprintf(cause, "no current pane");
819 else {
820 *oo = wp->options;
821 scope = OPTIONS_TABLE_PANE;
822 }
823 break;
824 }
825 /* FALLTHROUGH */
826 case OPTIONS_TABLE_WINDOW:
827 if (args_has(args, 'g')) {
828 *oo = global_w_options;
829 scope = OPTIONS_TABLE_WINDOW;
830 } else if (wl == NULL && target != NULL)
831 xasprintf(cause, "no such window: %s", target);
832 else if (wl == NULL)
833 xasprintf(cause, "no current window");
834 else {
835 *oo = wl->window->options;
836 scope = OPTIONS_TABLE_WINDOW;
837 }
838 break;
839 }
840 return (scope);
841 }
842
843 int
options_scope_from_flags(struct args * args,int window,struct cmd_find_state * fs,struct options ** oo,char ** cause)844 options_scope_from_flags(struct args *args, int window,
845 struct cmd_find_state *fs, struct options **oo, char **cause)
846 {
847 struct session *s = fs->s;
848 struct winlink *wl = fs->wl;
849 struct window_pane *wp = fs->wp;
850 const char *target = args_get(args, 't');
851
852 if (args_has(args, 's')) {
853 *oo = global_options;
854 return (OPTIONS_TABLE_SERVER);
855 }
856
857 if (args_has(args, 'p')) {
858 if (wp == NULL) {
859 if (target != NULL)
860 xasprintf(cause, "no such pane: %s", target);
861 else
862 xasprintf(cause, "no current pane");
863 return (OPTIONS_TABLE_NONE);
864 }
865 *oo = wp->options;
866 return (OPTIONS_TABLE_PANE);
867 } else if (window || args_has(args, 'w')) {
868 if (args_has(args, 'g')) {
869 *oo = global_w_options;
870 return (OPTIONS_TABLE_WINDOW);
871 }
872 if (wl == NULL) {
873 if (target != NULL)
874 xasprintf(cause, "no such window: %s", target);
875 else
876 xasprintf(cause, "no current window");
877 return (OPTIONS_TABLE_NONE);
878 }
879 *oo = wl->window->options;
880 return (OPTIONS_TABLE_WINDOW);
881 } else {
882 if (args_has(args, 'g')) {
883 *oo = global_s_options;
884 return (OPTIONS_TABLE_SESSION);
885 }
886 if (s == NULL) {
887 if (target != NULL)
888 xasprintf(cause, "no such session: %s", target);
889 else
890 xasprintf(cause, "no current session");
891 return (OPTIONS_TABLE_NONE);
892 }
893 *oo = s->options;
894 return (OPTIONS_TABLE_SESSION);
895 }
896 }
897
898 struct style *
options_string_to_style(struct options * oo,const char * name,struct format_tree * ft)899 options_string_to_style(struct options *oo, const char *name,
900 struct format_tree *ft)
901 {
902 struct options_entry *o;
903 const char *s;
904 char *expanded;
905
906 o = options_get(oo, name);
907 if (o == NULL || !OPTIONS_IS_STRING(o))
908 return (NULL);
909
910 if (o->cached)
911 return (&o->style);
912 s = o->value.string;
913 log_debug("%s: %s is '%s'", __func__, name, s);
914
915 style_set(&o->style, &grid_default_cell);
916 o->cached = (strstr(s, "#{") == NULL);
917
918 if (ft != NULL && !o->cached) {
919 expanded = format_expand(ft, s);
920 if (style_parse(&o->style, &grid_default_cell, expanded) != 0) {
921 free(expanded);
922 return (NULL);
923 }
924 free(expanded);
925 } else {
926 if (style_parse(&o->style, &grid_default_cell, s) != 0)
927 return (NULL);
928 }
929 return (&o->style);
930 }
931
932 static int
options_from_string_check(const struct options_table_entry * oe,const char * value,char ** cause)933 options_from_string_check(const struct options_table_entry *oe,
934 const char *value, char **cause)
935 {
936 struct style sy;
937
938 if (oe == NULL)
939 return (0);
940 if (strcmp(oe->name, "default-shell") == 0 && !checkshell(value)) {
941 xasprintf(cause, "not a suitable shell: %s", value);
942 return (-1);
943 }
944 if (oe->pattern != NULL && fnmatch(oe->pattern, value, 0) != 0) {
945 xasprintf(cause, "value is invalid: %s", value);
946 return (-1);
947 }
948 if ((oe->flags & OPTIONS_TABLE_IS_STYLE) &&
949 strstr(value, "#{") == NULL &&
950 style_parse(&sy, &grid_default_cell, value) != 0) {
951 xasprintf(cause, "invalid style: %s", value);
952 return (-1);
953 }
954 return (0);
955 }
956
957 static int
options_from_string_flag(struct options * oo,const char * name,const char * value,char ** cause)958 options_from_string_flag(struct options *oo, const char *name,
959 const char *value, char **cause)
960 {
961 int flag;
962
963 if (value == NULL || *value == '\0')
964 flag = !options_get_number(oo, name);
965 else if (strcmp(value, "1") == 0 ||
966 strcasecmp(value, "on") == 0 ||
967 strcasecmp(value, "yes") == 0)
968 flag = 1;
969 else if (strcmp(value, "0") == 0 ||
970 strcasecmp(value, "off") == 0 ||
971 strcasecmp(value, "no") == 0)
972 flag = 0;
973 else {
974 xasprintf(cause, "bad value: %s", value);
975 return (-1);
976 }
977 options_set_number(oo, name, flag);
978 return (0);
979 }
980
981 static int
options_from_string_choice(const struct options_table_entry * oe,struct options * oo,const char * name,const char * value,char ** cause)982 options_from_string_choice(const struct options_table_entry *oe,
983 struct options *oo, const char *name, const char *value, char **cause)
984 {
985 const char **cp;
986 int n, choice = -1;
987
988 if (value == NULL) {
989 choice = options_get_number(oo, name);
990 if (choice < 2)
991 choice = !choice;
992 } else {
993 n = 0;
994 for (cp = oe->choices; *cp != NULL; cp++) {
995 if (strcmp(*cp, value) == 0)
996 choice = n;
997 n++;
998 }
999 if (choice == -1) {
1000 xasprintf(cause, "unknown value: %s", value);
1001 return (-1);
1002 }
1003 }
1004 options_set_number(oo, name, choice);
1005 return (0);
1006 }
1007
1008 int
options_from_string(struct options * oo,const struct options_table_entry * oe,const char * name,const char * value,int append,char ** cause)1009 options_from_string(struct options *oo, const struct options_table_entry *oe,
1010 const char *name, const char *value, int append, char **cause)
1011 {
1012 enum options_table_type type;
1013 long long number;
1014 const char *errstr, *new;
1015 char *old;
1016 key_code key;
1017
1018 if (oe != NULL) {
1019 if (value == NULL &&
1020 oe->type != OPTIONS_TABLE_FLAG &&
1021 oe->type != OPTIONS_TABLE_CHOICE) {
1022 xasprintf(cause, "empty value");
1023 return (-1);
1024 }
1025 type = oe->type;
1026 } else {
1027 if (*name != '@') {
1028 xasprintf(cause, "bad option name");
1029 return (-1);
1030 }
1031 type = OPTIONS_TABLE_STRING;
1032 }
1033
1034 switch (type) {
1035 case OPTIONS_TABLE_STRING:
1036 old = xstrdup(options_get_string(oo, name));
1037 options_set_string(oo, name, append, "%s", value);
1038
1039 new = options_get_string(oo, name);
1040 if (options_from_string_check(oe, new, cause) != 0) {
1041 options_set_string(oo, name, 0, "%s", old);
1042 free(old);
1043 return (-1);
1044 }
1045 free(old);
1046 return (0);
1047 case OPTIONS_TABLE_NUMBER:
1048 number = strtonum(value, oe->minimum, oe->maximum, &errstr);
1049 if (errstr != NULL) {
1050 xasprintf(cause, "value is %s: %s", errstr, value);
1051 return (-1);
1052 }
1053 options_set_number(oo, name, number);
1054 return (0);
1055 case OPTIONS_TABLE_KEY:
1056 key = key_string_lookup_string(value);
1057 if (key == KEYC_UNKNOWN) {
1058 xasprintf(cause, "bad key: %s", value);
1059 return (-1);
1060 }
1061 options_set_number(oo, name, key);
1062 return (0);
1063 case OPTIONS_TABLE_COLOUR:
1064 if ((number = colour_fromstring(value)) == -1) {
1065 xasprintf(cause, "bad colour: %s", value);
1066 return (-1);
1067 }
1068 options_set_number(oo, name, number);
1069 return (0);
1070 case OPTIONS_TABLE_FLAG:
1071 return (options_from_string_flag(oo, name, value, cause));
1072 case OPTIONS_TABLE_CHOICE:
1073 return (options_from_string_choice(oe, oo, name, value, cause));
1074 case OPTIONS_TABLE_COMMAND:
1075 break;
1076 }
1077 return (-1);
1078 }
1079
1080 void
options_push_changes(const char * name)1081 options_push_changes(const char *name)
1082 {
1083 struct client *loop;
1084 struct session *s;
1085 struct window *w;
1086 struct window_pane *wp;
1087
1088 if (strcmp(name, "automatic-rename") == 0) {
1089 RB_FOREACH(w, windows, &windows) {
1090 if (w->active == NULL)
1091 continue;
1092 if (options_get_number(w->options, "automatic-rename"))
1093 w->active->flags |= PANE_CHANGED;
1094 }
1095 }
1096 if (strcmp(name, "key-table") == 0) {
1097 TAILQ_FOREACH(loop, &clients, entry)
1098 server_client_set_key_table(loop, NULL);
1099 }
1100 if (strcmp(name, "user-keys") == 0) {
1101 TAILQ_FOREACH(loop, &clients, entry) {
1102 if (loop->tty.flags & TTY_OPENED)
1103 tty_keys_build(&loop->tty);
1104 }
1105 }
1106 if (strcmp(name, "status") == 0 ||
1107 strcmp(name, "status-interval") == 0)
1108 status_timer_start_all();
1109 if (strcmp(name, "monitor-silence") == 0)
1110 alerts_reset_all();
1111 if (strcmp(name, "window-style") == 0 ||
1112 strcmp(name, "window-active-style") == 0) {
1113 RB_FOREACH(wp, window_pane_tree, &all_window_panes)
1114 wp->flags |= PANE_STYLECHANGED;
1115 }
1116 if (strcmp(name, "pane-border-status") == 0) {
1117 RB_FOREACH(w, windows, &windows)
1118 layout_fix_panes(w, NULL);
1119 }
1120 RB_FOREACH(s, sessions, &sessions)
1121 status_update_cache(s);
1122
1123 recalculate_sizes();
1124 TAILQ_FOREACH(loop, &clients, entry) {
1125 if (loop->session != NULL)
1126 server_redraw_client(loop);
1127 }
1128 }
1129
1130 int
options_remove_or_default(struct options_entry * o,int idx,char ** cause)1131 options_remove_or_default(struct options_entry *o, int idx, char **cause)
1132 {
1133 struct options *oo = o->owner;
1134
1135 if (idx == -1) {
1136 if (o->tableentry != NULL &&
1137 (oo == global_options ||
1138 oo == global_s_options ||
1139 oo == global_w_options))
1140 options_default(oo, o->tableentry);
1141 else
1142 options_remove(o);
1143 } else if (options_array_set(o, idx, NULL, 0, cause) != 0)
1144 return (-1);
1145 return (0);
1146 }
1147