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