1706f2543Smrg/*
2706f2543Smrg * Copyright (c) 1998-2003 by The XFree86 Project, Inc.
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Software"),
6706f2543Smrg * to deal in the Software without restriction, including without limitation
7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, subject to the following conditions:
10706f2543Smrg *
11706f2543Smrg * The above copyright notice and this permission notice shall be included in
12706f2543Smrg * all copies or substantial portions of the Software.
13706f2543Smrg *
14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17706f2543Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20706f2543Smrg * OTHER DEALINGS IN THE SOFTWARE.
21706f2543Smrg *
22706f2543Smrg * Except as contained in this notice, the name of the copyright holder(s)
23706f2543Smrg * and author(s) shall not be used in advertising or otherwise to promote
24706f2543Smrg * the sale, use or other dealings in this Software without prior written
25706f2543Smrg * authorization from the copyright holder(s) and author(s).
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg/*
29706f2543Smrg * Author: David Dawes <dawes@xfree86.org>
30706f2543Smrg *
31706f2543Smrg * This file includes public option handling functions.
32706f2543Smrg */
33706f2543Smrg
34706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
35706f2543Smrg#include <xorg-config.h>
36706f2543Smrg#endif
37706f2543Smrg
38706f2543Smrg#include <stdlib.h>
39706f2543Smrg#include <ctype.h>
40706f2543Smrg#include <X11/X.h>
41706f2543Smrg#include "os.h"
42706f2543Smrg#include "xf86.h"
43706f2543Smrg#include "xf86Xinput.h"
44706f2543Smrg#include "xf86Optrec.h"
45706f2543Smrg#include "xf86Parser.h"
46706f2543Smrg
47706f2543Smrgstatic Bool ParseOptionValue(int scrnIndex, pointer options, OptionInfoPtr p,
48706f2543Smrg			     Bool markUsed);
49706f2543Smrg
50706f2543Smrg/*
51706f2543Smrg * xf86CollectOptions collects the options from each of the config file
52706f2543Smrg * sections used by the screen and puts the combined list in pScrn->options.
53706f2543Smrg * This function requires that the following have been initialised:
54706f2543Smrg *
55706f2543Smrg *	pScrn->confScreen
56706f2543Smrg *	pScrn->Entities[i]->device
57706f2543Smrg *	pScrn->display
58706f2543Smrg *	pScrn->monitor
59706f2543Smrg *
60706f2543Smrg * The extraOpts parameter may optionally contain a list of additional options
61706f2543Smrg * to include.
62706f2543Smrg *
63706f2543Smrg * The order of precedence for options is:
64706f2543Smrg *
65706f2543Smrg *   extraOpts, display, confScreen, monitor, device
66706f2543Smrg */
67706f2543Smrg
68706f2543Smrgvoid
69706f2543Smrgxf86CollectOptions(ScrnInfoPtr pScrn, pointer extraOpts)
70706f2543Smrg{
71706f2543Smrg    XF86OptionPtr tmp;
72706f2543Smrg    XF86OptionPtr extras = (XF86OptionPtr)extraOpts;
73706f2543Smrg    GDevPtr device;
74706f2543Smrg
75706f2543Smrg    int i;
76706f2543Smrg
77706f2543Smrg    pScrn->options = NULL;
78706f2543Smrg
79706f2543Smrg    for (i=pScrn->numEntities - 1; i >= 0; i--) {
80706f2543Smrg	device = xf86GetDevFromEntity(pScrn->entityList[i],
81706f2543Smrg					pScrn->entityInstanceList[i]);
82706f2543Smrg	if (device && device->options) {
83706f2543Smrg	    tmp = xf86optionListDup(device->options);
84706f2543Smrg	    if (pScrn->options)
85706f2543Smrg		xf86optionListMerge(pScrn->options,tmp);
86706f2543Smrg	    else
87706f2543Smrg		pScrn->options = tmp;
88706f2543Smrg	}
89706f2543Smrg    }
90706f2543Smrg    if (pScrn->monitor->options) {
91706f2543Smrg	tmp = xf86optionListDup(pScrn->monitor->options);
92706f2543Smrg	if (pScrn->options)
93706f2543Smrg	    pScrn->options = xf86optionListMerge(pScrn->options, tmp);
94706f2543Smrg	else
95706f2543Smrg	    pScrn->options = tmp;
96706f2543Smrg    }
97706f2543Smrg    if (pScrn->confScreen->options) {
98706f2543Smrg	tmp = xf86optionListDup(pScrn->confScreen->options);
99706f2543Smrg	if (pScrn->options)
100706f2543Smrg	    pScrn->options = xf86optionListMerge(pScrn->options, tmp);
101706f2543Smrg	else
102706f2543Smrg	    pScrn->options = tmp;
103706f2543Smrg    }
104706f2543Smrg    if (pScrn->display->options) {
105706f2543Smrg	tmp = xf86optionListDup(pScrn->display->options);
106706f2543Smrg	if (pScrn->options)
107706f2543Smrg	    pScrn->options = xf86optionListMerge(pScrn->options, tmp);
108706f2543Smrg	else
109706f2543Smrg	    pScrn->options = tmp;
110706f2543Smrg    }
111706f2543Smrg    if (extras) {
112706f2543Smrg	tmp = xf86optionListDup(extras);
113706f2543Smrg	if (pScrn->options)
114706f2543Smrg	    pScrn->options = xf86optionListMerge(pScrn->options, tmp);
115706f2543Smrg	else
116706f2543Smrg	    pScrn->options = tmp;
117706f2543Smrg    }
118706f2543Smrg}
119706f2543Smrg
120706f2543Smrg/*
121706f2543Smrg * xf86CollectInputOptions collects extra options for an InputDevice (other
122706f2543Smrg * than those added by the config backend).
123706f2543Smrg * The options are merged into the existing ones and thus take precedence
124706f2543Smrg * over the others.
125706f2543Smrg */
126706f2543Smrg
127706f2543Smrgvoid
128706f2543Smrgxf86CollectInputOptions(InputInfoPtr pInfo, const char **defaultOpts)
129706f2543Smrg{
130706f2543Smrg    if (defaultOpts) {
131706f2543Smrg	XF86OptionPtr tmp =xf86optionListCreate(defaultOpts, -1, 0);
132706f2543Smrg	if (pInfo->options)
133706f2543Smrg	    pInfo->options = xf86optionListMerge(tmp, pInfo->options);
134706f2543Smrg	else
135706f2543Smrg	    pInfo->options = tmp;
136706f2543Smrg    }
137706f2543Smrg}
138706f2543Smrg
139706f2543Smrg/**
140706f2543Smrg * Duplicate the option list passed in. The returned pointer will be a newly
141706f2543Smrg * allocated option list and must be freed by the caller.
142706f2543Smrg */
143706f2543Smrgpointer
144706f2543Smrgxf86OptionListDuplicate(pointer options)
145706f2543Smrg{
146706f2543Smrg    pointer o = NULL;
147706f2543Smrg
148706f2543Smrg    while (options)
149706f2543Smrg    {
150706f2543Smrg        o = xf86AddNewOption(o, xf86OptionName(options), xf86OptionValue(options));
151706f2543Smrg        options = xf86nextOption(options);
152706f2543Smrg    }
153706f2543Smrg
154706f2543Smrg    return o;
155706f2543Smrg}
156706f2543Smrg
157706f2543Smrg
158706f2543Smrg/* Created for new XInput stuff -- essentially extensions to the parser	*/
159706f2543Smrg
160706f2543Smrgstatic int
161706f2543SmrgLookupIntOption(pointer optlist, const char *name, int deflt, Bool markUsed)
162706f2543Smrg{
163706f2543Smrg    OptionInfoRec o;
164706f2543Smrg
165706f2543Smrg    o.name = name;
166706f2543Smrg    o.type = OPTV_INTEGER;
167706f2543Smrg    if (ParseOptionValue(-1, optlist, &o, markUsed))
168706f2543Smrg	deflt = o.value.num;
169706f2543Smrg    return deflt;
170706f2543Smrg}
171706f2543Smrg
172706f2543Smrg
173706f2543Smrgstatic double
174706f2543SmrgLookupRealOption(pointer optlist, const char *name, double deflt,
175706f2543Smrg		 Bool markUsed)
176706f2543Smrg{
177706f2543Smrg    OptionInfoRec o;
178706f2543Smrg
179706f2543Smrg    o.name = name;
180706f2543Smrg    o.type = OPTV_REAL;
181706f2543Smrg    if (ParseOptionValue(-1, optlist, &o, markUsed))
182706f2543Smrg	deflt = o.value.realnum;
183706f2543Smrg    return deflt;
184706f2543Smrg}
185706f2543Smrg
186706f2543Smrg
187706f2543Smrgstatic char *
188706f2543SmrgLookupStrOption(pointer optlist, const char *name, char *deflt, Bool markUsed)
189706f2543Smrg{
190706f2543Smrg    OptionInfoRec o;
191706f2543Smrg
192706f2543Smrg    o.name = name;
193706f2543Smrg    o.type = OPTV_STRING;
194706f2543Smrg    if (ParseOptionValue(-1, optlist, &o, markUsed))
195706f2543Smrg        deflt = o.value.str;
196706f2543Smrg    if (deflt)
197706f2543Smrg	return strdup(deflt);
198706f2543Smrg    else
199706f2543Smrg	return NULL;
200706f2543Smrg}
201706f2543Smrg
202706f2543Smrg
203706f2543Smrgstatic int
204706f2543SmrgLookupBoolOption(pointer optlist, const char *name, int deflt, Bool markUsed)
205706f2543Smrg{
206706f2543Smrg    OptionInfoRec o;
207706f2543Smrg
208706f2543Smrg    o.name = name;
209706f2543Smrg    o.type = OPTV_BOOLEAN;
210706f2543Smrg    if (ParseOptionValue(-1, optlist, &o, markUsed))
211706f2543Smrg	deflt = o.value.bool;
212706f2543Smrg    return deflt;
213706f2543Smrg}
214706f2543Smrg
215706f2543Smrgstatic double
216706f2543SmrgLookupPercentOption(pointer optlist, const char *name, double deflt, Bool markUsed)
217706f2543Smrg{
218706f2543Smrg    OptionInfoRec o;
219706f2543Smrg
220706f2543Smrg    o.name = name;
221706f2543Smrg    o.type = OPTV_PERCENT;
222706f2543Smrg    if (ParseOptionValue(-1, optlist, &o, markUsed))
223706f2543Smrg	deflt = o.value.realnum;
224706f2543Smrg    return deflt;
225706f2543Smrg}
226706f2543Smrg
227706f2543Smrg/* These xf86Set* functions are intended for use by non-screen specific code */
228706f2543Smrg
229706f2543Smrgint
230706f2543Smrgxf86SetIntOption(pointer optlist, const char *name, int deflt)
231706f2543Smrg{
232706f2543Smrg    return LookupIntOption(optlist, name, deflt, TRUE);
233706f2543Smrg}
234706f2543Smrg
235706f2543Smrg
236706f2543Smrgdouble
237706f2543Smrgxf86SetRealOption(pointer optlist, const char *name, double deflt)
238706f2543Smrg{
239706f2543Smrg    return LookupRealOption(optlist, name, deflt, TRUE);
240706f2543Smrg}
241706f2543Smrg
242706f2543Smrg
243706f2543Smrgchar *
244706f2543Smrgxf86SetStrOption(pointer optlist, const char *name, char *deflt)
245706f2543Smrg{
246706f2543Smrg    return LookupStrOption(optlist, name, deflt, TRUE);
247706f2543Smrg}
248706f2543Smrg
249706f2543Smrg
250706f2543Smrgint
251706f2543Smrgxf86SetBoolOption(pointer optlist, const char *name, int deflt)
252706f2543Smrg{
253706f2543Smrg    return LookupBoolOption(optlist, name, deflt, TRUE);
254706f2543Smrg}
255706f2543Smrg
256706f2543Smrgdouble
257706f2543Smrgxf86SetPercentOption(pointer optlist, const char *name, double deflt)
258706f2543Smrg{
259706f2543Smrg    return LookupPercentOption(optlist, name, deflt, TRUE);
260706f2543Smrg}
261706f2543Smrg
262706f2543Smrg/*
263706f2543Smrg * These are like the Set*Option functions, but they don't mark the options
264706f2543Smrg * as used.
265706f2543Smrg */
266706f2543Smrgint
267706f2543Smrgxf86CheckIntOption(pointer optlist, const char *name, int deflt)
268706f2543Smrg{
269706f2543Smrg    return LookupIntOption(optlist, name, deflt, FALSE);
270706f2543Smrg}
271706f2543Smrg
272706f2543Smrg
273706f2543Smrgdouble
274706f2543Smrgxf86CheckRealOption(pointer optlist, const char *name, double deflt)
275706f2543Smrg{
276706f2543Smrg    return LookupRealOption(optlist, name, deflt, FALSE);
277706f2543Smrg}
278706f2543Smrg
279706f2543Smrg
280706f2543Smrgchar *
281706f2543Smrgxf86CheckStrOption(pointer optlist, const char *name, char *deflt)
282706f2543Smrg{
283706f2543Smrg    return LookupStrOption(optlist, name, deflt, FALSE);
284706f2543Smrg}
285706f2543Smrg
286706f2543Smrg
287706f2543Smrgint
288706f2543Smrgxf86CheckBoolOption(pointer optlist, const char *name, int deflt)
289706f2543Smrg{
290706f2543Smrg    return LookupBoolOption(optlist, name, deflt, FALSE);
291706f2543Smrg}
292706f2543Smrg
293706f2543Smrg
294706f2543Smrgdouble
295706f2543Smrgxf86CheckPercentOption(pointer optlist, const char *name, double deflt)
296706f2543Smrg{
297706f2543Smrg    return LookupPercentOption(optlist, name, deflt, FALSE);
298706f2543Smrg}
299706f2543Smrg/*
300706f2543Smrg * addNewOption() has the required property of replacing the option value
301706f2543Smrg * if the option is already present.
302706f2543Smrg */
303706f2543Smrgpointer
304706f2543Smrgxf86ReplaceIntOption(pointer optlist, const char *name, const int val)
305706f2543Smrg{
306706f2543Smrg    char tmp[16];
307706f2543Smrg    sprintf(tmp,"%i",val);
308706f2543Smrg    return xf86AddNewOption(optlist,name,tmp);
309706f2543Smrg}
310706f2543Smrg
311706f2543Smrgpointer
312706f2543Smrgxf86ReplaceRealOption(pointer optlist, const char *name, const double val)
313706f2543Smrg{
314706f2543Smrg    char tmp[32];
315706f2543Smrg    snprintf(tmp,32,"%f",val);
316706f2543Smrg    return xf86AddNewOption(optlist,name,tmp);
317706f2543Smrg}
318706f2543Smrg
319706f2543Smrgpointer
320706f2543Smrgxf86ReplaceBoolOption(pointer optlist, const char *name, const Bool val)
321706f2543Smrg{
322706f2543Smrg    return xf86AddNewOption(optlist,name,val?"True":"False");
323706f2543Smrg}
324706f2543Smrg
325706f2543Smrgpointer
326706f2543Smrgxf86ReplacePercentOption(pointer optlist, const char *name, const double val)
327706f2543Smrg{
328706f2543Smrg    char tmp[16];
329706f2543Smrg    sprintf(tmp, "%lf%%", val);
330706f2543Smrg    return xf86AddNewOption(optlist,name,tmp);
331706f2543Smrg}
332706f2543Smrg
333706f2543Smrgpointer
334706f2543Smrgxf86ReplaceStrOption(pointer optlist, const char *name, const char* val)
335706f2543Smrg{
336706f2543Smrg      return xf86AddNewOption(optlist,name,val);
337706f2543Smrg}
338706f2543Smrg
339706f2543Smrgpointer
340706f2543Smrgxf86AddNewOption(pointer head, const char *name, const char *val)
341706f2543Smrg{
342706f2543Smrg    /* XXX These should actually be allocated in the parser library. */
343706f2543Smrg    char *tmp = val ? strdup(val) : NULL;
344706f2543Smrg    char *tmp_name = strdup(name);
345706f2543Smrg
346706f2543Smrg    return xf86addNewOption(head, tmp_name, tmp);
347706f2543Smrg}
348706f2543Smrg
349706f2543Smrg
350706f2543Smrgpointer
351706f2543Smrgxf86NewOption(char *name, char *value)
352706f2543Smrg{
353706f2543Smrg    return xf86newOption(name, value);
354706f2543Smrg}
355706f2543Smrg
356706f2543Smrg
357706f2543Smrgpointer
358706f2543Smrgxf86NextOption(pointer list)
359706f2543Smrg{
360706f2543Smrg    return xf86nextOption(list);
361706f2543Smrg}
362706f2543Smrg
363706f2543Smrgpointer
364706f2543Smrgxf86OptionListCreate(const char **options, int count, int used)
365706f2543Smrg{
366706f2543Smrg	return xf86optionListCreate(options, count, used);
367706f2543Smrg}
368706f2543Smrg
369706f2543Smrgpointer
370706f2543Smrgxf86OptionListMerge(pointer head, pointer tail)
371706f2543Smrg{
372706f2543Smrg	return xf86optionListMerge(head, tail);
373706f2543Smrg}
374706f2543Smrg
375706f2543Smrgvoid
376706f2543Smrgxf86OptionListFree(pointer opt)
377706f2543Smrg{
378706f2543Smrg	xf86optionListFree(opt);
379706f2543Smrg}
380706f2543Smrg
381706f2543Smrgchar *
382706f2543Smrgxf86OptionName(pointer opt)
383706f2543Smrg{
384706f2543Smrg	return xf86optionName(opt);
385706f2543Smrg}
386706f2543Smrg
387706f2543Smrgchar *
388706f2543Smrgxf86OptionValue(pointer opt)
389706f2543Smrg{
390706f2543Smrg	return xf86optionValue(opt);
391706f2543Smrg}
392706f2543Smrg
393706f2543Smrgvoid
394706f2543Smrgxf86OptionListReport(pointer parm)
395706f2543Smrg{
396706f2543Smrg    XF86OptionPtr opts = parm;
397706f2543Smrg
398706f2543Smrg    while(opts) {
399706f2543Smrg	if (xf86optionValue(opts))
400706f2543Smrg	    xf86ErrorFVerb(5, "\tOption \"%s\" \"%s\"\n",
401706f2543Smrg			    xf86optionName(opts), xf86optionValue(opts));
402706f2543Smrg	else
403706f2543Smrg	    xf86ErrorFVerb( 5, "\tOption \"%s\"\n", xf86optionName(opts));
404706f2543Smrg	opts = xf86nextOption(opts);
405706f2543Smrg    }
406706f2543Smrg}
407706f2543Smrg
408706f2543Smrg/* End of XInput-caused section	*/
409706f2543Smrg
410706f2543Smrgpointer
411706f2543Smrgxf86FindOption(pointer options, const char *name)
412706f2543Smrg{
413706f2543Smrg    return xf86findOption(options, name);
414706f2543Smrg}
415706f2543Smrg
416706f2543Smrg
417706f2543Smrgchar *
418706f2543Smrgxf86FindOptionValue(pointer options, const char *name)
419706f2543Smrg{
420706f2543Smrg    return xf86findOptionValue(options, name);
421706f2543Smrg}
422706f2543Smrg
423706f2543Smrg
424706f2543Smrgvoid
425706f2543Smrgxf86MarkOptionUsed(pointer option)
426706f2543Smrg{
427706f2543Smrg    if (option != NULL)
428706f2543Smrg	((XF86OptionPtr)option)->opt_used = TRUE;
429706f2543Smrg}
430706f2543Smrg
431706f2543Smrg
432706f2543Smrgvoid
433706f2543Smrgxf86MarkOptionUsedByName(pointer options, const char *name)
434706f2543Smrg{
435706f2543Smrg    XF86OptionPtr opt;
436706f2543Smrg
437706f2543Smrg    opt = xf86findOption(options, name);
438706f2543Smrg    if (opt != NULL)
439706f2543Smrg	opt->opt_used = TRUE;
440706f2543Smrg}
441706f2543Smrg
442706f2543SmrgBool
443706f2543Smrgxf86CheckIfOptionUsed(pointer option)
444706f2543Smrg{
445706f2543Smrg    if (option != NULL)
446706f2543Smrg	return ((XF86OptionPtr)option)->opt_used;
447706f2543Smrg    else
448706f2543Smrg	return FALSE;
449706f2543Smrg}
450706f2543Smrg
451706f2543SmrgBool
452706f2543Smrgxf86CheckIfOptionUsedByName(pointer options, const char *name)
453706f2543Smrg{
454706f2543Smrg    XF86OptionPtr opt;
455706f2543Smrg
456706f2543Smrg    opt = xf86findOption(options, name);
457706f2543Smrg    if (opt != NULL)
458706f2543Smrg	return opt->opt_used;
459706f2543Smrg    else
460706f2543Smrg	return FALSE;
461706f2543Smrg}
462706f2543Smrg
463706f2543Smrgvoid
464706f2543Smrgxf86ShowUnusedOptions(int scrnIndex, pointer options)
465706f2543Smrg{
466706f2543Smrg    XF86OptionPtr opt = options;
467706f2543Smrg
468706f2543Smrg    while (opt) {
469706f2543Smrg	if (opt->opt_name && !opt->opt_used) {
470706f2543Smrg	    xf86DrvMsg(scrnIndex, X_WARNING, "Option \"%s\" is not used\n",
471706f2543Smrg			opt->opt_name);
472706f2543Smrg	}
473706f2543Smrg	opt = opt->list.next;
474706f2543Smrg    }
475706f2543Smrg}
476706f2543Smrg
477706f2543Smrg
478706f2543Smrgstatic Bool
479706f2543SmrgGetBoolValue(OptionInfoPtr p, const char *s)
480706f2543Smrg{
481706f2543Smrg    return xf86getBoolValue(&p->value.bool, s);
482706f2543Smrg}
483706f2543Smrg
484706f2543Smrgstatic Bool
485706f2543SmrgParseOptionValue(int scrnIndex, pointer options, OptionInfoPtr p,
486706f2543Smrg		 Bool markUsed)
487706f2543Smrg{
488706f2543Smrg    char *s, *end;
489706f2543Smrg    Bool wasUsed = FALSE;
490706f2543Smrg
491706f2543Smrg    if ((s = xf86findOptionValue(options, p->name)) != NULL) {
492706f2543Smrg	if (markUsed) {
493706f2543Smrg	    wasUsed = xf86CheckIfOptionUsedByName(options, p->name);
494706f2543Smrg	    xf86MarkOptionUsedByName(options, p->name);
495706f2543Smrg	}
496706f2543Smrg	switch (p->type) {
497706f2543Smrg	case OPTV_INTEGER:
498706f2543Smrg	    if (*s == '\0') {
499706f2543Smrg		if (markUsed) {
500706f2543Smrg		    xf86DrvMsg(scrnIndex, X_WARNING,
501706f2543Smrg			       "Option \"%s\" requires an integer value\n",
502706f2543Smrg			       p->name);
503706f2543Smrg		}
504706f2543Smrg		p->found = FALSE;
505706f2543Smrg	    } else {
506706f2543Smrg		p->value.num = strtoul(s, &end, 0);
507706f2543Smrg		if (*end == '\0') {
508706f2543Smrg		    p->found = TRUE;
509706f2543Smrg		} else {
510706f2543Smrg		    if (markUsed) {
511706f2543Smrg			xf86DrvMsg(scrnIndex, X_WARNING,
512706f2543Smrg				   "Option \"%s\" requires an integer value\n",
513706f2543Smrg				    p->name);
514706f2543Smrg		    }
515706f2543Smrg		    p->found = FALSE;
516706f2543Smrg		}
517706f2543Smrg	    }
518706f2543Smrg	    break;
519706f2543Smrg	case OPTV_STRING:
520706f2543Smrg	    if (*s == '\0') {
521706f2543Smrg		if (markUsed) {
522706f2543Smrg		    xf86DrvMsg(scrnIndex, X_WARNING,
523706f2543Smrg			       "Option \"%s\" requires an string value\n",
524706f2543Smrg			       p->name);
525706f2543Smrg		}
526706f2543Smrg		p->found = FALSE;
527706f2543Smrg	    } else {
528706f2543Smrg		p->value.str = s;
529706f2543Smrg		p->found = TRUE;
530706f2543Smrg	    }
531706f2543Smrg	    break;
532706f2543Smrg	case OPTV_ANYSTR:
533706f2543Smrg	    p->value.str = s;
534706f2543Smrg	    p->found = TRUE;
535706f2543Smrg	    break;
536706f2543Smrg	case OPTV_REAL:
537706f2543Smrg	    if (*s == '\0') {
538706f2543Smrg		if (markUsed) {
539706f2543Smrg		    xf86DrvMsg(scrnIndex, X_WARNING,
540706f2543Smrg			       "Option \"%s\" requires a floating point "
541706f2543Smrg			       "value\n", p->name);
542706f2543Smrg		}
543706f2543Smrg		p->found = FALSE;
544706f2543Smrg	    } else {
545706f2543Smrg		p->value.realnum = strtod(s, &end);
546706f2543Smrg		if (*end == '\0') {
547706f2543Smrg		    p->found = TRUE;
548706f2543Smrg		} else {
549706f2543Smrg		    if (markUsed) {
550706f2543Smrg			xf86DrvMsg(scrnIndex, X_WARNING,
551706f2543Smrg				"Option \"%s\" requires a floating point "
552706f2543Smrg				"value\n", p->name);
553706f2543Smrg		    }
554706f2543Smrg		    p->found = FALSE;
555706f2543Smrg		}
556706f2543Smrg	    }
557706f2543Smrg	    break;
558706f2543Smrg	case OPTV_BOOLEAN:
559706f2543Smrg	    if (GetBoolValue(p, s)) {
560706f2543Smrg		p->found = TRUE;
561706f2543Smrg	    } else {
562706f2543Smrg		if (markUsed) {
563706f2543Smrg		    xf86DrvMsg(scrnIndex, X_WARNING,
564706f2543Smrg			       "Option \"%s\" requires a boolean value\n",
565706f2543Smrg			       p->name);
566706f2543Smrg		}
567706f2543Smrg		p->found = FALSE;
568706f2543Smrg	    }
569706f2543Smrg	    break;
570706f2543Smrg	case OPTV_PERCENT:
571706f2543Smrg	    {
572706f2543Smrg		char tmp = 0;
573706f2543Smrg		/* awkward match, but %% doesn't increase the match counter,
574706f2543Smrg		 * hence 100 looks the same as 100% to the caller of sccanf
575706f2543Smrg		 */
576706f2543Smrg		if (sscanf(s, "%lf%c", &p->value.realnum, &tmp) != 2 || tmp != '%') {
577706f2543Smrg		    if (markUsed) {
578706f2543Smrg			xf86DrvMsg(scrnIndex, X_WARNING,
579706f2543Smrg			       "Option \"%s\" requires a percent value\n", p->name);
580706f2543Smrg		    }
581706f2543Smrg		    p->found = FALSE;
582706f2543Smrg		} else {
583706f2543Smrg		    p->found = TRUE;
584706f2543Smrg		}
585706f2543Smrg	    }
586706f2543Smrg	    break;
587706f2543Smrg	case OPTV_FREQ:
588706f2543Smrg	    if (*s == '\0') {
589706f2543Smrg		if (markUsed) {
590706f2543Smrg		    xf86DrvMsg(scrnIndex, X_WARNING,
591706f2543Smrg			       "Option \"%s\" requires a frequency value\n",
592706f2543Smrg			       p->name);
593706f2543Smrg		}
594706f2543Smrg		p->found = FALSE;
595706f2543Smrg	    } else {
596706f2543Smrg		double freq = strtod(s, &end);
597706f2543Smrg		int    units = 0;
598706f2543Smrg
599706f2543Smrg		if (end != s) {
600706f2543Smrg		    p->found = TRUE;
601706f2543Smrg		    if (!xf86NameCmp(end, "Hz"))
602706f2543Smrg			units = 1;
603706f2543Smrg		    else if (!xf86NameCmp(end, "kHz") ||
604706f2543Smrg			     !xf86NameCmp(end, "k"))
605706f2543Smrg			units = 1000;
606706f2543Smrg		    else if (!xf86NameCmp(end, "MHz") ||
607706f2543Smrg			     !xf86NameCmp(end, "M"))
608706f2543Smrg			units = 1000000;
609706f2543Smrg		    else {
610706f2543Smrg			if (markUsed) {
611706f2543Smrg			    xf86DrvMsg(scrnIndex, X_WARNING,
612706f2543Smrg				"Option \"%s\" requires a frequency value\n",
613706f2543Smrg				p->name);
614706f2543Smrg			}
615706f2543Smrg			p->found = FALSE;
616706f2543Smrg		    }
617706f2543Smrg		    if (p->found)
618706f2543Smrg			freq *= (double)units;
619706f2543Smrg		} else {
620706f2543Smrg		    if (markUsed) {
621706f2543Smrg			xf86DrvMsg(scrnIndex, X_WARNING,
622706f2543Smrg				"Option \"%s\" requires a frequency value\n",
623706f2543Smrg				p->name);
624706f2543Smrg		    }
625706f2543Smrg		    p->found = FALSE;
626706f2543Smrg		}
627706f2543Smrg		if (p->found) {
628706f2543Smrg		    p->value.freq.freq = freq;
629706f2543Smrg		    p->value.freq.units = units;
630706f2543Smrg		}
631706f2543Smrg	    }
632706f2543Smrg	    break;
633706f2543Smrg	case OPTV_NONE:
634706f2543Smrg	    /* Should never get here */
635706f2543Smrg	    p->found = FALSE;
636706f2543Smrg	    break;
637706f2543Smrg	}
638706f2543Smrg	if (p->found && markUsed) {
639706f2543Smrg	    int verb = 2;
640706f2543Smrg	    if (wasUsed)
641706f2543Smrg		verb = 4;
642706f2543Smrg	    xf86DrvMsgVerb(scrnIndex, X_CONFIG, verb, "Option \"%s\"", p->name);
643706f2543Smrg	    if (!(p->type == OPTV_BOOLEAN && *s == 0)) {
644706f2543Smrg		xf86ErrorFVerb(verb, " \"%s\"", s);
645706f2543Smrg	    }
646706f2543Smrg	    xf86ErrorFVerb(verb, "\n");
647706f2543Smrg	}
648706f2543Smrg    } else if (p->type == OPTV_BOOLEAN) {
649706f2543Smrg	/* Look for matches with options with or without a "No" prefix. */
650706f2543Smrg	char *n, *newn;
651706f2543Smrg	OptionInfoRec opt;
652706f2543Smrg
653706f2543Smrg	n = xf86NormalizeName(p->name);
654706f2543Smrg	if (!n) {
655706f2543Smrg	    p->found = FALSE;
656706f2543Smrg	    return FALSE;
657706f2543Smrg	}
658706f2543Smrg	if (strncmp(n, "no", 2) == 0) {
659706f2543Smrg	    newn = n + 2;
660706f2543Smrg	} else {
661706f2543Smrg	    free(n);
662706f2543Smrg	    if (asprintf(&n, "No%s", p->name) == -1) {
663706f2543Smrg		p->found = FALSE;
664706f2543Smrg		return FALSE;
665706f2543Smrg	    }
666706f2543Smrg	    newn = n;
667706f2543Smrg	}
668706f2543Smrg	if ((s = xf86findOptionValue(options, newn)) != NULL) {
669706f2543Smrg	    if (markUsed)
670706f2543Smrg		xf86MarkOptionUsedByName(options, newn);
671706f2543Smrg	    if (GetBoolValue(&opt, s)) {
672706f2543Smrg		p->value.bool = !opt.value.bool;
673706f2543Smrg		p->found = TRUE;
674706f2543Smrg	    } else {
675706f2543Smrg		xf86DrvMsg(scrnIndex, X_WARNING,
676706f2543Smrg			   "Option \"%s\" requires a boolean value\n", newn);
677706f2543Smrg		p->found = FALSE;
678706f2543Smrg	    }
679706f2543Smrg	} else {
680706f2543Smrg	    p->found = FALSE;
681706f2543Smrg	}
682706f2543Smrg	if (p->found && markUsed) {
683706f2543Smrg	    xf86DrvMsgVerb(scrnIndex, X_CONFIG, 2, "Option \"%s\"", newn);
684706f2543Smrg	    if (*s != 0) {
685706f2543Smrg		xf86ErrorFVerb(2, " \"%s\"", s);
686706f2543Smrg	    }
687706f2543Smrg	    xf86ErrorFVerb(2, "\n");
688706f2543Smrg	}
689706f2543Smrg	free(n);
690706f2543Smrg    } else {
691706f2543Smrg	p->found = FALSE;
692706f2543Smrg    }
693706f2543Smrg    return p->found;
694706f2543Smrg}
695706f2543Smrg
696706f2543Smrg
697706f2543Smrgvoid
698706f2543Smrgxf86ProcessOptions(int scrnIndex, pointer options, OptionInfoPtr optinfo)
699706f2543Smrg{
700706f2543Smrg    OptionInfoPtr p;
701706f2543Smrg
702706f2543Smrg    for (p = optinfo; p->name != NULL; p++) {
703706f2543Smrg	ParseOptionValue(scrnIndex, options, p, TRUE);
704706f2543Smrg    }
705706f2543Smrg}
706706f2543Smrg
707706f2543Smrg
708706f2543SmrgOptionInfoPtr
709706f2543Smrgxf86TokenToOptinfo(const OptionInfoRec *table, int token)
710706f2543Smrg{
711706f2543Smrg    const OptionInfoRec *p, *match = NULL, *set = NULL;
712706f2543Smrg
713706f2543Smrg    if (!table) {
714706f2543Smrg	ErrorF("xf86TokenToOptinfo: table is NULL\n");
715706f2543Smrg	return NULL;
716706f2543Smrg    }
717706f2543Smrg
718706f2543Smrg    for (p = table; p->token >= 0; p++) {
719706f2543Smrg	if (p->token == token) {
720706f2543Smrg	    match = p;
721706f2543Smrg	    if (p->found)
722706f2543Smrg		set = p;
723706f2543Smrg	}
724706f2543Smrg    }
725706f2543Smrg
726706f2543Smrg    if (set)
727706f2543Smrg	return (OptionInfoPtr)set;
728706f2543Smrg    else if (match)
729706f2543Smrg	return (OptionInfoPtr)match;
730706f2543Smrg    else
731706f2543Smrg	return NULL;
732706f2543Smrg}
733706f2543Smrg
734706f2543Smrg
735706f2543Smrgconst char *
736706f2543Smrgxf86TokenToOptName(const OptionInfoRec *table, int token)
737706f2543Smrg{
738706f2543Smrg    const OptionInfoRec *p;
739706f2543Smrg
740706f2543Smrg    p = xf86TokenToOptinfo(table, token);
741706f2543Smrg    return p->name;
742706f2543Smrg}
743706f2543Smrg
744706f2543Smrg
745706f2543SmrgBool
746706f2543Smrgxf86IsOptionSet(const OptionInfoRec *table, int token)
747706f2543Smrg{
748706f2543Smrg    OptionInfoPtr p;
749706f2543Smrg
750706f2543Smrg    p = xf86TokenToOptinfo(table, token);
751706f2543Smrg    return p && p->found;
752706f2543Smrg}
753706f2543Smrg
754706f2543Smrg
755706f2543Smrgchar *
756706f2543Smrgxf86GetOptValString(const OptionInfoRec *table, int token)
757706f2543Smrg{
758706f2543Smrg    OptionInfoPtr p;
759706f2543Smrg
760706f2543Smrg    p = xf86TokenToOptinfo(table, token);
761706f2543Smrg    if (p && p->found)
762706f2543Smrg	return p->value.str;
763706f2543Smrg    else
764706f2543Smrg	return NULL;
765706f2543Smrg}
766706f2543Smrg
767706f2543Smrg
768706f2543SmrgBool
769706f2543Smrgxf86GetOptValInteger(const OptionInfoRec *table, int token, int *value)
770706f2543Smrg{
771706f2543Smrg    OptionInfoPtr p;
772706f2543Smrg
773706f2543Smrg    p = xf86TokenToOptinfo(table, token);
774706f2543Smrg    if (p && p->found) {
775706f2543Smrg	*value = p->value.num;
776706f2543Smrg	return TRUE;
777706f2543Smrg    } else
778706f2543Smrg	return FALSE;
779706f2543Smrg}
780706f2543Smrg
781706f2543Smrg
782706f2543SmrgBool
783706f2543Smrgxf86GetOptValULong(const OptionInfoRec *table, int token, unsigned long *value)
784706f2543Smrg{
785706f2543Smrg    OptionInfoPtr p;
786706f2543Smrg
787706f2543Smrg    p = xf86TokenToOptinfo(table, token);
788706f2543Smrg    if (p && p->found) {
789706f2543Smrg	*value = p->value.num;
790706f2543Smrg	return TRUE;
791706f2543Smrg    } else
792706f2543Smrg	return FALSE;
793706f2543Smrg}
794706f2543Smrg
795706f2543Smrg
796706f2543SmrgBool
797706f2543Smrgxf86GetOptValReal(const OptionInfoRec *table, int token, double *value)
798706f2543Smrg{
799706f2543Smrg    OptionInfoPtr p;
800706f2543Smrg
801706f2543Smrg    p = xf86TokenToOptinfo(table, token);
802706f2543Smrg    if (p && p->found) {
803706f2543Smrg	*value = p->value.realnum;
804706f2543Smrg	return TRUE;
805706f2543Smrg    } else
806706f2543Smrg	return FALSE;
807706f2543Smrg}
808706f2543Smrg
809706f2543Smrg
810706f2543SmrgBool
811706f2543Smrgxf86GetOptValFreq(const OptionInfoRec *table, int token,
812706f2543Smrg		  OptFreqUnits expectedUnits, double *value)
813706f2543Smrg{
814706f2543Smrg    OptionInfoPtr p;
815706f2543Smrg
816706f2543Smrg    p = xf86TokenToOptinfo(table, token);
817706f2543Smrg    if (p && p->found) {
818706f2543Smrg	if (p->value.freq.units > 0) {
819706f2543Smrg	    /* Units give, so the scaling is known. */
820706f2543Smrg	    switch (expectedUnits) {
821706f2543Smrg	    case OPTUNITS_HZ:
822706f2543Smrg		*value = p->value.freq.freq;
823706f2543Smrg		break;
824706f2543Smrg	    case OPTUNITS_KHZ:
825706f2543Smrg		*value = p->value.freq.freq / 1000.0;
826706f2543Smrg		break;
827706f2543Smrg	    case OPTUNITS_MHZ:
828706f2543Smrg		*value = p->value.freq.freq / 1000000.0;
829706f2543Smrg		break;
830706f2543Smrg	    }
831706f2543Smrg	} else {
832706f2543Smrg	    /* No units given, so try to guess the scaling. */
833706f2543Smrg	    switch (expectedUnits) {
834706f2543Smrg	    case OPTUNITS_HZ:
835706f2543Smrg		*value = p->value.freq.freq;
836706f2543Smrg		break;
837706f2543Smrg	    case OPTUNITS_KHZ:
838706f2543Smrg		if (p->value.freq.freq > 1000.0)
839706f2543Smrg		    *value = p->value.freq.freq / 1000.0;
840706f2543Smrg		else
841706f2543Smrg		    *value = p->value.freq.freq;
842706f2543Smrg		break;
843706f2543Smrg	    case OPTUNITS_MHZ:
844706f2543Smrg		if (p->value.freq.freq > 1000000.0)
845706f2543Smrg		    *value = p->value.freq.freq / 1000000.0;
846706f2543Smrg		else if (p->value.freq.freq > 1000.0)
847706f2543Smrg		    *value = p->value.freq.freq / 1000.0;
848706f2543Smrg		else
849706f2543Smrg		    *value = p->value.freq.freq;
850706f2543Smrg	    }
851706f2543Smrg	}
852706f2543Smrg	return TRUE;
853706f2543Smrg    } else
854706f2543Smrg	return FALSE;
855706f2543Smrg}
856706f2543Smrg
857706f2543Smrg
858706f2543SmrgBool
859706f2543Smrgxf86GetOptValBool(const OptionInfoRec *table, int token, Bool *value)
860706f2543Smrg{
861706f2543Smrg    OptionInfoPtr p;
862706f2543Smrg
863706f2543Smrg    p = xf86TokenToOptinfo(table, token);
864706f2543Smrg    if (p && p->found) {
865706f2543Smrg	*value = p->value.bool;
866706f2543Smrg	return TRUE;
867706f2543Smrg    } else
868706f2543Smrg	return FALSE;
869706f2543Smrg}
870706f2543Smrg
871706f2543Smrg
872706f2543SmrgBool
873706f2543Smrgxf86ReturnOptValBool(const OptionInfoRec *table, int token, Bool def)
874706f2543Smrg{
875706f2543Smrg    OptionInfoPtr p;
876706f2543Smrg
877706f2543Smrg    p = xf86TokenToOptinfo(table, token);
878706f2543Smrg    if (p && p->found) {
879706f2543Smrg	return p->value.bool;
880706f2543Smrg    } else
881706f2543Smrg	return def;
882706f2543Smrg}
883706f2543Smrg
884706f2543Smrg
885706f2543Smrgint
886706f2543Smrgxf86NameCmp(const char *s1, const char *s2)
887706f2543Smrg{
888706f2543Smrg    return xf86nameCompare(s1, s2);
889706f2543Smrg}
890706f2543Smrg
891706f2543Smrgchar *
892706f2543Smrgxf86NormalizeName(const char *s)
893706f2543Smrg{
894706f2543Smrg    char *ret, *q;
895706f2543Smrg    const char *p;
896706f2543Smrg
897706f2543Smrg    if (s == NULL)
898706f2543Smrg	return NULL;
899706f2543Smrg
900706f2543Smrg    ret = malloc(strlen(s) + 1);
901706f2543Smrg    for (p = s, q = ret; *p != 0; p++) {
902706f2543Smrg	switch (*p) {
903706f2543Smrg	case '_':
904706f2543Smrg	case ' ':
905706f2543Smrg	case '\t':
906706f2543Smrg	    continue;
907706f2543Smrg	default:
908706f2543Smrg	    if (isupper(*p))
909706f2543Smrg		*q++ = tolower(*p);
910706f2543Smrg	    else
911706f2543Smrg		*q++ = *p;
912706f2543Smrg	}
913706f2543Smrg    }
914706f2543Smrg    *q = '\0';
915706f2543Smrg    return ret;
916706f2543Smrg}
917