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