1706f2543Smrg/*
2706f2543Smrg * Copyright (c) 1997  Metro Link Incorporated
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Software"),
6706f2543Smrg * to deal in the Software without restriction, including without limitation
7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, subject to the following conditions:
10706f2543Smrg *
11706f2543Smrg * The above copyright notice and this permission notice shall be included in
12706f2543Smrg * all copies or substantial portions of the Software.
13706f2543Smrg *
14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17706f2543Smrg * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18706f2543Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19706f2543Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20706f2543Smrg * SOFTWARE.
21706f2543Smrg *
22706f2543Smrg * Except as contained in this notice, the name of the Metro Link shall not be
23706f2543Smrg * used in advertising or otherwise to promote the sale, use or other dealings
24706f2543Smrg * in this Software without prior written authorization from Metro Link.
25706f2543Smrg *
26706f2543Smrg */
27706f2543Smrg/*
28706f2543Smrg * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
29706f2543Smrg *
30706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
31706f2543Smrg * copy of this software and associated documentation files (the "Software"),
32706f2543Smrg * to deal in the Software without restriction, including without limitation
33706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
35706f2543Smrg * Software is furnished to do so, subject to the following conditions:
36706f2543Smrg *
37706f2543Smrg * The above copyright notice and this permission notice shall be included in
38706f2543Smrg * all copies or substantial portions of the Software.
39706f2543Smrg *
40706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
43706f2543Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
44706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
45706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
46706f2543Smrg * OTHER DEALINGS IN THE SOFTWARE.
47706f2543Smrg *
48706f2543Smrg * Except as contained in this notice, the name of the copyright holder(s)
49706f2543Smrg * and author(s) shall not be used in advertising or otherwise to promote
50706f2543Smrg * the sale, use or other dealings in this Software without prior written
51706f2543Smrg * authorization from the copyright holder(s) and author(s).
52706f2543Smrg */
53706f2543Smrg
54706f2543Smrg
55706f2543Smrg/* View/edit this file with tab stops set to 4 */
56706f2543Smrg
57706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
58706f2543Smrg#include <xorg-config.h>
59706f2543Smrg#endif
60706f2543Smrg
61706f2543Smrg#include <ctype.h>
62706f2543Smrg#include <stdio.h>
63706f2543Smrg#include <stdlib.h>
64706f2543Smrg#include <string.h>
65706f2543Smrg#include <sys/types.h>
66706f2543Smrg#include <dirent.h>
67706f2543Smrg#include <unistd.h>
68706f2543Smrg#include <stdarg.h>
69706f2543Smrg#include <X11/Xdefs.h>
70706f2543Smrg#include <X11/Xfuncproto.h>
71706f2543Smrg
72706f2543Smrg#if defined(_POSIX_SOURCE)
73706f2543Smrg#include <limits.h>
74706f2543Smrg#else
75706f2543Smrg#define _POSIX_SOURCE
76706f2543Smrg#include <limits.h>
77706f2543Smrg#undef _POSIX_SOURCE
78706f2543Smrg#endif /* _POSIX_SOURCE */
79706f2543Smrg
80706f2543Smrg#if !defined(PATH_MAX)
81706f2543Smrg#if defined(MAXPATHLEN)
82706f2543Smrg#define PATH_MAX MAXPATHLEN
83706f2543Smrg#else
84706f2543Smrg#define PATH_MAX 1024
85706f2543Smrg#endif /* MAXPATHLEN */
86706f2543Smrg#endif /* !PATH_MAX */
87706f2543Smrg
88706f2543Smrg#if !defined(MAXHOSTNAMELEN)
89706f2543Smrg#define MAXHOSTNAMELEN 32
90706f2543Smrg#endif /* !MAXHOSTNAMELEN */
91706f2543Smrg
92706f2543Smrg#include "Configint.h"
93706f2543Smrg#include "xf86tokens.h"
94706f2543Smrg
95706f2543Smrg#define CONFIG_BUF_LEN     1024
96706f2543Smrg#define CONFIG_MAX_FILES   64
97706f2543Smrg
98706f2543Smrgstatic int StringToToken (char *, xf86ConfigSymTabRec *);
99706f2543Smrg
100706f2543Smrgstatic struct {
101706f2543Smrg	FILE *file;
102706f2543Smrg	char *path;
103706f2543Smrg} configFiles[CONFIG_MAX_FILES];
104706f2543Smrgstatic const char **builtinConfig = NULL;
105706f2543Smrgstatic int builtinIndex = 0;
106706f2543Smrgstatic int configPos = 0;		/* current readers position */
107706f2543Smrgstatic int configLineNo = 0;	/* linenumber */
108706f2543Smrgstatic char *configBuf, *configRBuf;	/* buffer for lines */
109706f2543Smrgstatic char *configPath;		/* path to config file */
110706f2543Smrgstatic char *configDirPath;		/* path to config dir */
111706f2543Smrgstatic char *configSection = NULL;	/* name of current section being parsed */
112706f2543Smrgstatic int numFiles = 0;		/* number of config files */
113706f2543Smrgstatic int curFileIndex = 0;		/* index of current config file */
114706f2543Smrgstatic int pushToken = LOCK_TOKEN;
115706f2543Smrgstatic int eol_seen = 0;		/* private state to handle comments */
116706f2543SmrgLexRec val;
117706f2543Smrg
118706f2543Smrg/*
119706f2543Smrg * xf86getNextLine --
120706f2543Smrg *
121706f2543Smrg *  read from the configFiles FILE stream until we encounter a new
122706f2543Smrg *  line; this is effectively just a big wrapper for fgets(3).
123706f2543Smrg *
124706f2543Smrg *  xf86getToken() assumes that we will read up to the next
125706f2543Smrg *  newline; we need to grow configBuf and configRBuf as needed to
126706f2543Smrg *  support that.
127706f2543Smrg */
128706f2543Smrg
129706f2543Smrgstatic char*
130706f2543Smrgxf86getNextLine(void)
131706f2543Smrg{
132706f2543Smrg	static int configBufLen = CONFIG_BUF_LEN;
133706f2543Smrg	char *tmpConfigBuf, *tmpConfigRBuf;
134706f2543Smrg	int c, i, pos = 0, eolFound = 0;
135706f2543Smrg	char *ret = NULL;
136706f2543Smrg
137706f2543Smrg	/*
138706f2543Smrg	 * reallocate the string if it was grown last time (i.e., is no
139706f2543Smrg	 * longer CONFIG_BUF_LEN); we malloc the new strings first, so
140706f2543Smrg	 * that if either of the mallocs fail, we can fall back on the
141706f2543Smrg	 * existing buffer allocations
142706f2543Smrg	 */
143706f2543Smrg
144706f2543Smrg	if (configBufLen != CONFIG_BUF_LEN) {
145706f2543Smrg
146706f2543Smrg		tmpConfigBuf = malloc(CONFIG_BUF_LEN);
147706f2543Smrg		tmpConfigRBuf = malloc(CONFIG_BUF_LEN);
148706f2543Smrg
149706f2543Smrg		if (!tmpConfigBuf || !tmpConfigRBuf) {
150706f2543Smrg
151706f2543Smrg			/*
152706f2543Smrg			 * at least one of the mallocs failed; keep the old buffers
153706f2543Smrg			 * and free any partial allocations
154706f2543Smrg			 */
155706f2543Smrg
156706f2543Smrg			free(tmpConfigBuf);
157706f2543Smrg			free(tmpConfigRBuf);
158706f2543Smrg
159706f2543Smrg		} else {
160706f2543Smrg
161706f2543Smrg			/*
162706f2543Smrg			 * malloc succeeded; free the old buffers and use the new
163706f2543Smrg			 * buffers
164706f2543Smrg			 */
165706f2543Smrg
166706f2543Smrg			configBufLen = CONFIG_BUF_LEN;
167706f2543Smrg
168706f2543Smrg			free(configBuf);
169706f2543Smrg			free(configRBuf);
170706f2543Smrg
171706f2543Smrg			configBuf = tmpConfigBuf;
172706f2543Smrg			configRBuf = tmpConfigRBuf;
173706f2543Smrg		}
174706f2543Smrg	}
175706f2543Smrg
176706f2543Smrg	/* read in another block of chars */
177706f2543Smrg
178706f2543Smrg	do {
179706f2543Smrg		ret = fgets(configBuf + pos, configBufLen - pos - 1,
180706f2543Smrg			    configFiles[curFileIndex].file);
181706f2543Smrg
182706f2543Smrg		if (!ret) {
183706f2543Smrg			/*
184706f2543Smrg			 * if the file doesn't end in a newline, add one
185706f2543Smrg			 * and trigger another read
186706f2543Smrg			 */
187706f2543Smrg			if (pos != 0) {
188706f2543Smrg				strcpy(&configBuf[pos], "\n");
189706f2543Smrg				ret = configBuf;
190706f2543Smrg			} else
191706f2543Smrg				break;
192706f2543Smrg		}
193706f2543Smrg
194706f2543Smrg		/* search for EOL in the new block of chars */
195706f2543Smrg
196706f2543Smrg		for (i = pos; i < (configBufLen - 1); i++) {
197706f2543Smrg			c = configBuf[i];
198706f2543Smrg
199706f2543Smrg			if (c == '\0') break;
200706f2543Smrg
201706f2543Smrg			if ((c == '\n') || (c == '\r')) {
202706f2543Smrg				eolFound = 1;
203706f2543Smrg				break;
204706f2543Smrg			}
205706f2543Smrg		}
206706f2543Smrg
207706f2543Smrg		/*
208706f2543Smrg		 * if we didn't find EOL, then grow the string and
209706f2543Smrg		 * read in more
210706f2543Smrg		 */
211706f2543Smrg
212706f2543Smrg		if (!eolFound) {
213706f2543Smrg
214706f2543Smrg			tmpConfigBuf = realloc(configBuf, configBufLen + CONFIG_BUF_LEN);
215706f2543Smrg			tmpConfigRBuf = realloc(configRBuf, configBufLen + CONFIG_BUF_LEN);
216706f2543Smrg
217706f2543Smrg			if (!tmpConfigBuf || !tmpConfigRBuf) {
218706f2543Smrg
219706f2543Smrg				/*
220706f2543Smrg				 * at least one of the reallocations failed; use the
221706f2543Smrg				 * new allocation that succeeded, but we have to
222706f2543Smrg				 * fallback to the previous configBufLen size and use
223706f2543Smrg				 * the string we have, even though we don't have an
224706f2543Smrg				 * EOL
225706f2543Smrg				 */
226706f2543Smrg
227706f2543Smrg				if (tmpConfigBuf) configBuf = tmpConfigBuf;
228706f2543Smrg				if (tmpConfigRBuf) configRBuf = tmpConfigRBuf;
229706f2543Smrg
230706f2543Smrg				break;
231706f2543Smrg
232706f2543Smrg			} else {
233706f2543Smrg
234706f2543Smrg				/* reallocation succeeded */
235706f2543Smrg
236706f2543Smrg				configBuf = tmpConfigBuf;
237706f2543Smrg				configRBuf = tmpConfigRBuf;
238706f2543Smrg				pos = i;
239706f2543Smrg				configBufLen += CONFIG_BUF_LEN;
240706f2543Smrg			}
241706f2543Smrg		}
242706f2543Smrg
243706f2543Smrg	} while (!eolFound);
244706f2543Smrg
245706f2543Smrg	return ret;
246706f2543Smrg}
247706f2543Smrg
248706f2543Smrg/*
249706f2543Smrg * xf86getToken --
250706f2543Smrg *      Read next Token from the config file. Handle the global variable
251706f2543Smrg *      pushToken.
252706f2543Smrg */
253706f2543Smrgint
254706f2543Smrgxf86getToken (xf86ConfigSymTabRec * tab)
255706f2543Smrg{
256706f2543Smrg	int c, i;
257706f2543Smrg
258706f2543Smrg	/*
259706f2543Smrg	 * First check whether pushToken has a different value than LOCK_TOKEN.
260706f2543Smrg	 * In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the
261706f2543Smrg	 * oth * case the next token must be read from the input.
262706f2543Smrg	 */
263706f2543Smrg	if (pushToken == EOF_TOKEN)
264706f2543Smrg		return EOF_TOKEN;
265706f2543Smrg	else if (pushToken == LOCK_TOKEN)
266706f2543Smrg	{
267706f2543Smrg		/*
268706f2543Smrg		 * eol_seen is only set for the first token after a newline.
269706f2543Smrg		 */
270706f2543Smrg		eol_seen = 0;
271706f2543Smrg
272706f2543Smrg		c = configBuf[configPos];
273706f2543Smrg
274706f2543Smrg		/*
275706f2543Smrg		 * Get start of next Token. EOF is handled,
276706f2543Smrg		 * whitespaces are skipped.
277706f2543Smrg		 */
278706f2543Smrg
279706f2543Smrgagain:
280706f2543Smrg		if (!c)
281706f2543Smrg		{
282706f2543Smrg			char *ret;
283706f2543Smrg			if (numFiles > 0)
284706f2543Smrg				ret = xf86getNextLine();
285706f2543Smrg			else {
286706f2543Smrg				if (builtinConfig[builtinIndex] == NULL)
287706f2543Smrg					ret = NULL;
288706f2543Smrg				else {
289706f2543Smrg					ret = strncpy(configBuf, builtinConfig[builtinIndex],
290706f2543Smrg							CONFIG_BUF_LEN);
291706f2543Smrg					builtinIndex++;
292706f2543Smrg				}
293706f2543Smrg			}
294706f2543Smrg			if (ret == NULL)
295706f2543Smrg			{
296706f2543Smrg				/*
297706f2543Smrg				 * if necessary, move to the next file and
298706f2543Smrg				 * read the first line
299706f2543Smrg				 */
300706f2543Smrg				if (curFileIndex + 1 < numFiles) {
301706f2543Smrg					curFileIndex++;
302706f2543Smrg					configLineNo = 0;
303706f2543Smrg					goto again;
304706f2543Smrg				}
305706f2543Smrg				else
306706f2543Smrg					return pushToken = EOF_TOKEN;
307706f2543Smrg			}
308706f2543Smrg			configLineNo++;
309706f2543Smrg			configPos = 0;
310706f2543Smrg			eol_seen = 1;
311706f2543Smrg		}
312706f2543Smrg
313706f2543Smrg		i = 0;
314706f2543Smrg		for (;;) {
315706f2543Smrg			c = configBuf[configPos++];
316706f2543Smrg			configRBuf[i++] = c;
317706f2543Smrg			switch (c) {
318706f2543Smrg				case ' ':
319706f2543Smrg				case '\t':
320706f2543Smrg				case '\r':
321706f2543Smrg					continue;
322706f2543Smrg				case '\n':
323706f2543Smrg					i = 0;
324706f2543Smrg					continue;
325706f2543Smrg			}
326706f2543Smrg			break;
327706f2543Smrg		}
328706f2543Smrg		if (c == '\0')
329706f2543Smrg			goto again;
330706f2543Smrg
331706f2543Smrg		if (c == '#')
332706f2543Smrg		{
333706f2543Smrg			do
334706f2543Smrg			{
335706f2543Smrg				configRBuf[i++] = (c = configBuf[configPos++]);
336706f2543Smrg			}
337706f2543Smrg			while ((c != '\n') && (c != '\r') && (c != '\0'));
338706f2543Smrg			configRBuf[i] = '\0';
339706f2543Smrg			/* XXX no private copy.
340706f2543Smrg			 * Use xf86addComment when setting a comment.
341706f2543Smrg			 */
342706f2543Smrg			val.str = configRBuf;
343706f2543Smrg			return COMMENT;
344706f2543Smrg		}
345706f2543Smrg
346706f2543Smrg		/* GJA -- handle '-' and ','  * Be careful: "-hsync" is a keyword. */
347706f2543Smrg		else if ((c == ',') && !isalpha (configBuf[configPos]))
348706f2543Smrg		{
349706f2543Smrg			return COMMA;
350706f2543Smrg		}
351706f2543Smrg		else if ((c == '-') && !isalpha (configBuf[configPos]))
352706f2543Smrg		{
353706f2543Smrg			return DASH;
354706f2543Smrg		}
355706f2543Smrg
356706f2543Smrg		/*
357706f2543Smrg		 * Numbers are returned immediately ...
358706f2543Smrg		 */
359706f2543Smrg		if (isdigit (c))
360706f2543Smrg		{
361706f2543Smrg			int base;
362706f2543Smrg
363706f2543Smrg			if (c == '0')
364706f2543Smrg				if ((configBuf[configPos] == 'x') ||
365706f2543Smrg					(configBuf[configPos] == 'X'))
366706f2543Smrg                                {
367706f2543Smrg					base = 16;
368706f2543Smrg                                        val.numType = PARSE_HEX;
369706f2543Smrg                                }
370706f2543Smrg				else
371706f2543Smrg                                {
372706f2543Smrg					base = 8;
373706f2543Smrg                                        val.numType = PARSE_OCTAL;
374706f2543Smrg                                }
375706f2543Smrg			else
376706f2543Smrg                        {
377706f2543Smrg				base = 10;
378706f2543Smrg                                val.numType = PARSE_DECIMAL;
379706f2543Smrg                        }
380706f2543Smrg
381706f2543Smrg			configRBuf[0] = c;
382706f2543Smrg			i = 1;
383706f2543Smrg			while (isdigit (c = configBuf[configPos++]) ||
384706f2543Smrg				   (c == '.') || (c == 'x') || (c == 'X') ||
385706f2543Smrg				   ((base == 16) && (((c >= 'a') && (c <= 'f')) ||
386706f2543Smrg									 ((c >= 'A') && (c <= 'F')))))
387706f2543Smrg				configRBuf[i++] = c;
388706f2543Smrg			configPos--;		/* GJA -- one too far */
389706f2543Smrg			configRBuf[i] = '\0';
390706f2543Smrg			val.num = strtoul (configRBuf, NULL, 0);
391706f2543Smrg			val.realnum = atof (configRBuf);
392706f2543Smrg			return NUMBER;
393706f2543Smrg		}
394706f2543Smrg
395706f2543Smrg		/*
396706f2543Smrg		 * All Strings START with a \" ...
397706f2543Smrg		 */
398706f2543Smrg		else if (c == '\"')
399706f2543Smrg		{
400706f2543Smrg			i = -1;
401706f2543Smrg			do
402706f2543Smrg			{
403706f2543Smrg				configRBuf[++i] = (c = configBuf[configPos++]);
404706f2543Smrg			}
405706f2543Smrg			while ((c != '\"') && (c != '\n') && (c != '\r') && (c != '\0'));
406706f2543Smrg			configRBuf[i] = '\0';
407706f2543Smrg			val.str = malloc (strlen (configRBuf) + 1);
408706f2543Smrg			strcpy (val.str, configRBuf);	/* private copy ! */
409706f2543Smrg			return STRING;
410706f2543Smrg		}
411706f2543Smrg
412706f2543Smrg		/*
413706f2543Smrg		 * ... and now we MUST have a valid token.  The search is
414706f2543Smrg		 * handled later along with the pushed tokens.
415706f2543Smrg		 */
416706f2543Smrg		else
417706f2543Smrg		{
418706f2543Smrg			configRBuf[0] = c;
419706f2543Smrg			i = 0;
420706f2543Smrg			do
421706f2543Smrg			{
422706f2543Smrg				configRBuf[++i] = (c = configBuf[configPos++]);
423706f2543Smrg			}
424706f2543Smrg			while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') && (c != '\0') && (c != '#'));
425706f2543Smrg			--configPos;
426706f2543Smrg			configRBuf[i] = '\0';
427706f2543Smrg			i = 0;
428706f2543Smrg		}
429706f2543Smrg
430706f2543Smrg	}
431706f2543Smrg	else
432706f2543Smrg	{
433706f2543Smrg
434706f2543Smrg		/*
435706f2543Smrg		 * Here we deal with pushed tokens. Reinitialize pushToken again. If
436706f2543Smrg		 * the pushed token was NUMBER || STRING return them again ...
437706f2543Smrg		 */
438706f2543Smrg		int temp = pushToken;
439706f2543Smrg		pushToken = LOCK_TOKEN;
440706f2543Smrg
441706f2543Smrg		if (temp == COMMA || temp == DASH)
442706f2543Smrg			return temp;
443706f2543Smrg		if (temp == NUMBER || temp == STRING)
444706f2543Smrg			return temp;
445706f2543Smrg	}
446706f2543Smrg
447706f2543Smrg	/*
448706f2543Smrg	 * Joop, at last we have to lookup the token ...
449706f2543Smrg	 */
450706f2543Smrg	if (tab)
451706f2543Smrg	{
452706f2543Smrg		i = 0;
453706f2543Smrg		while (tab[i].token != -1)
454706f2543Smrg			if (xf86nameCompare (configRBuf, tab[i].name) == 0)
455706f2543Smrg				return tab[i].token;
456706f2543Smrg			else
457706f2543Smrg				i++;
458706f2543Smrg	}
459706f2543Smrg
460706f2543Smrg	return ERROR_TOKEN;		/* Error catcher */
461706f2543Smrg}
462706f2543Smrg
463706f2543Smrgint
464706f2543Smrgxf86getSubToken (char **comment)
465706f2543Smrg{
466706f2543Smrg	int token;
467706f2543Smrg
468706f2543Smrg	for (;;) {
469706f2543Smrg		token = xf86getToken(NULL);
470706f2543Smrg		if (token == COMMENT) {
471706f2543Smrg			if (comment)
472706f2543Smrg				*comment = xf86addComment(*comment, val.str);
473706f2543Smrg		}
474706f2543Smrg		else
475706f2543Smrg			return token;
476706f2543Smrg	}
477706f2543Smrg	/*NOTREACHED*/
478706f2543Smrg}
479706f2543Smrg
480706f2543Smrgint
481706f2543Smrgxf86getSubTokenWithTab (char **comment, xf86ConfigSymTabRec *tab)
482706f2543Smrg{
483706f2543Smrg	int token;
484706f2543Smrg
485706f2543Smrg	for (;;) {
486706f2543Smrg		token = xf86getToken(tab);
487706f2543Smrg		if (token == COMMENT) {
488706f2543Smrg			if (comment)
489706f2543Smrg				*comment = xf86addComment(*comment, val.str);
490706f2543Smrg		}
491706f2543Smrg		else
492706f2543Smrg			return token;
493706f2543Smrg	}
494706f2543Smrg	/*NOTREACHED*/
495706f2543Smrg}
496706f2543Smrg
497706f2543Smrgvoid
498706f2543Smrgxf86unGetToken (int token)
499706f2543Smrg{
500706f2543Smrg	pushToken = token;
501706f2543Smrg}
502706f2543Smrg
503706f2543Smrgchar *
504706f2543Smrgxf86tokenString (void)
505706f2543Smrg{
506706f2543Smrg	return configRBuf;
507706f2543Smrg}
508706f2543Smrg
509706f2543Smrgint
510706f2543Smrgxf86pathIsAbsolute(const char *path)
511706f2543Smrg{
512706f2543Smrg	if (path && path[0] == '/')
513706f2543Smrg		return 1;
514706f2543Smrg	return 0;
515706f2543Smrg}
516706f2543Smrg
517706f2543Smrg/* A path is "safe" if it is relative and if it contains no ".." elements. */
518706f2543Smrgint
519706f2543Smrgxf86pathIsSafe(const char *path)
520706f2543Smrg{
521706f2543Smrg	if (xf86pathIsAbsolute(path))
522706f2543Smrg		return 0;
523706f2543Smrg
524706f2543Smrg	/* Compare with ".." */
525706f2543Smrg	if (!strcmp(path, ".."))
526706f2543Smrg		return 0;
527706f2543Smrg
528706f2543Smrg	/* Look for leading "../" */
529706f2543Smrg	if (!strncmp(path, "../", 3))
530706f2543Smrg		return 0;
531706f2543Smrg
532706f2543Smrg	/* Look for trailing "/.." */
533706f2543Smrg	if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/.."))
534706f2543Smrg		return 0;
535706f2543Smrg
536706f2543Smrg	/* Look for "/../" */
537706f2543Smrg	if (strstr(path, "/../"))
538706f2543Smrg		return 0;
539706f2543Smrg
540706f2543Smrg	return 1;
541706f2543Smrg}
542706f2543Smrg
543706f2543Smrg/*
544706f2543Smrg * This function substitutes the following escape sequences:
545706f2543Smrg *
546706f2543Smrg *    %A    cmdline argument as an absolute path (must be absolute to match)
547706f2543Smrg *    %R    cmdline argument as a relative path
548706f2543Smrg *    %S    cmdline argument as a "safe" path (relative, and no ".." elements)
549706f2543Smrg *    %X    default config file name ("xorg.conf")
550706f2543Smrg *    %H    hostname
551706f2543Smrg *    %E    config file environment ($XORGCONFIG) as an absolute path
552706f2543Smrg *    %F    config file environment ($XORGCONFIG) as a relative path
553706f2543Smrg *    %G    config file environment ($XORGCONFIG) as a safe path
554706f2543Smrg *    %P    projroot
555706f2543Smrg *    %C    sysconfdir
556706f2543Smrg *    %D    datadir
557706f2543Smrg *    %%    %
558706f2543Smrg */
559706f2543Smrg
560706f2543Smrg#ifndef XCONFIGFILE
561706f2543Smrg#define XCONFIGFILE	"xorg.conf"
562706f2543Smrg#endif
563706f2543Smrg#ifndef XCONFIGDIR
564706f2543Smrg#define XCONFIGDIR	"xorg.conf.d"
565706f2543Smrg#endif
566706f2543Smrg#ifndef XCONFIGSUFFIX
567706f2543Smrg#define XCONFIGSUFFIX	".conf"
568706f2543Smrg#endif
569706f2543Smrg#ifndef PROJECTROOT
570706f2543Smrg#define PROJECTROOT	"/usr/X11R6"
571706f2543Smrg#endif
572706f2543Smrg#ifndef SYSCONFDIR
573706f2543Smrg#define SYSCONFDIR	PROJECTROOT "/etc"
574706f2543Smrg#endif
575706f2543Smrg#ifndef DATADIR
576706f2543Smrg#define DATADIR		PROJECTROOT "/share"
577706f2543Smrg#endif
578706f2543Smrg#ifndef XCONFENV
579706f2543Smrg#define XCONFENV	"XORGCONFIG"
580706f2543Smrg#endif
581706f2543Smrg
582706f2543Smrg#define BAIL_OUT		do {									\
583706f2543Smrg							free(result);				\
584706f2543Smrg							return NULL;						\
585706f2543Smrg						} while (0)
586706f2543Smrg
587706f2543Smrg#define CHECK_LENGTH	do {									\
588706f2543Smrg							if (l > PATH_MAX) {					\
589706f2543Smrg								BAIL_OUT;						\
590706f2543Smrg							}									\
591706f2543Smrg						} while (0)
592706f2543Smrg
593706f2543Smrg#define APPEND_STR(s)	do {									\
594706f2543Smrg							if (strlen(s) + l > PATH_MAX) {		\
595706f2543Smrg								BAIL_OUT;						\
596706f2543Smrg							} else {							\
597706f2543Smrg								strcpy(result + l, s);			\
598706f2543Smrg								l += strlen(s);					\
599706f2543Smrg							}									\
600706f2543Smrg						} while (0)
601706f2543Smrg
602706f2543Smrgstatic char *
603706f2543SmrgDoSubstitution(const char *template, const char *cmdline, const char *projroot,
604706f2543Smrg				int *cmdlineUsed, int *envUsed,
605706f2543Smrg				const char *XConfigFile)
606706f2543Smrg{
607706f2543Smrg	char *result;
608706f2543Smrg	int i, l;
609706f2543Smrg	static const char *env = NULL;
610706f2543Smrg	static char *hostname = NULL;
611706f2543Smrg
612706f2543Smrg	if (!template)
613706f2543Smrg		return NULL;
614706f2543Smrg
615706f2543Smrg	if (cmdlineUsed)
616706f2543Smrg		*cmdlineUsed = 0;
617706f2543Smrg	if (envUsed)
618706f2543Smrg		*envUsed = 0;
619706f2543Smrg
620706f2543Smrg	result = malloc(PATH_MAX + 1);
621706f2543Smrg	l = 0;
622706f2543Smrg	for (i = 0; template[i]; i++) {
623706f2543Smrg		if (template[i] != '%') {
624706f2543Smrg			result[l++] = template[i];
625706f2543Smrg			CHECK_LENGTH;
626706f2543Smrg		} else {
627706f2543Smrg			switch (template[++i]) {
628706f2543Smrg			case 'A':
629706f2543Smrg				if (cmdline && xf86pathIsAbsolute(cmdline)) {
630706f2543Smrg					APPEND_STR(cmdline);
631706f2543Smrg					if (cmdlineUsed)
632706f2543Smrg						*cmdlineUsed = 1;
633706f2543Smrg				} else
634706f2543Smrg					BAIL_OUT;
635706f2543Smrg				break;
636706f2543Smrg			case 'R':
637706f2543Smrg				if (cmdline && !xf86pathIsAbsolute(cmdline)) {
638706f2543Smrg					APPEND_STR(cmdline);
639706f2543Smrg					if (cmdlineUsed)
640706f2543Smrg						*cmdlineUsed = 1;
641706f2543Smrg				} else
642706f2543Smrg					BAIL_OUT;
643706f2543Smrg				break;
644706f2543Smrg			case 'S':
645706f2543Smrg				if (cmdline && xf86pathIsSafe(cmdline)) {
646706f2543Smrg					APPEND_STR(cmdline);
647706f2543Smrg					if (cmdlineUsed)
648706f2543Smrg						*cmdlineUsed = 1;
649706f2543Smrg				} else
650706f2543Smrg					BAIL_OUT;
651706f2543Smrg				break;
652706f2543Smrg			case 'X':
653706f2543Smrg				APPEND_STR(XConfigFile);
654706f2543Smrg				break;
655706f2543Smrg			case 'H':
656706f2543Smrg				if (!hostname) {
657706f2543Smrg					if ((hostname = malloc(MAXHOSTNAMELEN + 1))) {
658706f2543Smrg						if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
659706f2543Smrg							hostname[MAXHOSTNAMELEN] = '\0';
660706f2543Smrg						} else {
661706f2543Smrg							free(hostname);
662706f2543Smrg							hostname = NULL;
663706f2543Smrg						}
664706f2543Smrg					}
665706f2543Smrg				}
666706f2543Smrg				if (hostname)
667706f2543Smrg					APPEND_STR(hostname);
668706f2543Smrg				break;
669706f2543Smrg			case 'E':
670706f2543Smrg				if (!env)
671706f2543Smrg					env = getenv(XCONFENV);
672706f2543Smrg				if (env && xf86pathIsAbsolute(env)) {
673706f2543Smrg					APPEND_STR(env);
674706f2543Smrg					if (envUsed)
675706f2543Smrg						*envUsed = 1;
676706f2543Smrg				} else
677706f2543Smrg					BAIL_OUT;
678706f2543Smrg				break;
679706f2543Smrg			case 'F':
680706f2543Smrg				if (!env)
681706f2543Smrg					env = getenv(XCONFENV);
682706f2543Smrg				if (env && !xf86pathIsAbsolute(env)) {
683706f2543Smrg					APPEND_STR(env);
684706f2543Smrg					if (envUsed)
685706f2543Smrg						*envUsed = 1;
686706f2543Smrg				} else
687706f2543Smrg					BAIL_OUT;
688706f2543Smrg				break;
689706f2543Smrg			case 'G':
690706f2543Smrg				if (!env)
691706f2543Smrg					env = getenv(XCONFENV);
692706f2543Smrg				if (env && xf86pathIsSafe(env)) {
693706f2543Smrg					APPEND_STR(env);
694706f2543Smrg					if (envUsed)
695706f2543Smrg						*envUsed = 1;
696706f2543Smrg				} else
697706f2543Smrg					BAIL_OUT;
698706f2543Smrg				break;
699706f2543Smrg			case 'P':
700706f2543Smrg				if (projroot && xf86pathIsAbsolute(projroot))
701706f2543Smrg					APPEND_STR(projroot);
702706f2543Smrg				else
703706f2543Smrg					BAIL_OUT;
704706f2543Smrg				break;
705706f2543Smrg			case 'C':
706706f2543Smrg				APPEND_STR(SYSCONFDIR);
707706f2543Smrg				break;
708706f2543Smrg			case 'D':
709706f2543Smrg				APPEND_STR(DATADIR);
710706f2543Smrg				break;
711706f2543Smrg			case '%':
712706f2543Smrg				result[l++] = '%';
713706f2543Smrg				CHECK_LENGTH;
714706f2543Smrg				break;
715706f2543Smrg			default:
716706f2543Smrg				fprintf(stderr, "invalid escape %%%c found in path template\n",
717706f2543Smrg						template[i]);
718706f2543Smrg				BAIL_OUT;
719706f2543Smrg				break;
720706f2543Smrg			}
721706f2543Smrg		}
722706f2543Smrg	}
723706f2543Smrg#ifdef DEBUG
724706f2543Smrg	fprintf(stderr, "Converted `%s' to `%s'\n", template, result);
725706f2543Smrg#endif
726706f2543Smrg	return result;
727706f2543Smrg}
728706f2543Smrg
729706f2543Smrg/*
730706f2543Smrg * Given some searching parameters, locate and open the xorg config file.
731706f2543Smrg */
732706f2543Smrgstatic char *
733706f2543SmrgOpenConfigFile(const char *path, const char *cmdline, const char *projroot,
734706f2543Smrg	       const char *confname)
735706f2543Smrg{
736706f2543Smrg	char *filepath = NULL;
737706f2543Smrg	char *pathcopy;
738706f2543Smrg	const char *template;
739706f2543Smrg	int cmdlineUsed = 0;
740706f2543Smrg	FILE *file = NULL;
741706f2543Smrg
742706f2543Smrg	pathcopy = strdup(path);
743706f2543Smrg	for (template = strtok(pathcopy, ","); template && !file;
744706f2543Smrg	     template = strtok(NULL, ",")) {
745706f2543Smrg		filepath = DoSubstitution(template, cmdline, projroot,
746706f2543Smrg					  &cmdlineUsed, NULL, confname);
747706f2543Smrg		if (!filepath)
748706f2543Smrg			continue;
749706f2543Smrg		if (cmdline && !cmdlineUsed) {
750706f2543Smrg			free(filepath);
751706f2543Smrg			filepath = NULL;
752706f2543Smrg			continue;
753706f2543Smrg		}
754706f2543Smrg		file = fopen(filepath, "r");
755706f2543Smrg		if (!file) {
756706f2543Smrg			free(filepath);
757706f2543Smrg			filepath = NULL;
758706f2543Smrg		}
759706f2543Smrg	}
760706f2543Smrg
761706f2543Smrg	free(pathcopy);
762706f2543Smrg	if (file) {
763706f2543Smrg		configFiles[numFiles].file = file;
764706f2543Smrg		configFiles[numFiles].path = strdup(filepath);
765706f2543Smrg		numFiles++;
766706f2543Smrg	}
767706f2543Smrg	return filepath;
768706f2543Smrg}
769706f2543Smrg
770706f2543Smrg/*
771706f2543Smrg * Match non-hidden files in the xorg config directory with a .conf
772706f2543Smrg * suffix. This filter is passed to scandir(3).
773706f2543Smrg */
774706f2543Smrgstatic int
775706f2543SmrgConfigFilter(const struct dirent *de)
776706f2543Smrg{
777706f2543Smrg	const char *name = de->d_name;
778706f2543Smrg	size_t len;
779706f2543Smrg	size_t suflen = strlen(XCONFIGSUFFIX);
780706f2543Smrg
781706f2543Smrg	if (!name || name[0] == '.')
782706f2543Smrg		return 0;
783706f2543Smrg	len = strlen(name);
784706f2543Smrg	if(len <= suflen)
785706f2543Smrg		return 0;
786706f2543Smrg	if (strcmp(&name[len-suflen], XCONFIGSUFFIX) != 0)
787706f2543Smrg		return 0;
788706f2543Smrg	return 1;
789706f2543Smrg}
790706f2543Smrg
791706f2543Smrgstatic Bool
792706f2543SmrgAddConfigDirFiles(const char *dirpath, struct dirent **list, int num)
793706f2543Smrg{
794706f2543Smrg	int i;
795706f2543Smrg	Bool openedFile = FALSE;
796706f2543Smrg	Bool warnOnce = FALSE;
797706f2543Smrg
798706f2543Smrg	for (i = 0; i < num; i++) {
799706f2543Smrg		char *path;
800706f2543Smrg		FILE *file;
801706f2543Smrg
802706f2543Smrg		if (numFiles >= CONFIG_MAX_FILES) {
803706f2543Smrg			if (!warnOnce) {
804706f2543Smrg				ErrorF("Maximum number of configuration "
805706f2543Smrg				       "files opened\n");
806706f2543Smrg				warnOnce = TRUE;
807706f2543Smrg			}
808706f2543Smrg			free(list[i]);
809706f2543Smrg			continue;
810706f2543Smrg		}
811706f2543Smrg
812706f2543Smrg		path = malloc(PATH_MAX + 1);
813706f2543Smrg		snprintf(path, PATH_MAX + 1, "%s/%s", dirpath,
814706f2543Smrg			 list[i]->d_name);
815706f2543Smrg		free(list[i]);
816706f2543Smrg		file = fopen(path, "r");
817706f2543Smrg		if (!file) {
818706f2543Smrg			free(path);
819706f2543Smrg			continue;
820706f2543Smrg		}
821706f2543Smrg		openedFile = TRUE;
822706f2543Smrg
823706f2543Smrg		configFiles[numFiles].file = file;
824706f2543Smrg		configFiles[numFiles].path = path;
825706f2543Smrg		numFiles++;
826706f2543Smrg	}
827706f2543Smrg
828706f2543Smrg	return openedFile;
829706f2543Smrg}
830706f2543Smrg
831706f2543Smrg/*
832706f2543Smrg * Given some searching parameters, locate and open the xorg config
833706f2543Smrg * directory. The directory does not need to contain config files.
834706f2543Smrg */
835706f2543Smrgstatic char *
836706f2543SmrgOpenConfigDir(const char *path, const char *cmdline, const char *projroot,
837706f2543Smrg	      const char *confname)
838706f2543Smrg{
839706f2543Smrg	char *dirpath, *pathcopy;
840706f2543Smrg	const char *template;
841706f2543Smrg	Bool found = FALSE;
842706f2543Smrg	int cmdlineUsed = 0;
843706f2543Smrg
844706f2543Smrg	pathcopy = strdup(path);
845706f2543Smrg	for (template = strtok(pathcopy, ","); template && !found;
846706f2543Smrg	     template = strtok(NULL, ",")) {
847706f2543Smrg		struct dirent **list = NULL;
848706f2543Smrg		int num;
849706f2543Smrg
850706f2543Smrg		dirpath = DoSubstitution(template, cmdline, projroot,
851706f2543Smrg					 &cmdlineUsed, NULL, confname);
852706f2543Smrg		if (!dirpath)
853706f2543Smrg			continue;
854706f2543Smrg		if (cmdline && !cmdlineUsed) {
855706f2543Smrg			free(dirpath);
856706f2543Smrg			dirpath = NULL;
857706f2543Smrg			continue;
858706f2543Smrg		}
859706f2543Smrg
860706f2543Smrg		/* match files named *.conf */
861706f2543Smrg		num = scandir(dirpath, &list, ConfigFilter, alphasort);
862706f2543Smrg		found = AddConfigDirFiles(dirpath, list, num);
863706f2543Smrg		if (!found) {
864706f2543Smrg			free(dirpath);
865706f2543Smrg			dirpath = NULL;
866706f2543Smrg			free(list);
867706f2543Smrg		}
868706f2543Smrg	}
869706f2543Smrg
870706f2543Smrg	free(pathcopy);
871706f2543Smrg	return dirpath;
872706f2543Smrg}
873706f2543Smrg
874706f2543Smrg/*
875706f2543Smrg * xf86initConfigFiles -- Setup global variables and buffers.
876706f2543Smrg */
877706f2543Smrgvoid
878706f2543Smrgxf86initConfigFiles(void)
879706f2543Smrg{
880706f2543Smrg	curFileIndex = 0;
881706f2543Smrg	configPos = 0;
882706f2543Smrg	configLineNo = 0;
883706f2543Smrg	pushToken = LOCK_TOKEN;
884706f2543Smrg
885706f2543Smrg	configBuf = malloc(CONFIG_BUF_LEN);
886706f2543Smrg	configRBuf = malloc(CONFIG_BUF_LEN);
887706f2543Smrg	configBuf[0] = '\0';	/* sanity ... */
888706f2543Smrg}
889706f2543Smrg
890706f2543Smrg/*
891706f2543Smrg * xf86openConfigFile --
892706f2543Smrg *
893706f2543Smrg * This function take a config file search path (optional), a command-line
894706f2543Smrg * specified file name (optional) and the ProjectRoot path (optional) and
895706f2543Smrg * locates and opens a config file based on that information.  If a
896706f2543Smrg * command-line file name is specified, then this function fails if none
897706f2543Smrg * of the located files.
898706f2543Smrg *
899706f2543Smrg * The return value is a pointer to the actual name of the file that was
900706f2543Smrg * opened.  When no file is found, the return value is NULL.
901706f2543Smrg *
902706f2543Smrg * The escape sequences allowed in the search path are defined above.
903706f2543Smrg *
904706f2543Smrg */
905706f2543Smrg
906706f2543Smrg#ifndef DEFAULT_CONF_PATH
907706f2543Smrg#define DEFAULT_CONF_PATH	"/etc/X11/%S," \
908706f2543Smrg							"%P/etc/X11/%S," \
909706f2543Smrg							"/etc/X11/%G," \
910706f2543Smrg							"%P/etc/X11/%G," \
911706f2543Smrg							"/etc/X11/%X-%M," \
912706f2543Smrg							"/etc/X11/%X," \
913706f2543Smrg							"/etc/%X," \
914706f2543Smrg							"%P/etc/X11/%X.%H," \
915706f2543Smrg							"%P/etc/X11/%X-%M," \
916706f2543Smrg							"%P/etc/X11/%X," \
917706f2543Smrg							"%P/lib/X11/%X.%H," \
918706f2543Smrg							"%P/lib/X11/%X-%M," \
919706f2543Smrg							"%P/lib/X11/%X"
920706f2543Smrg#endif
921706f2543Smrg
922706f2543Smrgconst char *
923706f2543Smrgxf86openConfigFile(const char *path, const char *cmdline, const char *projroot)
924706f2543Smrg{
925706f2543Smrg	if (!path || !path[0])
926706f2543Smrg		path = DEFAULT_CONF_PATH;
927706f2543Smrg	if (!projroot || !projroot[0])
928706f2543Smrg		projroot = PROJECTROOT;
929706f2543Smrg
930706f2543Smrg	/* Search for a config file */
931706f2543Smrg	configPath = OpenConfigFile(path, cmdline, projroot, XCONFIGFILE);
932706f2543Smrg	return configPath;
933706f2543Smrg}
934706f2543Smrg
935706f2543Smrg/*
936706f2543Smrg * xf86openConfigDirFiles --
937706f2543Smrg *
938706f2543Smrg * This function take a config directory search path (optional), a
939706f2543Smrg * command-line specified directory name (optional) and the ProjectRoot path
940706f2543Smrg * (optional) and locates and opens a config directory based on that
941706f2543Smrg * information.  If a command-line name is specified, then this function
942706f2543Smrg * fails if it is not found.
943706f2543Smrg *
944706f2543Smrg * The return value is a pointer to the actual name of the direcoty that was
945706f2543Smrg * opened.  When no directory is found, the return value is NULL.
946706f2543Smrg *
947706f2543Smrg * The escape sequences allowed in the search path are defined above.
948706f2543Smrg *
949706f2543Smrg */
950706f2543Smrgconst char *
951706f2543Smrgxf86openConfigDirFiles(const char *path, const char *cmdline,
952706f2543Smrg		       const char *projroot)
953706f2543Smrg{
954706f2543Smrg	if (!path || !path[0])
955706f2543Smrg		path = DEFAULT_CONF_PATH;
956706f2543Smrg	if (!projroot || !projroot[0])
957706f2543Smrg		projroot = PROJECTROOT;
958706f2543Smrg
959706f2543Smrg	/* Search for the multiconf directory */
960706f2543Smrg	configDirPath = OpenConfigDir(path, cmdline, projroot, XCONFIGDIR);
961706f2543Smrg	return configDirPath;
962706f2543Smrg}
963706f2543Smrg
964706f2543Smrgvoid
965706f2543Smrgxf86closeConfigFile (void)
966706f2543Smrg{
967706f2543Smrg	int i;
968706f2543Smrg
969706f2543Smrg	free (configPath);
970706f2543Smrg	configPath = NULL;
971706f2543Smrg	free (configDirPath);
972706f2543Smrg	configDirPath = NULL;
973706f2543Smrg	free (configRBuf);
974706f2543Smrg	configRBuf = NULL;
975706f2543Smrg	free (configBuf);
976706f2543Smrg	configBuf = NULL;
977706f2543Smrg
978706f2543Smrg	if (numFiles == 0) {
979706f2543Smrg		builtinConfig = NULL;
980706f2543Smrg		builtinIndex = 0;
981706f2543Smrg	}
982706f2543Smrg	for (i = 0; i < numFiles; i++) {
983706f2543Smrg		fclose(configFiles[i].file);
984706f2543Smrg		configFiles[i].file = NULL;
985706f2543Smrg		free(configFiles[i].path);
986706f2543Smrg		configFiles[i].path = NULL;
987706f2543Smrg	}
988706f2543Smrg	numFiles = 0;
989706f2543Smrg}
990706f2543Smrg
991706f2543Smrgvoid
992706f2543Smrgxf86setBuiltinConfig(const char *config[])
993706f2543Smrg{
994706f2543Smrg	builtinConfig = config;
995706f2543Smrg}
996706f2543Smrg
997706f2543Smrgvoid
998706f2543Smrgxf86parseError (char *format,...)
999706f2543Smrg{
1000706f2543Smrg	va_list ap;
1001706f2543Smrg	char *filename = numFiles ? configFiles[curFileIndex].path :
1002706f2543Smrg			 "<builtin configuration>";
1003706f2543Smrg
1004706f2543Smrg	ErrorF ("Parse error on line %d of section %s in file %s\n\t",
1005706f2543Smrg		 configLineNo, configSection, filename);
1006706f2543Smrg	va_start (ap, format);
1007706f2543Smrg	VErrorF (format, ap);
1008706f2543Smrg	va_end (ap);
1009706f2543Smrg
1010706f2543Smrg	ErrorF ("\n");
1011706f2543Smrg}
1012706f2543Smrg
1013706f2543Smrgvoid
1014706f2543Smrgxf86validationError (char *format,...)
1015706f2543Smrg{
1016706f2543Smrg	va_list ap;
1017706f2543Smrg	char *filename = numFiles ? configFiles[curFileIndex].path :
1018706f2543Smrg			 "<builtin configuration>";
1019706f2543Smrg
1020706f2543Smrg	ErrorF ("Data incomplete in file %s\n\t", filename);
1021706f2543Smrg	va_start (ap, format);
1022706f2543Smrg	VErrorF (format, ap);
1023706f2543Smrg	va_end (ap);
1024706f2543Smrg
1025706f2543Smrg	ErrorF ("\n");
1026706f2543Smrg}
1027706f2543Smrg
1028706f2543Smrgvoid
1029706f2543Smrgxf86setSection (char *section)
1030706f2543Smrg{
1031706f2543Smrg	free(configSection);
1032706f2543Smrg	configSection = strdup(section);
1033706f2543Smrg}
1034706f2543Smrg
1035706f2543Smrg/*
1036706f2543Smrg * xf86getToken --
1037706f2543Smrg *  Lookup a string if it is actually a token in disguise.
1038706f2543Smrg */
1039706f2543Smrgint
1040706f2543Smrgxf86getStringToken (xf86ConfigSymTabRec * tab)
1041706f2543Smrg{
1042706f2543Smrg	return StringToToken (val.str, tab);
1043706f2543Smrg}
1044706f2543Smrg
1045706f2543Smrgstatic int
1046706f2543SmrgStringToToken (char *str, xf86ConfigSymTabRec * tab)
1047706f2543Smrg{
1048706f2543Smrg	int i;
1049706f2543Smrg
1050706f2543Smrg	for (i = 0; tab[i].token != -1; i++)
1051706f2543Smrg	{
1052706f2543Smrg		if (!xf86nameCompare (tab[i].name, str))
1053706f2543Smrg			return tab[i].token;
1054706f2543Smrg	}
1055706f2543Smrg	return ERROR_TOKEN;
1056706f2543Smrg}
1057706f2543Smrg
1058706f2543Smrg
1059706f2543Smrg/*
1060706f2543Smrg * Compare two names.  The characters '_', ' ', and '\t' are ignored
1061706f2543Smrg * in the comparison.
1062706f2543Smrg */
1063706f2543Smrgint
1064706f2543Smrgxf86nameCompare (const char *s1, const char *s2)
1065706f2543Smrg{
1066706f2543Smrg	char c1, c2;
1067706f2543Smrg
1068706f2543Smrg	if (!s1 || *s1 == 0) {
1069706f2543Smrg		if (!s2 || *s2 == 0)
1070706f2543Smrg			return 0;
1071706f2543Smrg		else
1072706f2543Smrg			return 1;
1073706f2543Smrg		}
1074706f2543Smrg
1075706f2543Smrg	while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1076706f2543Smrg		s1++;
1077706f2543Smrg	while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1078706f2543Smrg		s2++;
1079706f2543Smrg	c1 = (isupper (*s1) ? tolower (*s1) : *s1);
1080706f2543Smrg	c2 = (isupper (*s2) ? tolower (*s2) : *s2);
1081706f2543Smrg	while (c1 == c2)
1082706f2543Smrg	{
1083706f2543Smrg		if (c1 == '\0')
1084706f2543Smrg			return 0;
1085706f2543Smrg		s1++;
1086706f2543Smrg		s2++;
1087706f2543Smrg		while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1088706f2543Smrg			s1++;
1089706f2543Smrg		while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1090706f2543Smrg			s2++;
1091706f2543Smrg		c1 = (isupper (*s1) ? tolower (*s1) : *s1);
1092706f2543Smrg		c2 = (isupper (*s2) ? tolower (*s2) : *s2);
1093706f2543Smrg	}
1094706f2543Smrg	return c1 - c2;
1095706f2543Smrg}
1096706f2543Smrg
1097706f2543Smrgchar *
1098706f2543Smrgxf86addComment(char *cur, char *add)
1099706f2543Smrg{
1100706f2543Smrg	char *str;
1101706f2543Smrg	int len, curlen, iscomment, hasnewline = 0, endnewline;
1102706f2543Smrg
1103706f2543Smrg	if (add == NULL || add[0] == '\0')
1104706f2543Smrg		return cur;
1105706f2543Smrg
1106706f2543Smrg	if (cur) {
1107706f2543Smrg		curlen = strlen(cur);
1108706f2543Smrg		if (curlen)
1109706f2543Smrg		    hasnewline = cur[curlen - 1] == '\n';
1110706f2543Smrg		eol_seen = 0;
1111706f2543Smrg	}
1112706f2543Smrg	else
1113706f2543Smrg		curlen = 0;
1114706f2543Smrg
1115706f2543Smrg	str = add;
1116706f2543Smrg	iscomment = 0;
1117706f2543Smrg	while (*str) {
1118706f2543Smrg	    if (*str != ' ' && *str != '\t')
1119706f2543Smrg		break;
1120706f2543Smrg	    ++str;
1121706f2543Smrg	}
1122706f2543Smrg	iscomment = (*str == '#');
1123706f2543Smrg
1124706f2543Smrg	len = strlen(add);
1125706f2543Smrg	endnewline = add[len - 1] == '\n';
1126706f2543Smrg	len +=  1 + iscomment + (!hasnewline) + (!endnewline) + eol_seen;
1127706f2543Smrg
1128706f2543Smrg	if ((str = realloc(cur, len + curlen)) == NULL)
1129706f2543Smrg		return cur;
1130706f2543Smrg
1131706f2543Smrg	cur = str;
1132706f2543Smrg
1133706f2543Smrg	if (eol_seen || (curlen && !hasnewline))
1134706f2543Smrg		cur[curlen++] = '\n';
1135706f2543Smrg	if (!iscomment)
1136706f2543Smrg		cur[curlen++] = '#';
1137706f2543Smrg	strcpy(cur + curlen, add);
1138706f2543Smrg	if (!endnewline)
1139706f2543Smrg		strcat(cur, "\n");
1140706f2543Smrg
1141706f2543Smrg	return cur;
1142706f2543Smrg}
1143706f2543Smrg
1144706f2543SmrgBool
1145706f2543Smrgxf86getBoolValue(Bool *val, const char *str)
1146706f2543Smrg{
1147706f2543Smrg	if (!val || !str)
1148706f2543Smrg		return FALSE;
1149706f2543Smrg	if (*str == '\0') {
1150706f2543Smrg		*val = TRUE;
1151706f2543Smrg	} else {
1152706f2543Smrg		if (xf86nameCompare(str, "1") == 0)
1153706f2543Smrg			*val = TRUE;
1154706f2543Smrg		else if (xf86nameCompare(str, "on") == 0)
1155706f2543Smrg			*val = TRUE;
1156706f2543Smrg		else if (xf86nameCompare(str, "true") == 0)
1157706f2543Smrg			*val = TRUE;
1158706f2543Smrg		else if (xf86nameCompare(str, "yes") == 0)
1159706f2543Smrg			*val = TRUE;
1160706f2543Smrg		else if (xf86nameCompare(str, "0") == 0)
1161706f2543Smrg			*val = FALSE;
1162706f2543Smrg		else if (xf86nameCompare(str, "off") == 0)
1163706f2543Smrg			*val = FALSE;
1164706f2543Smrg		else if (xf86nameCompare(str, "false") == 0)
1165706f2543Smrg			*val = FALSE;
1166706f2543Smrg		else if (xf86nameCompare(str, "no") == 0)
1167706f2543Smrg			*val = FALSE;
1168706f2543Smrg		else
1169706f2543Smrg			return FALSE;
1170706f2543Smrg	}
1171706f2543Smrg	return TRUE;
1172706f2543Smrg}
1173