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(__UNCONST(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           long long                      number;
429 
430           if (!OPTIONS_IS_ARRAY(o)) {
431                     if (cause != NULL)
432                               *cause = xstrdup("not an array");
433                     return (-1);
434           }
435 
436           if (value == NULL) {
437                     a = options_array_item(o, idx);
438                     if (a != NULL)
439                               options_array_free(o, a);
440                     return (0);
441           }
442 
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;
454                     }
455 
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);
463           }
464 
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);
477           }
478 
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);
483                     }
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);
491           }
492 
493           if (cause != NULL)
494                     *cause = xstrdup("wrong array type");
495           return (-1);
496 }
497 
498 int
options_array_assign(struct options_entry * o,const char * s,char ** cause)499 options_array_assign(struct options_entry *o, const char *s, char **cause)
500 {
501           const char          *separator;
502           char                *copy, *next, *string;
503           u_int                i;
504 
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;
514                     }
515                     return (options_array_set(o, i, s, 0, cause));
516           }
517 
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;
527                     }
528                     if (i == UINT_MAX)
529                               break;
530                     if (options_array_set(o, i, next, 0, cause) != 0) {
531                               free(copy);
532                               return (-1);
533                     }
534           }
535           free(copy);
536           return (0);
537 }
538 
539 struct options_array_item *
options_array_first(struct options_entry * o)540 options_array_first(struct options_entry *o)
541 {
542           if (!OPTIONS_IS_ARRAY(o))
543                     return (NULL);
544           return (RB_MIN(options_array, &o->value.array));
545 }
546 
547 struct options_array_item *
options_array_next(struct options_array_item * a)548 options_array_next(struct options_array_item *a)
549 {
550           return (RB_NEXT(options_array, &o->value.array, a));
551 }
552 
553 u_int
options_array_item_index(struct options_array_item * a)554 options_array_item_index(struct options_array_item *a)
555 {
556           return (a->index);
557 }
558 
559 union options_value *
options_array_item_value(struct options_array_item * a)560 options_array_item_value(struct options_array_item *a)
561 {
562           return (&a->value);
563 }
564 
565 int
options_is_array(struct options_entry * o)566 options_is_array(struct options_entry *o)
567 {
568           return (OPTIONS_IS_ARRAY(o));
569 }
570 
571 int
options_is_string(struct options_entry * o)572 options_is_string(struct options_entry *o)
573 {
574           return (OPTIONS_IS_STRING(o));
575 }
576 
577 char *
options_to_string(struct options_entry * o,int idx,int numeric)578 options_to_string(struct options_entry *o, int idx, int numeric)
579 {
580           struct options_array_item     *a;
581           char                                    *result = NULL;
582           char                                    *last = NULL;
583           char                                    *next;
584 
585           if (OPTIONS_IS_ARRAY(o)) {
586                     if (idx == -1) {
587                               RB_FOREACH(a, options_array, &o->value.array) {
588                                         next = options_value_to_string(o, &a->value,
589                                             numeric);
590                                         if (last == NULL)
591                                                   result = next;
592                                         else {
593                                                   xasprintf(&result, "%s %s", last, next);
594                                                   free(last);
595                                                   free(next);
596                                         }
597                                         last = result;
598                               }
599                               if (result == NULL)
600                                         return (xstrdup(""));
601                               return (result);
602                     }
603                     a = options_array_item(o, idx);
604                     if (a == NULL)
605                               return (xstrdup(""));
606                     return (options_value_to_string(o, &a->value, numeric));
607           }
608           return (options_value_to_string(o, &o->value, numeric));
609 }
610 
611 char *
options_parse(const char * name,int * idx)612 options_parse(const char *name, int *idx)
613 {
614           char      *copy, *cp, *end;
615 
616           if (*name == '\0')
617                     return (NULL);
618           copy = xstrdup(name);
619           if ((cp = strchr(copy, '[')) == NULL) {
620                     *idx = -1;
621                     return (copy);
622           }
623           end = strchr(cp + 1, ']');
624           if (end == NULL || end[1] != '\0' || !isdigit((u_char)end[-1])) {
625                     free(copy);
626                     return (NULL);
627           }
628           if (sscanf(cp, "[%d]", idx) != 1 || *idx < 0) {
629                     free(copy);
630                     return (NULL);
631           }
632           *cp = '\0';
633           return (copy);
634 }
635 
636 struct options_entry *
options_parse_get(struct options * oo,const char * s,int * idx,int only)637 options_parse_get(struct options *oo, const char *s, int *idx, int only)
638 {
639           struct options_entry          *o;
640           char                          *name;
641 
642           name = options_parse(s, idx);
643           if (name == NULL)
644                     return (NULL);
645           if (only)
646                     o = options_get_only(oo, name);
647           else
648                     o = options_get(oo, name);
649           free(name);
650           return (o);
651 }
652 
653 char *
options_match(const char * s,int * idx,int * ambiguous)654 options_match(const char *s, int *idx, int *ambiguous)
655 {
656           const struct options_table_entry        *oe, *found;
657           char                                              *parsed;
658           const char                                        *name;
659           size_t                                             namelen;
660 
661           parsed = options_parse(s, idx);
662           if (parsed == NULL)
663                     return (NULL);
664           if (*parsed == '@') {
665                     *ambiguous = 0;
666                     return (parsed);
667           }
668 
669           name = options_map_name(parsed);
670           namelen = strlen(name);
671 
672           found = NULL;
673           for (oe = options_table; oe->name != NULL; oe++) {
674                     if (strcmp(oe->name, name) == 0) {
675                               found = oe;
676                               break;
677                     }
678                     if (strncmp(oe->name, name, namelen) == 0) {
679                               if (found != NULL) {
680                                         *ambiguous = 1;
681                                         free(parsed);
682                                         return (NULL);
683                               }
684                               found = oe;
685                     }
686           }
687           free(parsed);
688           if (found == NULL) {
689                     *ambiguous = 0;
690                     return (NULL);
691           }
692           return (xstrdup(found->name));
693 }
694 
695 struct options_entry *
options_match_get(struct options * oo,const char * s,int * idx,int only,int * ambiguous)696 options_match_get(struct options *oo, const char *s, int *idx, int only,
697     int *ambiguous)
698 {
699           char                          *name;
700           struct options_entry          *o;
701 
702           name = options_match(s, idx, ambiguous);
703           if (name == NULL)
704                     return (NULL);
705           *ambiguous = 0;
706           if (only)
707                     o = options_get_only(oo, name);
708           else
709                     o = options_get(oo, name);
710           free(name);
711           return (o);
712 }
713 
714 const char *
options_get_string(struct options * oo,const char * name)715 options_get_string(struct options *oo, const char *name)
716 {
717           struct options_entry          *o;
718 
719           o = options_get(oo, name);
720           if (o == NULL)
721                     fatalx("missing option %s", name);
722           if (!OPTIONS_IS_STRING(o))
723                     fatalx("option %s is not a string", name);
724           return (o->value.string);
725 }
726 
727 long long
options_get_number(struct options * oo,const char * name)728 options_get_number(struct options *oo, const char *name)
729 {
730           struct options_entry          *o;
731 
732           o = options_get(oo, name);
733           if (o == NULL)
734                     fatalx("missing option %s", name);
735           if (!OPTIONS_IS_NUMBER(o))
736                     fatalx("option %s is not a number", name);
737           return (o->value.number);
738 }
739 
740 struct options_entry *
options_set_string(struct options * oo,const char * name,int append,const char * fmt,...)741 options_set_string(struct options *oo, const char *name, int append,
742     const char *fmt, ...)
743 {
744           struct options_entry          *o;
745           va_list                        ap;
746           const char                    *separator = "";
747           char                          *s, *value;
748 
749           va_start(ap, fmt);
750           xvasprintf(&s, fmt, ap);
751           va_end(ap);
752 
753           o = options_get_only(oo, name);
754           if (o != NULL && append && OPTIONS_IS_STRING(o)) {
755                     if (*name != '@') {
756                               separator = o->tableentry->separator;
757                               if (separator == NULL)
758                                         separator = "";
759                     }
760                     xasprintf(&value, "%s%s%s", o->value.string, separator, s);
761                     free(s);
762           } else
763                     value = s;
764           if (o == NULL && *name == '@')
765                     o = options_add(oo, name);
766           else if (o == NULL) {
767                     o = options_default(oo, options_parent_table_entry(oo, name));
768                     if (o == NULL)
769                               return (NULL);
770           }
771 
772           if (!OPTIONS_IS_STRING(o))
773                     fatalx("option %s is not a string", name);
774           free(o->value.string);
775           o->value.string = value;
776           o->cached = 0;
777           return (o);
778 }
779 
780 struct options_entry *
options_set_number(struct options * oo,const char * name,long long value)781 options_set_number(struct options *oo, const char *name, long long value)
782 {
783           struct options_entry          *o;
784 
785           if (*name == '@')
786                     fatalx("user option %s must be a string", name);
787 
788           o = options_get_only(oo, name);
789           if (o == NULL) {
790                     o = options_default(oo, options_parent_table_entry(oo, name));
791                     if (o == NULL)
792                               return (NULL);
793           }
794 
795           if (!OPTIONS_IS_NUMBER(o))
796                     fatalx("option %s is not a number", name);
797           o->value.number = value;
798           return (o);
799 }
800 
801 int
options_scope_from_name(struct args * args,int window,const char * name,struct cmd_find_state * fs,struct options ** oo,char ** cause)802 options_scope_from_name(struct args *args, int window,
803     const char *name, struct cmd_find_state *fs, struct options **oo,
804     char **cause)
805 {
806           struct session                                    *s = fs->s;
807           struct winlink                                    *wl = fs->wl;
808           struct window_pane                      *wp = fs->wp;
809           const char                                        *target = args_get(args, 't');
810           const struct options_table_entry        *oe;
811           int                                                scope = OPTIONS_TABLE_NONE;
812 
813           if (*name == '@')
814                     return (options_scope_from_flags(args, window, fs, oo, cause));
815 
816           for (oe = options_table; oe->name != NULL; oe++) {
817                     if (strcmp(oe->name, name) == 0)
818                               break;
819           }
820           if (oe->name == NULL) {
821                     xasprintf(cause, "unknown option: %s", name);
822                     return (OPTIONS_TABLE_NONE);
823           }
824           switch (oe->scope) {
825           case OPTIONS_TABLE_SERVER:
826                     *oo = global_options;
827                     scope = OPTIONS_TABLE_SERVER;
828                     break;
829           case OPTIONS_TABLE_SESSION:
830                     if (args_has(args, 'g')) {
831                               *oo = global_s_options;
832                               scope = OPTIONS_TABLE_SESSION;
833                     } else if (s == NULL && target != NULL)
834                               xasprintf(cause, "no such session: %s", target);
835                     else if (s == NULL)
836                               xasprintf(cause, "no current session");
837                     else {
838                               *oo = s->options;
839                               scope = OPTIONS_TABLE_SESSION;
840                     }
841                     break;
842           case OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE:
843                     if (args_has(args, 'p')) {
844                               if (wp == NULL && target != NULL)
845                                         xasprintf(cause, "no such pane: %s", target);
846                               else if (wp == NULL)
847                                         xasprintf(cause, "no current pane");
848                               else {
849                                         *oo = wp->options;
850                                         scope = OPTIONS_TABLE_PANE;
851                               }
852                               break;
853                     }
854                     /* FALLTHROUGH */
855           case OPTIONS_TABLE_WINDOW:
856                     if (args_has(args, 'g')) {
857                               *oo = global_w_options;
858                               scope = OPTIONS_TABLE_WINDOW;
859                     } else if (wl == NULL && target != NULL)
860                               xasprintf(cause, "no such window: %s", target);
861                     else if (wl == NULL)
862                               xasprintf(cause, "no current window");
863                     else {
864                               *oo = wl->window->options;
865                               scope = OPTIONS_TABLE_WINDOW;
866                     }
867                     break;
868           }
869           return (scope);
870 }
871 
872 int
options_scope_from_flags(struct args * args,int window,struct cmd_find_state * fs,struct options ** oo,char ** cause)873 options_scope_from_flags(struct args *args, int window,
874     struct cmd_find_state *fs, struct options **oo, char **cause)
875 {
876           struct session                *s = fs->s;
877           struct winlink                *wl = fs->wl;
878           struct window_pane  *wp = fs->wp;
879           const char                    *target = args_get(args, 't');
880 
881           if (args_has(args, 's')) {
882                     *oo = global_options;
883                     return (OPTIONS_TABLE_SERVER);
884           }
885 
886           if (args_has(args, 'p')) {
887                     if (wp == NULL) {
888                               if (target != NULL)
889                                         xasprintf(cause, "no such pane: %s", target);
890                               else
891                                         xasprintf(cause, "no current pane");
892                               return (OPTIONS_TABLE_NONE);
893                     }
894                     *oo = wp->options;
895                     return (OPTIONS_TABLE_PANE);
896           } else if (window || args_has(args, 'w')) {
897                     if (args_has(args, 'g')) {
898                               *oo = global_w_options;
899                               return (OPTIONS_TABLE_WINDOW);
900                     }
901                     if (wl == NULL) {
902                               if (target != NULL)
903                                         xasprintf(cause, "no such window: %s", target);
904                               else
905                                         xasprintf(cause, "no current window");
906                               return (OPTIONS_TABLE_NONE);
907                     }
908                     *oo = wl->window->options;
909                     return (OPTIONS_TABLE_WINDOW);
910           } else {
911                     if (args_has(args, 'g')) {
912                               *oo = global_s_options;
913                               return (OPTIONS_TABLE_SESSION);
914                     }
915                     if (s == NULL) {
916                               if (target != NULL)
917                                         xasprintf(cause, "no such session: %s", target);
918                               else
919                                         xasprintf(cause, "no current session");
920                               return (OPTIONS_TABLE_NONE);
921                     }
922                     *oo = s->options;
923                     return (OPTIONS_TABLE_SESSION);
924           }
925 }
926 
927 struct style *
options_string_to_style(struct options * oo,const char * name,struct format_tree * ft)928 options_string_to_style(struct options *oo, const char *name,
929     struct format_tree *ft)
930 {
931           struct options_entry          *o;
932           const char                    *s;
933           char                          *expanded;
934 
935           o = options_get(oo, name);
936           if (o == NULL || !OPTIONS_IS_STRING(o))
937                     return (NULL);
938 
939           if (o->cached)
940                     return (&o->style);
941           s = o->value.string;
942           log_debug("%s: %s is '%s'", __func__, name, s);
943 
944           style_set(&o->style, &grid_default_cell);
945           o->cached = (strstr(s, "#{") == NULL);
946 
947           if (ft != NULL && !o->cached) {
948                     expanded = format_expand(ft, s);
949                     if (style_parse(&o->style, &grid_default_cell, expanded) != 0) {
950                               free(expanded);
951                               return (NULL);
952                     }
953                     free(expanded);
954           } else {
955                     if (style_parse(&o->style, &grid_default_cell, s) != 0)
956                               return (NULL);
957           }
958           return (&o->style);
959 }
960 
961 static int
options_from_string_check(const struct options_table_entry * oe,const char * value,char ** cause)962 options_from_string_check(const struct options_table_entry *oe,
963     const char *value, char **cause)
964 {
965           struct style        sy;
966 
967           if (oe == NULL)
968                     return (0);
969           if (strcmp(oe->name, "default-shell") == 0 && !checkshell(value)) {
970                     xasprintf(cause, "not a suitable shell: %s", value);
971                     return (-1);
972           }
973           if (oe->pattern != NULL && fnmatch(oe->pattern, value, 0) != 0) {
974                     xasprintf(cause, "value is invalid: %s", value);
975                     return (-1);
976           }
977           if ((oe->flags & OPTIONS_TABLE_IS_STYLE) &&
978               strstr(value, "#{") == NULL &&
979               style_parse(&sy, &grid_default_cell, value) != 0) {
980                     xasprintf(cause, "invalid style: %s", value);
981                     return (-1);
982           }
983           return (0);
984 }
985 
986 static int
options_from_string_flag(struct options * oo,const char * name,const char * value,char ** cause)987 options_from_string_flag(struct options *oo, const char *name,
988     const char *value, char **cause)
989 {
990           int       flag;
991 
992           if (value == NULL || *value == '\0')
993                     flag = !options_get_number(oo, name);
994           else if (strcmp(value, "1") == 0 ||
995               strcasecmp(value, "on") == 0 ||
996               strcasecmp(value, "yes") == 0)
997                     flag = 1;
998           else if (strcmp(value, "0") == 0 ||
999               strcasecmp(value, "off") == 0 ||
1000               strcasecmp(value, "no") == 0)
1001                     flag = 0;
1002           else {
1003                     xasprintf(cause, "bad value: %s", value);
1004                     return (-1);
1005           }
1006           options_set_number(oo, name, flag);
1007           return (0);
1008 }
1009 
1010 int
options_find_choice(const struct options_table_entry * oe,const char * value,char ** cause)1011 options_find_choice(const struct options_table_entry *oe, const char *value,
1012     char **cause)
1013 {
1014           const char          **cp;
1015           int                   n = 0, choice = -1;
1016 
1017           for (cp = oe->choices; *cp != NULL; cp++) {
1018                     if (strcmp(*cp, value) == 0)
1019                               choice = n;
1020                     n++;
1021           }
1022           if (choice == -1) {
1023                     xasprintf(cause, "unknown value: %s", value);
1024                     return (-1);
1025           }
1026           return (choice);
1027 }
1028 
1029 static int
options_from_string_choice(const struct options_table_entry * oe,struct options * oo,const char * name,const char * value,char ** cause)1030 options_from_string_choice(const struct options_table_entry *oe,
1031     struct options *oo, const char *name, const char *value, char **cause)
1032 {
1033           int       choice = -1;
1034 
1035           if (value == NULL) {
1036                     choice = options_get_number(oo, name);
1037                     if (choice < 2)
1038                               choice = !choice;
1039           } else {
1040                     choice = options_find_choice(oe, value, cause);
1041                     if (choice < 0)
1042                               return (-1);
1043           }
1044           options_set_number(oo, name, choice);
1045           return (0);
1046 }
1047 
1048 int
options_from_string(struct options * oo,const struct options_table_entry * oe,const char * name,const char * value,int append,char ** cause)1049 options_from_string(struct options *oo, const struct options_table_entry *oe,
1050     const char *name, const char *value, int append, char **cause)
1051 {
1052           enum options_table_type        type;
1053           long long            number;
1054           const char                    *errstr, *new;
1055           char                          *old;
1056           key_code             key;
1057 
1058           if (oe != NULL) {
1059                     if (value == NULL &&
1060                         oe->type != OPTIONS_TABLE_FLAG &&
1061                         oe->type != OPTIONS_TABLE_CHOICE) {
1062                               xasprintf(cause, "empty value");
1063                               return (-1);
1064                     }
1065                     type = oe->type;
1066           } else {
1067                     if (*name != '@') {
1068                               xasprintf(cause, "bad option name");
1069                               return (-1);
1070                     }
1071                     type = OPTIONS_TABLE_STRING;
1072           }
1073 
1074           switch (type) {
1075           case OPTIONS_TABLE_STRING:
1076                     old = xstrdup(options_get_string(oo, name));
1077                     options_set_string(oo, name, append, "%s", value);
1078 
1079                     new = options_get_string(oo, name);
1080                     if (options_from_string_check(oe, new, cause) != 0) {
1081                               options_set_string(oo, name, 0, "%s", old);
1082                               free(old);
1083                               return (-1);
1084                     }
1085                     free(old);
1086                     return (0);
1087           case OPTIONS_TABLE_NUMBER:
1088                     number = strtonum(value, oe->minimum, oe->maximum, &errstr);
1089                     if (errstr != NULL) {
1090                               xasprintf(cause, "value is %s: %s", errstr, value);
1091                               return (-1);
1092                     }
1093                     options_set_number(oo, name, number);
1094                     return (0);
1095           case OPTIONS_TABLE_KEY:
1096                     key = key_string_lookup_string(value);
1097                     if (key == KEYC_UNKNOWN) {
1098                               xasprintf(cause, "bad key: %s", value);
1099                               return (-1);
1100                     }
1101                     options_set_number(oo, name, key);
1102                     return (0);
1103           case OPTIONS_TABLE_COLOUR:
1104                     if ((number = colour_fromstring(value)) == -1) {
1105                               xasprintf(cause, "bad colour: %s", value);
1106                               return (-1);
1107                     }
1108                     options_set_number(oo, name, number);
1109                     return (0);
1110           case OPTIONS_TABLE_FLAG:
1111                     return (options_from_string_flag(oo, name, value, cause));
1112           case OPTIONS_TABLE_CHOICE:
1113                     return (options_from_string_choice(oe, oo, name, value, cause));
1114           case OPTIONS_TABLE_COMMAND:
1115                     break;
1116           }
1117           return (-1);
1118 }
1119 
1120 void
options_push_changes(const char * name)1121 options_push_changes(const char *name)
1122 {
1123           struct client                 *loop;
1124           struct session                *s;
1125           struct window                 *w;
1126           struct window_pane  *wp;
1127 
1128           log_debug("%s: %s", __func__, name);
1129 
1130           if (strcmp(name, "automatic-rename") == 0) {
1131                     RB_FOREACH(w, windows, &windows) {
1132                               if (w->active == NULL)
1133                                         continue;
1134                               if (options_get_number(w->options, name))
1135                                         w->active->flags |= PANE_CHANGED;
1136                     }
1137           }
1138           if (strcmp(name, "cursor-colour") == 0) {
1139                     RB_FOREACH(wp, window_pane_tree, &all_window_panes)
1140                               window_pane_default_cursor(wp);
1141           }
1142           if (strcmp(name, "cursor-style") == 0) {
1143                     RB_FOREACH(wp, window_pane_tree, &all_window_panes)
1144                               window_pane_default_cursor(wp);
1145           }
1146           if (strcmp(name, "fill-character") == 0) {
1147                     RB_FOREACH(w, windows, &windows)
1148                               window_set_fill_character(w);
1149           }
1150           if (strcmp(name, "key-table") == 0) {
1151                     TAILQ_FOREACH(loop, &clients, entry)
1152                               server_client_set_key_table(loop, NULL);
1153           }
1154           if (strcmp(name, "user-keys") == 0) {
1155                     TAILQ_FOREACH(loop, &clients, entry) {
1156                               if (loop->tty.flags & TTY_OPENED)
1157                                         tty_keys_build(&loop->tty);
1158                     }
1159           }
1160           if (strcmp(name, "status") == 0 ||
1161               strcmp(name, "status-interval") == 0)
1162                     status_timer_start_all();
1163           if (strcmp(name, "monitor-silence") == 0)
1164                     alerts_reset_all();
1165           if (strcmp(name, "window-style") == 0 ||
1166               strcmp(name, "window-active-style") == 0) {
1167                     RB_FOREACH(wp, window_pane_tree, &all_window_panes)
1168                               wp->flags |= PANE_STYLECHANGED;
1169           }
1170           if (strcmp(name, "pane-colours") == 0) {
1171                     RB_FOREACH(wp, window_pane_tree, &all_window_panes)
1172                               colour_palette_from_option(&wp->palette, wp->options);
1173           }
1174           if (strcmp(name, "pane-border-status") == 0) {
1175                     RB_FOREACH(w, windows, &windows)
1176                               layout_fix_panes(w, NULL);
1177           }
1178           RB_FOREACH(s, sessions, &sessions)
1179                     status_update_cache(s);
1180 
1181           recalculate_sizes();
1182           TAILQ_FOREACH(loop, &clients, entry) {
1183                     if (loop->session != NULL)
1184                               server_redraw_client(loop);
1185           }
1186 }
1187 
1188 int
options_remove_or_default(struct options_entry * o,int idx,char ** cause)1189 options_remove_or_default(struct options_entry *o, int idx, char **cause)
1190 {
1191           struct options      *oo = o->owner;
1192 
1193           if (idx == -1) {
1194                     if (o->tableentry != NULL &&
1195                         (oo == global_options ||
1196                         oo == global_s_options ||
1197                         oo == global_w_options))
1198                               options_default(oo, o->tableentry);
1199                     else
1200                               options_remove(o);
1201           } else if (options_array_set(o, idx, NULL, 0, cause) != 0)
1202                     return (-1);
1203           return (0);
1204 }
1205