1/* 2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3 * 4 *Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 *"Software"), to deal in the Software without restriction, including 7 *without limitation the rights to use, copy, modify, merge, publish, 8 *distribute, sublicense, and/or sell copies of the Software, and to 9 *permit persons to whom the Software is furnished to do so, subject to 10 *the following conditions: 11 * 12 *The above copyright notice and this permission notice shall be 13 *included in all copies or substantial portions of the Software. 14 * 15 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 19 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 *Except as contained in this notice, the name of the XFree86 Project 24 *shall not be used in advertising or otherwise to promote the sale, use 25 *or other dealings in this Software without prior written authorization 26 *from the XFree86 Project. 27 * 28 * Authors: Alexander Gottwald 29 */ 30 31#ifdef HAVE_XWIN_CONFIG_H 32#include <xwin-config.h> 33#endif 34#include "win.h" 35#include "winconfig.h" 36#include "winmsg.h" 37#include "globals.h" 38 39#include "xkbsrv.h" 40 41#ifdef XWIN_XF86CONFIG 42#ifndef CONFIGPATH 43#define CONFIGPATH "%A," "%R," \ 44 "/etc/X11/%R," "%P/etc/X11/%R," \ 45 "%E," "%F," \ 46 "/etc/X11/%F," "%P/etc/X11/%F," \ 47 "/etc/X11/%X-%M," "/etc/X11/%X," "/etc/%X," \ 48 "%P/etc/X11/%X.%H," "%P/etc/X11/%X-%M," \ 49 "%P/etc/X11/%X," \ 50 "%P/lib/X11/%X.%H," "%P/lib/X11/%X-%M," \ 51 "%P/lib/X11/%X" 52#endif 53#ifndef CONFIGDIRPATH 54#define CONFIGDIRPATH "/etc/X11/%X-%M," "/etc/X11/%X," "/etc/%X," \ 55 "%P/etc/X11/%X.%H," "%P/etc/X11/%X-%M," \ 56 "%P/etc/X11/%X," \ 57 "%P/lib/X11/%X.%H," "%P/lib/X11/%X-%M," \ 58 "%P/lib/X11/%X" 59#endif 60 61XF86ConfigPtr g_xf86configptr = NULL; 62#endif 63 64WinCmdlineRec g_cmdline = { 65#ifdef XWIN_XF86CONFIG 66 NULL, /* configFile */ 67 NULL, /* configDir */ 68#endif 69 NULL, /* fontPath */ 70#ifdef XWIN_XF86CONFIG 71 NULL, /* keyboard */ 72#endif 73 NULL, /* xkbRules */ 74 NULL, /* xkbModel */ 75 NULL, /* xkbLayout */ 76 NULL, /* xkbVariant */ 77 NULL, /* xkbOptions */ 78 NULL, /* screenname */ 79 NULL, /* mousename */ 80 FALSE, /* emulate3Buttons */ 81 0 /* emulate3Timeout */ 82}; 83 84winInfoRec g_winInfo = { 85 { /* keyboard */ 86 0, /* leds */ 87 500, /* delay */ 88 30 /* rate */ 89 } 90 , 91 { /* xkb */ 92 NULL, /* rules */ 93 NULL, /* model */ 94 NULL, /* layout */ 95 NULL, /* variant */ 96 NULL, /* options */ 97 } 98 , 99 { 100 FALSE, 101 50} 102}; 103 104#define NULL_IF_EMPTY(x) (winNameCompare(x,"")?x:NULL) 105 106#ifdef XWIN_XF86CONFIG 107serverLayoutRec g_winConfigLayout; 108 109static Bool ParseOptionValue(int scrnIndex, void *options, OptionInfoPtr p); 110static Bool configLayout(serverLayoutPtr, XF86ConfLayoutPtr, char *); 111static Bool configImpliedLayout(serverLayoutPtr, XF86ConfScreenPtr); 112static Bool GetBoolValue(OptionInfoPtr p, const char *s); 113 114Bool 115winReadConfigfile() 116{ 117 Bool retval = TRUE; 118 char *filename, *dirname; 119 MessageType filefrom = X_DEFAULT; 120 MessageType dirfrom = X_DEFAULT; 121 char *xf86ConfigFile = NULL; 122 char *xf86ConfigDir = NULL; 123 124 if (g_cmdline.configFile) { 125 filefrom = X_CMDLINE; 126 xf86ConfigFile = g_cmdline.configFile; 127 } 128 if (g_cmdline.configDir) { 129 dirfrom = X_CMDLINE; 130 xf86ConfigDir = g_cmdline.configDir; 131 } 132 133 /* Parse config file into data structure */ 134 xf86initConfigFiles(); 135 dirname = xf86openConfigDirFiles(CONFIGDIRPATH, xf86ConfigDir, PROJECTROOT); 136 filename = xf86openConfigFile(CONFIGPATH, xf86ConfigFile, PROJECTROOT); 137 138 /* Hack for backward compatibility */ 139 if (!filename && from == X_DEFAULT) 140 filename = xf86openConfigFile(CONFIGPATH, "XF86Config", PROJECTROOT); 141 142 if (filename) { 143 winMsg(from, "Using config file: \"%s\"\n", filename); 144 } 145 else { 146 winMsg(X_ERROR, "Unable to locate/open config file"); 147 if (xf86ConfigFile) 148 ErrorF(": \"%s\"", xf86ConfigFile); 149 ErrorF("\n"); 150 } 151 if (dirname) { 152 winMsg(from, "Using config directory: \"%s\"\n", dirname); 153 } 154 else { 155 winMsg(X_ERROR, "Unable to locate/open config directory"); 156 if (xf86ConfigDir) 157 ErrorF(": \"%s\"", xf86ConfigDir); 158 ErrorF("\n"); 159 } 160 if (!filename && !dirname) { 161 return FALSE; 162 } 163 free(filename); 164 free(dirname); 165 if ((g_xf86configptr = xf86readConfigFile()) == NULL) { 166 winMsg(X_ERROR, "Problem parsing the config file\n"); 167 return FALSE; 168 } 169 xf86closeConfigFile(); 170 171 LogPrintMarkers(); 172 173 /* set options from data structure */ 174 175 if (g_xf86configptr->conf_layout_lst == NULL || 176 g_cmdline.screenname != NULL) { 177 if (g_cmdline.screenname == NULL) { 178 winMsg(X_WARNING, 179 "No Layout section. Using the first Screen section.\n"); 180 } 181 if (!configImpliedLayout(&g_winConfigLayout, 182 g_xf86configptr->conf_screen_lst)) { 183 winMsg(X_ERROR, "Unable to determine the screen layout\n"); 184 return FALSE; 185 } 186 } 187 else { 188 /* Check if layout is given in the config file */ 189 if (g_xf86configptr->conf_flags != NULL) { 190 char *dfltlayout = NULL; 191 void *optlist = g_xf86configptr->conf_flags->flg_option_lst; 192 193 if (optlist && winFindOption(optlist, "defaultserverlayout")) 194 dfltlayout = 195 winSetStrOption(optlist, "defaultserverlayout", NULL); 196 197 if (!configLayout(&g_winConfigLayout, 198 g_xf86configptr->conf_layout_lst, dfltlayout)) { 199 winMsg(X_ERROR, "Unable to determine the screen layout\n"); 200 return FALSE; 201 } 202 } 203 else { 204 if (!configLayout(&g_winConfigLayout, 205 g_xf86configptr->conf_layout_lst, NULL)) { 206 winMsg(X_ERROR, "Unable to determine the screen layout\n"); 207 return FALSE; 208 } 209 } 210 } 211 212 /* setup special config files */ 213 winConfigFiles(); 214 return retval; 215} 216#endif 217 218/* load layout definitions */ 219#include "winlayouts.h" 220 221/* Set the keyboard configuration */ 222Bool 223winConfigKeyboard(DeviceIntPtr pDevice) 224{ 225 char layoutName[KL_NAMELENGTH]; 226 unsigned char layoutFriendlyName[256]; 227 unsigned int layoutNum = 0; 228 unsigned int deviceIdentifier = 0; 229 int keyboardType; 230 231#ifdef XWIN_XF86CONFIG 232 XF86ConfInputPtr kbd = NULL; 233 XF86ConfInputPtr input_list = NULL; 234 MessageType kbdfrom = X_CONFIG; 235#endif 236 MessageType from = X_DEFAULT; 237 char *s = NULL; 238 239 /* Setup defaults */ 240 XkbGetRulesDflts(&g_winInfo.xkb); 241 242 /* 243 * Query the windows autorepeat settings and change the xserver defaults. 244 */ 245 { 246 int kbd_delay; 247 DWORD kbd_speed; 248 249 if (SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &kbd_delay, 0) && 250 SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &kbd_speed, 0)) { 251 switch (kbd_delay) { 252 case 0: 253 g_winInfo.keyboard.delay = 250; 254 break; 255 case 1: 256 g_winInfo.keyboard.delay = 500; 257 break; 258 case 2: 259 g_winInfo.keyboard.delay = 750; 260 break; 261 default: 262 case 3: 263 g_winInfo.keyboard.delay = 1000; 264 break; 265 } 266 g_winInfo.keyboard.rate = (kbd_speed > 0) ? kbd_speed : 1; 267 winMsg(X_PROBED, "Setting autorepeat to delay=%ld, rate=%ld\n", 268 g_winInfo.keyboard.delay, g_winInfo.keyboard.rate); 269 270 } 271 } 272 273 keyboardType = GetKeyboardType(0); 274 if (keyboardType > 0 && GetKeyboardLayoutName(layoutName)) { 275 WinKBLayoutPtr pLayout; 276 Bool bfound = FALSE; 277 int pass; 278 279 layoutNum = strtoul(layoutName, (char **) NULL, 16); 280 if ((layoutNum & 0xffff) == 0x411) { 281 if (keyboardType == 7) { 282 /* Japanese layouts have problems with key event messages 283 such as the lack of WM_KEYUP for Caps Lock key. 284 Loading US layout fixes this problem. */ 285 if (LoadKeyboardLayout("00000409", KLF_ACTIVATE) != NULL) 286 winMsg(X_INFO, "Loading US keyboard layout.\n"); 287 else 288 winMsg(X_ERROR, "LoadKeyboardLayout failed.\n"); 289 } 290 } 291 292 /* Discover the friendly name of the current layout */ 293 { 294 HKEY regkey = NULL; 295 const char regtempl[] = 296 "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\"; 297 char *regpath; 298 DWORD namesize = sizeof(layoutFriendlyName); 299 300 regpath = malloc(sizeof(regtempl) + KL_NAMELENGTH + 1); 301 strcpy(regpath, regtempl); 302 strcat(regpath, layoutName); 303 304 if (!RegOpenKey(HKEY_LOCAL_MACHINE, regpath, ®key)) 305 RegQueryValueEx(regkey, "Layout Text", 0, NULL, 306 layoutFriendlyName, &namesize); 307 308 /* Close registry key */ 309 if (regkey) 310 RegCloseKey(regkey); 311 free(regpath); 312 } 313 314 winMsg(X_PROBED, 315 "Windows keyboard layout: \"%s\" (%08x) \"%s\", type %d\n", 316 layoutName, layoutNum, layoutFriendlyName, keyboardType); 317 318 deviceIdentifier = layoutNum >> 16; 319 for (pass = 0; pass < 2; pass++) { 320 /* If we didn't find an exact match for the input locale identifier, 321 try to find an match on the language identifier part only */ 322 if (pass == 1) 323 layoutNum = (layoutNum & 0xffff); 324 325 for (pLayout = winKBLayouts; pLayout->winlayout != -1; pLayout++) { 326 if (pLayout->winlayout != layoutNum) 327 continue; 328 if (pLayout->winkbtype > 0 && pLayout->winkbtype != keyboardType) 329 continue; 330 331 bfound = TRUE; 332 winMsg(X_PROBED, 333 "Found matching XKB configuration \"%s\"\n", 334 pLayout->layoutname); 335 336 winMsg(X_PROBED, 337 "Model = \"%s\" Layout = \"%s\"" 338 " Variant = \"%s\" Options = \"%s\"\n", 339 pLayout->xkbmodel ? pLayout->xkbmodel : "none", 340 pLayout->xkblayout ? pLayout->xkblayout : "none", 341 pLayout->xkbvariant ? pLayout->xkbvariant : "none", 342 pLayout->xkboptions ? pLayout->xkboptions : "none"); 343 344 g_winInfo.xkb.model = pLayout->xkbmodel; 345 g_winInfo.xkb.layout = pLayout->xkblayout; 346 g_winInfo.xkb.variant = pLayout->xkbvariant; 347 g_winInfo.xkb.options = pLayout->xkboptions; 348 349 if (deviceIdentifier == 0xa000) { 350 winMsg(X_PROBED, "Windows keyboard layout device identifier indicates Macintosh, setting Model = \"macintosh\""); 351 g_winInfo.xkb.model = "macintosh"; 352 } 353 354 break; 355 } 356 357 if (bfound) 358 break; 359 } 360 361 if (!bfound) { 362 winMsg(X_ERROR, 363 "Keyboardlayout \"%s\" (%s) is unknown, using X server default layout\n", 364 layoutFriendlyName, layoutName); 365 } 366 } 367 368 /* parse the configuration */ 369#ifdef XWIN_XF86CONFIG 370 if (g_cmdline.keyboard) 371 kbdfrom = X_CMDLINE; 372 373 /* 374 * Until the layout code is finished, I search for the keyboard 375 * device and configure the server with it. 376 */ 377 378 if (g_xf86configptr != NULL) 379 input_list = g_xf86configptr->conf_input_lst; 380 381 while (input_list != NULL) { 382 if (winNameCompare(input_list->inp_driver, "keyboard") == 0) { 383 /* Check if device name matches requested name */ 384 if (g_cmdline.keyboard && winNameCompare(input_list->inp_identifier, 385 g_cmdline.keyboard)) 386 continue; 387 kbd = input_list; 388 } 389 input_list = input_list->list.next; 390 } 391 392 if (kbd != NULL) { 393 394 if (kbd->inp_identifier) 395 winMsg(kbdfrom, "Using keyboard \"%s\" as primary keyboard\n", 396 kbd->inp_identifier); 397 398 if ((s = winSetStrOption(kbd->inp_option_lst, "AutoRepeat", NULL))) { 399 if ((sscanf(s, "%ld %ld", &g_winInfo.keyboard.delay, 400 &g_winInfo.keyboard.rate) != 2) || 401 (g_winInfo.keyboard.delay < 1) || 402 (g_winInfo.keyboard.rate == 0) || 403 (1000 / g_winInfo.keyboard.rate) < 1) { 404 winErrorFVerb(2, "\"%s\" is not a valid AutoRepeat value", s); 405 free(s); 406 return FALSE; 407 } 408 free(s); 409 winMsg(X_CONFIG, "AutoRepeat: %ld %ld\n", 410 g_winInfo.keyboard.delay, g_winInfo.keyboard.rate); 411 } 412#endif 413 414 s = NULL; 415 if (g_cmdline.xkbRules) { 416 s = g_cmdline.xkbRules; 417 from = X_CMDLINE; 418 } 419#ifdef XWIN_XF86CONFIG 420 else { 421 s = winSetStrOption(kbd->inp_option_lst, "XkbRules", NULL); 422 from = X_CONFIG; 423 } 424#endif 425 if (s) { 426 g_winInfo.xkb.rules = NULL_IF_EMPTY(s); 427 winMsg(from, "XKB: rules: \"%s\"\n", s); 428 } 429 430 s = NULL; 431 if (g_cmdline.xkbModel) { 432 s = g_cmdline.xkbModel; 433 from = X_CMDLINE; 434 } 435#ifdef XWIN_XF86CONFIG 436 else { 437 s = winSetStrOption(kbd->inp_option_lst, "XkbModel", NULL); 438 from = X_CONFIG; 439 } 440#endif 441 if (s) { 442 g_winInfo.xkb.model = NULL_IF_EMPTY(s); 443 winMsg(from, "XKB: model: \"%s\"\n", s); 444 } 445 446 s = NULL; 447 if (g_cmdline.xkbLayout) { 448 s = g_cmdline.xkbLayout; 449 from = X_CMDLINE; 450 } 451#ifdef XWIN_XF86CONFIG 452 else { 453 s = winSetStrOption(kbd->inp_option_lst, "XkbLayout", NULL); 454 from = X_CONFIG; 455 } 456#endif 457 if (s) { 458 g_winInfo.xkb.layout = NULL_IF_EMPTY(s); 459 winMsg(from, "XKB: layout: \"%s\"\n", s); 460 } 461 462 s = NULL; 463 if (g_cmdline.xkbVariant) { 464 s = g_cmdline.xkbVariant; 465 from = X_CMDLINE; 466 } 467#ifdef XWIN_XF86CONFIG 468 else { 469 s = winSetStrOption(kbd->inp_option_lst, "XkbVariant", NULL); 470 from = X_CONFIG; 471 } 472#endif 473 if (s) { 474 g_winInfo.xkb.variant = NULL_IF_EMPTY(s); 475 winMsg(from, "XKB: variant: \"%s\"\n", s); 476 } 477 478 s = NULL; 479 if (g_cmdline.xkbOptions) { 480 s = g_cmdline.xkbOptions; 481 from = X_CMDLINE; 482 } 483#ifdef XWIN_XF86CONFIG 484 else { 485 s = winSetStrOption(kbd->inp_option_lst, "XkbOptions", NULL); 486 from = X_CONFIG; 487 } 488#endif 489 if (s) { 490 g_winInfo.xkb.options = NULL_IF_EMPTY(s); 491 winMsg(from, "XKB: options: \"%s\"\n", s); 492 } 493 494#ifdef XWIN_XF86CONFIG 495 } 496#endif 497 498 return TRUE; 499} 500 501#ifdef XWIN_XF86CONFIG 502Bool 503winConfigMouse(DeviceIntPtr pDevice) 504{ 505 MessageType mousefrom = X_CONFIG; 506 507 XF86ConfInputPtr mouse = NULL; 508 XF86ConfInputPtr input_list = NULL; 509 510 if (g_cmdline.mouse) 511 mousefrom = X_CMDLINE; 512 513 if (g_xf86configptr != NULL) 514 input_list = g_xf86configptr->conf_input_lst; 515 516 while (input_list != NULL) { 517 if (winNameCompare(input_list->inp_driver, "mouse") == 0) { 518 /* Check if device name matches requested name */ 519 if (g_cmdline.mouse && winNameCompare(input_list->inp_identifier, 520 g_cmdline.mouse)) 521 continue; 522 mouse = input_list; 523 } 524 input_list = input_list->list.next; 525 } 526 527 if (mouse != NULL) { 528 if (mouse->inp_identifier) 529 winMsg(mousefrom, "Using pointer \"%s\" as primary pointer\n", 530 mouse->inp_identifier); 531 532 g_winInfo.pointer.emulate3Buttons = 533 winSetBoolOption(mouse->inp_option_lst, "Emulate3Buttons", FALSE); 534 if (g_cmdline.emulate3buttons) 535 g_winInfo.pointer.emulate3Buttons = g_cmdline.emulate3buttons; 536 537 g_winInfo.pointer.emulate3Timeout = 538 winSetIntOption(mouse->inp_option_lst, "Emulate3Timeout", 50); 539 if (g_cmdline.emulate3timeout) 540 g_winInfo.pointer.emulate3Timeout = g_cmdline.emulate3timeout; 541 } 542 else { 543 winMsg(X_ERROR, "No primary pointer configured\n"); 544 winMsg(X_DEFAULT, "Using compiletime defaults for pointer\n"); 545 } 546 547 return TRUE; 548} 549 550Bool 551winConfigFiles() 552{ 553 MessageType from; 554 XF86ConfFilesPtr filesptr = NULL; 555 556 /* set some shortcuts */ 557 if (g_xf86configptr != NULL) { 558 filesptr = g_xf86configptr->conf_files; 559 } 560 561 /* Fontpath */ 562 from = X_DEFAULT; 563 564 if (g_cmdline.fontPath) { 565 from = X_CMDLINE; 566 defaultFontPath = g_cmdline.fontPath; 567 } 568 else if (filesptr != NULL && filesptr->file_fontpath) { 569 from = X_CONFIG; 570 defaultFontPath = strdup(filesptr->file_fontpath); 571 } 572 winMsg(from, "FontPath set to \"%s\"\n", defaultFontPath); 573 574 return TRUE; 575} 576#else 577Bool 578winConfigFiles(void) 579{ 580 /* Fontpath */ 581 if (g_cmdline.fontPath) { 582 defaultFontPath = g_cmdline.fontPath; 583 winMsg(X_CMDLINE, "FontPath set to \"%s\"\n", defaultFontPath); 584 } 585 586 return TRUE; 587} 588#endif 589 590Bool 591winConfigOptions(void) 592{ 593 return TRUE; 594} 595 596Bool 597winConfigScreens(void) 598{ 599 return TRUE; 600} 601 602#ifdef XWIN_XF86CONFIG 603char * 604winSetStrOption(void *optlist, const char *name, char *deflt) 605{ 606 OptionInfoRec o; 607 608 o.name = name; 609 o.type = OPTV_STRING; 610 if (ParseOptionValue(-1, optlist, &o)) 611 deflt = o.value.str; 612 if (deflt) 613 return strdup(deflt); 614 else 615 return NULL; 616} 617 618int 619winSetBoolOption(void *optlist, const char *name, int deflt) 620{ 621 OptionInfoRec o; 622 623 o.name = name; 624 o.type = OPTV_BOOLEAN; 625 if (ParseOptionValue(-1, optlist, &o)) 626 deflt = o.value.boolean; 627 return deflt; 628} 629 630int 631winSetIntOption(void *optlist, const char *name, int deflt) 632{ 633 OptionInfoRec o; 634 635 o.name = name; 636 o.type = OPTV_INTEGER; 637 if (ParseOptionValue(-1, optlist, &o)) 638 deflt = o.value.num; 639 return deflt; 640} 641 642double 643winSetRealOption(void *optlist, const char *name, double deflt) 644{ 645 OptionInfoRec o; 646 647 o.name = name; 648 o.type = OPTV_REAL; 649 if (ParseOptionValue(-1, optlist, &o)) 650 deflt = o.value.realnum; 651 return deflt; 652} 653 654double 655winSetPercentOption(void *optlist, const char *name, double deflt) 656{ 657 OptionInfoRec o; 658 659 o.name = name; 660 o.type = OPTV_PERCENT; 661 if (ParseOptionValue(-1, optlist, &o)) 662 deflt = o.value.realnum; 663 return deflt; 664} 665#endif 666 667/* 668 * Compare two strings for equality. This is caseinsensitive and 669 * The characters '_', ' ' (space) and '\t' (tab) are treated as 670 * not existing. 671 */ 672 673int 674winNameCompare(const char *s1, const char *s2) 675{ 676 char c1, c2; 677 678 if (!s1 || *s1 == 0) { 679 if (!s2 || *s2 == 0) 680 return 0; 681 else 682 return 1; 683 } 684 685 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 686 s1++; 687 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 688 s2++; 689 690 c1 = (isupper((int) *s1) ? tolower((int) *s1) : *s1); 691 c2 = (isupper((int) *s2) ? tolower((int) *s2) : *s2); 692 693 while (c1 == c2) { 694 if (c1 == 0) 695 return 0; 696 s1++; 697 s2++; 698 699 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 700 s1++; 701 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 702 s2++; 703 704 c1 = (isupper((int) *s1) ? tolower((int) *s1) : *s1); 705 c2 = (isupper((int) *s2) ? tolower((int) *s2) : *s2); 706 } 707 return c1 - c2; 708} 709 710#ifdef XWIN_XF86CONFIG 711/* 712 * Find the named option in the list. 713 * @return the pointer to the option record, or NULL if not found. 714 */ 715 716XF86OptionPtr 717winFindOption(XF86OptionPtr list, const char *name) 718{ 719 while (list) { 720 if (winNameCompare(list->opt_name, name) == 0) 721 return list; 722 list = list->list.next; 723 } 724 return NULL; 725} 726 727/* 728 * Find the Value of an named option. 729 * @return The option value or NULL if not found. 730 */ 731 732char * 733winFindOptionValue(XF86OptionPtr list, const char *name) 734{ 735 list = winFindOption(list, name); 736 if (list) { 737 if (list->opt_val) 738 return list->opt_val; 739 else 740 return ""; 741 } 742 return NULL; 743} 744 745/* 746 * Parse the option. 747 */ 748 749static Bool 750ParseOptionValue(int scrnIndex, void *options, OptionInfoPtr p) 751{ 752 char *s, *end; 753 754 if ((s = winFindOptionValue(options, p->name)) != NULL) { 755 switch (p->type) { 756 case OPTV_INTEGER: 757 if (*s == '\0') { 758 winDrvMsg(scrnIndex, X_WARNING, 759 "Option \"%s\" requires an integer value\n", p->name); 760 p->found = FALSE; 761 } 762 else { 763 p->value.num = strtoul(s, &end, 0); 764 if (*end == '\0') { 765 p->found = TRUE; 766 } 767 else { 768 winDrvMsg(scrnIndex, X_WARNING, 769 "Option \"%s\" requires an integer value\n", 770 p->name); 771 p->found = FALSE; 772 } 773 } 774 break; 775 case OPTV_STRING: 776 if (*s == '\0') { 777 winDrvMsg(scrnIndex, X_WARNING, 778 "Option \"%s\" requires a string value\n", p->name); 779 p->found = FALSE; 780 } 781 else { 782 p->value.str = s; 783 p->found = TRUE; 784 } 785 break; 786 case OPTV_ANYSTR: 787 p->value.str = s; 788 p->found = TRUE; 789 break; 790 case OPTV_REAL: 791 if (*s == '\0') { 792 winDrvMsg(scrnIndex, X_WARNING, 793 "Option \"%s\" requires a floating point value\n", 794 p->name); 795 p->found = FALSE; 796 } 797 else { 798 p->value.realnum = strtod(s, &end); 799 if (*end == '\0') { 800 p->found = TRUE; 801 } 802 else { 803 winDrvMsg(scrnIndex, X_WARNING, 804 "Option \"%s\" requires a floating point value\n", 805 p->name); 806 p->found = FALSE; 807 } 808 } 809 break; 810 case OPTV_BOOLEAN: 811 if (GetBoolValue(p, s)) { 812 p->found = TRUE; 813 } 814 else { 815 winDrvMsg(scrnIndex, X_WARNING, 816 "Option \"%s\" requires a boolean value\n", p->name); 817 p->found = FALSE; 818 } 819 break; 820 case OPTV_PERCENT: 821 if (*s == '\0') { 822 winDrvMsg(scrnIndex, X_WARNING, 823 "Option \"%s\" requires a percent value\n", p->name); 824 p->found = FALSE; 825 } 826 else { 827 double percent = strtod(s, &end); 828 829 if (end != s && winNameCompare(end, "%")) { 830 p->found = TRUE; 831 p->value.realnum = percent; 832 } 833 else { 834 winDrvMsg(scrnIndex, X_WARNING, 835 "Option \"%s\" requires a frequency value\n", 836 p->name); 837 p->found = FALSE; 838 } 839 } 840 case OPTV_FREQ: 841 if (*s == '\0') { 842 winDrvMsg(scrnIndex, X_WARNING, 843 "Option \"%s\" requires a frequency value\n", 844 p->name); 845 p->found = FALSE; 846 } 847 else { 848 double freq = strtod(s, &end); 849 int units = 0; 850 851 if (end != s) { 852 p->found = TRUE; 853 if (!winNameCompare(end, "Hz")) 854 units = 1; 855 else if (!winNameCompare(end, "kHz") || 856 !winNameCompare(end, "k")) 857 units = 1000; 858 else if (!winNameCompare(end, "MHz") || 859 !winNameCompare(end, "M")) 860 units = 1000000; 861 else { 862 winDrvMsg(scrnIndex, X_WARNING, 863 "Option \"%s\" requires a frequency value\n", 864 p->name); 865 p->found = FALSE; 866 } 867 if (p->found) 868 freq *= (double) units; 869 } 870 else { 871 winDrvMsg(scrnIndex, X_WARNING, 872 "Option \"%s\" requires a frequency value\n", 873 p->name); 874 p->found = FALSE; 875 } 876 if (p->found) { 877 p->value.freq.freq = freq; 878 p->value.freq.units = units; 879 } 880 } 881 break; 882 case OPTV_NONE: 883 /* Should never get here */ 884 p->found = FALSE; 885 break; 886 } 887 if (p->found) { 888 winDrvMsgVerb(scrnIndex, X_CONFIG, 2, "Option \"%s\"", p->name); 889 if (!(p->type == OPTV_BOOLEAN && *s == 0)) { 890 winErrorFVerb(2, " \"%s\"", s); 891 } 892 winErrorFVerb(2, "\n"); 893 } 894 } 895 else if (p->type == OPTV_BOOLEAN) { 896 /* Look for matches with options with or without a "No" prefix. */ 897 char *n, *newn; 898 OptionInfoRec opt; 899 900 n = winNormalizeName(p->name); 901 if (!n) { 902 p->found = FALSE; 903 return FALSE; 904 } 905 if (strncmp(n, "no", 2) == 0) { 906 newn = n + 2; 907 } 908 else { 909 free(n); 910 n = malloc(strlen(p->name) + 2 + 1); 911 if (!n) { 912 p->found = FALSE; 913 return FALSE; 914 } 915 strcpy(n, "No"); 916 strcat(n, p->name); 917 newn = n; 918 } 919 if ((s = winFindOptionValue(options, newn)) != NULL) { 920 if (GetBoolValue(&opt, s)) { 921 p->value.boolean = !opt.value.boolean; 922 p->found = TRUE; 923 } 924 else { 925 winDrvMsg(scrnIndex, X_WARNING, 926 "Option \"%s\" requires a boolean value\n", newn); 927 p->found = FALSE; 928 } 929 } 930 else { 931 p->found = FALSE; 932 } 933 if (p->found) { 934 winDrvMsgVerb(scrnIndex, X_CONFIG, 2, "Option \"%s\"", newn); 935 if (*s != 0) { 936 winErrorFVerb(2, " \"%s\"", s); 937 } 938 winErrorFVerb(2, "\n"); 939 } 940 free(n); 941 } 942 else { 943 p->found = FALSE; 944 } 945 return p->found; 946} 947 948static Bool 949configLayout(serverLayoutPtr servlayoutp, XF86ConfLayoutPtr conf_layout, 950 char *default_layout) 951{ 952#if 0 953#pragma warn UNIMPLEMENTED 954#endif 955 return TRUE; 956} 957 958static Bool 959configImpliedLayout(serverLayoutPtr servlayoutp, XF86ConfScreenPtr conf_screen) 960{ 961#if 0 962#pragma warn UNIMPLEMENTED 963#endif 964 return TRUE; 965} 966 967static Bool 968GetBoolValue(OptionInfoPtr p, const char *s) 969{ 970 if (*s == 0) { 971 p->value.boolean = TRUE; 972 } 973 else { 974 if (winNameCompare(s, "1") == 0) 975 p->value.boolean = TRUE; 976 else if (winNameCompare(s, "on") == 0) 977 p->value.boolean = TRUE; 978 else if (winNameCompare(s, "true") == 0) 979 p->value.boolean = TRUE; 980 else if (winNameCompare(s, "yes") == 0) 981 p->value.boolean = TRUE; 982 else if (winNameCompare(s, "0") == 0) 983 p->value.boolean = FALSE; 984 else if (winNameCompare(s, "off") == 0) 985 p->value.boolean = FALSE; 986 else if (winNameCompare(s, "false") == 0) 987 p->value.boolean = FALSE; 988 else if (winNameCompare(s, "no") == 0) 989 p->value.boolean = FALSE; 990 } 991 return TRUE; 992} 993#endif 994 995char * 996winNormalizeName(const char *s) 997{ 998 char *ret, *q; 999 const char *p; 1000 1001 if (s == NULL) 1002 return NULL; 1003 1004 ret = malloc(strlen(s) + 1); 1005 for (p = s, q = ret; *p != 0; p++) { 1006 switch (*p) { 1007 case '_': 1008 case ' ': 1009 case '\t': 1010 continue; 1011 default: 1012 if (isupper((int) *p)) 1013 *q++ = tolower((int) *p); 1014 else 1015 *q++ = *p; 1016 } 1017 } 1018 *q = '\0'; 1019 return ret; 1020} 1021