xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

scan.c (30702B)


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