135c4bbdfSmrg/*
205b261ecSmrg * Copyright (c) 1997  Metro Link Incorporated
335c4bbdfSmrg *
405b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
535c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
605b261ecSmrg * to deal in the Software without restriction, including without limitation
705b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
805b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the
905b261ecSmrg * Software is furnished to do so, subject to the following conditions:
1035c4bbdfSmrg *
1105b261ecSmrg * The above copyright notice and this permission notice shall be included in
1205b261ecSmrg * all copies or substantial portions of the Software.
1335c4bbdfSmrg *
1405b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1705b261ecSmrg * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1805b261ecSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
1905b261ecSmrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2005b261ecSmrg * SOFTWARE.
2135c4bbdfSmrg *
2205b261ecSmrg * Except as contained in this notice, the name of the Metro Link shall not be
2305b261ecSmrg * used in advertising or otherwise to promote the sale, use or other dealings
2405b261ecSmrg * in this Software without prior written authorization from Metro Link.
2535c4bbdfSmrg *
2605b261ecSmrg */
2705b261ecSmrg/*
2805b261ecSmrg * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
2905b261ecSmrg *
3005b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
3105b261ecSmrg * copy of this software and associated documentation files (the "Software"),
3205b261ecSmrg * to deal in the Software without restriction, including without limitation
3305b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
3405b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the
3505b261ecSmrg * Software is furnished to do so, subject to the following conditions:
3605b261ecSmrg *
3705b261ecSmrg * The above copyright notice and this permission notice shall be included in
3805b261ecSmrg * all copies or substantial portions of the Software.
3905b261ecSmrg *
4005b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4105b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4205b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
4305b261ecSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
4405b261ecSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
4505b261ecSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
4605b261ecSmrg * OTHER DEALINGS IN THE SOFTWARE.
4705b261ecSmrg *
4805b261ecSmrg * Except as contained in this notice, the name of the copyright holder(s)
4905b261ecSmrg * and author(s) shall not be used in advertising or otherwise to promote
5005b261ecSmrg * the sale, use or other dealings in this Software without prior written
5105b261ecSmrg * authorization from the copyright holder(s) and author(s).
5205b261ecSmrg */
5305b261ecSmrg
5405b261ecSmrg#ifdef HAVE_XORG_CONFIG_H
5505b261ecSmrg#include <xorg-config.h>
5605b261ecSmrg#endif
5705b261ecSmrg
5805b261ecSmrg#include <ctype.h>
5905b261ecSmrg#include <stdio.h>
6005b261ecSmrg#include <stdlib.h>
6105b261ecSmrg#include <string.h>
626747b715Smrg#include <sys/types.h>
636747b715Smrg#include <dirent.h>
6405b261ecSmrg#include <unistd.h>
6505b261ecSmrg#include <stdarg.h>
666747b715Smrg#include <X11/Xdefs.h>
674642e01fSmrg#include <X11/Xfuncproto.h>
6805b261ecSmrg#include <limits.h>
6905b261ecSmrg
7005b261ecSmrg#if !defined(MAXHOSTNAMELEN)
7105b261ecSmrg#define MAXHOSTNAMELEN 32
7235c4bbdfSmrg#endif                          /* !MAXHOSTNAMELEN */
7335c4bbdfSmrg
7435c4bbdfSmrg/* For PATH_MAX */
7535c4bbdfSmrg#include "misc.h"
7605b261ecSmrg
7705b261ecSmrg#include "Configint.h"
7805b261ecSmrg#include "xf86tokens.h"
7905b261ecSmrg
8005b261ecSmrg#define CONFIG_BUF_LEN     1024
816747b715Smrg#define CONFIG_MAX_FILES   64
8205b261ecSmrg
836747b715Smrgstatic struct {
8435c4bbdfSmrg    FILE *file;
8535c4bbdfSmrg    char *path;
866747b715Smrg} configFiles[CONFIG_MAX_FILES];
8705b261ecSmrgstatic const char **builtinConfig = NULL;
8805b261ecSmrgstatic int builtinIndex = 0;
8935c4bbdfSmrgstatic int configPos = 0;       /* current readers position */
9035c4bbdfSmrgstatic int configLineNo = 0;    /* linenumber */
9135c4bbdfSmrgstatic char *configBuf, *configRBuf;    /* buffer for lines */
9235c4bbdfSmrgstatic char *configSection = NULL;      /* name of current section being parsed */
9335c4bbdfSmrgstatic int numFiles = 0;        /* number of config files */
9435c4bbdfSmrgstatic int curFileIndex = 0;    /* index of current config file */
9505b261ecSmrgstatic int pushToken = LOCK_TOKEN;
9635c4bbdfSmrgstatic int eol_seen = 0;        /* private state to handle comments */
9735c4bbdfSmrgLexRec xf86_lex_val;
9805b261ecSmrg
9905b261ecSmrg/*
10005b261ecSmrg * xf86getNextLine --
10105b261ecSmrg *
1026747b715Smrg *  read from the configFiles FILE stream until we encounter a new
10305b261ecSmrg *  line; this is effectively just a big wrapper for fgets(3).
10405b261ecSmrg *
10505b261ecSmrg *  xf86getToken() assumes that we will read up to the next
10605b261ecSmrg *  newline; we need to grow configBuf and configRBuf as needed to
10705b261ecSmrg *  support that.
10805b261ecSmrg */
10905b261ecSmrg
11035c4bbdfSmrgstatic char *
11105b261ecSmrgxf86getNextLine(void)
11205b261ecSmrg{
11335c4bbdfSmrg    static int configBufLen = CONFIG_BUF_LEN;
11435c4bbdfSmrg    char *tmpConfigBuf, *tmpConfigRBuf;
11535c4bbdfSmrg    int c, i, pos = 0, eolFound = 0;
11635c4bbdfSmrg    char *ret = NULL;
11705b261ecSmrg
11835c4bbdfSmrg    /*
11935c4bbdfSmrg     * reallocate the string if it was grown last time (i.e., is no
12035c4bbdfSmrg     * longer CONFIG_BUF_LEN); we malloc the new strings first, so
12135c4bbdfSmrg     * that if either of the mallocs fail, we can fall back on the
12235c4bbdfSmrg     * existing buffer allocations
12335c4bbdfSmrg     */
12405b261ecSmrg
12535c4bbdfSmrg    if (configBufLen != CONFIG_BUF_LEN) {
12605b261ecSmrg
12735c4bbdfSmrg        tmpConfigBuf = malloc(CONFIG_BUF_LEN);
12835c4bbdfSmrg        tmpConfigRBuf = malloc(CONFIG_BUF_LEN);
12905b261ecSmrg
13035c4bbdfSmrg        if (!tmpConfigBuf || !tmpConfigRBuf) {
13105b261ecSmrg
13235c4bbdfSmrg            /*
13335c4bbdfSmrg             * at least one of the mallocs failed; keep the old buffers
13435c4bbdfSmrg             * and free any partial allocations
13535c4bbdfSmrg             */
13605b261ecSmrg
13735c4bbdfSmrg            free(tmpConfigBuf);
13835c4bbdfSmrg            free(tmpConfigRBuf);
13905b261ecSmrg
14035c4bbdfSmrg        }
14135c4bbdfSmrg        else {
14205b261ecSmrg
14335c4bbdfSmrg            /*
14435c4bbdfSmrg             * malloc succeeded; free the old buffers and use the new
14535c4bbdfSmrg             * buffers
14635c4bbdfSmrg             */
14705b261ecSmrg
14835c4bbdfSmrg            configBufLen = CONFIG_BUF_LEN;
14905b261ecSmrg
15035c4bbdfSmrg            free(configBuf);
15135c4bbdfSmrg            free(configRBuf);
15205b261ecSmrg
15335c4bbdfSmrg            configBuf = tmpConfigBuf;
15435c4bbdfSmrg            configRBuf = tmpConfigRBuf;
15535c4bbdfSmrg        }
15635c4bbdfSmrg    }
15705b261ecSmrg
15835c4bbdfSmrg    /* read in another block of chars */
15905b261ecSmrg
16035c4bbdfSmrg    do {
16135c4bbdfSmrg        ret = fgets(configBuf + pos, configBufLen - pos - 1,
16235c4bbdfSmrg                    configFiles[curFileIndex].file);
16305b261ecSmrg
16435c4bbdfSmrg        if (!ret) {
16535c4bbdfSmrg            /*
16635c4bbdfSmrg             * if the file doesn't end in a newline, add one
16735c4bbdfSmrg             * and trigger another read
16835c4bbdfSmrg             */
16935c4bbdfSmrg            if (pos != 0) {
17035c4bbdfSmrg                strcpy(&configBuf[pos], "\n");
17135c4bbdfSmrg                ret = configBuf;
17235c4bbdfSmrg            }
17335c4bbdfSmrg            else
17435c4bbdfSmrg                break;
17535c4bbdfSmrg        }
17605b261ecSmrg
17735c4bbdfSmrg        /* search for EOL in the new block of chars */
17805b261ecSmrg
17935c4bbdfSmrg        for (i = pos; i < (configBufLen - 1); i++) {
18035c4bbdfSmrg            c = configBuf[i];
18105b261ecSmrg
18235c4bbdfSmrg            if (c == '\0')
18335c4bbdfSmrg                break;
18405b261ecSmrg
18535c4bbdfSmrg            if ((c == '\n') || (c == '\r')) {
18635c4bbdfSmrg                eolFound = 1;
18735c4bbdfSmrg                break;
18835c4bbdfSmrg            }
18935c4bbdfSmrg        }
19005b261ecSmrg
19135c4bbdfSmrg        /*
19235c4bbdfSmrg         * if we didn't find EOL, then grow the string and
19335c4bbdfSmrg         * read in more
19435c4bbdfSmrg         */
19505b261ecSmrg
19635c4bbdfSmrg        if (!eolFound) {
19705b261ecSmrg
19835c4bbdfSmrg            tmpConfigBuf = realloc(configBuf, configBufLen + CONFIG_BUF_LEN);
19935c4bbdfSmrg            tmpConfigRBuf = realloc(configRBuf, configBufLen + CONFIG_BUF_LEN);
20005b261ecSmrg
20135c4bbdfSmrg            if (!tmpConfigBuf || !tmpConfigRBuf) {
20205b261ecSmrg
20335c4bbdfSmrg                /*
20435c4bbdfSmrg                 * at least one of the reallocations failed; use the
20535c4bbdfSmrg                 * new allocation that succeeded, but we have to
20635c4bbdfSmrg                 * fallback to the previous configBufLen size and use
20735c4bbdfSmrg                 * the string we have, even though we don't have an
20835c4bbdfSmrg                 * EOL
20935c4bbdfSmrg                 */
21005b261ecSmrg
21135c4bbdfSmrg                if (tmpConfigBuf)
21235c4bbdfSmrg                    configBuf = tmpConfigBuf;
21335c4bbdfSmrg                if (tmpConfigRBuf)
21435c4bbdfSmrg                    configRBuf = tmpConfigRBuf;
21505b261ecSmrg
21635c4bbdfSmrg                break;
21705b261ecSmrg
21835c4bbdfSmrg            }
21935c4bbdfSmrg            else {
22005b261ecSmrg
22135c4bbdfSmrg                /* reallocation succeeded */
22205b261ecSmrg
22335c4bbdfSmrg                configBuf = tmpConfigBuf;
22435c4bbdfSmrg                configRBuf = tmpConfigRBuf;
22535c4bbdfSmrg                pos = i;
22635c4bbdfSmrg                configBufLen += CONFIG_BUF_LEN;
22735c4bbdfSmrg            }
22835c4bbdfSmrg        }
22905b261ecSmrg
23035c4bbdfSmrg    } while (!eolFound);
23105b261ecSmrg
23235c4bbdfSmrg    return ret;
23305b261ecSmrg}
23405b261ecSmrg
2351b5d61b8Smrgstatic int
2361b5d61b8SmrgStringToToken(const char *str, const xf86ConfigSymTabRec * tab)
2371b5d61b8Smrg{
2381b5d61b8Smrg    int i;
2391b5d61b8Smrg
2401b5d61b8Smrg    for (i = 0; tab[i].token != -1; i++) {
2411b5d61b8Smrg        if (!xf86nameCompare(tab[i].name, str))
2421b5d61b8Smrg            return tab[i].token;
2431b5d61b8Smrg    }
2441b5d61b8Smrg    return ERROR_TOKEN;
2451b5d61b8Smrg}
2461b5d61b8Smrg
24735c4bbdfSmrg/*
24805b261ecSmrg * xf86getToken --
24905b261ecSmrg *      Read next Token from the config file. Handle the global variable
25005b261ecSmrg *      pushToken.
25105b261ecSmrg */
25205b261ecSmrgint
2531b5d61b8Smrgxf86getToken(const xf86ConfigSymTabRec * tab)
25405b261ecSmrg{
25535c4bbdfSmrg    int c, i;
25635c4bbdfSmrg
25735c4bbdfSmrg    /*
25835c4bbdfSmrg     * First check whether pushToken has a different value than LOCK_TOKEN.
25935c4bbdfSmrg     * In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the
26035c4bbdfSmrg     * oth * case the next token must be read from the input.
26135c4bbdfSmrg     */
26235c4bbdfSmrg    if (pushToken == EOF_TOKEN)
26335c4bbdfSmrg        return EOF_TOKEN;
26435c4bbdfSmrg    else if (pushToken == LOCK_TOKEN) {
26535c4bbdfSmrg        /*
26635c4bbdfSmrg         * eol_seen is only set for the first token after a newline.
26735c4bbdfSmrg         */
26835c4bbdfSmrg        eol_seen = 0;
26935c4bbdfSmrg
27035c4bbdfSmrg        c = configBuf[configPos];
27135c4bbdfSmrg
27235c4bbdfSmrg        /*
27335c4bbdfSmrg         * Get start of next Token. EOF is handled,
27435c4bbdfSmrg         * whitespaces are skipped.
27535c4bbdfSmrg         */
27635c4bbdfSmrg
27735c4bbdfSmrg again:
27835c4bbdfSmrg        if (!c) {
27935c4bbdfSmrg            char *ret;
28035c4bbdfSmrg
28135c4bbdfSmrg            if (numFiles > 0)
28235c4bbdfSmrg                ret = xf86getNextLine();
28335c4bbdfSmrg            else {
28435c4bbdfSmrg                if (builtinConfig[builtinIndex] == NULL)
28535c4bbdfSmrg                    ret = NULL;
28635c4bbdfSmrg                else {
28735c4bbdfSmrg                    strlcpy(configBuf,
28835c4bbdfSmrg                            builtinConfig[builtinIndex], CONFIG_BUF_LEN);
28935c4bbdfSmrg                    ret = configBuf;
29035c4bbdfSmrg                    builtinIndex++;
29135c4bbdfSmrg                }
29235c4bbdfSmrg            }
29335c4bbdfSmrg            if (ret == NULL) {
29435c4bbdfSmrg                /*
29535c4bbdfSmrg                 * if necessary, move to the next file and
29635c4bbdfSmrg                 * read the first line
29735c4bbdfSmrg                 */
29835c4bbdfSmrg                if (curFileIndex + 1 < numFiles) {
29935c4bbdfSmrg                    curFileIndex++;
30035c4bbdfSmrg                    configLineNo = 0;
30135c4bbdfSmrg                    goto again;
30235c4bbdfSmrg                }
30335c4bbdfSmrg                else
30435c4bbdfSmrg                    return pushToken = EOF_TOKEN;
30535c4bbdfSmrg            }
30635c4bbdfSmrg            configLineNo++;
30735c4bbdfSmrg            configPos = 0;
30835c4bbdfSmrg            eol_seen = 1;
30935c4bbdfSmrg        }
31035c4bbdfSmrg
31135c4bbdfSmrg        i = 0;
31235c4bbdfSmrg        for (;;) {
31335c4bbdfSmrg            c = configBuf[configPos++];
31435c4bbdfSmrg            configRBuf[i++] = c;
31535c4bbdfSmrg            switch (c) {
31635c4bbdfSmrg            case ' ':
31735c4bbdfSmrg            case '\t':
31835c4bbdfSmrg            case '\r':
31935c4bbdfSmrg                continue;
32035c4bbdfSmrg            case '\n':
32135c4bbdfSmrg                i = 0;
32235c4bbdfSmrg                continue;
32335c4bbdfSmrg            }
32435c4bbdfSmrg            break;
32535c4bbdfSmrg        }
32635c4bbdfSmrg        if (c == '\0')
32735c4bbdfSmrg            goto again;
32835c4bbdfSmrg
32935c4bbdfSmrg        if (c == '#') {
33035c4bbdfSmrg            do {
33135c4bbdfSmrg                configRBuf[i++] = (c = configBuf[configPos++]);
33235c4bbdfSmrg            }
33335c4bbdfSmrg            while ((c != '\n') && (c != '\r') && (c != '\0'));
33435c4bbdfSmrg            configRBuf[i] = '\0';
33558cf2af7Smrg            /* XXX private copy.
33635c4bbdfSmrg             * Use xf86addComment when setting a comment.
33735c4bbdfSmrg             */
33858cf2af7Smrg            xf86_lex_val.str = strdup(configRBuf);
33935c4bbdfSmrg            return COMMENT;
34035c4bbdfSmrg        }
34135c4bbdfSmrg
34235c4bbdfSmrg        /* GJA -- handle '-' and ','  * Be careful: "-hsync" is a keyword. */
34335c4bbdfSmrg        else if ((c == ',') && !isalpha(configBuf[configPos])) {
34435c4bbdfSmrg            return COMMA;
34535c4bbdfSmrg        }
34635c4bbdfSmrg        else if ((c == '-') && !isalpha(configBuf[configPos])) {
34735c4bbdfSmrg            return DASH;
34835c4bbdfSmrg        }
34935c4bbdfSmrg
35035c4bbdfSmrg        /*
35135c4bbdfSmrg         * Numbers are returned immediately ...
35235c4bbdfSmrg         */
35335c4bbdfSmrg        if (isdigit(c)) {
35435c4bbdfSmrg            int base;
35535c4bbdfSmrg
35635c4bbdfSmrg            if (c == '0')
35735c4bbdfSmrg                if ((configBuf[configPos] == 'x') ||
35835c4bbdfSmrg                    (configBuf[configPos] == 'X')) {
35935c4bbdfSmrg                    base = 16;
36035c4bbdfSmrg                    xf86_lex_val.numType = PARSE_HEX;
36135c4bbdfSmrg                }
36235c4bbdfSmrg                else {
36335c4bbdfSmrg                    base = 8;
36435c4bbdfSmrg                    xf86_lex_val.numType = PARSE_OCTAL;
36535c4bbdfSmrg                }
36635c4bbdfSmrg            else {
36735c4bbdfSmrg                base = 10;
36835c4bbdfSmrg                xf86_lex_val.numType = PARSE_DECIMAL;
36935c4bbdfSmrg            }
37035c4bbdfSmrg
37135c4bbdfSmrg            configRBuf[0] = c;
37235c4bbdfSmrg            i = 1;
37335c4bbdfSmrg            while (isdigit(c = configBuf[configPos++]) ||
37435c4bbdfSmrg                   (c == '.') || (c == 'x') || (c == 'X') ||
37535c4bbdfSmrg                   ((base == 16) && (((c >= 'a') && (c <= 'f')) ||
37635c4bbdfSmrg                                     ((c >= 'A') && (c <= 'F')))))
37735c4bbdfSmrg                configRBuf[i++] = c;
37835c4bbdfSmrg            configPos--;        /* GJA -- one too far */
37935c4bbdfSmrg            configRBuf[i] = '\0';
38035c4bbdfSmrg            xf86_lex_val.num = strtoul(configRBuf, NULL, 0);
38135c4bbdfSmrg            xf86_lex_val.realnum = atof(configRBuf);
38235c4bbdfSmrg            return NUMBER;
38335c4bbdfSmrg        }
38435c4bbdfSmrg
38535c4bbdfSmrg        /*
38635c4bbdfSmrg         * All Strings START with a \" ...
38735c4bbdfSmrg         */
38835c4bbdfSmrg        else if (c == '\"') {
38935c4bbdfSmrg            i = -1;
39035c4bbdfSmrg            do {
39135c4bbdfSmrg                configRBuf[++i] = (c = configBuf[configPos++]);
39235c4bbdfSmrg            }
39335c4bbdfSmrg            while ((c != '\"') && (c != '\n') && (c != '\r') && (c != '\0'));
39435c4bbdfSmrg            configRBuf[i] = '\0';
39535c4bbdfSmrg            xf86_lex_val.str = malloc(strlen(configRBuf) + 1);
39635c4bbdfSmrg            strcpy(xf86_lex_val.str, configRBuf);        /* private copy ! */
39735c4bbdfSmrg            return STRING;
39835c4bbdfSmrg        }
39935c4bbdfSmrg
40035c4bbdfSmrg        /*
40135c4bbdfSmrg         * ... and now we MUST have a valid token.  The search is
40235c4bbdfSmrg         * handled later along with the pushed tokens.
40335c4bbdfSmrg         */
40435c4bbdfSmrg        else {
40535c4bbdfSmrg            configRBuf[0] = c;
40635c4bbdfSmrg            i = 0;
40735c4bbdfSmrg            do {
40835c4bbdfSmrg                configRBuf[++i] = (c = configBuf[configPos++]);
40935c4bbdfSmrg            }
41035c4bbdfSmrg            while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') &&
41135c4bbdfSmrg                   (c != '\0') && (c != '#'));
41235c4bbdfSmrg            --configPos;
41335c4bbdfSmrg            configRBuf[i] = '\0';
41435c4bbdfSmrg            i = 0;
41535c4bbdfSmrg        }
41635c4bbdfSmrg
41735c4bbdfSmrg    }
41835c4bbdfSmrg    else {
41935c4bbdfSmrg
42035c4bbdfSmrg        /*
42135c4bbdfSmrg         * Here we deal with pushed tokens. Reinitialize pushToken again. If
42235c4bbdfSmrg         * the pushed token was NUMBER || STRING return them again ...
42335c4bbdfSmrg         */
42435c4bbdfSmrg        int temp = pushToken;
42535c4bbdfSmrg
42635c4bbdfSmrg        pushToken = LOCK_TOKEN;
42735c4bbdfSmrg
42835c4bbdfSmrg        if (temp == COMMA || temp == DASH)
42935c4bbdfSmrg            return temp;
43035c4bbdfSmrg        if (temp == NUMBER || temp == STRING)
43135c4bbdfSmrg            return temp;
43235c4bbdfSmrg    }
43335c4bbdfSmrg
43435c4bbdfSmrg    /*
43535c4bbdfSmrg     * Joop, at last we have to lookup the token ...
43635c4bbdfSmrg     */
4371b5d61b8Smrg    if (tab)
4381b5d61b8Smrg        return StringToToken(configRBuf, tab);
43935c4bbdfSmrg
44035c4bbdfSmrg    return ERROR_TOKEN;         /* Error catcher */
44105b261ecSmrg}
44205b261ecSmrg
44305b261ecSmrgint
44435c4bbdfSmrgxf86getSubToken(char **comment)
44505b261ecSmrg{
44635c4bbdfSmrg    int token;
44735c4bbdfSmrg
44835c4bbdfSmrg    for (;;) {
44935c4bbdfSmrg        token = xf86getToken(NULL);
45035c4bbdfSmrg        if (token == COMMENT) {
45158cf2af7Smrg            if (comment) {
45235c4bbdfSmrg                *comment = xf86addComment(*comment, xf86_lex_val.str);
45358cf2af7Smrg                free(xf86_lex_val.str);
45458cf2af7Smrg                xf86_lex_val.str = NULL;
45558cf2af7Smrg            }
45635c4bbdfSmrg        }
45735c4bbdfSmrg        else
45835c4bbdfSmrg            return token;
45935c4bbdfSmrg    }
46035c4bbdfSmrg /*NOTREACHED*/}
46105b261ecSmrg
46205b261ecSmrgint
4631b5d61b8Smrgxf86getSubTokenWithTab(char **comment, const xf86ConfigSymTabRec * tab)
46405b261ecSmrg{
46535c4bbdfSmrg    int token;
46635c4bbdfSmrg
46735c4bbdfSmrg    for (;;) {
46835c4bbdfSmrg        token = xf86getToken(tab);
46935c4bbdfSmrg        if (token == COMMENT) {
47058cf2af7Smrg            if (comment) {
47135c4bbdfSmrg                *comment = xf86addComment(*comment, xf86_lex_val.str);
47258cf2af7Smrg                free(xf86_lex_val.str);
47358cf2af7Smrg                xf86_lex_val.str = NULL;
47458cf2af7Smrg            }
47535c4bbdfSmrg        }
47635c4bbdfSmrg        else
47735c4bbdfSmrg            return token;
47835c4bbdfSmrg    }
47935c4bbdfSmrg /*NOTREACHED*/}
48005b261ecSmrg
48105b261ecSmrgvoid
48235c4bbdfSmrgxf86unGetToken(int token)
48305b261ecSmrg{
48435c4bbdfSmrg    pushToken = token;
48505b261ecSmrg}
48605b261ecSmrg
48705b261ecSmrgchar *
48835c4bbdfSmrgxf86tokenString(void)
48905b261ecSmrg{
49035c4bbdfSmrg    return configRBuf;
49105b261ecSmrg}
49205b261ecSmrg
49305b261ecSmrgint
49405b261ecSmrgxf86pathIsAbsolute(const char *path)
49505b261ecSmrg{
49635c4bbdfSmrg    if (path && path[0] == '/')
49735c4bbdfSmrg        return 1;
49835c4bbdfSmrg    return 0;
49905b261ecSmrg}
50005b261ecSmrg
50105b261ecSmrg/* A path is "safe" if it is relative and if it contains no ".." elements. */
50205b261ecSmrgint
50305b261ecSmrgxf86pathIsSafe(const char *path)
50405b261ecSmrg{
50535c4bbdfSmrg    if (xf86pathIsAbsolute(path))
50635c4bbdfSmrg        return 0;
50705b261ecSmrg
50835c4bbdfSmrg    /* Compare with ".." */
50935c4bbdfSmrg    if (!strcmp(path, ".."))
51035c4bbdfSmrg        return 0;
51105b261ecSmrg
51235c4bbdfSmrg    /* Look for leading "../" */
51335c4bbdfSmrg    if (!strncmp(path, "../", 3))
51435c4bbdfSmrg        return 0;
51505b261ecSmrg
51635c4bbdfSmrg    /* Look for trailing "/.." */
51735c4bbdfSmrg    if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/.."))
51835c4bbdfSmrg        return 0;
51905b261ecSmrg
52035c4bbdfSmrg    /* Look for "/../" */
52135c4bbdfSmrg    if (strstr(path, "/../"))
52235c4bbdfSmrg        return 0;
52305b261ecSmrg
52435c4bbdfSmrg    return 1;
52505b261ecSmrg}
52605b261ecSmrg
52705b261ecSmrg/*
52805b261ecSmrg * This function substitutes the following escape sequences:
52905b261ecSmrg *
53005b261ecSmrg *    %A    cmdline argument as an absolute path (must be absolute to match)
53105b261ecSmrg *    %R    cmdline argument as a relative path
53205b261ecSmrg *    %S    cmdline argument as a "safe" path (relative, and no ".." elements)
53305b261ecSmrg *    %X    default config file name ("xorg.conf")
53405b261ecSmrg *    %H    hostname
53505b261ecSmrg *    %E    config file environment ($XORGCONFIG) as an absolute path
53605b261ecSmrg *    %F    config file environment ($XORGCONFIG) as a relative path
53705b261ecSmrg *    %G    config file environment ($XORGCONFIG) as a safe path
53805b261ecSmrg *    %P    projroot
5396747b715Smrg *    %C    sysconfdir
5406747b715Smrg *    %D    datadir
54105b261ecSmrg *    %%    %
54205b261ecSmrg */
54305b261ecSmrg
5446747b715Smrg#define XCONFIGSUFFIX	".conf"
5456747b715Smrg#define XCONFENV	"XORGCONFIG"
54605b261ecSmrg
54705b261ecSmrg#define BAIL_OUT		do {									\
5486747b715Smrg							free(result);				\
54905b261ecSmrg							return NULL;						\
55005b261ecSmrg						} while (0)
55105b261ecSmrg
55205b261ecSmrg#define CHECK_LENGTH	do {									\
55305b261ecSmrg							if (l > PATH_MAX) {					\
55405b261ecSmrg								BAIL_OUT;						\
55505b261ecSmrg							}									\
55605b261ecSmrg						} while (0)
55705b261ecSmrg
55805b261ecSmrg#define APPEND_STR(s)	do {									\
55905b261ecSmrg							if (strlen(s) + l > PATH_MAX) {		\
56005b261ecSmrg								BAIL_OUT;						\
56105b261ecSmrg							} else {							\
56205b261ecSmrg								strcpy(result + l, s);			\
56305b261ecSmrg								l += strlen(s);					\
56405b261ecSmrg							}									\
56505b261ecSmrg						} while (0)
56605b261ecSmrg
56705b261ecSmrgstatic char *
56805b261ecSmrgDoSubstitution(const char *template, const char *cmdline, const char *projroot,
56935c4bbdfSmrg               int *cmdlineUsed, int *envUsed, const char *XConfigFile)
57005b261ecSmrg{
57135c4bbdfSmrg    char *result;
57235c4bbdfSmrg    int i, l;
57335c4bbdfSmrg    static const char *env = NULL;
57435c4bbdfSmrg    static char *hostname = NULL;
57535c4bbdfSmrg
57635c4bbdfSmrg    if (!template)
57735c4bbdfSmrg        return NULL;
57835c4bbdfSmrg
57935c4bbdfSmrg    if (cmdlineUsed)
58035c4bbdfSmrg        *cmdlineUsed = 0;
58135c4bbdfSmrg    if (envUsed)
58235c4bbdfSmrg        *envUsed = 0;
58335c4bbdfSmrg
58435c4bbdfSmrg    result = malloc(PATH_MAX + 1);
58535c4bbdfSmrg    l = 0;
58635c4bbdfSmrg    for (i = 0; template[i]; i++) {
58735c4bbdfSmrg        if (template[i] != '%') {
58835c4bbdfSmrg            result[l++] = template[i];
58935c4bbdfSmrg            CHECK_LENGTH;
59035c4bbdfSmrg        }
59135c4bbdfSmrg        else {
59235c4bbdfSmrg            switch (template[++i]) {
59335c4bbdfSmrg            case 'A':
59435c4bbdfSmrg                if (cmdline && xf86pathIsAbsolute(cmdline)) {
59535c4bbdfSmrg                    APPEND_STR(cmdline);
59635c4bbdfSmrg                    if (cmdlineUsed)
59735c4bbdfSmrg                        *cmdlineUsed = 1;
59835c4bbdfSmrg                }
59935c4bbdfSmrg                else
60035c4bbdfSmrg                    BAIL_OUT;
60135c4bbdfSmrg                break;
60235c4bbdfSmrg            case 'R':
60335c4bbdfSmrg                if (cmdline && !xf86pathIsAbsolute(cmdline)) {
60435c4bbdfSmrg                    APPEND_STR(cmdline);
60535c4bbdfSmrg                    if (cmdlineUsed)
60635c4bbdfSmrg                        *cmdlineUsed = 1;
60735c4bbdfSmrg                }
60835c4bbdfSmrg                else
60935c4bbdfSmrg                    BAIL_OUT;
61035c4bbdfSmrg                break;
61135c4bbdfSmrg            case 'S':
61235c4bbdfSmrg                if (cmdline && xf86pathIsSafe(cmdline)) {
61335c4bbdfSmrg                    APPEND_STR(cmdline);
61435c4bbdfSmrg                    if (cmdlineUsed)
61535c4bbdfSmrg                        *cmdlineUsed = 1;
61635c4bbdfSmrg                }
61735c4bbdfSmrg                else
61835c4bbdfSmrg                    BAIL_OUT;
61935c4bbdfSmrg                break;
62035c4bbdfSmrg            case 'X':
62135c4bbdfSmrg                APPEND_STR(XConfigFile);
62235c4bbdfSmrg                break;
62335c4bbdfSmrg            case 'H':
62435c4bbdfSmrg                if (!hostname) {
62535c4bbdfSmrg                    if ((hostname = malloc(MAXHOSTNAMELEN + 1))) {
62635c4bbdfSmrg                        if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
62735c4bbdfSmrg                            hostname[MAXHOSTNAMELEN] = '\0';
62835c4bbdfSmrg                        }
62935c4bbdfSmrg                        else {
63035c4bbdfSmrg                            free(hostname);
63135c4bbdfSmrg                            hostname = NULL;
63235c4bbdfSmrg                        }
63335c4bbdfSmrg                    }
63435c4bbdfSmrg                }
63535c4bbdfSmrg                if (hostname)
63635c4bbdfSmrg                    APPEND_STR(hostname);
63735c4bbdfSmrg                break;
63835c4bbdfSmrg            case 'E':
63935c4bbdfSmrg                if (!env)
64035c4bbdfSmrg                    env = getenv(XCONFENV);
64135c4bbdfSmrg                if (env && xf86pathIsAbsolute(env)) {
64235c4bbdfSmrg                    APPEND_STR(env);
64335c4bbdfSmrg                    if (envUsed)
64435c4bbdfSmrg                        *envUsed = 1;
64535c4bbdfSmrg                }
64635c4bbdfSmrg                else
64735c4bbdfSmrg                    BAIL_OUT;
64835c4bbdfSmrg                break;
64935c4bbdfSmrg            case 'F':
65035c4bbdfSmrg                if (!env)
65135c4bbdfSmrg                    env = getenv(XCONFENV);
65235c4bbdfSmrg                if (env && !xf86pathIsAbsolute(env)) {
65335c4bbdfSmrg                    APPEND_STR(env);
65435c4bbdfSmrg                    if (envUsed)
65535c4bbdfSmrg                        *envUsed = 1;
65635c4bbdfSmrg                }
65735c4bbdfSmrg                else
65835c4bbdfSmrg                    BAIL_OUT;
65935c4bbdfSmrg                break;
66035c4bbdfSmrg            case 'G':
66135c4bbdfSmrg                if (!env)
66235c4bbdfSmrg                    env = getenv(XCONFENV);
66335c4bbdfSmrg                if (env && xf86pathIsSafe(env)) {
66435c4bbdfSmrg                    APPEND_STR(env);
66535c4bbdfSmrg                    if (envUsed)
66635c4bbdfSmrg                        *envUsed = 1;
66735c4bbdfSmrg                }
66835c4bbdfSmrg                else
66935c4bbdfSmrg                    BAIL_OUT;
67035c4bbdfSmrg                break;
67135c4bbdfSmrg            case 'P':
67235c4bbdfSmrg                if (projroot && xf86pathIsAbsolute(projroot))
67335c4bbdfSmrg                    APPEND_STR(projroot);
67435c4bbdfSmrg                else
67535c4bbdfSmrg                    BAIL_OUT;
67635c4bbdfSmrg                break;
67735c4bbdfSmrg            case 'C':
67835c4bbdfSmrg                APPEND_STR(SYSCONFDIR);
67935c4bbdfSmrg                break;
68035c4bbdfSmrg            case 'D':
68135c4bbdfSmrg                APPEND_STR(DATADIR);
68235c4bbdfSmrg                break;
68335c4bbdfSmrg            case '%':
68435c4bbdfSmrg                result[l++] = '%';
68535c4bbdfSmrg                CHECK_LENGTH;
68635c4bbdfSmrg                break;
68735c4bbdfSmrg            default:
68835c4bbdfSmrg                fprintf(stderr, "invalid escape %%%c found in path template\n",
68935c4bbdfSmrg                        template[i]);
69035c4bbdfSmrg                BAIL_OUT;
69135c4bbdfSmrg                break;
69235c4bbdfSmrg            }
69335c4bbdfSmrg        }
69435c4bbdfSmrg    }
69505b261ecSmrg#ifdef DEBUG
69635c4bbdfSmrg    fprintf(stderr, "Converted `%s' to `%s'\n", template, result);
69705b261ecSmrg#endif
69835c4bbdfSmrg    return result;
69905b261ecSmrg}
70005b261ecSmrg
7016747b715Smrg/*
7026747b715Smrg * Given some searching parameters, locate and open the xorg config file.
7036747b715Smrg */
7046747b715Smrgstatic char *
7056747b715SmrgOpenConfigFile(const char *path, const char *cmdline, const char *projroot,
70635c4bbdfSmrg               const char *confname)
7076747b715Smrg{
70835c4bbdfSmrg    char *filepath = NULL;
70935c4bbdfSmrg    char *pathcopy;
71035c4bbdfSmrg    const char *template;
71135c4bbdfSmrg    int cmdlineUsed = 0;
71235c4bbdfSmrg    FILE *file = NULL;
71335c4bbdfSmrg
71435c4bbdfSmrg    pathcopy = strdup(path);
71535c4bbdfSmrg    for (template = strtok(pathcopy, ","); template && !file;
71635c4bbdfSmrg         template = strtok(NULL, ",")) {
71735c4bbdfSmrg        filepath = DoSubstitution(template, cmdline, projroot,
71835c4bbdfSmrg                                  &cmdlineUsed, NULL, confname);
71935c4bbdfSmrg        if (!filepath)
72035c4bbdfSmrg            continue;
72135c4bbdfSmrg        if (cmdline && !cmdlineUsed) {
72235c4bbdfSmrg            free(filepath);
72335c4bbdfSmrg            filepath = NULL;
72435c4bbdfSmrg            continue;
72535c4bbdfSmrg        }
72635c4bbdfSmrg        file = fopen(filepath, "r");
72735c4bbdfSmrg        if (!file) {
72835c4bbdfSmrg            free(filepath);
72935c4bbdfSmrg            filepath = NULL;
73035c4bbdfSmrg        }
73135c4bbdfSmrg    }
73235c4bbdfSmrg
73335c4bbdfSmrg    free(pathcopy);
73435c4bbdfSmrg    if (file) {
73535c4bbdfSmrg        configFiles[numFiles].file = file;
73635c4bbdfSmrg        configFiles[numFiles].path = strdup(filepath);
73735c4bbdfSmrg        numFiles++;
73835c4bbdfSmrg    }
73935c4bbdfSmrg    return filepath;
7406747b715Smrg}
7416747b715Smrg
7426747b715Smrg/*
7436747b715Smrg * Match non-hidden files in the xorg config directory with a .conf
7446747b715Smrg * suffix. This filter is passed to scandir(3).
7456747b715Smrg */
7466747b715Smrgstatic int
7476747b715SmrgConfigFilter(const struct dirent *de)
7486747b715Smrg{
74935c4bbdfSmrg    const char *name = de->d_name;
75035c4bbdfSmrg    size_t len;
75135c4bbdfSmrg    size_t suflen = strlen(XCONFIGSUFFIX);
75235c4bbdfSmrg
75335c4bbdfSmrg    if (!name || name[0] == '.')
75435c4bbdfSmrg        return 0;
75535c4bbdfSmrg    len = strlen(name);
75635c4bbdfSmrg    if (len <= suflen)
75735c4bbdfSmrg        return 0;
75835c4bbdfSmrg    if (strcmp(&name[len - suflen], XCONFIGSUFFIX) != 0)
75935c4bbdfSmrg        return 0;
76035c4bbdfSmrg    return 1;
7616747b715Smrg}
7626747b715Smrg
7636747b715Smrgstatic Bool
7646747b715SmrgAddConfigDirFiles(const char *dirpath, struct dirent **list, int num)
7656747b715Smrg{
76635c4bbdfSmrg    int i;
76735c4bbdfSmrg    Bool openedFile = FALSE;
76835c4bbdfSmrg    Bool warnOnce = FALSE;
76935c4bbdfSmrg
77035c4bbdfSmrg    for (i = 0; i < num; i++) {
77135c4bbdfSmrg        char *path;
77235c4bbdfSmrg        FILE *file;
77335c4bbdfSmrg
77435c4bbdfSmrg        if (numFiles >= CONFIG_MAX_FILES) {
77535c4bbdfSmrg            if (!warnOnce) {
77635c4bbdfSmrg                ErrorF("Maximum number of configuration " "files opened\n");
77735c4bbdfSmrg                warnOnce = TRUE;
77835c4bbdfSmrg            }
77935c4bbdfSmrg            continue;
78035c4bbdfSmrg        }
78135c4bbdfSmrg
78235c4bbdfSmrg        path = malloc(PATH_MAX + 1);
78335c4bbdfSmrg        snprintf(path, PATH_MAX + 1, "%s/%s", dirpath, list[i]->d_name);
78435c4bbdfSmrg        file = fopen(path, "r");
78535c4bbdfSmrg        if (!file) {
78635c4bbdfSmrg            free(path);
78735c4bbdfSmrg            continue;
78835c4bbdfSmrg        }
78935c4bbdfSmrg        openedFile = TRUE;
79035c4bbdfSmrg
79135c4bbdfSmrg        configFiles[numFiles].file = file;
79235c4bbdfSmrg        configFiles[numFiles].path = path;
79335c4bbdfSmrg        numFiles++;
79435c4bbdfSmrg    }
79535c4bbdfSmrg
79635c4bbdfSmrg    return openedFile;
7976747b715Smrg}
7986747b715Smrg
7996747b715Smrg/*
8006747b715Smrg * Given some searching parameters, locate and open the xorg config
8016747b715Smrg * directory. The directory does not need to contain config files.
8026747b715Smrg */
8036747b715Smrgstatic char *
8046747b715SmrgOpenConfigDir(const char *path, const char *cmdline, const char *projroot,
80535c4bbdfSmrg              const char *confname)
8066747b715Smrg{
80735c4bbdfSmrg    char *dirpath = NULL, *pathcopy;
80835c4bbdfSmrg    const char *template;
80935c4bbdfSmrg    Bool found = FALSE;
81035c4bbdfSmrg    int cmdlineUsed = 0;
81135c4bbdfSmrg
81235c4bbdfSmrg    pathcopy = strdup(path);
81335c4bbdfSmrg    for (template = strtok(pathcopy, ","); template && !found;
81435c4bbdfSmrg         template = strtok(NULL, ",")) {
81535c4bbdfSmrg        struct dirent **list = NULL;
81635c4bbdfSmrg        int num;
81735c4bbdfSmrg
81835c4bbdfSmrg        dirpath = DoSubstitution(template, cmdline, projroot,
81935c4bbdfSmrg                                 &cmdlineUsed, NULL, confname);
82035c4bbdfSmrg        if (!dirpath)
82135c4bbdfSmrg            continue;
82235c4bbdfSmrg        if (cmdline && !cmdlineUsed) {
82335c4bbdfSmrg            free(dirpath);
82435c4bbdfSmrg            dirpath = NULL;
82535c4bbdfSmrg            continue;
82635c4bbdfSmrg        }
82735c4bbdfSmrg
82835c4bbdfSmrg        /* match files named *.conf */
82935c4bbdfSmrg        num = scandir(dirpath, &list, ConfigFilter, alphasort);
83035c4bbdfSmrg        if (num < 0) {
83135c4bbdfSmrg            list = NULL;
83235c4bbdfSmrg            num = 0;
83335c4bbdfSmrg        }
83435c4bbdfSmrg        found = AddConfigDirFiles(dirpath, list, num);
83535c4bbdfSmrg        if (!found) {
83635c4bbdfSmrg            free(dirpath);
83735c4bbdfSmrg            dirpath = NULL;
83835c4bbdfSmrg        }
83935c4bbdfSmrg        while (num--)
84035c4bbdfSmrg            free(list[num]);
84135c4bbdfSmrg        free(list);
84235c4bbdfSmrg    }
84335c4bbdfSmrg
84435c4bbdfSmrg    free(pathcopy);
84535c4bbdfSmrg    return dirpath;
8466747b715Smrg}
8476747b715Smrg
8486747b715Smrg/*
8496747b715Smrg * xf86initConfigFiles -- Setup global variables and buffers.
8506747b715Smrg */
8516747b715Smrgvoid
8526747b715Smrgxf86initConfigFiles(void)
8536747b715Smrg{
85435c4bbdfSmrg    curFileIndex = 0;
85535c4bbdfSmrg    configPos = 0;
85635c4bbdfSmrg    configLineNo = 0;
85735c4bbdfSmrg    pushToken = LOCK_TOKEN;
85835c4bbdfSmrg
85935c4bbdfSmrg    configBuf = malloc(CONFIG_BUF_LEN);
86035c4bbdfSmrg    configRBuf = malloc(CONFIG_BUF_LEN);
86135c4bbdfSmrg    configBuf[0] = '\0';        /* sanity ... */
8626747b715Smrg}
8636747b715Smrg
8646747b715Smrg/*
86505b261ecSmrg * xf86openConfigFile --
86605b261ecSmrg *
86705b261ecSmrg * This function take a config file search path (optional), a command-line
86805b261ecSmrg * specified file name (optional) and the ProjectRoot path (optional) and
86905b261ecSmrg * locates and opens a config file based on that information.  If a
87005b261ecSmrg * command-line file name is specified, then this function fails if none
87105b261ecSmrg * of the located files.
87205b261ecSmrg *
87305b261ecSmrg * The return value is a pointer to the actual name of the file that was
87435c4bbdfSmrg * opened.  When no file is found, the return value is NULL. The caller should
87535c4bbdfSmrg * free() the returned value.
87605b261ecSmrg *
87705b261ecSmrg * The escape sequences allowed in the search path are defined above.
8786747b715Smrg *
87905b261ecSmrg */
88005b261ecSmrg
88105b261ecSmrg#ifndef DEFAULT_CONF_PATH
88205b261ecSmrg#define DEFAULT_CONF_PATH	"/etc/X11/%S," \
88305b261ecSmrg							"%P/etc/X11/%S," \
88405b261ecSmrg							"/etc/X11/%G," \
88505b261ecSmrg							"%P/etc/X11/%G," \
88605b261ecSmrg							"/etc/X11/%X-%M," \
88705b261ecSmrg							"/etc/X11/%X," \
88805b261ecSmrg							"/etc/%X," \
88905b261ecSmrg							"%P/etc/X11/%X.%H," \
89005b261ecSmrg							"%P/etc/X11/%X-%M," \
89105b261ecSmrg							"%P/etc/X11/%X," \
89205b261ecSmrg							"%P/lib/X11/%X.%H," \
89305b261ecSmrg							"%P/lib/X11/%X-%M," \
89405b261ecSmrg							"%P/lib/X11/%X"
89505b261ecSmrg#endif
89605b261ecSmrg
89735c4bbdfSmrgchar *
89805b261ecSmrgxf86openConfigFile(const char *path, const char *cmdline, const char *projroot)
89905b261ecSmrg{
90035c4bbdfSmrg    if (!path || !path[0])
90135c4bbdfSmrg        path = DEFAULT_CONF_PATH;
90235c4bbdfSmrg    if (!projroot || !projroot[0])
90335c4bbdfSmrg        projroot = PROJECTROOT;
90435c4bbdfSmrg
90535c4bbdfSmrg    /* Search for a config file */
90635c4bbdfSmrg    return OpenConfigFile(path, cmdline, projroot, XCONFIGFILE);
9076747b715Smrg}
90805b261ecSmrg
9096747b715Smrg/*
9106747b715Smrg * xf86openConfigDirFiles --
9116747b715Smrg *
9126747b715Smrg * This function take a config directory search path (optional), a
9136747b715Smrg * command-line specified directory name (optional) and the ProjectRoot path
9146747b715Smrg * (optional) and locates and opens a config directory based on that
9156747b715Smrg * information.  If a command-line name is specified, then this function
9166747b715Smrg * fails if it is not found.
9176747b715Smrg *
9181b5d61b8Smrg * The return value is a pointer to the actual name of the directory that was
91935c4bbdfSmrg * opened.  When no directory is found, the return value is NULL. The caller
92035c4bbdfSmrg * should free() the returned value.
9216747b715Smrg *
9226747b715Smrg * The escape sequences allowed in the search path are defined above.
9236747b715Smrg *
9246747b715Smrg */
92535c4bbdfSmrgchar *
9266747b715Smrgxf86openConfigDirFiles(const char *path, const char *cmdline,
92735c4bbdfSmrg                       const char *projroot)
9286747b715Smrg{
92935c4bbdfSmrg    if (!path || !path[0])
93035c4bbdfSmrg        path = DEFAULT_CONF_PATH;
93135c4bbdfSmrg    if (!projroot || !projroot[0])
93235c4bbdfSmrg        projroot = PROJECTROOT;
93335c4bbdfSmrg
93435c4bbdfSmrg    /* Search for the multiconf directory */
93535c4bbdfSmrg    return OpenConfigDir(path, cmdline, projroot, XCONFIGDIR);
93605b261ecSmrg}
93705b261ecSmrg
93805b261ecSmrgvoid
93935c4bbdfSmrgxf86closeConfigFile(void)
94005b261ecSmrg{
94135c4bbdfSmrg    int i;
94235c4bbdfSmrg
94335c4bbdfSmrg    free(configRBuf);
94435c4bbdfSmrg    configRBuf = NULL;
94535c4bbdfSmrg    free(configBuf);
94635c4bbdfSmrg    configBuf = NULL;
94735c4bbdfSmrg
94835c4bbdfSmrg    if (numFiles == 0) {
94935c4bbdfSmrg        builtinConfig = NULL;
95035c4bbdfSmrg        builtinIndex = 0;
95135c4bbdfSmrg    }
95235c4bbdfSmrg    for (i = 0; i < numFiles; i++) {
95335c4bbdfSmrg        fclose(configFiles[i].file);
95435c4bbdfSmrg        configFiles[i].file = NULL;
95535c4bbdfSmrg        free(configFiles[i].path);
95635c4bbdfSmrg        configFiles[i].path = NULL;
95735c4bbdfSmrg    }
95835c4bbdfSmrg    numFiles = 0;
95905b261ecSmrg}
96005b261ecSmrg
96105b261ecSmrgvoid
96205b261ecSmrgxf86setBuiltinConfig(const char *config[])
96305b261ecSmrg{
96435c4bbdfSmrg    builtinConfig = config;
96505b261ecSmrg}
96605b261ecSmrg
96705b261ecSmrgvoid
96835c4bbdfSmrgxf86parseError(const char *format, ...)
96905b261ecSmrg{
97035c4bbdfSmrg    va_list ap;
97135c4bbdfSmrg    const char *filename = numFiles ? configFiles[curFileIndex].path
97235c4bbdfSmrg        : "<builtin configuration>";
97305b261ecSmrg
97435c4bbdfSmrg    ErrorF("Parse error on line %d of section %s in file %s\n\t",
97535c4bbdfSmrg           configLineNo, configSection, filename);
97635c4bbdfSmrg    va_start(ap, format);
97735c4bbdfSmrg    VErrorF(format, ap);
97835c4bbdfSmrg    va_end(ap);
97905b261ecSmrg
98035c4bbdfSmrg    ErrorF("\n");
98105b261ecSmrg}
98205b261ecSmrg
98305b261ecSmrgvoid
98435c4bbdfSmrgxf86validationError(const char *format, ...)
98505b261ecSmrg{
98635c4bbdfSmrg    va_list ap;
98735c4bbdfSmrg    const char *filename = numFiles ? configFiles[curFileIndex].path
98835c4bbdfSmrg        : "<builtin configuration>";
98905b261ecSmrg
99035c4bbdfSmrg    ErrorF("Data incomplete in file %s\n\t", filename);
99135c4bbdfSmrg    va_start(ap, format);
99235c4bbdfSmrg    VErrorF(format, ap);
99335c4bbdfSmrg    va_end(ap);
99405b261ecSmrg
99535c4bbdfSmrg    ErrorF("\n");
99605b261ecSmrg}
99705b261ecSmrg
99805b261ecSmrgvoid
99935c4bbdfSmrgxf86setSection(const char *section)
100005b261ecSmrg{
100135c4bbdfSmrg    free(configSection);
100235c4bbdfSmrg    configSection = strdup(section);
100305b261ecSmrg}
100405b261ecSmrg
100535c4bbdfSmrg/*
100605b261ecSmrg * xf86getToken --
100705b261ecSmrg *  Lookup a string if it is actually a token in disguise.
100805b261ecSmrg */
100905b261ecSmrgint
10101b5d61b8Smrgxf86getStringToken(const xf86ConfigSymTabRec * tab)
101105b261ecSmrg{
101235c4bbdfSmrg    return StringToToken(xf86_lex_val.str, tab);
101305b261ecSmrg}
101405b261ecSmrg
101535c4bbdfSmrg/*
101605b261ecSmrg * Compare two names.  The characters '_', ' ', and '\t' are ignored
101705b261ecSmrg * in the comparison.
101805b261ecSmrg */
10196747b715Smrgint
102035c4bbdfSmrgxf86nameCompare(const char *s1, const char *s2)
102105b261ecSmrg{
102235c4bbdfSmrg    char c1, c2;
102335c4bbdfSmrg
102435c4bbdfSmrg    if (!s1 || *s1 == 0) {
102535c4bbdfSmrg        if (!s2 || *s2 == 0)
102635c4bbdfSmrg            return 0;
102735c4bbdfSmrg        else
102835c4bbdfSmrg            return 1;
10291b5d61b8Smrg    } else if (!s2 || *s2 == 0) {
10301b5d61b8Smrg        return -1;
103135c4bbdfSmrg    }
103235c4bbdfSmrg
103335c4bbdfSmrg    while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
103435c4bbdfSmrg        s1++;
103535c4bbdfSmrg    while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
103635c4bbdfSmrg        s2++;
103735c4bbdfSmrg    c1 = (isupper(*s1) ? tolower(*s1) : *s1);
103835c4bbdfSmrg    c2 = (isupper(*s2) ? tolower(*s2) : *s2);
103935c4bbdfSmrg    while (c1 == c2) {
104035c4bbdfSmrg        if (c1 == '\0')
104135c4bbdfSmrg            return 0;
104235c4bbdfSmrg        s1++;
104335c4bbdfSmrg        s2++;
104435c4bbdfSmrg        while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
104535c4bbdfSmrg            s1++;
104635c4bbdfSmrg        while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
104735c4bbdfSmrg            s2++;
104835c4bbdfSmrg        c1 = (isupper(*s1) ? tolower(*s1) : *s1);
104935c4bbdfSmrg        c2 = (isupper(*s2) ? tolower(*s2) : *s2);
105035c4bbdfSmrg    }
105135c4bbdfSmrg    return c1 - c2;
105205b261ecSmrg}
105305b261ecSmrg
105405b261ecSmrgchar *
105535c4bbdfSmrgxf86addComment(char *cur, const char *add)
105605b261ecSmrg{
105735c4bbdfSmrg    char *str;
105835c4bbdfSmrg    const char *cstr;
105935c4bbdfSmrg    int len, curlen, iscomment, hasnewline = 0, insnewline, endnewline;
106035c4bbdfSmrg
106135c4bbdfSmrg    if (add == NULL || add[0] == '\0')
106235c4bbdfSmrg        return cur;
106335c4bbdfSmrg
106435c4bbdfSmrg    if (cur) {
106535c4bbdfSmrg        curlen = strlen(cur);
106635c4bbdfSmrg        if (curlen)
106735c4bbdfSmrg            hasnewline = cur[curlen - 1] == '\n';
106835c4bbdfSmrg        eol_seen = 0;
106935c4bbdfSmrg    }
107035c4bbdfSmrg    else
107135c4bbdfSmrg        curlen = 0;
107235c4bbdfSmrg
107335c4bbdfSmrg    cstr = add;
107435c4bbdfSmrg    iscomment = 0;
107535c4bbdfSmrg    while (*cstr) {
107635c4bbdfSmrg        if (*cstr != ' ' && *cstr != '\t')
107735c4bbdfSmrg            break;
107835c4bbdfSmrg        ++cstr;
107935c4bbdfSmrg    }
108035c4bbdfSmrg    iscomment = (*cstr == '#');
108135c4bbdfSmrg
108235c4bbdfSmrg    len = strlen(add);
108335c4bbdfSmrg    endnewline = add[len - 1] == '\n';
108435c4bbdfSmrg
108535c4bbdfSmrg    insnewline = eol_seen || (curlen && !hasnewline);
108635c4bbdfSmrg    if (insnewline)
108735c4bbdfSmrg        len++;
108835c4bbdfSmrg    if (!iscomment)
108935c4bbdfSmrg        len++;
109035c4bbdfSmrg    if (!endnewline)
109135c4bbdfSmrg        len++;
109235c4bbdfSmrg
109335c4bbdfSmrg    /* Allocate + 1 char for '\0' terminator. */
109435c4bbdfSmrg    str = realloc(cur, curlen + len + 1);
109535c4bbdfSmrg    if (!str)
109635c4bbdfSmrg        return cur;
109735c4bbdfSmrg
109835c4bbdfSmrg    cur = str;
109935c4bbdfSmrg
110035c4bbdfSmrg    if (insnewline)
110135c4bbdfSmrg        cur[curlen++] = '\n';
110235c4bbdfSmrg    if (!iscomment)
110335c4bbdfSmrg        cur[curlen++] = '#';
110435c4bbdfSmrg    strcpy(cur + curlen, add);
110535c4bbdfSmrg    if (!endnewline)
110635c4bbdfSmrg        strcat(cur, "\n");
110735c4bbdfSmrg
110835c4bbdfSmrg    return cur;
11096747b715Smrg}
11106747b715Smrg
11116747b715SmrgBool
11126747b715Smrgxf86getBoolValue(Bool *val, const char *str)
11136747b715Smrg{
111435c4bbdfSmrg    if (!val || !str)
111535c4bbdfSmrg        return FALSE;
111635c4bbdfSmrg    if (*str == '\0') {
111735c4bbdfSmrg        *val = TRUE;
111835c4bbdfSmrg    }
111935c4bbdfSmrg    else {
112035c4bbdfSmrg        if (xf86nameCompare(str, "1") == 0)
112135c4bbdfSmrg            *val = TRUE;
112235c4bbdfSmrg        else if (xf86nameCompare(str, "on") == 0)
112335c4bbdfSmrg            *val = TRUE;
112435c4bbdfSmrg        else if (xf86nameCompare(str, "true") == 0)
112535c4bbdfSmrg            *val = TRUE;
112635c4bbdfSmrg        else if (xf86nameCompare(str, "yes") == 0)
112735c4bbdfSmrg            *val = TRUE;
112835c4bbdfSmrg        else if (xf86nameCompare(str, "0") == 0)
112935c4bbdfSmrg            *val = FALSE;
113035c4bbdfSmrg        else if (xf86nameCompare(str, "off") == 0)
113135c4bbdfSmrg            *val = FALSE;
113235c4bbdfSmrg        else if (xf86nameCompare(str, "false") == 0)
113335c4bbdfSmrg            *val = FALSE;
113435c4bbdfSmrg        else if (xf86nameCompare(str, "no") == 0)
113535c4bbdfSmrg            *val = FALSE;
113635c4bbdfSmrg        else
113735c4bbdfSmrg            return FALSE;
113835c4bbdfSmrg    }
113935c4bbdfSmrg    return TRUE;
114005b261ecSmrg}
1141