scan.c revision 58cf2af7
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 83static struct { 84 FILE *file; 85 char *path; 86} configFiles[CONFIG_MAX_FILES]; 87static const char **builtinConfig = NULL; 88static int builtinIndex = 0; 89static int configPos = 0; /* current readers position */ 90static int configLineNo = 0; /* linenumber */ 91static char *configBuf, *configRBuf; /* buffer for lines */ 92static char *configSection = NULL; /* name of current section being parsed */ 93static int numFiles = 0; /* number of config files */ 94static int curFileIndex = 0; /* index of current config file */ 95static int pushToken = LOCK_TOKEN; 96static int eol_seen = 0; /* private state to handle comments */ 97LexRec 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 110static char * 111xf86getNextLine(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 235static int 236StringToToken(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 */ 252int 253xf86getToken(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 private copy. 336 * Use xf86addComment when setting a comment. 337 */ 338 xf86_lex_val.str = strdup(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 443int 444xf86getSubToken(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 free(xf86_lex_val.str); 454 xf86_lex_val.str = NULL; 455 } 456 } 457 else 458 return token; 459 } 460 /*NOTREACHED*/} 461 462int 463xf86getSubTokenWithTab(char **comment, const 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 free(xf86_lex_val.str); 473 xf86_lex_val.str = NULL; 474 } 475 } 476 else 477 return token; 478 } 479 /*NOTREACHED*/} 480 481void 482xf86unGetToken(int token) 483{ 484 pushToken = token; 485} 486 487char * 488xf86tokenString(void) 489{ 490 return configRBuf; 491} 492 493int 494xf86pathIsAbsolute(const char *path) 495{ 496 if (path && path[0] == '/') 497 return 1; 498 return 0; 499} 500 501/* A path is "safe" if it is relative and if it contains no ".." elements. */ 502int 503xf86pathIsSafe(const char *path) 504{ 505 if (xf86pathIsAbsolute(path)) 506 return 0; 507 508 /* Compare with ".." */ 509 if (!strcmp(path, "..")) 510 return 0; 511 512 /* Look for leading "../" */ 513 if (!strncmp(path, "../", 3)) 514 return 0; 515 516 /* Look for trailing "/.." */ 517 if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/..")) 518 return 0; 519 520 /* Look for "/../" */ 521 if (strstr(path, "/../")) 522 return 0; 523 524 return 1; 525} 526 527/* 528 * This function substitutes the following escape sequences: 529 * 530 * %A cmdline argument as an absolute path (must be absolute to match) 531 * %R cmdline argument as a relative path 532 * %S cmdline argument as a "safe" path (relative, and no ".." elements) 533 * %X default config file name ("xorg.conf") 534 * %H hostname 535 * %E config file environment ($XORGCONFIG) as an absolute path 536 * %F config file environment ($XORGCONFIG) as a relative path 537 * %G config file environment ($XORGCONFIG) as a safe path 538 * %P projroot 539 * %C sysconfdir 540 * %D datadir 541 * %% % 542 */ 543 544#define XCONFIGSUFFIX ".conf" 545#define XCONFENV "XORGCONFIG" 546 547#define BAIL_OUT do { \ 548 free(result); \ 549 return NULL; \ 550 } while (0) 551 552#define CHECK_LENGTH do { \ 553 if (l > PATH_MAX) { \ 554 BAIL_OUT; \ 555 } \ 556 } while (0) 557 558#define APPEND_STR(s) do { \ 559 if (strlen(s) + l > PATH_MAX) { \ 560 BAIL_OUT; \ 561 } else { \ 562 strcpy(result + l, s); \ 563 l += strlen(s); \ 564 } \ 565 } while (0) 566 567static char * 568DoSubstitution(const char *template, const char *cmdline, const char *projroot, 569 int *cmdlineUsed, int *envUsed, const char *XConfigFile) 570{ 571 char *result; 572 int i, l; 573 static const char *env = NULL; 574 static char *hostname = NULL; 575 576 if (!template) 577 return NULL; 578 579 if (cmdlineUsed) 580 *cmdlineUsed = 0; 581 if (envUsed) 582 *envUsed = 0; 583 584 result = malloc(PATH_MAX + 1); 585 l = 0; 586 for (i = 0; template[i]; i++) { 587 if (template[i] != '%') { 588 result[l++] = template[i]; 589 CHECK_LENGTH; 590 } 591 else { 592 switch (template[++i]) { 593 case 'A': 594 if (cmdline && xf86pathIsAbsolute(cmdline)) { 595 APPEND_STR(cmdline); 596 if (cmdlineUsed) 597 *cmdlineUsed = 1; 598 } 599 else 600 BAIL_OUT; 601 break; 602 case 'R': 603 if (cmdline && !xf86pathIsAbsolute(cmdline)) { 604 APPEND_STR(cmdline); 605 if (cmdlineUsed) 606 *cmdlineUsed = 1; 607 } 608 else 609 BAIL_OUT; 610 break; 611 case 'S': 612 if (cmdline && xf86pathIsSafe(cmdline)) { 613 APPEND_STR(cmdline); 614 if (cmdlineUsed) 615 *cmdlineUsed = 1; 616 } 617 else 618 BAIL_OUT; 619 break; 620 case 'X': 621 APPEND_STR(XConfigFile); 622 break; 623 case 'H': 624 if (!hostname) { 625 if ((hostname = malloc(MAXHOSTNAMELEN + 1))) { 626 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { 627 hostname[MAXHOSTNAMELEN] = '\0'; 628 } 629 else { 630 free(hostname); 631 hostname = NULL; 632 } 633 } 634 } 635 if (hostname) 636 APPEND_STR(hostname); 637 break; 638 case 'E': 639 if (!env) 640 env = getenv(XCONFENV); 641 if (env && xf86pathIsAbsolute(env)) { 642 APPEND_STR(env); 643 if (envUsed) 644 *envUsed = 1; 645 } 646 else 647 BAIL_OUT; 648 break; 649 case 'F': 650 if (!env) 651 env = getenv(XCONFENV); 652 if (env && !xf86pathIsAbsolute(env)) { 653 APPEND_STR(env); 654 if (envUsed) 655 *envUsed = 1; 656 } 657 else 658 BAIL_OUT; 659 break; 660 case 'G': 661 if (!env) 662 env = getenv(XCONFENV); 663 if (env && xf86pathIsSafe(env)) { 664 APPEND_STR(env); 665 if (envUsed) 666 *envUsed = 1; 667 } 668 else 669 BAIL_OUT; 670 break; 671 case 'P': 672 if (projroot && xf86pathIsAbsolute(projroot)) 673 APPEND_STR(projroot); 674 else 675 BAIL_OUT; 676 break; 677 case 'C': 678 APPEND_STR(SYSCONFDIR); 679 break; 680 case 'D': 681 APPEND_STR(DATADIR); 682 break; 683 case '%': 684 result[l++] = '%'; 685 CHECK_LENGTH; 686 break; 687 default: 688 fprintf(stderr, "invalid escape %%%c found in path template\n", 689 template[i]); 690 BAIL_OUT; 691 break; 692 } 693 } 694 } 695#ifdef DEBUG 696 fprintf(stderr, "Converted `%s' to `%s'\n", template, result); 697#endif 698 return result; 699} 700 701/* 702 * Given some searching parameters, locate and open the xorg config file. 703 */ 704static char * 705OpenConfigFile(const char *path, const char *cmdline, const char *projroot, 706 const char *confname) 707{ 708 char *filepath = NULL; 709 char *pathcopy; 710 const char *template; 711 int cmdlineUsed = 0; 712 FILE *file = NULL; 713 714 pathcopy = strdup(path); 715 for (template = strtok(pathcopy, ","); template && !file; 716 template = strtok(NULL, ",")) { 717 filepath = DoSubstitution(template, cmdline, projroot, 718 &cmdlineUsed, NULL, confname); 719 if (!filepath) 720 continue; 721 if (cmdline && !cmdlineUsed) { 722 free(filepath); 723 filepath = NULL; 724 continue; 725 } 726 file = fopen(filepath, "r"); 727 if (!file) { 728 free(filepath); 729 filepath = NULL; 730 } 731 } 732 733 free(pathcopy); 734 if (file) { 735 configFiles[numFiles].file = file; 736 configFiles[numFiles].path = strdup(filepath); 737 numFiles++; 738 } 739 return filepath; 740} 741 742/* 743 * Match non-hidden files in the xorg config directory with a .conf 744 * suffix. This filter is passed to scandir(3). 745 */ 746static int 747ConfigFilter(const struct dirent *de) 748{ 749 const char *name = de->d_name; 750 size_t len; 751 size_t suflen = strlen(XCONFIGSUFFIX); 752 753 if (!name || name[0] == '.') 754 return 0; 755 len = strlen(name); 756 if (len <= suflen) 757 return 0; 758 if (strcmp(&name[len - suflen], XCONFIGSUFFIX) != 0) 759 return 0; 760 return 1; 761} 762 763static Bool 764AddConfigDirFiles(const char *dirpath, struct dirent **list, int num) 765{ 766 int i; 767 Bool openedFile = FALSE; 768 Bool warnOnce = FALSE; 769 770 for (i = 0; i < num; i++) { 771 char *path; 772 FILE *file; 773 774 if (numFiles >= CONFIG_MAX_FILES) { 775 if (!warnOnce) { 776 ErrorF("Maximum number of configuration " "files opened\n"); 777 warnOnce = TRUE; 778 } 779 continue; 780 } 781 782 path = malloc(PATH_MAX + 1); 783 snprintf(path, PATH_MAX + 1, "%s/%s", dirpath, list[i]->d_name); 784 file = fopen(path, "r"); 785 if (!file) { 786 free(path); 787 continue; 788 } 789 openedFile = TRUE; 790 791 configFiles[numFiles].file = file; 792 configFiles[numFiles].path = path; 793 numFiles++; 794 } 795 796 return openedFile; 797} 798 799/* 800 * Given some searching parameters, locate and open the xorg config 801 * directory. The directory does not need to contain config files. 802 */ 803static char * 804OpenConfigDir(const char *path, const char *cmdline, const char *projroot, 805 const char *confname) 806{ 807 char *dirpath = NULL, *pathcopy; 808 const char *template; 809 Bool found = FALSE; 810 int cmdlineUsed = 0; 811 812 pathcopy = strdup(path); 813 for (template = strtok(pathcopy, ","); template && !found; 814 template = strtok(NULL, ",")) { 815 struct dirent **list = NULL; 816 int num; 817 818 dirpath = DoSubstitution(template, cmdline, projroot, 819 &cmdlineUsed, NULL, confname); 820 if (!dirpath) 821 continue; 822 if (cmdline && !cmdlineUsed) { 823 free(dirpath); 824 dirpath = NULL; 825 continue; 826 } 827 828 /* match files named *.conf */ 829 num = scandir(dirpath, &list, ConfigFilter, alphasort); 830 if (num < 0) { 831 list = NULL; 832 num = 0; 833 } 834 found = AddConfigDirFiles(dirpath, list, num); 835 if (!found) { 836 free(dirpath); 837 dirpath = NULL; 838 } 839 while (num--) 840 free(list[num]); 841 free(list); 842 } 843 844 free(pathcopy); 845 return dirpath; 846} 847 848/* 849 * xf86initConfigFiles -- Setup global variables and buffers. 850 */ 851void 852xf86initConfigFiles(void) 853{ 854 curFileIndex = 0; 855 configPos = 0; 856 configLineNo = 0; 857 pushToken = LOCK_TOKEN; 858 859 configBuf = malloc(CONFIG_BUF_LEN); 860 configRBuf = malloc(CONFIG_BUF_LEN); 861 configBuf[0] = '\0'; /* sanity ... */ 862} 863 864/* 865 * xf86openConfigFile -- 866 * 867 * This function take a config file search path (optional), a command-line 868 * specified file name (optional) and the ProjectRoot path (optional) and 869 * locates and opens a config file based on that information. If a 870 * command-line file name is specified, then this function fails if none 871 * of the located files. 872 * 873 * The return value is a pointer to the actual name of the file that was 874 * opened. When no file is found, the return value is NULL. The caller should 875 * free() the returned value. 876 * 877 * The escape sequences allowed in the search path are defined above. 878 * 879 */ 880 881#ifndef DEFAULT_CONF_PATH 882#define DEFAULT_CONF_PATH "/etc/X11/%S," \ 883 "%P/etc/X11/%S," \ 884 "/etc/X11/%G," \ 885 "%P/etc/X11/%G," \ 886 "/etc/X11/%X-%M," \ 887 "/etc/X11/%X," \ 888 "/etc/%X," \ 889 "%P/etc/X11/%X.%H," \ 890 "%P/etc/X11/%X-%M," \ 891 "%P/etc/X11/%X," \ 892 "%P/lib/X11/%X.%H," \ 893 "%P/lib/X11/%X-%M," \ 894 "%P/lib/X11/%X" 895#endif 896 897char * 898xf86openConfigFile(const char *path, const char *cmdline, const char *projroot) 899{ 900 if (!path || !path[0]) 901 path = DEFAULT_CONF_PATH; 902 if (!projroot || !projroot[0]) 903 projroot = PROJECTROOT; 904 905 /* Search for a config file */ 906 return OpenConfigFile(path, cmdline, projroot, XCONFIGFILE); 907} 908 909/* 910 * xf86openConfigDirFiles -- 911 * 912 * This function take a config directory search path (optional), a 913 * command-line specified directory name (optional) and the ProjectRoot path 914 * (optional) and locates and opens a config directory based on that 915 * information. If a command-line name is specified, then this function 916 * fails if it is not found. 917 * 918 * The return value is a pointer to the actual name of the directory that was 919 * opened. When no directory is found, the return value is NULL. The caller 920 * should free() the returned value. 921 * 922 * The escape sequences allowed in the search path are defined above. 923 * 924 */ 925char * 926xf86openConfigDirFiles(const char *path, const char *cmdline, 927 const char *projroot) 928{ 929 if (!path || !path[0]) 930 path = DEFAULT_CONF_PATH; 931 if (!projroot || !projroot[0]) 932 projroot = PROJECTROOT; 933 934 /* Search for the multiconf directory */ 935 return OpenConfigDir(path, cmdline, projroot, XCONFIGDIR); 936} 937 938void 939xf86closeConfigFile(void) 940{ 941 int i; 942 943 free(configRBuf); 944 configRBuf = NULL; 945 free(configBuf); 946 configBuf = NULL; 947 948 if (numFiles == 0) { 949 builtinConfig = NULL; 950 builtinIndex = 0; 951 } 952 for (i = 0; i < numFiles; i++) { 953 fclose(configFiles[i].file); 954 configFiles[i].file = NULL; 955 free(configFiles[i].path); 956 configFiles[i].path = NULL; 957 } 958 numFiles = 0; 959} 960 961void 962xf86setBuiltinConfig(const char *config[]) 963{ 964 builtinConfig = config; 965} 966 967void 968xf86parseError(const char *format, ...) 969{ 970 va_list ap; 971 const char *filename = numFiles ? configFiles[curFileIndex].path 972 : "<builtin configuration>"; 973 974 ErrorF("Parse error on line %d of section %s in file %s\n\t", 975 configLineNo, configSection, filename); 976 va_start(ap, format); 977 VErrorF(format, ap); 978 va_end(ap); 979 980 ErrorF("\n"); 981} 982 983void 984xf86validationError(const char *format, ...) 985{ 986 va_list ap; 987 const char *filename = numFiles ? configFiles[curFileIndex].path 988 : "<builtin configuration>"; 989 990 ErrorF("Data incomplete in file %s\n\t", filename); 991 va_start(ap, format); 992 VErrorF(format, ap); 993 va_end(ap); 994 995 ErrorF("\n"); 996} 997 998void 999xf86setSection(const char *section) 1000{ 1001 free(configSection); 1002 configSection = strdup(section); 1003} 1004 1005/* 1006 * xf86getToken -- 1007 * Lookup a string if it is actually a token in disguise. 1008 */ 1009int 1010xf86getStringToken(const xf86ConfigSymTabRec * tab) 1011{ 1012 return StringToToken(xf86_lex_val.str, tab); 1013} 1014 1015/* 1016 * Compare two names. The characters '_', ' ', and '\t' are ignored 1017 * in the comparison. 1018 */ 1019int 1020xf86nameCompare(const char *s1, const char *s2) 1021{ 1022 char c1, c2; 1023 1024 if (!s1 || *s1 == 0) { 1025 if (!s2 || *s2 == 0) 1026 return 0; 1027 else 1028 return 1; 1029 } else if (!s2 || *s2 == 0) { 1030 return -1; 1031 } 1032 1033 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 1034 s1++; 1035 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 1036 s2++; 1037 c1 = (isupper(*s1) ? tolower(*s1) : *s1); 1038 c2 = (isupper(*s2) ? tolower(*s2) : *s2); 1039 while (c1 == c2) { 1040 if (c1 == '\0') 1041 return 0; 1042 s1++; 1043 s2++; 1044 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 1045 s1++; 1046 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 1047 s2++; 1048 c1 = (isupper(*s1) ? tolower(*s1) : *s1); 1049 c2 = (isupper(*s2) ? tolower(*s2) : *s2); 1050 } 1051 return c1 - c2; 1052} 1053 1054char * 1055xf86addComment(char *cur, const char *add) 1056{ 1057 char *str; 1058 const char *cstr; 1059 int len, curlen, iscomment, hasnewline = 0, insnewline, endnewline; 1060 1061 if (add == NULL || add[0] == '\0') 1062 return cur; 1063 1064 if (cur) { 1065 curlen = strlen(cur); 1066 if (curlen) 1067 hasnewline = cur[curlen - 1] == '\n'; 1068 eol_seen = 0; 1069 } 1070 else 1071 curlen = 0; 1072 1073 cstr = add; 1074 iscomment = 0; 1075 while (*cstr) { 1076 if (*cstr != ' ' && *cstr != '\t') 1077 break; 1078 ++cstr; 1079 } 1080 iscomment = (*cstr == '#'); 1081 1082 len = strlen(add); 1083 endnewline = add[len - 1] == '\n'; 1084 1085 insnewline = eol_seen || (curlen && !hasnewline); 1086 if (insnewline) 1087 len++; 1088 if (!iscomment) 1089 len++; 1090 if (!endnewline) 1091 len++; 1092 1093 /* Allocate + 1 char for '\0' terminator. */ 1094 str = realloc(cur, curlen + len + 1); 1095 if (!str) 1096 return cur; 1097 1098 cur = str; 1099 1100 if (insnewline) 1101 cur[curlen++] = '\n'; 1102 if (!iscomment) 1103 cur[curlen++] = '#'; 1104 strcpy(cur + curlen, add); 1105 if (!endnewline) 1106 strcat(cur, "\n"); 1107 1108 return cur; 1109} 1110 1111Bool 1112xf86getBoolValue(Bool *val, const char *str) 1113{ 1114 if (!val || !str) 1115 return FALSE; 1116 if (*str == '\0') { 1117 *val = TRUE; 1118 } 1119 else { 1120 if (xf86nameCompare(str, "1") == 0) 1121 *val = TRUE; 1122 else if (xf86nameCompare(str, "on") == 0) 1123 *val = TRUE; 1124 else if (xf86nameCompare(str, "true") == 0) 1125 *val = TRUE; 1126 else if (xf86nameCompare(str, "yes") == 0) 1127 *val = TRUE; 1128 else if (xf86nameCompare(str, "0") == 0) 1129 *val = FALSE; 1130 else if (xf86nameCompare(str, "off") == 0) 1131 *val = FALSE; 1132 else if (xf86nameCompare(str, "false") == 0) 1133 *val = FALSE; 1134 else if (xf86nameCompare(str, "no") == 0) 1135 *val = FALSE; 1136 else 1137 return FALSE; 1138 } 1139 return TRUE; 1140} 1141