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