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