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 
61 XF86ConfigPtr g_xf86configptr = NULL;
62 #endif
63 
64 WinCmdlineRec 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 
84 winInfoRec 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
107 serverLayoutRec g_winConfigLayout;
108 
109 static Bool ParseOptionValue(int scrnIndex, void *options, OptionInfoPtr p);
110 static Bool configLayout(serverLayoutPtr, XF86ConfLayoutPtr, char *);
111 static Bool configImpliedLayout(serverLayoutPtr, XF86ConfScreenPtr);
112 static Bool GetBoolValue(OptionInfoPtr p, const char *s);
113 
114 Bool
winReadConfigfile()115 winReadConfigfile()
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 */
222 Bool
winConfigKeyboard(DeviceIntPtr pDevice)223 winConfigKeyboard(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, &regkey))
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 identifer,
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
502 Bool
winConfigMouse(DeviceIntPtr pDevice)503 winConfigMouse(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 
550 Bool
winConfigFiles()551 winConfigFiles()
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
577 Bool
winConfigFiles(void)578 winConfigFiles(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 
590 Bool
winConfigOptions(void)591 winConfigOptions(void)
592 {
593     return TRUE;
594 }
595 
596 Bool
winConfigScreens(void)597 winConfigScreens(void)
598 {
599     return TRUE;
600 }
601 
602 #ifdef XWIN_XF86CONFIG
603 char *
winSetStrOption(void * optlist,const char * name,char * deflt)604 winSetStrOption(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 
618 int
winSetBoolOption(void * optlist,const char * name,int deflt)619 winSetBoolOption(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.bool;
627     return deflt;
628 }
629 
630 int
winSetIntOption(void * optlist,const char * name,int deflt)631 winSetIntOption(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 
642 double
winSetRealOption(void * optlist,const char * name,double deflt)643 winSetRealOption(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 
654 double
winSetPercentOption(void * optlist,const char * name,double deflt)655 winSetPercentOption(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 
673 int
winNameCompare(const char * s1,const char * s2)674 winNameCompare(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 
716 XF86OptionPtr
winFindOption(XF86OptionPtr list,const char * name)717 winFindOption(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 
732 char *
winFindOptionValue(XF86OptionPtr list,const char * name)733 winFindOptionValue(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 
749 static Bool
ParseOptionValue(int scrnIndex,void * options,OptionInfoPtr p)750 ParseOptionValue(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.bool = !opt.value.bool;
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 
948 static Bool
configLayout(serverLayoutPtr servlayoutp,XF86ConfLayoutPtr conf_layout,char * default_layout)949 configLayout(serverLayoutPtr servlayoutp, XF86ConfLayoutPtr conf_layout,
950              char *default_layout)
951 {
952 #if 0
953 #pragma warn UNIMPLEMENTED
954 #endif
955     return TRUE;
956 }
957 
958 static Bool
configImpliedLayout(serverLayoutPtr servlayoutp,XF86ConfScreenPtr conf_screen)959 configImpliedLayout(serverLayoutPtr servlayoutp, XF86ConfScreenPtr conf_screen)
960 {
961 #if 0
962 #pragma warn UNIMPLEMENTED
963 #endif
964     return TRUE;
965 }
966 
967 static Bool
GetBoolValue(OptionInfoPtr p,const char * s)968 GetBoolValue(OptionInfoPtr p, const char *s)
969 {
970     if (*s == 0) {
971         p->value.bool = TRUE;
972     }
973     else {
974         if (winNameCompare(s, "1") == 0)
975             p->value.bool = TRUE;
976         else if (winNameCompare(s, "on") == 0)
977             p->value.bool = TRUE;
978         else if (winNameCompare(s, "true") == 0)
979             p->value.bool = TRUE;
980         else if (winNameCompare(s, "yes") == 0)
981             p->value.bool = TRUE;
982         else if (winNameCompare(s, "0") == 0)
983             p->value.bool = FALSE;
984         else if (winNameCompare(s, "off") == 0)
985             p->value.bool = FALSE;
986         else if (winNameCompare(s, "false") == 0)
987             p->value.bool = FALSE;
988         else if (winNameCompare(s, "no") == 0)
989             p->value.bool = FALSE;
990     }
991     return TRUE;
992 }
993 #endif
994 
995 char *
winNormalizeName(const char * s)996 winNormalizeName(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