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, pointer options,
110			      OptionInfoPtr p);
111static Bool configLayout (serverLayoutPtr, XF86ConfLayoutPtr, char *);
112static Bool configImpliedLayout (serverLayoutPtr, XF86ConfScreenPtr);
113static Bool GetBoolValue (OptionInfoPtr p, const char *s);
114
115
116Bool
117winReadConfigfile ()
118{
119  Bool		retval = TRUE;
120  const char	*filename, *dirname;
121  MessageType	filefrom = X_DEFAULT;
122  MessageType	dirfrom = X_DEFAULT;
123  char		*xf86ConfigFile = NULL;
124  char		*xf86ConfigDir = NULL;
125
126  if (g_cmdline.configFile)
127    {
128      filefrom = X_CMDLINE;
129      xf86ConfigFile = g_cmdline.configFile;
130    }
131  if (g_cmdline.configDir)
132    {
133      dirfrom = X_CMDLINE;
134      xf86ConfigDir = g_cmdline.configDir;
135    }
136
137  /* Parse config file into data structure */
138  xf86initConfigFiles();
139  dirname = xf86openConfigDirFiles (CONFIGDIRPATH, xf86ConfigDir, PROJECTROOT);
140  filename = xf86openConfigFile (CONFIGPATH, xf86ConfigFile, PROJECTROOT);
141
142  /* Hack for backward compatibility */
143  if (!filename && from == X_DEFAULT)
144    filename = xf86openConfigFile (CONFIGPATH, "XF86Config", PROJECTROOT);
145
146  if (filename)
147    {
148      winMsg (from, "Using config file: \"%s\"\n", filename);
149    }
150  else
151    {
152      winMsg (X_ERROR, "Unable to locate/open config file");
153      if (xf86ConfigFile)
154	ErrorF (": \"%s\"", xf86ConfigFile);
155      ErrorF ("\n");
156    }
157  if (dirname)
158    {
159      winMsg (from, "Using config directory: \"%s\"\n", dirname);
160    }
161  else
162    {
163      winMsg (X_ERROR, "Unable to locate/open config directory");
164      if (xf86ConfigDir)
165	ErrorF (": \"%s\"", xf86ConfigDir);
166      ErrorF ("\n");
167    }
168  if (!filename && !dirname)
169    {
170      return FALSE;
171    }
172  if ((g_xf86configptr = xf86readConfigFile ()) == NULL)
173    {
174      winMsg (X_ERROR, "Problem parsing the config file\n");
175      return FALSE;
176    }
177  xf86closeConfigFile ();
178
179  LogPrintMarkers();
180
181  /* set options from data structure */
182
183  if (g_xf86configptr->conf_layout_lst == NULL || g_cmdline.screenname != NULL)
184    {
185      if (g_cmdline.screenname == NULL)
186	{
187	  winMsg (X_WARNING,
188		  "No Layout section. Using the first Screen section.\n");
189	}
190      if (!configImpliedLayout (&g_winConfigLayout,
191				g_xf86configptr->conf_screen_lst))
192	{
193	  winMsg (X_ERROR, "Unable to determine the screen layout\n");
194	  return FALSE;
195	}
196    }
197  else
198    {
199      /* Check if layout is given in the config file */
200      if (g_xf86configptr->conf_flags != NULL)
201	{
202	  char *dfltlayout = NULL;
203	  pointer optlist = g_xf86configptr->conf_flags->flg_option_lst;
204
205	  if (optlist && winFindOption (optlist, "defaultserverlayout"))
206	    dfltlayout =
207	      winSetStrOption (optlist, "defaultserverlayout", NULL);
208
209	  if (!configLayout (&g_winConfigLayout,
210			     g_xf86configptr->conf_layout_lst,
211			     dfltlayout))
212	    {
213	      winMsg (X_ERROR, "Unable to determine the screen layout\n");
214	      return FALSE;
215	    }
216	}
217      else
218	{
219	  if (!configLayout (&g_winConfigLayout,
220			     g_xf86configptr->conf_layout_lst,
221			     NULL))
222	    {
223	      winMsg (X_ERROR, "Unable to determine the screen layout\n");
224	      return FALSE;
225	    }
226	}
227    }
228
229  /* setup special config files */
230  winConfigFiles ();
231  return retval;
232}
233#endif
234
235/* load layout definitions */
236#include "winlayouts.h"
237
238/* Set the keyboard configuration */
239Bool
240winConfigKeyboard (DeviceIntPtr pDevice)
241{
242  char                          layoutName[KL_NAMELENGTH];
243  unsigned char                 layoutFriendlyName[256];
244  static unsigned int           layoutNum = 0;
245  int                           keyboardType;
246#ifdef XWIN_XF86CONFIG
247  XF86ConfInputPtr		kbd = NULL;
248  XF86ConfInputPtr		input_list = NULL;
249  MessageType			kbdfrom = X_CONFIG;
250#endif
251  MessageType			from = X_DEFAULT;
252  char				*s = NULL;
253
254  /* Setup defaults */
255  XkbGetRulesDflts(&g_winInfo.xkb);
256
257  /*
258   * Query the windows autorepeat settings and change the xserver defaults.
259   */
260  {
261    int kbd_delay;
262    DWORD kbd_speed;
263    if (SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &kbd_delay, 0) &&
264        SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &kbd_speed, 0))
265      {
266        switch (kbd_delay)
267          {
268            case 0:  g_winInfo.keyboard.delay = 250; break;
269            case 1:  g_winInfo.keyboard.delay = 500; break;
270            case 2:  g_winInfo.keyboard.delay = 750; break;
271            default:
272            case 3:  g_winInfo.keyboard.delay = 1000; break;
273          }
274        g_winInfo.keyboard.rate = (kbd_speed>0)?kbd_speed:1;
275        winMsgVerb(X_PROBED, 1, "Setting autorepeat to delay=%d, rate=%d\n",
276                g_winInfo.keyboard.delay, g_winInfo.keyboard.rate);
277      }
278  }
279
280
281  keyboardType = GetKeyboardType (0);
282  if (keyboardType > 0 && GetKeyboardLayoutName (layoutName))
283  {
284    WinKBLayoutPtr	pLayout;
285    Bool                bfound = FALSE;
286
287    if (! layoutNum)
288      layoutNum = strtoul (layoutName, (char **)NULL, 16);
289    if ((layoutNum & 0xffff) == 0x411) {
290        /* The japanese layouts know a lot of different IMEs which all have
291	   different layout numbers set. Map them to a single entry.
292	   Same might apply for chinese, korean and other symbol languages
293	   too */
294        layoutNum = (layoutNum & 0xffff);
295	if (keyboardType == 7)
296	  {
297	    /* Japanese layouts have problems with key event messages
298	       such as the lack of WM_KEYUP for Caps Lock key.
299	       Loading US layout fixes this problem. */
300	    if (LoadKeyboardLayout("00000409", KLF_ACTIVATE) != NULL)
301	      winMsg (X_INFO, "Loading US keyboard layout.\n");
302	    else
303	      winMsg (X_ERROR, "LoadKeyboardLayout failed.\n");
304	  }
305    }
306
307    /* Discover the friendly name of the current layout */
308    {
309      HKEY                regkey = NULL;
310      const char          regtempl[] = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
311      char                *regpath;
312      DWORD               namesize = sizeof(layoutFriendlyName);
313
314      regpath = malloc(sizeof(regtempl) + KL_NAMELENGTH + 1);
315      strcpy(regpath, regtempl);
316      strcat(regpath, layoutName);
317
318      if (!RegOpenKey(HKEY_LOCAL_MACHINE, regpath, &regkey))
319          RegQueryValueEx(regkey, "Layout Text", 0, NULL, layoutFriendlyName, &namesize);
320
321      /* Close registry key */
322      if (regkey)
323        RegCloseKey (regkey);
324      free(regpath);
325    }
326
327    winMsg (X_PROBED, "Windows keyboard layout: \"%s\" (%08x) \"%s\", type %d\n",
328            layoutName, layoutNum, layoutFriendlyName, keyboardType);
329
330    for (pLayout = winKBLayouts; pLayout->winlayout != -1; pLayout++)
331      {
332	if (pLayout->winlayout != layoutNum)
333	  continue;
334	if (pLayout->winkbtype > 0 && pLayout->winkbtype != keyboardType)
335	  continue;
336
337        bfound = TRUE;
338	winMsg (X_PROBED,
339		"Found matching XKB configuration \"%s\"\n",
340		pLayout->layoutname);
341
342        winMsg(X_PROBED,
343               "Model = \"%s\" Layout = \"%s\""
344               " Variant = \"%s\" Options = \"%s\"\n",
345               pLayout->xkbmodel ? pLayout->xkbmodel : "none",
346               pLayout->xkblayout ? pLayout->xkblayout : "none",
347               pLayout->xkbvariant ? pLayout->xkbvariant : "none",
348               pLayout->xkboptions ? pLayout->xkboptions : "none");
349
350	g_winInfo.xkb.model = pLayout->xkbmodel;
351	g_winInfo.xkb.layout = pLayout->xkblayout;
352	g_winInfo.xkb.variant = pLayout->xkbvariant;
353	g_winInfo.xkb.options = pLayout->xkboptions;
354
355
356	break;
357      }
358
359    if (!bfound)
360      {
361        winMsg (X_ERROR, "Keyboardlayout \"%s\" (%s) is unknown, using X server default layout\n", layoutFriendlyName, layoutName);
362      }
363  }
364
365  /* parse the configuration */
366#ifdef XWIN_XF86CONFIG
367  if (g_cmdline.keyboard)
368    kbdfrom = X_CMDLINE;
369
370  /*
371   * Until the layout code is finished, I search for the keyboard
372   * device and configure the server with it.
373   */
374
375  if (g_xf86configptr != NULL)
376    input_list = g_xf86configptr->conf_input_lst;
377
378  while (input_list != NULL)
379    {
380      if (winNameCompare (input_list->inp_driver, "keyboard") == 0)
381	{
382	  /* Check if device name matches requested name */
383	  if (g_cmdline.keyboard && winNameCompare (input_list->inp_identifier,
384						    g_cmdline.keyboard))
385	    continue;
386	  kbd = input_list;
387	}
388      input_list = input_list->list.next;
389    }
390
391  if (kbd != NULL)
392    {
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        {
400          if ((sscanf(s, "%ld %ld", &g_winInfo.keyboard.delay,
401                      &g_winInfo.keyboard.rate) != 2) ||
402                  (g_winInfo.keyboard.delay < 1) ||
403                  (g_winInfo.keyboard.rate == 0) ||
404                  (1000 / g_winInfo.keyboard.rate) < 1)
405            {
406              winErrorFVerb (2, "\"%s\" is not a valid AutoRepeat value", s);
407              free(s);
408              return FALSE;
409            }
410          free(s);
411          winMsg (X_CONFIG, "AutoRepeat: %ld %ld\n",
412                  g_winInfo.keyboard.delay, g_winInfo.keyboard.rate);
413        }
414#endif
415
416        s = NULL;
417        if (g_cmdline.xkbRules)
418          {
419            s = g_cmdline.xkbRules;
420            from = X_CMDLINE;
421          }
422#ifdef XWIN_XF86CONFIG
423        else
424          {
425            s = winSetStrOption (kbd->inp_option_lst, "XkbRules", NULL);
426            from = X_CONFIG;
427          }
428#endif
429        if (s)
430          {
431            g_winInfo.xkb.rules = NULL_IF_EMPTY (s);
432            winMsg (from, "XKB: rules: \"%s\"\n", s);
433	  }
434
435        s = NULL;
436        if (g_cmdline.xkbModel)
437          {
438            s = g_cmdline.xkbModel;
439            from = X_CMDLINE;
440          }
441#ifdef XWIN_XF86CONFIG
442        else
443          {
444            s = winSetStrOption (kbd->inp_option_lst, "XkbModel", NULL);
445            from = X_CONFIG;
446          }
447#endif
448        if (s)
449	  {
450	    g_winInfo.xkb.model = NULL_IF_EMPTY (s);
451	    winMsg (from, "XKB: model: \"%s\"\n", s);
452	  }
453
454        s = NULL;
455        if (g_cmdline.xkbLayout)
456          {
457            s = g_cmdline.xkbLayout;
458            from = X_CMDLINE;
459          }
460#ifdef XWIN_XF86CONFIG
461        else
462          {
463            s = winSetStrOption (kbd->inp_option_lst, "XkbLayout", NULL);
464            from = X_CONFIG;
465          }
466#endif
467        if (s)
468          {
469	    g_winInfo.xkb.layout = NULL_IF_EMPTY (s);
470	    winMsg (from, "XKB: layout: \"%s\"\n", s);
471	  }
472
473        s = NULL;
474        if (g_cmdline.xkbVariant)
475          {
476            s = g_cmdline.xkbVariant;
477            from = X_CMDLINE;
478          }
479#ifdef XWIN_XF86CONFIG
480        else
481          {
482            s = winSetStrOption (kbd->inp_option_lst, "XkbVariant", NULL);
483            from = X_CONFIG;
484          }
485#endif
486	if (s)
487	  {
488	    g_winInfo.xkb.variant = NULL_IF_EMPTY (s);
489	    winMsg (from, "XKB: variant: \"%s\"\n", s);
490	  }
491
492        s = NULL;
493        if (g_cmdline.xkbOptions)
494          {
495            s = g_cmdline.xkbOptions;
496            from = X_CMDLINE;
497          }
498#ifdef XWIN_XF86CONFIG
499        else
500          {
501            s = winSetStrOption (kbd->inp_option_lst, "XkbOptions", NULL);
502            from = X_CONFIG;
503          }
504#endif
505        if (s)
506	  {
507	    g_winInfo.xkb.options = NULL_IF_EMPTY (s);
508	    winMsg (from, "XKB: options: \"%s\"\n", s);
509	  }
510
511#ifdef XWIN_XF86CONFIG
512    }
513#endif
514
515  return TRUE;
516}
517
518
519#ifdef XWIN_XF86CONFIG
520Bool
521winConfigMouse (DeviceIntPtr pDevice)
522{
523  MessageType			mousefrom = X_CONFIG;
524
525  XF86ConfInputPtr		mouse = NULL;
526  XF86ConfInputPtr		input_list = NULL;
527
528  if (g_cmdline.mouse)
529    mousefrom = X_CMDLINE;
530
531  if (g_xf86configptr != NULL)
532    input_list = g_xf86configptr->conf_input_lst;
533
534  while (input_list != NULL)
535    {
536      if (winNameCompare (input_list->inp_driver, "mouse") == 0)
537	{
538	  /* Check if device name matches requested name */
539	  if (g_cmdline.mouse && winNameCompare (input_list->inp_identifier,
540						 g_cmdline.mouse))
541	    continue;
542	  mouse = input_list;
543	}
544      input_list = input_list->list.next;
545    }
546
547  if (mouse != NULL)
548    {
549      if (mouse->inp_identifier)
550	winMsg (mousefrom, "Using pointer \"%s\" as primary pointer\n",
551		mouse->inp_identifier);
552
553      g_winInfo.pointer.emulate3Buttons =
554	winSetBoolOption (mouse->inp_option_lst, "Emulate3Buttons", FALSE);
555      if (g_cmdline.emulate3buttons)
556	g_winInfo.pointer.emulate3Buttons = g_cmdline.emulate3buttons;
557
558      g_winInfo.pointer.emulate3Timeout =
559	winSetIntOption (mouse->inp_option_lst, "Emulate3Timeout", 50);
560      if (g_cmdline.emulate3timeout)
561	g_winInfo.pointer.emulate3Timeout = g_cmdline.emulate3timeout;
562    }
563  else
564    {
565      winMsg (X_ERROR, "No primary pointer configured\n");
566      winMsg (X_DEFAULT, "Using compiletime defaults for pointer\n");
567    }
568
569  return TRUE;
570}
571
572
573Bool
574winConfigFiles ()
575{
576  MessageType from;
577  XF86ConfFilesPtr filesptr = NULL;
578
579  /* set some shortcuts */
580  if (g_xf86configptr != NULL)
581    {
582      filesptr = g_xf86configptr->conf_files;
583    }
584
585
586  /* Fontpath */
587  from = X_DEFAULT;
588
589  if (g_cmdline.fontPath)
590    {
591      from = X_CMDLINE;
592      defaultFontPath = g_cmdline.fontPath;
593    }
594  else if (filesptr != NULL && filesptr->file_fontpath)
595    {
596      from = X_CONFIG;
597      defaultFontPath = strdup (filesptr->file_fontpath);
598    }
599  winMsg (from, "FontPath set to \"%s\"\n", defaultFontPath);
600
601  return TRUE;
602}
603#else
604Bool
605winConfigFiles (void)
606{
607  /* Fontpath */
608  if (g_cmdline.fontPath)
609    {
610      defaultFontPath = g_cmdline.fontPath;
611      winMsg (X_CMDLINE, "FontPath set to \"%s\"\n", defaultFontPath);
612    }
613
614  return TRUE;
615}
616#endif
617
618
619Bool
620winConfigOptions (void)
621{
622  return TRUE;
623}
624
625
626Bool
627winConfigScreens (void)
628{
629  return TRUE;
630}
631
632
633#ifdef XWIN_XF86CONFIG
634char *
635winSetStrOption (pointer optlist, const char *name, char *deflt)
636{
637  OptionInfoRec o;
638
639  o.name = name;
640  o.type = OPTV_STRING;
641  if (ParseOptionValue (-1, optlist, &o))
642    deflt = o.value.str;
643  if (deflt)
644    return strdup (deflt);
645  else
646    return NULL;
647}
648
649
650int
651winSetBoolOption (pointer optlist, const char *name, int deflt)
652{
653  OptionInfoRec o;
654
655  o.name = name;
656  o.type = OPTV_BOOLEAN;
657  if (ParseOptionValue (-1, optlist, &o))
658    deflt = o.value.bool;
659  return deflt;
660}
661
662
663int
664winSetIntOption (pointer optlist, const char *name, int deflt)
665{
666  OptionInfoRec o;
667
668  o.name = name;
669  o.type = OPTV_INTEGER;
670  if (ParseOptionValue (-1, optlist, &o))
671    deflt = o.value.num;
672  return deflt;
673}
674
675
676double
677winSetRealOption (pointer optlist, const char *name, double deflt)
678{
679  OptionInfoRec o;
680
681  o.name = name;
682  o.type = OPTV_REAL;
683  if (ParseOptionValue (-1, optlist, &o))
684    deflt = o.value.realnum;
685  return deflt;
686}
687
688double
689winSetPercentOption (pointer optlist, const char *name, double deflt)
690{
691  OptionInfoRec o;
692
693  o.name = name;
694  o.type = OPTV_PERCENT;
695  if (ParseOptionValue (-1, optlist, &o))
696    deflt = o.value.realnum;
697  return deflt;
698}
699#endif
700
701
702/*
703 * Compare two strings for equality. This is caseinsensitive  and
704 * The characters '_', ' ' (space) and '\t' (tab) are treated as
705 * not existing.
706 */
707
708int
709winNameCompare (const char *s1, const char *s2)
710{
711  char c1, c2;
712
713  if (!s1 || *s1 == 0)
714    {
715      if (!s2 || *s2 == 0)
716	return 0;
717      else
718	return 1;
719    }
720
721  while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
722    s1++;
723  while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
724    s2++;
725
726  c1 = (isupper ((int)*s1) ? tolower ((int)*s1) : *s1);
727  c2 = (isupper ((int)*s2) ? tolower ((int)*s2) : *s2);
728
729  while (c1 == c2)
730    {
731      if (c1 == 0)
732	return 0;
733      s1++;
734      s2++;
735
736      while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
737	s1++;
738      while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
739	s2++;
740
741      c1 = (isupper ((int)*s1) ? tolower ((int)*s1) : *s1);
742      c2 = (isupper ((int)*s2) ? tolower ((int)*s2) : *s2);
743    }
744  return c1 - c2;
745}
746
747
748#ifdef XWIN_XF86CONFIG
749/*
750 * Find the named option in the list.
751 * @return the pointer to the option record, or NULL if not found.
752 */
753
754XF86OptionPtr
755winFindOption (XF86OptionPtr list, const char *name)
756{
757  while (list)
758    {
759      if (winNameCompare (list->opt_name, name) == 0)
760	return list;
761      list = list->list.next;
762    }
763  return NULL;
764}
765
766
767/*
768 * Find the Value of an named option.
769 * @return The option value or NULL if not found.
770 */
771
772char *
773winFindOptionValue (XF86OptionPtr list, const char *name)
774{
775  list = winFindOption (list, name);
776  if (list)
777    {
778      if (list->opt_val)
779	return list->opt_val;
780      else
781	return "";
782    }
783  return NULL;
784}
785
786
787/*
788 * Parse the option.
789 */
790
791static Bool
792ParseOptionValue (int scrnIndex, pointer options, OptionInfoPtr p)
793{
794  char *s, *end;
795
796  if ((s = winFindOptionValue (options, p->name)) != NULL)
797    {
798      switch (p->type)
799	{
800	case OPTV_INTEGER:
801	  if (*s == '\0')
802	    {
803	      winDrvMsg (scrnIndex, X_WARNING,
804			 "Option \"%s\" requires an integer value\n",
805			 p->name);
806	      p->found = FALSE;
807	    }
808	  else
809	    {
810	      p->value.num = strtoul (s, &end, 0);
811	      if (*end == '\0')
812		{
813		  p->found = TRUE;
814		}
815	      else
816		{
817		  winDrvMsg (scrnIndex, X_WARNING,
818			     "Option \"%s\" requires an integer value\n",
819			     p->name);
820		  p->found = FALSE;
821		}
822	    }
823	  break;
824	case OPTV_STRING:
825	  if (*s == '\0')
826	    {
827	      winDrvMsg (scrnIndex, X_WARNING,
828			 "Option \"%s\" requires an string value\n", p->name);
829	      p->found = FALSE;
830	    }
831	  else
832	    {
833	      p->value.str = s;
834	      p->found = TRUE;
835	    }
836	  break;
837	case OPTV_ANYSTR:
838	  p->value.str = s;
839	  p->found = TRUE;
840	  break;
841	case OPTV_REAL:
842	  if (*s == '\0')
843	    {
844	      winDrvMsg (scrnIndex, X_WARNING,
845			 "Option \"%s\" requires a floating point value\n",
846			 p->name);
847	      p->found = FALSE;
848	    }
849	  else
850	    {
851	      p->value.realnum = strtod (s, &end);
852	      if (*end == '\0')
853		{
854		  p->found = TRUE;
855		}
856	      else
857		{
858		  winDrvMsg (scrnIndex, X_WARNING,
859			     "Option \"%s\" requires a floating point value\n",
860			     p->name);
861		  p->found = FALSE;
862		}
863	    }
864	  break;
865	case OPTV_BOOLEAN:
866	  if (GetBoolValue (p, s))
867	    {
868	      p->found = TRUE;
869	    }
870	  else
871	    {
872	      winDrvMsg (scrnIndex, X_WARNING,
873			 "Option \"%s\" requires a boolean value\n", p->name);
874	      p->found = FALSE;
875	    }
876	  break;
877	case OPTV_PERCENT:
878	  if (*s == '\0')
879	    {
880	      winDrvMsg (scrnIndex, X_WARNING,
881			 "Option \"%s\" requires a percent value\n",
882			 p->name);
883	      p->found = FALSE;
884	    }
885	  else
886	    {
887	       double percent = strtod (s, &end);
888
889	       if (end != s && winNameCompare (end, "%"))
890		 {
891		   p->found = TRUE;
892		   p->value.realnum = percent;
893		 }
894	       else
895		 {
896		   winDrvMsg (scrnIndex, X_WARNING,
897			      "Option \"%s\" requires a frequency value\n",
898			       p->name);
899		   p->found = FALSE;
900		 }
901	    }
902	case OPTV_FREQ:
903	  if (*s == '\0')
904	    {
905	      winDrvMsg (scrnIndex, X_WARNING,
906			 "Option \"%s\" requires a frequency value\n",
907			 p->name);
908	      p->found = FALSE;
909	    }
910	  else
911	    {
912	      double freq = strtod (s, &end);
913	      int units = 0;
914
915	      if (end != s)
916		{
917		  p->found = TRUE;
918		  if (!winNameCompare (end, "Hz"))
919		    units = 1;
920		  else if (!winNameCompare (end, "kHz") ||
921			   !winNameCompare (end, "k"))
922		    units = 1000;
923		  else if (!winNameCompare (end, "MHz") ||
924			   !winNameCompare (end, "M"))
925		    units = 1000000;
926		  else
927		    {
928		      winDrvMsg (scrnIndex, X_WARNING,
929				 "Option \"%s\" requires a frequency value\n",
930				 p->name);
931		      p->found = FALSE;
932		    }
933		  if (p->found)
934		    freq *= (double) units;
935		}
936	      else
937		{
938		  winDrvMsg (scrnIndex, X_WARNING,
939			     "Option \"%s\" requires a frequency value\n",
940			     p->name);
941		  p->found = FALSE;
942		}
943	      if (p->found)
944		{
945		  p->value.freq.freq = freq;
946		  p->value.freq.units = units;
947		}
948	    }
949	  break;
950	case OPTV_NONE:
951	  /* Should never get here */
952	  p->found = FALSE;
953	  break;
954	}
955      if (p->found)
956	{
957	  winDrvMsgVerb (scrnIndex, X_CONFIG, 2, "Option \"%s\"", p->name);
958	  if (!(p->type == OPTV_BOOLEAN && *s == 0))
959	    {
960	      winErrorFVerb (2, " \"%s\"", s);
961	    }
962	  winErrorFVerb (2, "\n");
963	}
964    }
965  else if (p->type == OPTV_BOOLEAN)
966    {
967      /* Look for matches with options with or without a "No" prefix. */
968      char *n, *newn;
969      OptionInfoRec opt;
970
971      n = winNormalizeName (p->name);
972      if (!n)
973	{
974	  p->found = FALSE;
975	  return FALSE;
976	}
977      if (strncmp (n, "no", 2) == 0)
978	{
979	  newn = n + 2;
980	}
981      else
982	{
983	  free (n);
984	  n = malloc (strlen (p->name) + 2 + 1);
985	  if (!n)
986	    {
987	      p->found = FALSE;
988	      return FALSE;
989	    }
990	  strcpy (n, "No");
991	  strcat (n, p->name);
992	  newn = n;
993	}
994      if ((s = winFindOptionValue (options, newn)) != NULL)
995	{
996	  if (GetBoolValue (&opt, s))
997	    {
998	      p->value.bool = !opt.value.bool;
999	      p->found = TRUE;
1000	    }
1001	  else
1002	    {
1003	      winDrvMsg (scrnIndex, X_WARNING,
1004			 "Option \"%s\" requires a boolean value\n", newn);
1005	      p->found = FALSE;
1006	    }
1007	}
1008      else
1009	{
1010	  p->found = FALSE;
1011	}
1012      if (p->found)
1013	{
1014	  winDrvMsgVerb (scrnIndex, X_CONFIG, 2, "Option \"%s\"", newn);
1015	  if (*s != 0)
1016	    {
1017	      winErrorFVerb (2, " \"%s\"", s);
1018	    }
1019	  winErrorFVerb (2, "\n");
1020	}
1021      free (n);
1022    }
1023  else
1024    {
1025      p->found = FALSE;
1026    }
1027  return p->found;
1028}
1029
1030
1031static Bool
1032configLayout (serverLayoutPtr servlayoutp, XF86ConfLayoutPtr conf_layout,
1033	      char *default_layout)
1034{
1035#if 0
1036#pragma warn UNIMPLEMENTED
1037#endif
1038  return TRUE;
1039}
1040
1041
1042static Bool
1043configImpliedLayout (serverLayoutPtr servlayoutp,
1044		     XF86ConfScreenPtr conf_screen)
1045{
1046#if 0
1047#pragma warn UNIMPLEMENTED
1048#endif
1049  return TRUE;
1050}
1051
1052
1053static Bool
1054GetBoolValue (OptionInfoPtr p, const char *s)
1055{
1056  if (*s == 0)
1057    {
1058      p->value.bool = TRUE;
1059    }
1060  else
1061    {
1062      if (winNameCompare (s, "1") == 0)
1063	p->value.bool = TRUE;
1064      else if (winNameCompare (s, "on") == 0)
1065	p->value.bool = TRUE;
1066      else if (winNameCompare (s, "true") == 0)
1067	p->value.bool = TRUE;
1068      else if (winNameCompare (s, "yes") == 0)
1069	p->value.bool = TRUE;
1070      else if (winNameCompare (s, "0") == 0)
1071	p->value.bool = FALSE;
1072      else if (winNameCompare (s, "off") == 0)
1073	p->value.bool = FALSE;
1074      else if (winNameCompare (s, "false") == 0)
1075	p->value.bool = FALSE;
1076      else if (winNameCompare (s, "no") == 0)
1077	p->value.bool = FALSE;
1078    }
1079  return TRUE;
1080}
1081#endif
1082
1083
1084char *
1085winNormalizeName (const char *s)
1086{
1087  char *ret, *q;
1088  const char *p;
1089
1090  if (s == NULL)
1091    return NULL;
1092
1093  ret = malloc (strlen (s) + 1);
1094  for (p = s, q = ret; *p != 0; p++)
1095    {
1096      switch (*p)
1097	{
1098	case '_':
1099	case ' ':
1100	case '\t':
1101	  continue;
1102	default:
1103	  if (isupper ((int)*p))
1104	    *q++ = tolower ((int)*p);
1105	  else
1106	    *q++ = *p;
1107	}
1108    }
1109  *q = '\0';
1110  return ret;
1111}
1112
1113