options.c revision 1.13
1/* $OpenBSD: options.c,v 1.13 2015/10/27 15:58:42 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 <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
37int	options_cmp(struct options_entry *, struct options_entry *);
38RB_PROTOTYPE(options_tree, options_entry, entry, options_cmp);
39RB_GENERATE(options_tree, options_entry, entry, options_cmp);
40
41int
42options_cmp(struct options_entry *o1, struct options_entry *o2)
43{
44	return (strcmp(o1->name, o2->name));
45}
46
47struct options *
48options_create(struct options *parent)
49{
50	struct options *oo;
51
52	oo = xcalloc(1, sizeof *oo);
53	RB_INIT(&oo->tree);
54	oo->parent = parent;
55	return (oo);
56}
57
58void
59options_free(struct options *oo)
60{
61	struct options_entry	*o;
62
63	while (!RB_EMPTY(&oo->tree)) {
64		o = RB_ROOT(&oo->tree);
65		RB_REMOVE(options_tree, &oo->tree, o);
66		free(o->name);
67		if (o->type == OPTIONS_STRING)
68			free(o->str);
69		free(o);
70	}
71	free(oo);
72}
73
74struct options_entry *
75options_first(struct options *oo)
76{
77	return (RB_MIN(options_tree, &oo->tree));
78}
79
80struct options_entry *
81options_next(struct options_entry *o)
82{
83	return (RB_NEXT(options_tree, &oo->tree, o));
84}
85
86struct options_entry *
87options_find1(struct options *oo, const char *name)
88{
89	struct options_entry	p;
90
91	p.name = (char *) name;
92	return (RB_FIND(options_tree, &oo->tree, &p));
93}
94
95struct options_entry *
96options_find(struct options *oo, const char *name)
97{
98	struct options_entry	*o, p;
99
100	p.name = (char *) name;
101	o = RB_FIND(options_tree, &oo->tree, &p);
102	while (o == NULL) {
103		oo = oo->parent;
104		if (oo == NULL)
105			break;
106		o = RB_FIND(options_tree, &oo->tree, &p);
107	}
108	return (o);
109}
110
111void
112options_remove(struct options *oo, const char *name)
113{
114	struct options_entry	*o;
115
116	if ((o = options_find1(oo, name)) == NULL)
117		return;
118
119	RB_REMOVE(options_tree, &oo->tree, o);
120	free(o->name);
121	if (o->type == OPTIONS_STRING)
122		free(o->str);
123	free(o);
124}
125
126struct options_entry *
127options_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
147char *
148options_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");
154	if (o->type != OPTIONS_STRING)
155		fatalx("option not a string");
156	return (o->str);
157}
158
159struct options_entry *
160options_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
177long long
178options_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");
184	if (o->type != OPTIONS_NUMBER)
185		fatalx("option not a number");
186	return (o->num);
187}
188
189struct options_entry *
190options_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
217struct grid_cell *
218options_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");
224	if (o->type != OPTIONS_STYLE)
225		fatalx("option not a style");
226	return (&o->style);
227}
228