xref: /openbsd/usr.bin/tmux/options.c (revision 264ca280)
1 /* $OpenBSD: options.c,v 1.18 2016/01/19 15:59:12 nicm Exp $ */
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 <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "tmux.h"
26 
27 /*
28  * Option handling; each option has a name, type and value and is stored in
29  * a red-black tree.
30  */
31 
32 struct options {
33 	RB_HEAD(options_tree, options_entry) tree;
34 	struct options	*parent;
35 };
36 
37 static int	options_cmp(struct options_entry *, struct options_entry *);
38 RB_PROTOTYPE(options_tree, options_entry, entry, options_cmp);
39 RB_GENERATE(options_tree, options_entry, entry, options_cmp);
40 
41 static void	options_free1(struct options *, struct options_entry *);
42 
43 static int
44 options_cmp(struct options_entry *o1, struct options_entry *o2)
45 {
46 	return (strcmp(o1->name, o2->name));
47 }
48 
49 struct options *
50 options_create(struct options *parent)
51 {
52 	struct options	*oo;
53 
54 	oo = xcalloc(1, sizeof *oo);
55 	RB_INIT(&oo->tree);
56 	oo->parent = parent;
57 	return (oo);
58 }
59 
60 static void
61 options_free1(struct options *oo, struct options_entry *o)
62 {
63 	RB_REMOVE(options_tree, &oo->tree, o);
64 	free((char *)o->name);
65 	if (o->type == OPTIONS_STRING)
66 		free(o->str);
67 	free(o);
68 }
69 
70 void
71 options_free(struct options *oo)
72 {
73 	struct options_entry	*o, *o1;
74 
75 	RB_FOREACH_SAFE (o, options_tree, &oo->tree, o1)
76 		options_free1(oo, o);
77 	free(oo);
78 }
79 
80 struct options_entry *
81 options_first(struct options *oo)
82 {
83 	return (RB_MIN(options_tree, &oo->tree));
84 }
85 
86 struct options_entry *
87 options_next(struct options_entry *o)
88 {
89 	return (RB_NEXT(options_tree, &oo->tree, o));
90 }
91 
92 struct options_entry *
93 options_find1(struct options *oo, const char *name)
94 {
95 	struct options_entry	p;
96 
97 	p.name = (char *)name;
98 	return (RB_FIND(options_tree, &oo->tree, &p));
99 }
100 
101 struct options_entry *
102 options_find(struct options *oo, const char *name)
103 {
104 	struct options_entry	*o, p;
105 
106 	p.name = (char *)name;
107 	o = RB_FIND(options_tree, &oo->tree, &p);
108 	while (o == NULL) {
109 		oo = oo->parent;
110 		if (oo == NULL)
111 			break;
112 		o = RB_FIND(options_tree, &oo->tree, &p);
113 	}
114 	return (o);
115 }
116 
117 void
118 options_remove(struct options *oo, const char *name)
119 {
120 	struct options_entry	*o;
121 
122 	if ((o = options_find1(oo, name)) != NULL)
123 		options_free1(oo, o);
124 }
125 
126 struct options_entry *
127 options_set_string(struct options *oo, const char *name, const char *fmt, ...)
128 {
129 	struct options_entry	*o;
130 	va_list			 ap;
131 
132 	if ((o = options_find1(oo, name)) == NULL) {
133 		o = xmalloc(sizeof *o);
134 		o->name = xstrdup(name);
135 		RB_INSERT(options_tree, &oo->tree, o);
136 		memcpy(&o->style, &grid_default_cell, sizeof o->style);
137 	} else if (o->type == OPTIONS_STRING)
138 		free(o->str);
139 
140 	va_start(ap, fmt);
141 	o->type = OPTIONS_STRING;
142 	xvasprintf(&o->str, fmt, ap);
143 	va_end(ap);
144 	return (o);
145 }
146 
147 char *
148 options_get_string(struct options *oo, const char *name)
149 {
150 	struct options_entry	*o;
151 
152 	if ((o = options_find(oo, name)) == NULL)
153 		fatalx("missing option %s", name);
154 	if (o->type != OPTIONS_STRING)
155 		fatalx("option %s not a string", name);
156 	return (o->str);
157 }
158 
159 struct options_entry *
160 options_set_number(struct options *oo, const char *name, long long value)
161 {
162 	struct options_entry	*o;
163 
164 	if ((o = options_find1(oo, name)) == NULL) {
165 		o = xmalloc(sizeof *o);
166 		o->name = xstrdup(name);
167 		RB_INSERT(options_tree, &oo->tree, o);
168 		memcpy(&o->style, &grid_default_cell, sizeof o->style);
169 	} else if (o->type == OPTIONS_STRING)
170 		free(o->str);
171 
172 	o->type = OPTIONS_NUMBER;
173 	o->num = value;
174 	return (o);
175 }
176 
177 long long
178 options_get_number(struct options *oo, const char *name)
179 {
180 	struct options_entry	*o;
181 
182 	if ((o = options_find(oo, name)) == NULL)
183 		fatalx("missing option %s", name);
184 	if (o->type != OPTIONS_NUMBER)
185 		fatalx("option %s not a number", name);
186 	return (o->num);
187 }
188 
189 struct options_entry *
190 options_set_style(struct options *oo, const char *name, const char *value,
191     int append)
192 {
193 	struct options_entry	*o;
194 	struct grid_cell	 tmpgc;
195 
196 	o = options_find1(oo, name);
197 	if (o == NULL || !append)
198 		memcpy(&tmpgc, &grid_default_cell, sizeof tmpgc);
199 	else
200 		memcpy(&tmpgc, &o->style, sizeof tmpgc);
201 
202 	if (style_parse(&grid_default_cell, &tmpgc, value) == -1)
203 		return (NULL);
204 
205 	if (o == NULL) {
206 		o = xmalloc(sizeof *o);
207 		o->name = xstrdup(name);
208 		RB_INSERT(options_tree, &oo->tree, o);
209 	} else if (o->type == OPTIONS_STRING)
210 		free(o->str);
211 
212 	o->type = OPTIONS_STYLE;
213 	memcpy(&o->style, &tmpgc, sizeof o->style);
214 	return (o);
215 }
216 
217 struct grid_cell *
218 options_get_style(struct options *oo, const char *name)
219 {
220 	struct options_entry	*o;
221 
222 	if ((o = options_find(oo, name)) == NULL)
223 		fatalx("missing option %s", name);
224 	if (o->type != OPTIONS_STYLE)
225 		fatalx("option %s not a style", name);
226 	return (&o->style);
227 }
228