xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/parser/scan.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 1997  Metro Link Incorporated
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun  * all copies or substantial portions of the Software.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*4882a593Smuzhiyun  * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18*4882a593Smuzhiyun  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19*4882a593Smuzhiyun  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20*4882a593Smuzhiyun  * SOFTWARE.
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  * Except as contained in this notice, the name of the Metro Link shall not be
23*4882a593Smuzhiyun  * used in advertising or otherwise to promote the sale, use or other dealings
24*4882a593Smuzhiyun  * in this Software without prior written authorization from Metro Link.
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  */
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
31*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
32*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
33*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
35*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
36*4882a593Smuzhiyun  *
37*4882a593Smuzhiyun  * The above copyright notice and this permission notice shall be included in
38*4882a593Smuzhiyun  * all copies or substantial portions of the Software.
39*4882a593Smuzhiyun  *
40*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
43*4882a593Smuzhiyun  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
44*4882a593Smuzhiyun  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
45*4882a593Smuzhiyun  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
46*4882a593Smuzhiyun  * OTHER DEALINGS IN THE SOFTWARE.
47*4882a593Smuzhiyun  *
48*4882a593Smuzhiyun  * Except as contained in this notice, the name of the copyright holder(s)
49*4882a593Smuzhiyun  * and author(s) shall not be used in advertising or otherwise to promote
50*4882a593Smuzhiyun  * the sale, use or other dealings in this Software without prior written
51*4882a593Smuzhiyun  * authorization from the copyright holder(s) and author(s).
52*4882a593Smuzhiyun  */
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #ifdef HAVE_XORG_CONFIG_H
55*4882a593Smuzhiyun #include <xorg-config.h>
56*4882a593Smuzhiyun #endif
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #include <ctype.h>
59*4882a593Smuzhiyun #include <stdio.h>
60*4882a593Smuzhiyun #include <stdlib.h>
61*4882a593Smuzhiyun #include <string.h>
62*4882a593Smuzhiyun #include <sys/types.h>
63*4882a593Smuzhiyun #include <dirent.h>
64*4882a593Smuzhiyun #include <unistd.h>
65*4882a593Smuzhiyun #include <stdarg.h>
66*4882a593Smuzhiyun #include <X11/Xdefs.h>
67*4882a593Smuzhiyun #include <X11/Xfuncproto.h>
68*4882a593Smuzhiyun #include <limits.h>
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #if !defined(MAXHOSTNAMELEN)
71*4882a593Smuzhiyun #define MAXHOSTNAMELEN 32
72*4882a593Smuzhiyun #endif                          /* !MAXHOSTNAMELEN */
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun /* For PATH_MAX */
75*4882a593Smuzhiyun #include "misc.h"
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun #include "Configint.h"
78*4882a593Smuzhiyun #include "xf86tokens.h"
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun #define CONFIG_BUF_LEN     1024
81*4882a593Smuzhiyun #define CONFIG_MAX_FILES   64
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun static struct {
84*4882a593Smuzhiyun     FILE *file;
85*4882a593Smuzhiyun     char *path;
86*4882a593Smuzhiyun } configFiles[CONFIG_MAX_FILES];
87*4882a593Smuzhiyun static const char **builtinConfig = NULL;
88*4882a593Smuzhiyun static int builtinIndex = 0;
89*4882a593Smuzhiyun static int configPos = 0;       /* current readers position */
90*4882a593Smuzhiyun static int configLineNo = 0;    /* linenumber */
91*4882a593Smuzhiyun static char *configBuf, *configRBuf;    /* buffer for lines */
92*4882a593Smuzhiyun static char *configSection = NULL;      /* name of current section being parsed */
93*4882a593Smuzhiyun static int numFiles = 0;        /* number of config files */
94*4882a593Smuzhiyun static int curFileIndex = 0;    /* index of current config file */
95*4882a593Smuzhiyun static int pushToken = LOCK_TOKEN;
96*4882a593Smuzhiyun static int eol_seen = 0;        /* private state to handle comments */
97*4882a593Smuzhiyun LexRec xf86_lex_val;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /*
100*4882a593Smuzhiyun  * xf86getNextLine --
101*4882a593Smuzhiyun  *
102*4882a593Smuzhiyun  *  read from the configFiles FILE stream until we encounter a new
103*4882a593Smuzhiyun  *  line; this is effectively just a big wrapper for fgets(3).
104*4882a593Smuzhiyun  *
105*4882a593Smuzhiyun  *  xf86getToken() assumes that we will read up to the next
106*4882a593Smuzhiyun  *  newline; we need to grow configBuf and configRBuf as needed to
107*4882a593Smuzhiyun  *  support that.
108*4882a593Smuzhiyun  */
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun static char *
xf86getNextLine(void)111*4882a593Smuzhiyun xf86getNextLine(void)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun     static int configBufLen = CONFIG_BUF_LEN;
114*4882a593Smuzhiyun     char *tmpConfigBuf, *tmpConfigRBuf;
115*4882a593Smuzhiyun     int c, i, pos = 0, eolFound = 0;
116*4882a593Smuzhiyun     char *ret = NULL;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun     /*
119*4882a593Smuzhiyun      * reallocate the string if it was grown last time (i.e., is no
120*4882a593Smuzhiyun      * longer CONFIG_BUF_LEN); we malloc the new strings first, so
121*4882a593Smuzhiyun      * that if either of the mallocs fail, we can fall back on the
122*4882a593Smuzhiyun      * existing buffer allocations
123*4882a593Smuzhiyun      */
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun     if (configBufLen != CONFIG_BUF_LEN) {
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun         tmpConfigBuf = malloc(CONFIG_BUF_LEN);
128*4882a593Smuzhiyun         tmpConfigRBuf = malloc(CONFIG_BUF_LEN);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun         if (!tmpConfigBuf || !tmpConfigRBuf) {
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun             /*
133*4882a593Smuzhiyun              * at least one of the mallocs failed; keep the old buffers
134*4882a593Smuzhiyun              * and free any partial allocations
135*4882a593Smuzhiyun              */
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun             free(tmpConfigBuf);
138*4882a593Smuzhiyun             free(tmpConfigRBuf);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun         }
141*4882a593Smuzhiyun         else {
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun             /*
144*4882a593Smuzhiyun              * malloc succeeded; free the old buffers and use the new
145*4882a593Smuzhiyun              * buffers
146*4882a593Smuzhiyun              */
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun             configBufLen = CONFIG_BUF_LEN;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun             free(configBuf);
151*4882a593Smuzhiyun             free(configRBuf);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun             configBuf = tmpConfigBuf;
154*4882a593Smuzhiyun             configRBuf = tmpConfigRBuf;
155*4882a593Smuzhiyun         }
156*4882a593Smuzhiyun     }
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun     /* read in another block of chars */
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun     do {
161*4882a593Smuzhiyun         ret = fgets(configBuf + pos, configBufLen - pos - 1,
162*4882a593Smuzhiyun                     configFiles[curFileIndex].file);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun         if (!ret) {
165*4882a593Smuzhiyun             /*
166*4882a593Smuzhiyun              * if the file doesn't end in a newline, add one
167*4882a593Smuzhiyun              * and trigger another read
168*4882a593Smuzhiyun              */
169*4882a593Smuzhiyun             if (pos != 0) {
170*4882a593Smuzhiyun                 strcpy(&configBuf[pos], "\n");
171*4882a593Smuzhiyun                 ret = configBuf;
172*4882a593Smuzhiyun             }
173*4882a593Smuzhiyun             else
174*4882a593Smuzhiyun                 break;
175*4882a593Smuzhiyun         }
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun         /* search for EOL in the new block of chars */
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun         for (i = pos; i < (configBufLen - 1); i++) {
180*4882a593Smuzhiyun             c = configBuf[i];
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun             if (c == '\0')
183*4882a593Smuzhiyun                 break;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun             if ((c == '\n') || (c == '\r')) {
186*4882a593Smuzhiyun                 eolFound = 1;
187*4882a593Smuzhiyun                 break;
188*4882a593Smuzhiyun             }
189*4882a593Smuzhiyun         }
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun         /*
192*4882a593Smuzhiyun          * if we didn't find EOL, then grow the string and
193*4882a593Smuzhiyun          * read in more
194*4882a593Smuzhiyun          */
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun         if (!eolFound) {
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun             tmpConfigBuf = realloc(configBuf, configBufLen + CONFIG_BUF_LEN);
199*4882a593Smuzhiyun             tmpConfigRBuf = realloc(configRBuf, configBufLen + CONFIG_BUF_LEN);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun             if (!tmpConfigBuf || !tmpConfigRBuf) {
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun                 /*
204*4882a593Smuzhiyun                  * at least one of the reallocations failed; use the
205*4882a593Smuzhiyun                  * new allocation that succeeded, but we have to
206*4882a593Smuzhiyun                  * fallback to the previous configBufLen size and use
207*4882a593Smuzhiyun                  * the string we have, even though we don't have an
208*4882a593Smuzhiyun                  * EOL
209*4882a593Smuzhiyun                  */
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun                 if (tmpConfigBuf)
212*4882a593Smuzhiyun                     configBuf = tmpConfigBuf;
213*4882a593Smuzhiyun                 if (tmpConfigRBuf)
214*4882a593Smuzhiyun                     configRBuf = tmpConfigRBuf;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun                 break;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun             }
219*4882a593Smuzhiyun             else {
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun                 /* reallocation succeeded */
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun                 configBuf = tmpConfigBuf;
224*4882a593Smuzhiyun                 configRBuf = tmpConfigRBuf;
225*4882a593Smuzhiyun                 pos = i;
226*4882a593Smuzhiyun                 configBufLen += CONFIG_BUF_LEN;
227*4882a593Smuzhiyun             }
228*4882a593Smuzhiyun         }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun     } while (!eolFound);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun     return ret;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun static int
StringToToken(const char * str,const xf86ConfigSymTabRec * tab)236*4882a593Smuzhiyun StringToToken(const char *str, const xf86ConfigSymTabRec * tab)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun     int i;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun     for (i = 0; tab[i].token != -1; i++) {
241*4882a593Smuzhiyun         if (!xf86nameCompare(tab[i].name, str))
242*4882a593Smuzhiyun             return tab[i].token;
243*4882a593Smuzhiyun     }
244*4882a593Smuzhiyun     return ERROR_TOKEN;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun /*
248*4882a593Smuzhiyun  * xf86getToken --
249*4882a593Smuzhiyun  *      Read next Token from the config file. Handle the global variable
250*4882a593Smuzhiyun  *      pushToken.
251*4882a593Smuzhiyun  */
252*4882a593Smuzhiyun int
xf86getToken(const xf86ConfigSymTabRec * tab)253*4882a593Smuzhiyun xf86getToken(const xf86ConfigSymTabRec * tab)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun     int c, i;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun     /*
258*4882a593Smuzhiyun      * First check whether pushToken has a different value than LOCK_TOKEN.
259*4882a593Smuzhiyun      * In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the
260*4882a593Smuzhiyun      * oth * case the next token must be read from the input.
261*4882a593Smuzhiyun      */
262*4882a593Smuzhiyun     if (pushToken == EOF_TOKEN)
263*4882a593Smuzhiyun         return EOF_TOKEN;
264*4882a593Smuzhiyun     else if (pushToken == LOCK_TOKEN) {
265*4882a593Smuzhiyun         /*
266*4882a593Smuzhiyun          * eol_seen is only set for the first token after a newline.
267*4882a593Smuzhiyun          */
268*4882a593Smuzhiyun         eol_seen = 0;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun         c = configBuf[configPos];
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun         /*
273*4882a593Smuzhiyun          * Get start of next Token. EOF is handled,
274*4882a593Smuzhiyun          * whitespaces are skipped.
275*4882a593Smuzhiyun          */
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun  again:
278*4882a593Smuzhiyun         if (!c) {
279*4882a593Smuzhiyun             char *ret;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun             if (numFiles > 0)
282*4882a593Smuzhiyun                 ret = xf86getNextLine();
283*4882a593Smuzhiyun             else {
284*4882a593Smuzhiyun                 if (builtinConfig[builtinIndex] == NULL)
285*4882a593Smuzhiyun                     ret = NULL;
286*4882a593Smuzhiyun                 else {
287*4882a593Smuzhiyun                     strlcpy(configBuf,
288*4882a593Smuzhiyun                             builtinConfig[builtinIndex], CONFIG_BUF_LEN);
289*4882a593Smuzhiyun                     ret = configBuf;
290*4882a593Smuzhiyun                     builtinIndex++;
291*4882a593Smuzhiyun                 }
292*4882a593Smuzhiyun             }
293*4882a593Smuzhiyun             if (ret == NULL) {
294*4882a593Smuzhiyun                 /*
295*4882a593Smuzhiyun                  * if necessary, move to the next file and
296*4882a593Smuzhiyun                  * read the first line
297*4882a593Smuzhiyun                  */
298*4882a593Smuzhiyun                 if (curFileIndex + 1 < numFiles) {
299*4882a593Smuzhiyun                     curFileIndex++;
300*4882a593Smuzhiyun                     configLineNo = 0;
301*4882a593Smuzhiyun                     goto again;
302*4882a593Smuzhiyun                 }
303*4882a593Smuzhiyun                 else
304*4882a593Smuzhiyun                     return pushToken = EOF_TOKEN;
305*4882a593Smuzhiyun             }
306*4882a593Smuzhiyun             configLineNo++;
307*4882a593Smuzhiyun             configPos = 0;
308*4882a593Smuzhiyun             eol_seen = 1;
309*4882a593Smuzhiyun         }
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun         i = 0;
312*4882a593Smuzhiyun         for (;;) {
313*4882a593Smuzhiyun             c = configBuf[configPos++];
314*4882a593Smuzhiyun             configRBuf[i++] = c;
315*4882a593Smuzhiyun             switch (c) {
316*4882a593Smuzhiyun             case ' ':
317*4882a593Smuzhiyun             case '\t':
318*4882a593Smuzhiyun             case '\r':
319*4882a593Smuzhiyun                 continue;
320*4882a593Smuzhiyun             case '\n':
321*4882a593Smuzhiyun                 i = 0;
322*4882a593Smuzhiyun                 continue;
323*4882a593Smuzhiyun             }
324*4882a593Smuzhiyun             break;
325*4882a593Smuzhiyun         }
326*4882a593Smuzhiyun         if (c == '\0')
327*4882a593Smuzhiyun             goto again;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun         if (c == '#') {
330*4882a593Smuzhiyun             do {
331*4882a593Smuzhiyun                 configRBuf[i++] = (c = configBuf[configPos++]);
332*4882a593Smuzhiyun             }
333*4882a593Smuzhiyun             while ((c != '\n') && (c != '\r') && (c != '\0'));
334*4882a593Smuzhiyun             configRBuf[i] = '\0';
335*4882a593Smuzhiyun             /* XXX no private copy.
336*4882a593Smuzhiyun              * Use xf86addComment when setting a comment.
337*4882a593Smuzhiyun              */
338*4882a593Smuzhiyun             xf86_lex_val.str = configRBuf;
339*4882a593Smuzhiyun             return COMMENT;
340*4882a593Smuzhiyun         }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun         /* GJA -- handle '-' and ','  * Be careful: "-hsync" is a keyword. */
343*4882a593Smuzhiyun         else if ((c == ',') && !isalpha(configBuf[configPos])) {
344*4882a593Smuzhiyun             return COMMA;
345*4882a593Smuzhiyun         }
346*4882a593Smuzhiyun         else if ((c == '-') && !isalpha(configBuf[configPos])) {
347*4882a593Smuzhiyun             return DASH;
348*4882a593Smuzhiyun         }
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun         /*
351*4882a593Smuzhiyun          * Numbers are returned immediately ...
352*4882a593Smuzhiyun          */
353*4882a593Smuzhiyun         if (isdigit(c)) {
354*4882a593Smuzhiyun             int base;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun             if (c == '0')
357*4882a593Smuzhiyun                 if ((configBuf[configPos] == 'x') ||
358*4882a593Smuzhiyun                     (configBuf[configPos] == 'X')) {
359*4882a593Smuzhiyun                     base = 16;
360*4882a593Smuzhiyun                     xf86_lex_val.numType = PARSE_HEX;
361*4882a593Smuzhiyun                 }
362*4882a593Smuzhiyun                 else {
363*4882a593Smuzhiyun                     base = 8;
364*4882a593Smuzhiyun                     xf86_lex_val.numType = PARSE_OCTAL;
365*4882a593Smuzhiyun                 }
366*4882a593Smuzhiyun             else {
367*4882a593Smuzhiyun                 base = 10;
368*4882a593Smuzhiyun                 xf86_lex_val.numType = PARSE_DECIMAL;
369*4882a593Smuzhiyun             }
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun             configRBuf[0] = c;
372*4882a593Smuzhiyun             i = 1;
373*4882a593Smuzhiyun             while (isdigit(c = configBuf[configPos++]) ||
374*4882a593Smuzhiyun                    (c == '.') || (c == 'x') || (c == 'X') ||
375*4882a593Smuzhiyun                    ((base == 16) && (((c >= 'a') && (c <= 'f')) ||
376*4882a593Smuzhiyun                                      ((c >= 'A') && (c <= 'F')))))
377*4882a593Smuzhiyun                 configRBuf[i++] = c;
378*4882a593Smuzhiyun             configPos--;        /* GJA -- one too far */
379*4882a593Smuzhiyun             configRBuf[i] = '\0';
380*4882a593Smuzhiyun             xf86_lex_val.num = strtoul(configRBuf, NULL, 0);
381*4882a593Smuzhiyun             xf86_lex_val.realnum = atof(configRBuf);
382*4882a593Smuzhiyun             return NUMBER;
383*4882a593Smuzhiyun         }
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun         /*
386*4882a593Smuzhiyun          * All Strings START with a \" ...
387*4882a593Smuzhiyun          */
388*4882a593Smuzhiyun         else if (c == '\"') {
389*4882a593Smuzhiyun             i = -1;
390*4882a593Smuzhiyun             do {
391*4882a593Smuzhiyun                 configRBuf[++i] = (c = configBuf[configPos++]);
392*4882a593Smuzhiyun             }
393*4882a593Smuzhiyun             while ((c != '\"') && (c != '\n') && (c != '\r') && (c != '\0'));
394*4882a593Smuzhiyun             configRBuf[i] = '\0';
395*4882a593Smuzhiyun             xf86_lex_val.str = malloc(strlen(configRBuf) + 1);
396*4882a593Smuzhiyun             strcpy(xf86_lex_val.str, configRBuf);        /* private copy ! */
397*4882a593Smuzhiyun             return STRING;
398*4882a593Smuzhiyun         }
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun         /*
401*4882a593Smuzhiyun          * ... and now we MUST have a valid token.  The search is
402*4882a593Smuzhiyun          * handled later along with the pushed tokens.
403*4882a593Smuzhiyun          */
404*4882a593Smuzhiyun         else {
405*4882a593Smuzhiyun             configRBuf[0] = c;
406*4882a593Smuzhiyun             i = 0;
407*4882a593Smuzhiyun             do {
408*4882a593Smuzhiyun                 configRBuf[++i] = (c = configBuf[configPos++]);
409*4882a593Smuzhiyun             }
410*4882a593Smuzhiyun             while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') &&
411*4882a593Smuzhiyun                    (c != '\0') && (c != '#'));
412*4882a593Smuzhiyun             --configPos;
413*4882a593Smuzhiyun             configRBuf[i] = '\0';
414*4882a593Smuzhiyun             i = 0;
415*4882a593Smuzhiyun         }
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun     }
418*4882a593Smuzhiyun     else {
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun         /*
421*4882a593Smuzhiyun          * Here we deal with pushed tokens. Reinitialize pushToken again. If
422*4882a593Smuzhiyun          * the pushed token was NUMBER || STRING return them again ...
423*4882a593Smuzhiyun          */
424*4882a593Smuzhiyun         int temp = pushToken;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun         pushToken = LOCK_TOKEN;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun         if (temp == COMMA || temp == DASH)
429*4882a593Smuzhiyun             return temp;
430*4882a593Smuzhiyun         if (temp == NUMBER || temp == STRING)
431*4882a593Smuzhiyun             return temp;
432*4882a593Smuzhiyun     }
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun     /*
435*4882a593Smuzhiyun      * Joop, at last we have to lookup the token ...
436*4882a593Smuzhiyun      */
437*4882a593Smuzhiyun     if (tab)
438*4882a593Smuzhiyun         return StringToToken(configRBuf, tab);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun     return ERROR_TOKEN;         /* Error catcher */
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun int
xf86getSubToken(char ** comment)444*4882a593Smuzhiyun xf86getSubToken(char **comment)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun     int token;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun     for (;;) {
449*4882a593Smuzhiyun         token = xf86getToken(NULL);
450*4882a593Smuzhiyun         if (token == COMMENT) {
451*4882a593Smuzhiyun             if (comment)
452*4882a593Smuzhiyun                 *comment = xf86addComment(*comment, xf86_lex_val.str);
453*4882a593Smuzhiyun         }
454*4882a593Smuzhiyun         else
455*4882a593Smuzhiyun             return token;
456*4882a593Smuzhiyun     }
457*4882a593Smuzhiyun  /*NOTREACHED*/}
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun int
xf86getSubTokenWithTab(char ** comment,const xf86ConfigSymTabRec * tab)460*4882a593Smuzhiyun xf86getSubTokenWithTab(char **comment, const xf86ConfigSymTabRec * tab)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun     int token;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun     for (;;) {
465*4882a593Smuzhiyun         token = xf86getToken(tab);
466*4882a593Smuzhiyun         if (token == COMMENT) {
467*4882a593Smuzhiyun             if (comment)
468*4882a593Smuzhiyun                 *comment = xf86addComment(*comment, xf86_lex_val.str);
469*4882a593Smuzhiyun         }
470*4882a593Smuzhiyun         else
471*4882a593Smuzhiyun             return token;
472*4882a593Smuzhiyun     }
473*4882a593Smuzhiyun  /*NOTREACHED*/}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun void
xf86unGetToken(int token)476*4882a593Smuzhiyun xf86unGetToken(int token)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun     pushToken = token;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun char *
xf86tokenString(void)482*4882a593Smuzhiyun xf86tokenString(void)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun     return configRBuf;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun int
xf86pathIsAbsolute(const char * path)488*4882a593Smuzhiyun xf86pathIsAbsolute(const char *path)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun     if (path && path[0] == '/')
491*4882a593Smuzhiyun         return 1;
492*4882a593Smuzhiyun     return 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun /* A path is "safe" if it is relative and if it contains no ".." elements. */
496*4882a593Smuzhiyun int
xf86pathIsSafe(const char * path)497*4882a593Smuzhiyun xf86pathIsSafe(const char *path)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun     if (xf86pathIsAbsolute(path))
500*4882a593Smuzhiyun         return 0;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun     /* Compare with ".." */
503*4882a593Smuzhiyun     if (!strcmp(path, ".."))
504*4882a593Smuzhiyun         return 0;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun     /* Look for leading "../" */
507*4882a593Smuzhiyun     if (!strncmp(path, "../", 3))
508*4882a593Smuzhiyun         return 0;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun     /* Look for trailing "/.." */
511*4882a593Smuzhiyun     if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/.."))
512*4882a593Smuzhiyun         return 0;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun     /* Look for "/../" */
515*4882a593Smuzhiyun     if (strstr(path, "/../"))
516*4882a593Smuzhiyun         return 0;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun     return 1;
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun /*
522*4882a593Smuzhiyun  * This function substitutes the following escape sequences:
523*4882a593Smuzhiyun  *
524*4882a593Smuzhiyun  *    %A    cmdline argument as an absolute path (must be absolute to match)
525*4882a593Smuzhiyun  *    %R    cmdline argument as a relative path
526*4882a593Smuzhiyun  *    %S    cmdline argument as a "safe" path (relative, and no ".." elements)
527*4882a593Smuzhiyun  *    %X    default config file name ("xorg.conf")
528*4882a593Smuzhiyun  *    %H    hostname
529*4882a593Smuzhiyun  *    %E    config file environment ($XORGCONFIG) as an absolute path
530*4882a593Smuzhiyun  *    %F    config file environment ($XORGCONFIG) as a relative path
531*4882a593Smuzhiyun  *    %G    config file environment ($XORGCONFIG) as a safe path
532*4882a593Smuzhiyun  *    %P    projroot
533*4882a593Smuzhiyun  *    %C    sysconfdir
534*4882a593Smuzhiyun  *    %D    datadir
535*4882a593Smuzhiyun  *    %%    %
536*4882a593Smuzhiyun  */
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun #define XCONFIGSUFFIX	".conf"
539*4882a593Smuzhiyun #define XCONFENV	"XORGCONFIG"
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun #define BAIL_OUT		do {									\
542*4882a593Smuzhiyun 							free(result);				\
543*4882a593Smuzhiyun 							return NULL;						\
544*4882a593Smuzhiyun 						} while (0)
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun #define CHECK_LENGTH	do {									\
547*4882a593Smuzhiyun 							if (l > PATH_MAX) {					\
548*4882a593Smuzhiyun 								BAIL_OUT;						\
549*4882a593Smuzhiyun 							}									\
550*4882a593Smuzhiyun 						} while (0)
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun #define APPEND_STR(s)	do {									\
553*4882a593Smuzhiyun 							if (strlen(s) + l > PATH_MAX) {		\
554*4882a593Smuzhiyun 								BAIL_OUT;						\
555*4882a593Smuzhiyun 							} else {							\
556*4882a593Smuzhiyun 								strcpy(result + l, s);			\
557*4882a593Smuzhiyun 								l += strlen(s);					\
558*4882a593Smuzhiyun 							}									\
559*4882a593Smuzhiyun 						} while (0)
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun static char *
DoSubstitution(const char * template,const char * cmdline,const char * projroot,int * cmdlineUsed,int * envUsed,const char * XConfigFile)562*4882a593Smuzhiyun DoSubstitution(const char *template, const char *cmdline, const char *projroot,
563*4882a593Smuzhiyun                int *cmdlineUsed, int *envUsed, const char *XConfigFile)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun     char *result;
566*4882a593Smuzhiyun     int i, l;
567*4882a593Smuzhiyun     static const char *env = NULL;
568*4882a593Smuzhiyun     static char *hostname = NULL;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun     if (!template)
571*4882a593Smuzhiyun         return NULL;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun     if (cmdlineUsed)
574*4882a593Smuzhiyun         *cmdlineUsed = 0;
575*4882a593Smuzhiyun     if (envUsed)
576*4882a593Smuzhiyun         *envUsed = 0;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun     result = malloc(PATH_MAX + 1);
579*4882a593Smuzhiyun     l = 0;
580*4882a593Smuzhiyun     for (i = 0; template[i]; i++) {
581*4882a593Smuzhiyun         if (template[i] != '%') {
582*4882a593Smuzhiyun             result[l++] = template[i];
583*4882a593Smuzhiyun             CHECK_LENGTH;
584*4882a593Smuzhiyun         }
585*4882a593Smuzhiyun         else {
586*4882a593Smuzhiyun             switch (template[++i]) {
587*4882a593Smuzhiyun             case 'A':
588*4882a593Smuzhiyun                 if (cmdline && xf86pathIsAbsolute(cmdline)) {
589*4882a593Smuzhiyun                     APPEND_STR(cmdline);
590*4882a593Smuzhiyun                     if (cmdlineUsed)
591*4882a593Smuzhiyun                         *cmdlineUsed = 1;
592*4882a593Smuzhiyun                 }
593*4882a593Smuzhiyun                 else
594*4882a593Smuzhiyun                     BAIL_OUT;
595*4882a593Smuzhiyun                 break;
596*4882a593Smuzhiyun             case 'R':
597*4882a593Smuzhiyun                 if (cmdline && !xf86pathIsAbsolute(cmdline)) {
598*4882a593Smuzhiyun                     APPEND_STR(cmdline);
599*4882a593Smuzhiyun                     if (cmdlineUsed)
600*4882a593Smuzhiyun                         *cmdlineUsed = 1;
601*4882a593Smuzhiyun                 }
602*4882a593Smuzhiyun                 else
603*4882a593Smuzhiyun                     BAIL_OUT;
604*4882a593Smuzhiyun                 break;
605*4882a593Smuzhiyun             case 'S':
606*4882a593Smuzhiyun                 if (cmdline && xf86pathIsSafe(cmdline)) {
607*4882a593Smuzhiyun                     APPEND_STR(cmdline);
608*4882a593Smuzhiyun                     if (cmdlineUsed)
609*4882a593Smuzhiyun                         *cmdlineUsed = 1;
610*4882a593Smuzhiyun                 }
611*4882a593Smuzhiyun                 else
612*4882a593Smuzhiyun                     BAIL_OUT;
613*4882a593Smuzhiyun                 break;
614*4882a593Smuzhiyun             case 'X':
615*4882a593Smuzhiyun                 APPEND_STR(XConfigFile);
616*4882a593Smuzhiyun                 break;
617*4882a593Smuzhiyun             case 'H':
618*4882a593Smuzhiyun                 if (!hostname) {
619*4882a593Smuzhiyun                     if ((hostname = malloc(MAXHOSTNAMELEN + 1))) {
620*4882a593Smuzhiyun                         if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
621*4882a593Smuzhiyun                             hostname[MAXHOSTNAMELEN] = '\0';
622*4882a593Smuzhiyun                         }
623*4882a593Smuzhiyun                         else {
624*4882a593Smuzhiyun                             free(hostname);
625*4882a593Smuzhiyun                             hostname = NULL;
626*4882a593Smuzhiyun                         }
627*4882a593Smuzhiyun                     }
628*4882a593Smuzhiyun                 }
629*4882a593Smuzhiyun                 if (hostname)
630*4882a593Smuzhiyun                     APPEND_STR(hostname);
631*4882a593Smuzhiyun                 break;
632*4882a593Smuzhiyun             case 'E':
633*4882a593Smuzhiyun                 if (!env)
634*4882a593Smuzhiyun                     env = getenv(XCONFENV);
635*4882a593Smuzhiyun                 if (env && xf86pathIsAbsolute(env)) {
636*4882a593Smuzhiyun                     APPEND_STR(env);
637*4882a593Smuzhiyun                     if (envUsed)
638*4882a593Smuzhiyun                         *envUsed = 1;
639*4882a593Smuzhiyun                 }
640*4882a593Smuzhiyun                 else
641*4882a593Smuzhiyun                     BAIL_OUT;
642*4882a593Smuzhiyun                 break;
643*4882a593Smuzhiyun             case 'F':
644*4882a593Smuzhiyun                 if (!env)
645*4882a593Smuzhiyun                     env = getenv(XCONFENV);
646*4882a593Smuzhiyun                 if (env && !xf86pathIsAbsolute(env)) {
647*4882a593Smuzhiyun                     APPEND_STR(env);
648*4882a593Smuzhiyun                     if (envUsed)
649*4882a593Smuzhiyun                         *envUsed = 1;
650*4882a593Smuzhiyun                 }
651*4882a593Smuzhiyun                 else
652*4882a593Smuzhiyun                     BAIL_OUT;
653*4882a593Smuzhiyun                 break;
654*4882a593Smuzhiyun             case 'G':
655*4882a593Smuzhiyun                 if (!env)
656*4882a593Smuzhiyun                     env = getenv(XCONFENV);
657*4882a593Smuzhiyun                 if (env && xf86pathIsSafe(env)) {
658*4882a593Smuzhiyun                     APPEND_STR(env);
659*4882a593Smuzhiyun                     if (envUsed)
660*4882a593Smuzhiyun                         *envUsed = 1;
661*4882a593Smuzhiyun                 }
662*4882a593Smuzhiyun                 else
663*4882a593Smuzhiyun                     BAIL_OUT;
664*4882a593Smuzhiyun                 break;
665*4882a593Smuzhiyun             case 'P':
666*4882a593Smuzhiyun                 if (projroot && xf86pathIsAbsolute(projroot))
667*4882a593Smuzhiyun                     APPEND_STR(projroot);
668*4882a593Smuzhiyun                 else
669*4882a593Smuzhiyun                     BAIL_OUT;
670*4882a593Smuzhiyun                 break;
671*4882a593Smuzhiyun             case 'C':
672*4882a593Smuzhiyun                 APPEND_STR(SYSCONFDIR);
673*4882a593Smuzhiyun                 break;
674*4882a593Smuzhiyun             case 'D':
675*4882a593Smuzhiyun                 APPEND_STR(DATADIR);
676*4882a593Smuzhiyun                 break;
677*4882a593Smuzhiyun             case '%':
678*4882a593Smuzhiyun                 result[l++] = '%';
679*4882a593Smuzhiyun                 CHECK_LENGTH;
680*4882a593Smuzhiyun                 break;
681*4882a593Smuzhiyun             default:
682*4882a593Smuzhiyun                 fprintf(stderr, "invalid escape %%%c found in path template\n",
683*4882a593Smuzhiyun                         template[i]);
684*4882a593Smuzhiyun                 BAIL_OUT;
685*4882a593Smuzhiyun                 break;
686*4882a593Smuzhiyun             }
687*4882a593Smuzhiyun         }
688*4882a593Smuzhiyun     }
689*4882a593Smuzhiyun #ifdef DEBUG
690*4882a593Smuzhiyun     fprintf(stderr, "Converted `%s' to `%s'\n", template, result);
691*4882a593Smuzhiyun #endif
692*4882a593Smuzhiyun     return result;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun /*
696*4882a593Smuzhiyun  * Given some searching parameters, locate and open the xorg config file.
697*4882a593Smuzhiyun  */
698*4882a593Smuzhiyun static char *
OpenConfigFile(const char * path,const char * cmdline,const char * projroot,const char * confname)699*4882a593Smuzhiyun OpenConfigFile(const char *path, const char *cmdline, const char *projroot,
700*4882a593Smuzhiyun                const char *confname)
701*4882a593Smuzhiyun {
702*4882a593Smuzhiyun     char *filepath = NULL;
703*4882a593Smuzhiyun     char *pathcopy;
704*4882a593Smuzhiyun     const char *template;
705*4882a593Smuzhiyun     int cmdlineUsed = 0;
706*4882a593Smuzhiyun     FILE *file = NULL;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun     pathcopy = strdup(path);
709*4882a593Smuzhiyun     for (template = strtok(pathcopy, ","); template && !file;
710*4882a593Smuzhiyun          template = strtok(NULL, ",")) {
711*4882a593Smuzhiyun         filepath = DoSubstitution(template, cmdline, projroot,
712*4882a593Smuzhiyun                                   &cmdlineUsed, NULL, confname);
713*4882a593Smuzhiyun         if (!filepath)
714*4882a593Smuzhiyun             continue;
715*4882a593Smuzhiyun         if (cmdline && !cmdlineUsed) {
716*4882a593Smuzhiyun             free(filepath);
717*4882a593Smuzhiyun             filepath = NULL;
718*4882a593Smuzhiyun             continue;
719*4882a593Smuzhiyun         }
720*4882a593Smuzhiyun         file = fopen(filepath, "r");
721*4882a593Smuzhiyun         if (!file) {
722*4882a593Smuzhiyun             free(filepath);
723*4882a593Smuzhiyun             filepath = NULL;
724*4882a593Smuzhiyun         }
725*4882a593Smuzhiyun     }
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun     free(pathcopy);
728*4882a593Smuzhiyun     if (file) {
729*4882a593Smuzhiyun         configFiles[numFiles].file = file;
730*4882a593Smuzhiyun         configFiles[numFiles].path = strdup(filepath);
731*4882a593Smuzhiyun         numFiles++;
732*4882a593Smuzhiyun     }
733*4882a593Smuzhiyun     return filepath;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun /*
737*4882a593Smuzhiyun  * Match non-hidden files in the xorg config directory with a .conf
738*4882a593Smuzhiyun  * suffix. This filter is passed to scandir(3).
739*4882a593Smuzhiyun  */
740*4882a593Smuzhiyun static int
ConfigFilter(const struct dirent * de)741*4882a593Smuzhiyun ConfigFilter(const struct dirent *de)
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun     const char *name = de->d_name;
744*4882a593Smuzhiyun     size_t len;
745*4882a593Smuzhiyun     size_t suflen = strlen(XCONFIGSUFFIX);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun     if (!name || name[0] == '.')
748*4882a593Smuzhiyun         return 0;
749*4882a593Smuzhiyun     len = strlen(name);
750*4882a593Smuzhiyun     if (len <= suflen)
751*4882a593Smuzhiyun         return 0;
752*4882a593Smuzhiyun     if (strcmp(&name[len - suflen], XCONFIGSUFFIX) != 0)
753*4882a593Smuzhiyun         return 0;
754*4882a593Smuzhiyun     return 1;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun static Bool
AddConfigDirFiles(const char * dirpath,struct dirent ** list,int num)758*4882a593Smuzhiyun AddConfigDirFiles(const char *dirpath, struct dirent **list, int num)
759*4882a593Smuzhiyun {
760*4882a593Smuzhiyun     int i;
761*4882a593Smuzhiyun     Bool openedFile = FALSE;
762*4882a593Smuzhiyun     Bool warnOnce = FALSE;
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun     for (i = 0; i < num; i++) {
765*4882a593Smuzhiyun         char *path;
766*4882a593Smuzhiyun         FILE *file;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun         if (numFiles >= CONFIG_MAX_FILES) {
769*4882a593Smuzhiyun             if (!warnOnce) {
770*4882a593Smuzhiyun                 ErrorF("Maximum number of configuration " "files opened\n");
771*4882a593Smuzhiyun                 warnOnce = TRUE;
772*4882a593Smuzhiyun             }
773*4882a593Smuzhiyun             continue;
774*4882a593Smuzhiyun         }
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun         path = malloc(PATH_MAX + 1);
777*4882a593Smuzhiyun         snprintf(path, PATH_MAX + 1, "%s/%s", dirpath, list[i]->d_name);
778*4882a593Smuzhiyun         file = fopen(path, "r");
779*4882a593Smuzhiyun         if (!file) {
780*4882a593Smuzhiyun             free(path);
781*4882a593Smuzhiyun             continue;
782*4882a593Smuzhiyun         }
783*4882a593Smuzhiyun         openedFile = TRUE;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun         configFiles[numFiles].file = file;
786*4882a593Smuzhiyun         configFiles[numFiles].path = path;
787*4882a593Smuzhiyun         numFiles++;
788*4882a593Smuzhiyun     }
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun     return openedFile;
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun /*
794*4882a593Smuzhiyun  * Given some searching parameters, locate and open the xorg config
795*4882a593Smuzhiyun  * directory. The directory does not need to contain config files.
796*4882a593Smuzhiyun  */
797*4882a593Smuzhiyun static char *
OpenConfigDir(const char * path,const char * cmdline,const char * projroot,const char * confname)798*4882a593Smuzhiyun OpenConfigDir(const char *path, const char *cmdline, const char *projroot,
799*4882a593Smuzhiyun               const char *confname)
800*4882a593Smuzhiyun {
801*4882a593Smuzhiyun     char *dirpath = NULL, *pathcopy;
802*4882a593Smuzhiyun     const char *template;
803*4882a593Smuzhiyun     Bool found = FALSE;
804*4882a593Smuzhiyun     int cmdlineUsed = 0;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun     pathcopy = strdup(path);
807*4882a593Smuzhiyun     for (template = strtok(pathcopy, ","); template && !found;
808*4882a593Smuzhiyun          template = strtok(NULL, ",")) {
809*4882a593Smuzhiyun         struct dirent **list = NULL;
810*4882a593Smuzhiyun         int num;
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun         dirpath = DoSubstitution(template, cmdline, projroot,
813*4882a593Smuzhiyun                                  &cmdlineUsed, NULL, confname);
814*4882a593Smuzhiyun         if (!dirpath)
815*4882a593Smuzhiyun             continue;
816*4882a593Smuzhiyun         if (cmdline && !cmdlineUsed) {
817*4882a593Smuzhiyun             free(dirpath);
818*4882a593Smuzhiyun             dirpath = NULL;
819*4882a593Smuzhiyun             continue;
820*4882a593Smuzhiyun         }
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun         /* match files named *.conf */
823*4882a593Smuzhiyun         num = scandir(dirpath, &list, ConfigFilter, alphasort);
824*4882a593Smuzhiyun         if (num < 0) {
825*4882a593Smuzhiyun             list = NULL;
826*4882a593Smuzhiyun             num = 0;
827*4882a593Smuzhiyun         }
828*4882a593Smuzhiyun         found = AddConfigDirFiles(dirpath, list, num);
829*4882a593Smuzhiyun         if (!found) {
830*4882a593Smuzhiyun             free(dirpath);
831*4882a593Smuzhiyun             dirpath = NULL;
832*4882a593Smuzhiyun         }
833*4882a593Smuzhiyun         while (num--)
834*4882a593Smuzhiyun             free(list[num]);
835*4882a593Smuzhiyun         free(list);
836*4882a593Smuzhiyun     }
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun     free(pathcopy);
839*4882a593Smuzhiyun     return dirpath;
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun /*
843*4882a593Smuzhiyun  * xf86initConfigFiles -- Setup global variables and buffers.
844*4882a593Smuzhiyun  */
845*4882a593Smuzhiyun void
xf86initConfigFiles(void)846*4882a593Smuzhiyun xf86initConfigFiles(void)
847*4882a593Smuzhiyun {
848*4882a593Smuzhiyun     curFileIndex = 0;
849*4882a593Smuzhiyun     configPos = 0;
850*4882a593Smuzhiyun     configLineNo = 0;
851*4882a593Smuzhiyun     pushToken = LOCK_TOKEN;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun     configBuf = malloc(CONFIG_BUF_LEN);
854*4882a593Smuzhiyun     configRBuf = malloc(CONFIG_BUF_LEN);
855*4882a593Smuzhiyun     configBuf[0] = '\0';        /* sanity ... */
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun /*
859*4882a593Smuzhiyun  * xf86openConfigFile --
860*4882a593Smuzhiyun  *
861*4882a593Smuzhiyun  * This function take a config file search path (optional), a command-line
862*4882a593Smuzhiyun  * specified file name (optional) and the ProjectRoot path (optional) and
863*4882a593Smuzhiyun  * locates and opens a config file based on that information.  If a
864*4882a593Smuzhiyun  * command-line file name is specified, then this function fails if none
865*4882a593Smuzhiyun  * of the located files.
866*4882a593Smuzhiyun  *
867*4882a593Smuzhiyun  * The return value is a pointer to the actual name of the file that was
868*4882a593Smuzhiyun  * opened.  When no file is found, the return value is NULL. The caller should
869*4882a593Smuzhiyun  * free() the returned value.
870*4882a593Smuzhiyun  *
871*4882a593Smuzhiyun  * The escape sequences allowed in the search path are defined above.
872*4882a593Smuzhiyun  *
873*4882a593Smuzhiyun  */
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun #ifndef DEFAULT_CONF_PATH
876*4882a593Smuzhiyun #define DEFAULT_CONF_PATH	"/etc/X11/%S," \
877*4882a593Smuzhiyun 							"%P/etc/X11/%S," \
878*4882a593Smuzhiyun 							"/etc/X11/%G," \
879*4882a593Smuzhiyun 							"%P/etc/X11/%G," \
880*4882a593Smuzhiyun 							"/etc/X11/%X-%M," \
881*4882a593Smuzhiyun 							"/etc/X11/%X," \
882*4882a593Smuzhiyun 							"/etc/%X," \
883*4882a593Smuzhiyun 							"%P/etc/X11/%X.%H," \
884*4882a593Smuzhiyun 							"%P/etc/X11/%X-%M," \
885*4882a593Smuzhiyun 							"%P/etc/X11/%X," \
886*4882a593Smuzhiyun 							"%P/lib/X11/%X.%H," \
887*4882a593Smuzhiyun 							"%P/lib/X11/%X-%M," \
888*4882a593Smuzhiyun 							"%P/lib/X11/%X"
889*4882a593Smuzhiyun #endif
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun char *
xf86openConfigFile(const char * path,const char * cmdline,const char * projroot)892*4882a593Smuzhiyun xf86openConfigFile(const char *path, const char *cmdline, const char *projroot)
893*4882a593Smuzhiyun {
894*4882a593Smuzhiyun     if (!path || !path[0])
895*4882a593Smuzhiyun         path = DEFAULT_CONF_PATH;
896*4882a593Smuzhiyun     if (!projroot || !projroot[0])
897*4882a593Smuzhiyun         projroot = PROJECTROOT;
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun     /* Search for a config file */
900*4882a593Smuzhiyun     return OpenConfigFile(path, cmdline, projroot, XCONFIGFILE);
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun /*
904*4882a593Smuzhiyun  * xf86openConfigDirFiles --
905*4882a593Smuzhiyun  *
906*4882a593Smuzhiyun  * This function take a config directory search path (optional), a
907*4882a593Smuzhiyun  * command-line specified directory name (optional) and the ProjectRoot path
908*4882a593Smuzhiyun  * (optional) and locates and opens a config directory based on that
909*4882a593Smuzhiyun  * information.  If a command-line name is specified, then this function
910*4882a593Smuzhiyun  * fails if it is not found.
911*4882a593Smuzhiyun  *
912*4882a593Smuzhiyun  * The return value is a pointer to the actual name of the directory that was
913*4882a593Smuzhiyun  * opened.  When no directory is found, the return value is NULL. The caller
914*4882a593Smuzhiyun  * should free() the returned value.
915*4882a593Smuzhiyun  *
916*4882a593Smuzhiyun  * The escape sequences allowed in the search path are defined above.
917*4882a593Smuzhiyun  *
918*4882a593Smuzhiyun  */
919*4882a593Smuzhiyun char *
xf86openConfigDirFiles(const char * path,const char * cmdline,const char * projroot)920*4882a593Smuzhiyun xf86openConfigDirFiles(const char *path, const char *cmdline,
921*4882a593Smuzhiyun                        const char *projroot)
922*4882a593Smuzhiyun {
923*4882a593Smuzhiyun     if (!path || !path[0])
924*4882a593Smuzhiyun         path = DEFAULT_CONF_PATH;
925*4882a593Smuzhiyun     if (!projroot || !projroot[0])
926*4882a593Smuzhiyun         projroot = PROJECTROOT;
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun     /* Search for the multiconf directory */
929*4882a593Smuzhiyun     return OpenConfigDir(path, cmdline, projroot, XCONFIGDIR);
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun void
xf86closeConfigFile(void)933*4882a593Smuzhiyun xf86closeConfigFile(void)
934*4882a593Smuzhiyun {
935*4882a593Smuzhiyun     int i;
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun     free(configRBuf);
938*4882a593Smuzhiyun     configRBuf = NULL;
939*4882a593Smuzhiyun     free(configBuf);
940*4882a593Smuzhiyun     configBuf = NULL;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun     if (numFiles == 0) {
943*4882a593Smuzhiyun         builtinConfig = NULL;
944*4882a593Smuzhiyun         builtinIndex = 0;
945*4882a593Smuzhiyun     }
946*4882a593Smuzhiyun     for (i = 0; i < numFiles; i++) {
947*4882a593Smuzhiyun         fclose(configFiles[i].file);
948*4882a593Smuzhiyun         configFiles[i].file = NULL;
949*4882a593Smuzhiyun         free(configFiles[i].path);
950*4882a593Smuzhiyun         configFiles[i].path = NULL;
951*4882a593Smuzhiyun     }
952*4882a593Smuzhiyun     numFiles = 0;
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun void
xf86setBuiltinConfig(const char * config[])956*4882a593Smuzhiyun xf86setBuiltinConfig(const char *config[])
957*4882a593Smuzhiyun {
958*4882a593Smuzhiyun     builtinConfig = config;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun void
xf86parseError(const char * format,...)962*4882a593Smuzhiyun xf86parseError(const char *format, ...)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun     va_list ap;
965*4882a593Smuzhiyun     const char *filename = numFiles ? configFiles[curFileIndex].path
966*4882a593Smuzhiyun         : "<builtin configuration>";
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun     ErrorF("Parse error on line %d of section %s in file %s\n\t",
969*4882a593Smuzhiyun            configLineNo, configSection, filename);
970*4882a593Smuzhiyun     va_start(ap, format);
971*4882a593Smuzhiyun     VErrorF(format, ap);
972*4882a593Smuzhiyun     va_end(ap);
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun     ErrorF("\n");
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun void
xf86validationError(const char * format,...)978*4882a593Smuzhiyun xf86validationError(const char *format, ...)
979*4882a593Smuzhiyun {
980*4882a593Smuzhiyun     va_list ap;
981*4882a593Smuzhiyun     const char *filename = numFiles ? configFiles[curFileIndex].path
982*4882a593Smuzhiyun         : "<builtin configuration>";
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun     ErrorF("Data incomplete in file %s\n\t", filename);
985*4882a593Smuzhiyun     va_start(ap, format);
986*4882a593Smuzhiyun     VErrorF(format, ap);
987*4882a593Smuzhiyun     va_end(ap);
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun     ErrorF("\n");
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun void
xf86setSection(const char * section)993*4882a593Smuzhiyun xf86setSection(const char *section)
994*4882a593Smuzhiyun {
995*4882a593Smuzhiyun     free(configSection);
996*4882a593Smuzhiyun     configSection = strdup(section);
997*4882a593Smuzhiyun }
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun /*
1000*4882a593Smuzhiyun  * xf86getToken --
1001*4882a593Smuzhiyun  *  Lookup a string if it is actually a token in disguise.
1002*4882a593Smuzhiyun  */
1003*4882a593Smuzhiyun int
xf86getStringToken(const xf86ConfigSymTabRec * tab)1004*4882a593Smuzhiyun xf86getStringToken(const xf86ConfigSymTabRec * tab)
1005*4882a593Smuzhiyun {
1006*4882a593Smuzhiyun     return StringToToken(xf86_lex_val.str, tab);
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun /*
1010*4882a593Smuzhiyun  * Compare two names.  The characters '_', ' ', and '\t' are ignored
1011*4882a593Smuzhiyun  * in the comparison.
1012*4882a593Smuzhiyun  */
1013*4882a593Smuzhiyun int
xf86nameCompare(const char * s1,const char * s2)1014*4882a593Smuzhiyun xf86nameCompare(const char *s1, const char *s2)
1015*4882a593Smuzhiyun {
1016*4882a593Smuzhiyun     char c1, c2;
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun     if (!s1 || *s1 == 0) {
1019*4882a593Smuzhiyun         if (!s2 || *s2 == 0)
1020*4882a593Smuzhiyun             return 0;
1021*4882a593Smuzhiyun         else
1022*4882a593Smuzhiyun             return 1;
1023*4882a593Smuzhiyun     } else if (!s2 || *s2 == 0) {
1024*4882a593Smuzhiyun         return -1;
1025*4882a593Smuzhiyun     }
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun     while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1028*4882a593Smuzhiyun         s1++;
1029*4882a593Smuzhiyun     while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1030*4882a593Smuzhiyun         s2++;
1031*4882a593Smuzhiyun     c1 = (isupper(*s1) ? tolower(*s1) : *s1);
1032*4882a593Smuzhiyun     c2 = (isupper(*s2) ? tolower(*s2) : *s2);
1033*4882a593Smuzhiyun     while (c1 == c2) {
1034*4882a593Smuzhiyun         if (c1 == '\0')
1035*4882a593Smuzhiyun             return 0;
1036*4882a593Smuzhiyun         s1++;
1037*4882a593Smuzhiyun         s2++;
1038*4882a593Smuzhiyun         while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1039*4882a593Smuzhiyun             s1++;
1040*4882a593Smuzhiyun         while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1041*4882a593Smuzhiyun             s2++;
1042*4882a593Smuzhiyun         c1 = (isupper(*s1) ? tolower(*s1) : *s1);
1043*4882a593Smuzhiyun         c2 = (isupper(*s2) ? tolower(*s2) : *s2);
1044*4882a593Smuzhiyun     }
1045*4882a593Smuzhiyun     return c1 - c2;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun char *
xf86addComment(char * cur,const char * add)1049*4882a593Smuzhiyun xf86addComment(char *cur, const char *add)
1050*4882a593Smuzhiyun {
1051*4882a593Smuzhiyun     char *str;
1052*4882a593Smuzhiyun     const char *cstr;
1053*4882a593Smuzhiyun     int len, curlen, iscomment, hasnewline = 0, insnewline, endnewline;
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun     if (add == NULL || add[0] == '\0')
1056*4882a593Smuzhiyun         return cur;
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun     if (cur) {
1059*4882a593Smuzhiyun         curlen = strlen(cur);
1060*4882a593Smuzhiyun         if (curlen)
1061*4882a593Smuzhiyun             hasnewline = cur[curlen - 1] == '\n';
1062*4882a593Smuzhiyun         eol_seen = 0;
1063*4882a593Smuzhiyun     }
1064*4882a593Smuzhiyun     else
1065*4882a593Smuzhiyun         curlen = 0;
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun     cstr = add;
1068*4882a593Smuzhiyun     iscomment = 0;
1069*4882a593Smuzhiyun     while (*cstr) {
1070*4882a593Smuzhiyun         if (*cstr != ' ' && *cstr != '\t')
1071*4882a593Smuzhiyun             break;
1072*4882a593Smuzhiyun         ++cstr;
1073*4882a593Smuzhiyun     }
1074*4882a593Smuzhiyun     iscomment = (*cstr == '#');
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun     len = strlen(add);
1077*4882a593Smuzhiyun     endnewline = add[len - 1] == '\n';
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun     insnewline = eol_seen || (curlen && !hasnewline);
1080*4882a593Smuzhiyun     if (insnewline)
1081*4882a593Smuzhiyun         len++;
1082*4882a593Smuzhiyun     if (!iscomment)
1083*4882a593Smuzhiyun         len++;
1084*4882a593Smuzhiyun     if (!endnewline)
1085*4882a593Smuzhiyun         len++;
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun     /* Allocate + 1 char for '\0' terminator. */
1088*4882a593Smuzhiyun     str = realloc(cur, curlen + len + 1);
1089*4882a593Smuzhiyun     if (!str)
1090*4882a593Smuzhiyun         return cur;
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun     cur = str;
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun     if (insnewline)
1095*4882a593Smuzhiyun         cur[curlen++] = '\n';
1096*4882a593Smuzhiyun     if (!iscomment)
1097*4882a593Smuzhiyun         cur[curlen++] = '#';
1098*4882a593Smuzhiyun     strcpy(cur + curlen, add);
1099*4882a593Smuzhiyun     if (!endnewline)
1100*4882a593Smuzhiyun         strcat(cur, "\n");
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun     return cur;
1103*4882a593Smuzhiyun }
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun Bool
xf86getBoolValue(Bool * val,const char * str)1106*4882a593Smuzhiyun xf86getBoolValue(Bool *val, const char *str)
1107*4882a593Smuzhiyun {
1108*4882a593Smuzhiyun     if (!val || !str)
1109*4882a593Smuzhiyun         return FALSE;
1110*4882a593Smuzhiyun     if (*str == '\0') {
1111*4882a593Smuzhiyun         *val = TRUE;
1112*4882a593Smuzhiyun     }
1113*4882a593Smuzhiyun     else {
1114*4882a593Smuzhiyun         if (xf86nameCompare(str, "1") == 0)
1115*4882a593Smuzhiyun             *val = TRUE;
1116*4882a593Smuzhiyun         else if (xf86nameCompare(str, "on") == 0)
1117*4882a593Smuzhiyun             *val = TRUE;
1118*4882a593Smuzhiyun         else if (xf86nameCompare(str, "true") == 0)
1119*4882a593Smuzhiyun             *val = TRUE;
1120*4882a593Smuzhiyun         else if (xf86nameCompare(str, "yes") == 0)
1121*4882a593Smuzhiyun             *val = TRUE;
1122*4882a593Smuzhiyun         else if (xf86nameCompare(str, "0") == 0)
1123*4882a593Smuzhiyun             *val = FALSE;
1124*4882a593Smuzhiyun         else if (xf86nameCompare(str, "off") == 0)
1125*4882a593Smuzhiyun             *val = FALSE;
1126*4882a593Smuzhiyun         else if (xf86nameCompare(str, "false") == 0)
1127*4882a593Smuzhiyun             *val = FALSE;
1128*4882a593Smuzhiyun         else if (xf86nameCompare(str, "no") == 0)
1129*4882a593Smuzhiyun             *val = FALSE;
1130*4882a593Smuzhiyun         else
1131*4882a593Smuzhiyun             return FALSE;
1132*4882a593Smuzhiyun     }
1133*4882a593Smuzhiyun     return TRUE;
1134*4882a593Smuzhiyun }
1135