1/* $NetBSD: config.c,v 1.2 2003/03/04 19:28:59 jmmv Exp $ */
2
3/*
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julio M. Merino Vidal.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. The name authors may not be used to endorse or promote products
16 *    derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33
34#ifndef lint
35__RCSID("$NetBSD: config.c,v 1.2 2003/03/04 19:28:59 jmmv Exp $");
36#endif /* not lint */
37
38#include <sys/time.h>
39#include <dev/wscons/wsconsio.h>
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <err.h>
44#include <errno.h>
45#include <string.h>
46
47#include "pathnames.h"
48#include "wsmoused.h"
49
50/* --------------------------------------------------------------------- */
51
52/*
53 * Global variables.
54 */
55
56static struct block *Global = NULL;
57
58/* --------------------------------------------------------------------- */
59
60/* Prototypes for config_yacc.y (only used here) */
61struct block *config_parse(FILE *);
62
63/* --------------------------------------------------------------------- */
64
65/* Creates a new, empty property.  Returns a pointer to it. */
66struct prop *
67prop_new(void)
68{
69	struct prop *p;
70
71	p = (struct prop *) calloc(1, sizeof(struct prop));
72	if (p == NULL)
73		err(EXIT_FAILURE, "calloc");
74	return p;
75}
76
77/* --------------------------------------------------------------------- */
78
79/* Frees a property created with prop_new.  All data stored in the property
80 * is also destroyed. */
81void
82prop_free(struct prop *p)
83{
84
85	free(p->p_name);
86	free(p->p_value);
87	free(p);
88}
89
90/* --------------------------------------------------------------------- */
91
92/* Creates a new, empty block, with the specified type (see BLOCK_* macros).
93 * Returns a pointer to it. */
94struct block *
95block_new(int type)
96{
97	struct block *b;
98
99	b = (struct block *) calloc(1, sizeof(struct block));
100	if (b == NULL)
101		err(EXIT_FAILURE, "calloc");
102	b->b_type = type;
103	return b;
104}
105
106/* --------------------------------------------------------------------- */
107
108/* Frees a block created with block_new.  All data contained inside the block
109 * is also destroyed. */
110void
111block_free(struct block *b)
112{
113	int i;
114
115	if (b->b_name != NULL)
116		free(b->b_name);
117
118	for (i = 0; i < b->b_prop_count; i++)
119		prop_free(b->b_prop[i]);
120	for (i = 0; i < b->b_child_count; i++)
121		block_free(b->b_child[i]);
122
123	free(b);
124}
125
126/* --------------------------------------------------------------------- */
127
128/* Adds a property to a block. */
129void
130block_add_prop(struct block *b, struct prop *p)
131{
132
133	if (p == NULL)
134		return;
135
136	if (b->b_prop_count >= MAX_PROPS)
137		errx(EXIT_FAILURE, "too many properties for current block");
138	else {
139		b->b_prop[b->b_prop_count] = p;
140		b->b_prop_count++;
141	}
142}
143
144/* --------------------------------------------------------------------- */
145
146/* Adds a child (block) to a block. */
147void
148block_add_child(struct block *b, struct block *c)
149{
150
151	if (c == NULL)
152		return;
153
154	if (b->b_child_count >= MAX_BLOCKS)
155		errx(EXIT_FAILURE, "too many childs for current block");
156	else {
157		c->b_parent = b;
158		b->b_child[b->b_child_count] = c;
159		b->b_child_count++;
160	}
161}
162
163/* --------------------------------------------------------------------- */
164
165/* Get the value of a property in the specified block (or in its parents).
166 * If not found, return the value given in def. */
167char *
168block_get_propval(struct block *b, const char *pname, char *def)
169{
170	int pc;
171
172	if (b == NULL)
173		return def;
174
175	while (b != NULL) {
176		for (pc = 0; pc < b->b_prop_count; pc++)
177			if (strcmp(b->b_prop[pc]->p_name, pname) == 0)
178				return b->b_prop[pc]->p_value;
179		b = b->b_parent;
180	}
181
182	return def;
183}
184
185/* --------------------------------------------------------------------- */
186
187/* Get the value of a property in the specified block converting it to an
188 * integer, if possible.  If the property cannot be found in the given
189 * block, all its parents are tried.  If after all not found (or conversion
190 * not possible), return the value given in def. */
191int
192block_get_propval_int(struct block *b, const char *pname, int def)
193{
194	char *ptr;
195	int pc, ret;
196
197	if (b == NULL)
198		return def;
199
200	while (b != NULL) {
201		for (pc = 0; pc < b->b_prop_count; pc++)
202			if (strcmp(b->b_prop[pc]->p_name, pname) == 0) {
203				ret = (int) strtol(b->b_prop[pc]->p_value,
204				    &ptr, 10);
205				if (b->b_prop[pc]->p_value == ptr) {
206					warnx("expected integer in `%s' "
207					    "property", pname);
208					return def;
209				}
210				return ret;
211			}
212		b = b->b_parent;
213	}
214
215	return def;
216}
217
218/* --------------------------------------------------------------------- */
219
220/* Gets a mode block (childs of the global scope), which matches the
221 * specified name. */
222struct block *
223config_get_mode(const char *modename)
224{
225	int bc;
226	struct block *b;
227
228	b = Global;
229
230	if (strcmp(modename, "Global") == 0)
231		return Global;
232
233	if (b != NULL)
234		for (bc = 0; bc < b->b_child_count; bc++)
235			if (strcmp(b->b_child[bc]->b_name, modename) == 0)
236				return b->b_child[bc];
237
238	return NULL;
239}
240
241/* --------------------------------------------------------------------- */
242
243/* Reads the configuration file. */
244void
245config_read(const char *conffile, int opt)
246{
247	FILE *f;
248
249	errno = 0;
250	f = fopen(conffile, "r");
251	if (f != NULL) {
252		Global = config_parse(f);
253		if (Global == NULL)
254			errx(EXIT_FAILURE, "%s contains fatal errors",
255			     conffile);
256	} else if (errno != ENOENT || opt) {
257		err(EXIT_FAILURE, "cannot open %s", conffile);
258	}
259}
260
261/* --------------------------------------------------------------------- */
262
263/* Destroys all the configuration data. */
264void
265config_free(void)
266{
267
268	if (Global != NULL)
269		block_free(Global);
270}
271