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