xref: /openbsd-src/usr.bin/tmux/options.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /* $OpenBSD: options.c,v 1.5 2009/09/22 12:38:10 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
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 <string.h>
23 
24 #include "tmux.h"
25 
26 /*
27  * Option handling; each option has a name, type and value and is stored in
28  * a splay tree.
29  */
30 
31 SPLAY_GENERATE(options_tree, options_entry, entry, options_cmp);
32 
33 int
34 options_cmp(struct options_entry *o1, struct options_entry *o2)
35 {
36 	return (strcmp(o1->name, o2->name));
37 }
38 
39 void
40 options_init(struct options *oo, struct options *parent)
41 {
42 	SPLAY_INIT(&oo->tree);
43 	oo->parent = parent;
44 }
45 
46 void
47 options_free(struct options *oo)
48 {
49 	struct options_entry	*o;
50 
51 	while (!SPLAY_EMPTY(&oo->tree)) {
52 		o = SPLAY_ROOT(&oo->tree);
53 		SPLAY_REMOVE(options_tree, &oo->tree, o);
54 		xfree(o->name);
55 		if (o->type == OPTIONS_STRING)
56 			xfree(o->str);
57 		else if (o->type == OPTIONS_DATA)
58 			o->freefn(o->data);
59 		xfree(o);
60 	}
61 }
62 
63 struct options_entry *
64 options_find1(struct options *oo, const char *name)
65 {
66 	struct options_entry	p;
67 
68 	p.name = (char *) name;
69 	return (SPLAY_FIND(options_tree, &oo->tree, &p));
70 }
71 
72 struct options_entry *
73 options_find(struct options *oo, const char *name)
74 {
75 	struct options_entry	*o, p;
76 
77 	p.name = (char *) name;
78 	o = SPLAY_FIND(options_tree, &oo->tree, &p);
79 	while (o == NULL) {
80 		oo = oo->parent;
81 		if (oo == NULL)
82 			break;
83 		o = SPLAY_FIND(options_tree, &oo->tree, &p);
84 	}
85 	return (o);
86 }
87 
88 void
89 options_remove(struct options *oo, const char *name)
90 {
91 	struct options_entry	*o;
92 
93 	if ((o = options_find1(oo, name)) == NULL)
94 		return;
95 
96 	SPLAY_REMOVE(options_tree, &oo->tree, o);
97 	xfree(o->name);
98 	if (o->type == OPTIONS_STRING)
99 		xfree(o->str);
100 	else if (o->type == OPTIONS_DATA)
101 		o->freefn(o->data);
102 	xfree(o);
103 }
104 
105 struct options_entry *printflike3
106 options_set_string(struct options *oo, const char *name, const char *fmt, ...)
107 {
108 	struct options_entry	*o;
109 	va_list			 ap;
110 
111 	if ((o = options_find1(oo, name)) == NULL) {
112 		o = xmalloc(sizeof *o);
113 		o->name = xstrdup(name);
114 		SPLAY_INSERT(options_tree, &oo->tree, o);
115 	} else if (o->type == OPTIONS_STRING)
116 		xfree(o->str);
117 	else if (o->type == OPTIONS_DATA)
118 		o->freefn(o->data);
119 
120 	va_start(ap, fmt);
121 	o->type = OPTIONS_STRING;
122 	xvasprintf(&o->str, fmt, ap);
123 	va_end(ap);
124 	return (o);
125 }
126 
127 char *
128 options_get_string(struct options *oo, const char *name)
129 {
130 	struct options_entry	*o;
131 
132 	if ((o = options_find(oo, name)) == NULL)
133 		fatalx("missing option");
134 	if (o->type != OPTIONS_STRING)
135 		fatalx("option not a string");
136 	return (o->str);
137 }
138 
139 struct options_entry *
140 options_set_number(struct options *oo, const char *name, long long value)
141 {
142 	struct options_entry	*o;
143 
144 	if ((o = options_find1(oo, name)) == NULL) {
145 		o = xmalloc(sizeof *o);
146 		o->name = xstrdup(name);
147 		SPLAY_INSERT(options_tree, &oo->tree, o);
148 	} else if (o->type == OPTIONS_STRING)
149 		xfree(o->str);
150 	else if (o->type == OPTIONS_DATA)
151 		o->freefn(o->data);
152 
153 	o->type = OPTIONS_NUMBER;
154 	o->num = value;
155 	return (o);
156 }
157 
158 long long
159 options_get_number(struct options *oo, const char *name)
160 {
161 	struct options_entry	*o;
162 
163 	if ((o = options_find(oo, name)) == NULL)
164 		fatalx("missing option");
165 	if (o->type != OPTIONS_NUMBER)
166 		fatalx("option not a number");
167 	return (o->num);
168 }
169 
170 struct options_entry *
171 options_set_data(
172     struct options *oo, const char *name, void *value, void (*freefn)(void *))
173 {
174 	struct options_entry	*o;
175 
176 	if ((o = options_find1(oo, name)) == NULL) {
177 		o = xmalloc(sizeof *o);
178 		o->name = xstrdup(name);
179 		SPLAY_INSERT(options_tree, &oo->tree, o);
180 	} else if (o->type == OPTIONS_STRING)
181 		xfree(o->str);
182 	else if (o->type == OPTIONS_DATA)
183 		o->freefn(o->data);
184 
185 	o->type = OPTIONS_DATA;
186 	o->data = value;
187 	o->freefn = freefn;
188 	return (o);
189 }
190 
191 void *
192 options_get_data(struct options *oo, const char *name)
193 {
194 	struct options_entry	*o;
195 
196 	if ((o = options_find(oo, name)) == NULL)
197 		fatalx("missing option");
198 	if (o->type != OPTIONS_DATA)
199 		fatalx("option not data");
200 	return (o->data);
201 }
202