xkbconfig.c revision 8c9fbc29
1/* $Xorg: xkbconfig.c,v 1.4 2000/08/17 19:46:43 cpqbld Exp $ */
2/************************************************************
3 Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
4
5 Permission to use, copy, modify, and distribute this
6 software and its documentation for any purpose and without
7 fee is hereby granted, provided that the above copyright
8 notice appear in all copies and that both that copyright
9 notice and this permission notice appear in supporting
10 documentation, and that the name of Silicon Graphics not be
11 used in advertising or publicity pertaining to distribution
12 of the software without specific prior written permission.
13 Silicon Graphics makes no representation about the suitability
14 of this software for any purpose. It is provided "as is"
15 without any express or implied warranty.
16
17 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
20 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
21 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
23 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
24 THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
26 ********************************************************/
27/* $XFree86: xc/lib/xkbfile/xkbconfig.c,v 3.7 2001/11/30 12:11:51 eich Exp $ */
28
29#ifdef HAVE_DIX_CONFIG_H
30#include <dix-config.h>
31#elif defined(HAVE_CONFIG_H)
32#include <config.h>
33#endif
34
35#include <stdio.h>
36#include <ctype.h>
37#include <stdlib.h>
38
39#include <X11/Xfuncs.h>
40
41#include <X11/Xfuncs.h>
42
43#ifndef XKB_IN_SERVER
44
45#include <X11/Xos.h>
46#include <X11/Xlib.h>
47#include <X11/keysym.h>
48#include <X11/XKBlib.h>
49#include "XKBfileInt.h"
50
51#else
52
53#include <X11/X.h>
54#define	NEED_EVENTS
55#include <X11/keysym.h>
56#include <X11/Xproto.h>
57#include "misc.h"
58#include "inputstr.h"
59#include "dix.h"
60#define	XKBSRV_NEED_FILE_FUNCS
61#include <X11/extensions/XKBsrv.h>
62#endif
63
64#include <X11/extensions/XKBconfig.h>
65
66/***====================================================================***/
67
68#define	XKBCF_MAX_STR_LEN	100
69static char _XkbCF_rtrn[XKBCF_MAX_STR_LEN+1];
70
71static int
72ScanIdent(FILE *file,int ch,XkbCFScanResultPtr val_rtrn)
73{
74register int	i;
75char *		str;
76
77    val_rtrn->str= str= _XkbCF_rtrn;
78    for (i=0;(isalpha(ch)||isdigit(ch)||(ch=='_'));ch=getc(file)) {
79	if (i<XKBCF_MAX_STR_LEN)
80	    str[i++]= ch;
81    }
82    if ((ch!=EOF)&&(ch!=' ')&&(ch!='\t'))
83	ungetc(ch,file);
84    str[i]= '\0';
85    return XkbCF_Ident;
86}
87
88static int
89ScanString(FILE *file,int quote,XkbCFScanResultPtr val_rtrn)
90{
91int	ch,nInBuf;
92
93    nInBuf = 0;
94    while ( ((ch=getc(file))!=EOF) && (ch!='\n') && (ch!=quote) ) {
95	if ( ch == '\\' ) {
96	    if ((ch = getc(file))!=EOF) {
97		if ( ch=='n' )		ch = '\n';
98		else if ( ch == 't' )	ch = '\t';
99		else if ( ch == 'v' )	ch = '\v';
100		else if ( ch == 'b' )	ch = '\b';
101		else if ( ch == 'r' )	ch = '\r';
102		else if ( ch == 'f' )	ch = '\f';
103		else if ( ch == 'e' )	ch = '\033';
104		else if ( ch == '0' ) {
105		    int tmp,stop;
106		    ch = stop = 0;
107		    if (((tmp=getc(file))!=EOF) && (isdigit(tmp)) &&
108						(tmp!='8') && (tmp!='9')) {
109			ch= (ch*8)+(tmp-'0');
110		    }
111		    else {
112			stop= 1;
113			ungetc(tmp,file);
114		    }
115		    if ((!stop) && ((tmp=getc(file))!=EOF) && (isdigit(tmp)) &&
116						(tmp!='8') && (tmp!='9')) {
117			ch= (ch*8)+(tmp-'0');
118		    }
119		    else {
120			stop= 1;
121			ungetc(tmp,file);
122		    }
123		    if ((!stop) && ((tmp=getc(file))!=EOF) && (isdigit(tmp)) &&
124						(tmp!='8') && (tmp!='9')) {
125			ch= (ch*8)+(tmp-'0');
126		    }
127		    else {
128			stop= 1;
129			ungetc(tmp,file);
130		    }
131		}
132	    }
133	    else return XkbCF_EOF;
134	}
135
136	if ( nInBuf < XKBCF_MAX_STR_LEN-1 )
137	    _XkbCF_rtrn[nInBuf++] = ch;
138    }
139    if ( ch == quote ) {
140	_XkbCF_rtrn[nInBuf++] = '\0';
141	val_rtrn->str= _XkbCF_rtrn;
142	return XkbCF_String;
143    }
144    return XkbCF_UnterminatedString;
145}
146
147static int
148ScanInteger(FILE *file,int ch,XkbCFScanResultPtr val_rtrn)
149{
150int	i;
151
152    if (isdigit(ch))
153	ungetc(ch,file);
154    if (fscanf(file,"%i",&i)==1) {
155	val_rtrn->ival= i;
156	return XkbCF_Integer;
157    }
158    return XkbCF_Unknown;
159}
160
161int
162XkbCFScan(FILE *file,XkbCFScanResultPtr val_rtrn,XkbConfigRtrnPtr rtrn)
163{
164int	ch;
165
166    do {
167	ch= getc(file);
168    } while ((ch=='\t')||(ch==' '));
169    if (isalpha(ch))
170	 return ScanIdent(file,ch,val_rtrn);
171    else if (isdigit(ch))
172	 return ScanInteger(file,ch,val_rtrn);
173    else if (ch=='"')
174	 return ScanString(file,ch,val_rtrn);
175    else if (ch=='\n') {
176	rtrn->line++;
177	return XkbCF_EOL;
178    }
179    else if (ch==';')
180	return XkbCF_Semi;
181    else if (ch=='=')
182	return XkbCF_Equals;
183    else if (ch=='+') {
184	ch= getc(file);
185	if (ch=='=')
186	    return XkbCF_PlusEquals;
187	if ((ch!=EOF)&&(ch!=' ')&&(ch!='\t'))
188	    ungetc(ch,file);
189	return XkbCF_Plus;
190    }
191    else if (ch=='-') {
192	ch= getc(file);
193	if (ch=='=')
194	    return XkbCF_MinusEquals;
195	if ((ch!=EOF)&&(ch!=' ')&&(ch!='\t'))
196	    ungetc(ch,file);
197	return XkbCF_Minus;
198    }
199    else if (ch==EOF)
200	return XkbCF_EOF;
201    else if ((ch=='#')||((ch=='/')&&(getc(file)=='/'))) {
202	while ((ch!='\n')&&(ch!=EOF))
203	    ch= getc(file);
204	rtrn->line++;
205	return XkbCF_EOL;
206    }
207    return XkbCF_Unknown;
208}
209
210/***====================================================================***/
211
212#define	_XkbCF_Illegal			0
213#define	_XkbCF_Keymap		 	1
214#define	_XkbCF_Keycodes		 	2
215#define	_XkbCF_Geometry		 	3
216#define	_XkbCF_PhysSymbols	 	4
217#define _XkbCF_Symbols		 	5
218#define	_XkbCF_Types		 	6
219#define	_XkbCF_CompatMap	 	7
220
221#define	_XkbCF_RulesFile		8
222#define	_XkbCF_Model			9
223#define	_XkbCF_Layout			10
224#define	_XkbCF_Variant			11
225#define	_XkbCF_Options			12
226
227#define	_XkbCF_InitialMods	 	13
228#define	_XkbCF_InitialCtrls	 	14
229
230#define	_XkbCF_ClickVolume	 	15
231#define	_XkbCF_BellVolume	 	16
232#define	_XkbCF_BellPitch	 	17
233#define	_XkbCF_BellDuration	 	18
234#define	_XkbCF_RepeatDelay	 	19
235#define	_XkbCF_RepeatInterval	 	20
236#define	_XkbCF_SlowKeysDelay	 	21
237#define	_XkbCF_DebounceDelay		22
238#define	_XkbCF_MouseKeysDelay		23
239#define	_XkbCF_MouseKeysInterval	24
240#define	_XkbCF_MouseKeysTimeToMax	25
241#define	_XkbCF_MouseKeysMaxSpeed	26
242#define	_XkbCF_MouseKeysCurve		27
243#define	_XkbCF_AccessXTimeout		28
244#define	_XkbCF_AccessXTimeoutCtrlsOn	29
245#define	_XkbCF_AccessXTimeoutCtrlsOff	30
246#define	_XkbCF_AccessXTimeoutOptsOn	31
247#define	_XkbCF_AccessXTimeoutOptsOff	32
248
249#define	_XkbCF_IgnoreLockMods		33
250#define	_XkbCF_IgnoreGroupLock		34
251#define	_XkbCF_InternalMods		35
252
253#define	_XkbCF_GroupsWrap		36
254#define	_XkbCF_InitialFeedback		37
255
256static Bool
257AddCtrlByName(XkbConfigRtrnPtr rtrn,char *name,unsigned long *ctrls_rtrn)
258{
259    if ((_XkbStrCaseCmp(name,"repeat")==0)||
260	(_XkbStrCaseCmp(name,"repeatkeys")==0))
261	*ctrls_rtrn= XkbRepeatKeysMask;
262    else if (_XkbStrCaseCmp(name,"slowkeys")==0)
263	*ctrls_rtrn= XkbSlowKeysMask;
264    else if (_XkbStrCaseCmp(name,"bouncekeys")==0)
265	*ctrls_rtrn= XkbBounceKeysMask;
266    else if (_XkbStrCaseCmp(name,"stickykeys")==0)
267	*ctrls_rtrn= XkbStickyKeysMask;
268    else if (_XkbStrCaseCmp(name,"mousekeys")==0)
269	*ctrls_rtrn= XkbMouseKeysMask;
270    else if (_XkbStrCaseCmp(name,"mousekeysaccel")==0)
271	*ctrls_rtrn= XkbMouseKeysAccelMask;
272    else if (_XkbStrCaseCmp(name,"accessxkeys")==0)
273	*ctrls_rtrn= XkbAccessXKeysMask;
274    else if (_XkbStrCaseCmp(name,"accessxtimeout")==0)
275	*ctrls_rtrn= XkbAccessXTimeoutMask;
276    else if (_XkbStrCaseCmp(name,"accessxfeedback")==0)
277	*ctrls_rtrn= XkbAccessXFeedbackMask;
278    else if (_XkbStrCaseCmp(name,"audiblebell")==0)
279	*ctrls_rtrn= XkbAudibleBellMask;
280    else if (_XkbStrCaseCmp(name,"overlay1")==0)
281	*ctrls_rtrn= XkbOverlay1Mask;
282    else if (_XkbStrCaseCmp(name,"overlay2")==0)
283	*ctrls_rtrn= XkbOverlay2Mask;
284    else if (_XkbStrCaseCmp(name,"ignoregrouplock")==0)
285	*ctrls_rtrn= XkbIgnoreGroupLockMask;
286    else {
287	rtrn->error= XkbCF_ExpectedControl;
288	return False;
289    }
290    return True;
291}
292
293static Bool
294AddAXTimeoutOptByName(	XkbConfigRtrnPtr	rtrn,
295			char *			name,
296			unsigned short *	opts_rtrn)
297{
298    if (_XkbStrCaseCmp(name,"slowkeyspress")==0)
299	*opts_rtrn= XkbAX_SKPressFBMask;
300    else if (_XkbStrCaseCmp(name,"slowkeysaccept")==0)
301	*opts_rtrn= XkbAX_SKAcceptFBMask;
302    else if (_XkbStrCaseCmp(name,"feature")==0)
303	*opts_rtrn= XkbAX_FeatureFBMask;
304    else if (_XkbStrCaseCmp(name,"slowwarn")==0)
305	*opts_rtrn= XkbAX_SlowWarnFBMask;
306    else if (_XkbStrCaseCmp(name,"indicator")==0)
307	*opts_rtrn= XkbAX_IndicatorFBMask;
308    else if (_XkbStrCaseCmp(name,"stickykeys")==0)
309	*opts_rtrn= XkbAX_StickyKeysFBMask;
310    else if (_XkbStrCaseCmp(name,"twokeys")==0)
311	*opts_rtrn= XkbAX_TwoKeysMask;
312    else if (_XkbStrCaseCmp(name,"latchtolock")==0)
313	*opts_rtrn= XkbAX_LatchToLockMask;
314    else if (_XkbStrCaseCmp(name,"slowkeysrelease")==0)
315	*opts_rtrn= XkbAX_SKReleaseFBMask;
316    else if (_XkbStrCaseCmp(name,"slowkeysreject")==0)
317	*opts_rtrn= XkbAX_SKRejectFBMask;
318    else if (_XkbStrCaseCmp(name,"bouncekeysreject")==0)
319	*opts_rtrn= XkbAX_BKRejectFBMask;
320    else if (_XkbStrCaseCmp(name,"dumbbell")==0)
321	*opts_rtrn= XkbAX_DumbBellFBMask;
322    else {
323	rtrn->error= XkbCF_ExpectedControl;
324	return False;
325    }
326    return True;
327}
328
329XkbConfigUnboundModPtr
330XkbCFAddModByName(	XkbConfigRtrnPtr	rtrn,
331			int			what,
332			char *			name,
333			Bool			merge,
334			XkbConfigUnboundModPtr	last)
335{
336    if (rtrn->num_unbound_mods>=rtrn->sz_unbound_mods) {
337	rtrn->sz_unbound_mods+= 5;
338	rtrn->unbound_mods= _XkbTypedRealloc(rtrn->unbound_mods,
339						  rtrn->sz_unbound_mods,
340						  XkbConfigUnboundModRec);
341	if (rtrn->unbound_mods==NULL) {
342	    rtrn->error= XkbCF_BadAlloc;
343	    return False;
344	}
345    }
346    if (last==NULL) {
347	last= &rtrn->unbound_mods[rtrn->num_unbound_mods++];
348	last->what= what;
349	last->mods= 0;
350	last->vmods= 0;
351	last->merge= merge;
352	last->name= NULL;
353    }
354    if (_XkbStrCaseCmp(name,"shift")==0)
355	last->mods|= ShiftMask;
356    else if (_XkbStrCaseCmp(name,"lock")==0)
357	last->mods|= LockMask;
358    else if ((_XkbStrCaseCmp(name,"control")==0)||
359		(_XkbStrCaseCmp(name,"ctrl")==0))
360	last->mods|= ControlMask;
361    else if (_XkbStrCaseCmp(name,"mod1")==0)
362	last->mods|= Mod1Mask;
363    else if (_XkbStrCaseCmp(name,"mod2")==0)
364	last->mods|= Mod2Mask;
365    else if (_XkbStrCaseCmp(name,"mod3")==0)
366	last->mods|= Mod3Mask;
367    else if (_XkbStrCaseCmp(name,"mod4")==0)
368	last->mods|= Mod4Mask;
369    else if (_XkbStrCaseCmp(name,"mod5")==0)
370	last->mods|= Mod5Mask;
371    else {
372	if (last->name!=NULL) {
373	    last= &rtrn->unbound_mods[rtrn->num_unbound_mods++];
374	    last->what= what;
375	    last->mods= 0;
376	    last->vmods= 0;
377	    last->merge= merge;
378	    last->name= NULL;
379	}
380	last->name= _XkbDupString(name);
381    }
382    return last;
383}
384
385int
386XkbCFBindMods(XkbConfigRtrnPtr rtrn,XkbDescPtr xkb)
387{
388register int 		n,v;
389Atom			name;
390XkbConfigUnboundModPtr	mod;
391int			missing;
392
393    if (rtrn->num_unbound_mods<1)
394	return 0;
395    if ((xkb==NULL) || (xkb->names==NULL))
396	return -1;
397
398    missing= 0;
399    for (n=0,mod=rtrn->unbound_mods;n<rtrn->num_unbound_mods;n++,mod++) {
400	if (mod->name!=NULL) {
401	    name= XkbInternAtom(xkb->dpy,mod->name,True);
402	    if (name==None)
403		continue;
404	    for (v=0;v<XkbNumVirtualMods;v++) {
405		if (xkb->names->vmods[v]==name) {
406		    mod->vmods= (1<<v);
407		    _XkbFree(mod->name);
408		    mod->name= NULL;
409		    break;
410		}
411	    }
412	    if (mod->name!=NULL)
413		missing++;
414	}
415    }
416    return missing;
417}
418
419Bool
420XkbCFApplyMods(XkbConfigRtrnPtr rtrn,int what,XkbConfigModInfoPtr info)
421{
422register int 		n;
423XkbConfigUnboundModPtr	mod;
424
425    if (rtrn->num_unbound_mods<1)
426	return True;
427
428    for (n=0,mod=rtrn->unbound_mods;n<rtrn->num_unbound_mods;n++,mod++) {
429	if (mod->what!=what)
430	    continue;
431 	if (mod->merge==XkbCF_MergeRemove) {
432	    info->mods_clear|= mod->mods;
433	    info->vmods_clear|= mod->vmods;
434	}
435	else {
436	    if (mod->merge==XkbCF_MergeSet)
437		info->replace= True;
438	    info->mods|= mod->mods;
439	    info->vmods|= mod->vmods;
440	}
441	if (mod->name==NULL) {
442	    mod->what= _XkbCF_Illegal;
443	}
444	else {
445	    mod->mods= 0;
446	    mod->vmods= 0;
447	}
448    }
449    return True;
450}
451
452/*ARGSUSED*/
453static Bool
454DefaultParser(	FILE *			file,
455		XkbConfigFieldsPtr	fields,
456		XkbConfigFieldPtr	field,
457		XkbDescPtr		xkb,
458		XkbConfigRtrnPtr	rtrn)
459{
460int			tok;
461XkbCFScanResultRec	val;
462char **			str;
463int			merge;
464unsigned long *		ctrls, ctrls_mask;
465unsigned short *	opts, opts_mask;
466int *			pival, sign;
467int			onoff;
468XkbConfigUnboundModPtr	last;
469unsigned		what;
470
471    tok= XkbCFScan(file,&val,rtrn);
472    str= NULL;
473    onoff= 0;
474    pival= NULL;
475    switch (field->field_id) {
476	case _XkbCF_RulesFile:	if (!str)	str= &rtrn->rules_file;
477	case _XkbCF_Model:	if (!str)	str= &rtrn->model;
478	case _XkbCF_Layout:	if (!str)	str= &rtrn->layout;
479	case _XkbCF_Variant:	if (!str)	str= &rtrn->variant;
480	case _XkbCF_Options:	if (!str)	str= &rtrn->options;
481	case _XkbCF_Keymap: 	if (!str)	str= &rtrn->keymap;
482	case _XkbCF_Keycodes: 	if (!str)	str= &rtrn->keycodes;
483	case _XkbCF_Geometry: 	if (!str)	str= &rtrn->geometry;
484	case _XkbCF_PhysSymbols:if (!str)	str= &rtrn->phys_symbols;
485	case _XkbCF_Symbols: 	if (!str)	str= &rtrn->symbols;
486	case _XkbCF_Types: 	if (!str)	str= &rtrn->types;
487	case _XkbCF_CompatMap:	if (!str)	str= &rtrn->compat;
488	    if (tok!=XkbCF_Equals) {
489		rtrn->error= XkbCF_MissingEquals;
490		goto BAILOUT;
491	    }
492	    tok= XkbCFScan(file,&val,rtrn);
493	    if ((tok!=XkbCF_String)&&(tok!=XkbCF_Ident)) {
494		rtrn->error= XkbCF_ExpectedString;
495		return False;
496	    }
497	    tok= XkbCFScan(file,&val,rtrn);
498	    if ((tok!=XkbCF_EOL)&&(tok!=XkbCF_Semi)&&(tok!=XkbCF_EOF)) {
499		rtrn->error= XkbCF_ExpectedEOS;
500		return False;
501	    }
502	    if (*str!=NULL)
503		_XkbFree(*str);
504	    *str= _XkbDupString(val.str);
505	    break;
506	case _XkbCF_InitialMods:
507	case _XkbCF_IgnoreLockMods:
508	case _XkbCF_InternalMods:
509	    what= XkbCF_InitialMods;
510	    if (field->field_id==_XkbCF_InitialMods)
511		rtrn->defined|= (what=XkbCF_InitialMods);
512	    else if (field->field_id==_XkbCF_InternalMods)
513		rtrn->defined|= (what=XkbCF_InternalMods);
514	    else if (field->field_id==_XkbCF_IgnoreLockMods)
515		rtrn->defined|= (what=XkbCF_IgnoreLockMods);
516	    if (tok==XkbCF_Equals)		merge= XkbCF_MergeSet;
517	    else if (tok==XkbCF_MinusEquals)	merge= XkbCF_MergeRemove;
518	    else if (tok==XkbCF_PlusEquals)	merge= XkbCF_MergeAdd;
519	    else {
520		rtrn->error= XkbCF_MissingEquals;
521		goto BAILOUT;
522	    }
523	    tok= XkbCFScan(file,&val,rtrn);
524	    if ((tok==XkbCF_EOL)||(tok==XkbCF_Semi)||(tok==XkbCF_EOF)) {
525		rtrn->error= XkbCF_ExpectedModifier;
526		return False;
527	    }
528	    last= NULL;
529	    while ((tok!=XkbCF_EOL)&&(tok!=XkbCF_Semi)&&(tok!=XkbCF_EOF)) {
530		if ((tok!=XkbCF_Ident)&&(tok!=XkbCF_String)) {
531		    rtrn->error= XkbCF_ExpectedModifier;
532		    return False;
533		}
534		last=XkbCFAddModByName(rtrn,what,val.str,merge,last);
535		if (last==NULL)
536		    return False;
537		if (merge==XkbCF_MergeSet)
538		    merge= XkbCF_MergeAdd;
539		tok= XkbCFScan(file,&val,rtrn);
540		if ((tok!=XkbCF_EOL)&&(tok!=XkbCF_EOF)&&(tok!=XkbCF_Semi)) {
541		    if (tok!=XkbCF_Plus) {
542			rtrn->error= XkbCF_ExpectedOperator;
543			return False;
544		    }
545		    tok= XkbCFScan(file,&val,rtrn);
546		}
547	    }
548	    break;
549	case _XkbCF_InitialCtrls:
550	    rtrn->defined|= XkbCF_InitialCtrls;
551	    ctrls= NULL;
552	    if (tok==XkbCF_PlusEquals)
553		ctrls= &rtrn->initial_ctrls;
554	    else if (tok==XkbCF_MinusEquals)
555		ctrls= &rtrn->initial_ctrls_clear;
556	    else if (tok==XkbCF_Equals) {
557		ctrls= &rtrn->initial_ctrls;
558		rtrn->replace_initial_ctrls= True;
559		*ctrls= 0;
560	    }
561	    else {
562		rtrn->error= XkbCF_MissingEquals;
563		goto BAILOUT;
564	    }
565	    tok= XkbCFScan(file,&val,rtrn);
566	    if ((tok==XkbCF_EOL)||(tok==XkbCF_Semi)||(tok==XkbCF_EOF)) {
567		rtrn->error= XkbCF_ExpectedControl;
568		return False;
569	    }
570	    while ((tok!=XkbCF_EOL)&&(tok!=XkbCF_Semi)&&(tok!=XkbCF_EOF)) {
571		if ((tok!=XkbCF_Ident)&&(tok!=XkbCF_String)) {
572		    rtrn->error= XkbCF_ExpectedControl;
573		    return False;
574		}
575		if (!AddCtrlByName(rtrn,val.str,&ctrls_mask)) {
576		    return False;
577		}
578		*ctrls |= ctrls_mask;
579		tok= XkbCFScan(file,&val,rtrn);
580		if ((tok!=XkbCF_EOL)&&(tok!=XkbCF_EOF)&&(tok!=XkbCF_Semi)) {
581		    if (tok!=XkbCF_Plus) {
582			rtrn->error= XkbCF_ExpectedOperator;
583			return False;
584		    }
585		    tok= XkbCFScan(file,&val,rtrn);
586		}
587	    }
588	    break;
589	case _XkbCF_AccessXTimeoutCtrlsOn:
590	case _XkbCF_AccessXTimeoutCtrlsOff:
591	    opts= NULL;
592	    if (tok==XkbCF_MinusEquals) {
593		ctrls= &rtrn->axt_ctrls_ignore;
594		opts= &rtrn->axt_opts_ignore;
595	    }
596	    else if ((tok==XkbCF_PlusEquals)||(tok==XkbCF_Equals)) {
597		if (field->field_id==_XkbCF_AccessXTimeoutCtrlsOff) {
598		    ctrls= &rtrn->axt_ctrls_off;
599		    opts= &rtrn->axt_opts_off;
600		    if (tok==XkbCF_Equals)
601			rtrn->replace_axt_ctrls_off= True;
602		}
603		else {
604		    ctrls= &rtrn->axt_ctrls_on;
605		    opts= &rtrn->axt_opts_on;
606		    if (tok==XkbCF_Equals)
607			rtrn->replace_axt_ctrls_on= True;
608		}
609		*ctrls= 0;
610	    }
611	    else {
612		rtrn->error= XkbCF_MissingEquals;
613		goto BAILOUT;
614	    }
615	    tok= XkbCFScan(file,&val,rtrn);
616	    if ((tok==XkbCF_EOL)||(tok==XkbCF_Semi)||(tok==XkbCF_EOF)) {
617		rtrn->error= XkbCF_ExpectedControl;
618		return False;
619	    }
620	    while ((tok!=XkbCF_EOL)&&(tok!=XkbCF_Semi)&&(tok!=XkbCF_EOF)) {
621		if ((tok!=XkbCF_Ident)&&(tok!=XkbCF_String)) {
622		    rtrn->error= XkbCF_ExpectedControl;
623		    return False;
624		}
625		if (!AddCtrlByName(rtrn,val.str,&ctrls_mask)) {
626		    if (!AddAXTimeoutOptByName(rtrn,val.str,&opts_mask))
627			return False;
628		    *opts |= opts_mask;
629		    if (field->field_id==_XkbCF_AccessXTimeoutCtrlsOff) {
630			rtrn->defined|= XkbCF_AccessXTimeoutOptsOff;
631			if (rtrn->replace_axt_ctrls_off)
632			    rtrn->replace_axt_opts_off= True;
633		    }
634		    else {
635			rtrn->defined|= XkbCF_AccessXTimeoutOptsOn;
636			if (rtrn->replace_axt_ctrls_on)
637			    rtrn->replace_axt_opts_on= True;
638		    }
639		}
640		else
641		    *ctrls |= ctrls_mask;
642		tok= XkbCFScan(file,&val,rtrn);
643		if ((tok!=XkbCF_EOL)&&(tok!=XkbCF_EOF)&&(tok!=XkbCF_Semi)) {
644		    if (tok!=XkbCF_Plus) {
645			rtrn->error= XkbCF_ExpectedOperator;
646			return False;
647		    }
648		    tok= XkbCFScan(file,&val,rtrn);
649		}
650	    }
651	    break;
652	case _XkbCF_InitialFeedback:
653	    rtrn->defined|= XkbCF_InitialOpts;
654	    opts= NULL;
655	    if (tok==XkbCF_PlusEquals)
656		opts= &rtrn->initial_opts;
657	    else if (tok==XkbCF_MinusEquals)
658		opts= &rtrn->initial_opts_clear;
659	    else if (tok==XkbCF_Equals) {
660		opts= &rtrn->initial_opts;
661		rtrn->replace_initial_opts= True;
662		*opts= 0;
663	    }
664	    else {
665		rtrn->error= XkbCF_MissingEquals;
666		goto BAILOUT;
667	    }
668	    tok= XkbCFScan(file,&val,rtrn);
669	    if ((tok==XkbCF_EOL)||(tok==XkbCF_Semi)||(tok==XkbCF_EOF)) {
670		rtrn->error= XkbCF_ExpectedAXOption;
671		return False;
672	    }
673	    while ((tok!=XkbCF_EOL)&&(tok!=XkbCF_Semi)&&(tok!=XkbCF_EOF)) {
674		if ((tok!=XkbCF_Ident)&&(tok!=XkbCF_String)) {
675		    rtrn->error= XkbCF_ExpectedAXOption;
676		    return False;
677		}
678		if (!AddAXTimeoutOptByName(rtrn,val.str,&opts_mask)) {
679		    return False;
680		}
681		*opts |= opts_mask;
682		tok= XkbCFScan(file,&val,rtrn);
683		if ((tok!=XkbCF_EOL)&&(tok!=XkbCF_EOF)&&(tok!=XkbCF_Semi)) {
684		    if (tok!=XkbCF_Plus) {
685			rtrn->error= XkbCF_ExpectedOperator;
686			return False;
687		    }
688		    tok= XkbCFScan(file,&val,rtrn);
689		}
690	    }
691	    break;
692	case _XkbCF_AccessXTimeoutOptsOff:
693	case _XkbCF_AccessXTimeoutOptsOn:
694	    opts= NULL;
695	    if (tok==XkbCF_MinusEquals)
696		opts= &rtrn->axt_opts_ignore;
697	    else if ((tok==XkbCF_PlusEquals)||(tok==XkbCF_Equals)) {
698		if (field->field_id==_XkbCF_AccessXTimeoutOptsOff) {
699		    opts= &rtrn->axt_opts_off;
700		    if (tok==XkbCF_Equals)
701			rtrn->replace_axt_opts_off= True;
702		}
703		else {
704		    opts= &rtrn->axt_opts_on;
705		    if (tok==XkbCF_Equals)
706			rtrn->replace_axt_opts_on= True;
707		}
708		*opts = 0;
709	    }
710	    else {
711		rtrn->error= XkbCF_MissingEquals;
712		goto BAILOUT;
713	    }
714	    tok= XkbCFScan(file,&val,rtrn);
715	    if ((tok==XkbCF_EOL)||(tok==XkbCF_Semi)||(tok==XkbCF_EOF)) {
716		rtrn->error= XkbCF_ExpectedControl;
717		return False;
718	    }
719	    while ((tok!=XkbCF_EOL)&&(tok!=XkbCF_Semi)&&(tok!=XkbCF_EOF)) {
720		if ((tok!=XkbCF_Ident)&&(tok!=XkbCF_String)) {
721		    rtrn->error= XkbCF_ExpectedControl;
722		    return False;
723		}
724		if (!AddAXTimeoutOptByName(rtrn,val.str,&opts_mask))
725		    return False;
726		*opts |= opts_mask;
727
728		tok= XkbCFScan(file,&val,rtrn);
729		if ((tok!=XkbCF_EOL)&&(tok!=XkbCF_EOF)&&(tok!=XkbCF_Semi)) {
730		    if (tok!=XkbCF_Plus) {
731			rtrn->error= XkbCF_ExpectedOperator;
732			return False;
733		    }
734		    tok= XkbCFScan(file,&val,rtrn);
735		}
736	    }
737	    break;
738	case _XkbCF_ClickVolume:
739	    if (!pival) {
740		pival= &rtrn->click_volume;
741		onoff= 100;
742	    }
743	case _XkbCF_BellVolume:
744	    if (!pival) {
745		pival= &rtrn->bell_volume;
746		onoff= 100;
747	    }
748	case _XkbCF_BellPitch:
749	    if (!pival)
750		pival= &rtrn->bell_pitch;
751	case _XkbCF_BellDuration:
752	    if (!pival)
753		pival= &rtrn->bell_duration;
754	case _XkbCF_RepeatDelay:
755	    if (!pival)
756		pival= &rtrn->repeat_delay;
757	case _XkbCF_RepeatInterval:
758	    if (!pival)
759		pival= &rtrn->repeat_interval;
760	case _XkbCF_SlowKeysDelay:
761	    if (!pival)
762		pival= &rtrn->slow_keys_delay;
763	case _XkbCF_DebounceDelay:
764	    if (!pival)
765		pival= &rtrn->debounce_delay;
766	case _XkbCF_MouseKeysDelay:
767	    if (!pival)
768		pival= &rtrn->mk_delay;
769	case _XkbCF_MouseKeysInterval:
770	    if (!pival)
771		pival= &rtrn->mk_interval;
772	case _XkbCF_MouseKeysTimeToMax:
773	    if (!pival)
774		pival= &rtrn->mk_time_to_max;
775	case _XkbCF_MouseKeysMaxSpeed:
776	    if (!pival)
777		pival= &rtrn->mk_max_speed;
778	case _XkbCF_MouseKeysCurve:
779	    if (!pival)
780		pival= &rtrn->mk_curve;
781	case _XkbCF_AccessXTimeout:
782	    if (!pival)
783		pival= &rtrn->ax_timeout;
784	    if (tok!=XkbCF_Equals) {
785		rtrn->error= XkbCF_MissingEquals;
786		goto BAILOUT;
787	    }
788	    tok= XkbCFScan(file,&val,rtrn);
789	    if (tok == XkbCF_Minus && field->field_id == _XkbCF_MouseKeysCurve) {
790		/* This can be a negative value */
791		tok = XkbCFScan(file,&val,rtrn);
792		sign = -1;
793	    }
794	    else
795		sign = 1;
796	    if (tok!=XkbCF_Integer) {
797		Bool ok= False;
798		if ((onoff)&&(tok==XkbCF_Ident)&&(val.str!=NULL)) {
799		    if (_XkbStrCaseCmp(val.str,"on")) {
800			val.ival= onoff;
801			ok= True;
802		    }
803		    else if (_XkbStrCaseCmp(val.str,"off")) {
804			val.ival= 0;
805			ok= True;
806		    }
807		}
808		if (!ok) {
809		    rtrn->error= XkbCF_ExpectedInteger;
810		    goto BAILOUT;
811		}
812	    }
813	    *pival= val.ival * sign;
814	    if (field->field_id == _XkbCF_AccessXTimeout)
815	        rtrn->defined|=XkbCF_AccessXTimeout;
816	    tok= XkbCFScan(file,&val,rtrn);
817	    if ((tok!=XkbCF_EOL)&&(tok!=XkbCF_Semi)&&(tok!=XkbCF_EOF)) {
818		rtrn->error= XkbCF_ExpectedEOS;
819		return False;
820	    }
821	    break;
822	case _XkbCF_GroupsWrap:
823	    if (tok!=XkbCF_Equals) {
824		rtrn->error= XkbCF_MissingEquals;
825		goto BAILOUT;
826	    }
827	    tok= XkbCFScan(file,&val,rtrn);
828	    if (tok==XkbCF_Ident) {
829		if (_XkbStrCaseCmp(val.str,"wrap")==0) {
830		    rtrn->groups_wrap= XkbSetGroupInfo(0,XkbWrapIntoRange,0);
831		}
832		else if (_XkbStrCaseCmp(val.str,"clamp")==0) {
833		    rtrn->groups_wrap= XkbSetGroupInfo(0,XkbClampIntoRange,0);
834		}
835		else {
836		    rtrn->error= XkbCF_ExpectedOORGroupBehavior;
837		    return False;
838		}
839	    }
840	    else if ((tok==XkbCF_Integer)&&(XkbIsLegalGroup(val.ival-1))) {
841		rtrn->groups_wrap= XkbSetGroupInfo(0,XkbRedirectIntoRange,
842								val.ival-1);
843	    }
844	    else {
845		rtrn->error= XkbCF_ExpectedOORGroupBehavior;
846		return False;
847	    }
848	    rtrn->defined|= XkbCF_GroupsWrap;
849	    tok= XkbCFScan(file,&val,rtrn);
850	    if ((tok!=XkbCF_EOL)&&(tok!=XkbCF_Semi)&&(tok!=XkbCF_EOF)) {
851		rtrn->error= XkbCF_ExpectedEOS;
852		return False;
853	    }
854	    break;
855	default:
856	    rtrn->error= XkbCF_ExpectedInteger;
857	    goto BAILOUT;
858
859    }
860    return True;
861BAILOUT:
862    return False;
863}
864
865static Bool
866DefaultCleanUp(XkbConfigRtrnPtr rtrn)
867{
868    if (rtrn->keymap)	_XkbFree(rtrn->keymap);
869    if (rtrn->keycodes)	_XkbFree(rtrn->keycodes);
870    if (rtrn->geometry)	_XkbFree(rtrn->geometry);
871    if (rtrn->phys_symbols)	_XkbFree(rtrn->phys_symbols);
872    if (rtrn->symbols)	_XkbFree(rtrn->symbols);
873    if (rtrn->types)	_XkbFree(rtrn->types);
874    if (rtrn->compat)	_XkbFree(rtrn->compat);
875    rtrn->keycodes= rtrn->geometry= NULL;
876    rtrn->symbols= rtrn->phys_symbols= NULL;
877    rtrn->types= rtrn->compat= NULL;
878    if ((rtrn->unbound_mods!=NULL)&&(rtrn->num_unbound_mods>0)) {
879	register int i;
880	for (i=0;i<rtrn->num_unbound_mods;i++) {
881	    if (rtrn->unbound_mods[i].name!=NULL) {
882		_XkbFree(rtrn->unbound_mods[i].name);
883		rtrn->unbound_mods[i].name= NULL;
884	    }
885	}
886	_XkbFree(rtrn->unbound_mods);
887	rtrn->sz_unbound_mods= 0;
888	rtrn->num_unbound_mods= 0;
889	rtrn->unbound_mods= NULL;
890    }
891    return True;
892}
893
894static Bool
895DefaultApplyNames(XkbConfigRtrnPtr rtrn,XkbDescPtr xkb)
896{
897char *str;
898
899    if (XkbAllocNames(xkb,XkbComponentNamesMask,0,0)!=Success)
900	return False;
901    if ((str=rtrn->keycodes)!=NULL) {
902	xkb->names->keycodes= XkbInternAtom(xkb->dpy,str,False);
903	_XkbFree(str);
904	rtrn->keycodes= NULL;
905    }
906    if ((str=rtrn->geometry)!=NULL) {
907	xkb->names->geometry= XkbInternAtom(xkb->dpy,str,False);
908	_XkbFree(str);
909	rtrn->geometry= NULL;
910    }
911    if ((str=rtrn->symbols)!=NULL) {
912	xkb->names->symbols= XkbInternAtom(xkb->dpy,str,False);
913	_XkbFree(str);
914	rtrn->symbols= NULL;
915    }
916    if ((str=rtrn->phys_symbols)!=NULL) {
917	xkb->names->phys_symbols= XkbInternAtom(xkb->dpy,str,False);
918	_XkbFree(str);
919	rtrn->phys_symbols= NULL;
920    }
921    if ((str=rtrn->types)!=NULL) {
922	xkb->names->types= XkbInternAtom(xkb->dpy,str,False);
923	_XkbFree(str);
924	rtrn->types= NULL;
925    }
926    if ((str=rtrn->compat)!=NULL) {
927	xkb->names->compat= XkbInternAtom(xkb->dpy,str,False);
928	_XkbFree(str);
929	rtrn->compat= NULL;
930    }
931    return True;
932}
933
934static Bool
935DefaultApplyControls(XkbConfigRtrnPtr rtrn,XkbDescPtr xkb)
936{
937unsigned	on,off;
938XkbControlsPtr	ctrls;
939unsigned int	mask;
940
941    if (XkbAllocControls(xkb,XkbAllControlsMask)!=Success)
942	return False;
943    ctrls= xkb->ctrls;
944    if (rtrn->replace_initial_ctrls)
945	 ctrls->enabled_ctrls=  rtrn->initial_ctrls;
946    else ctrls->enabled_ctrls|= rtrn->initial_ctrls;
947    ctrls->enabled_ctrls&= ~rtrn->initial_ctrls_clear;
948    if (rtrn->internal_mods.replace) {
949	ctrls->internal.real_mods= rtrn->internal_mods.mods;
950	ctrls->internal.vmods= rtrn->internal_mods.vmods;
951    }
952    else {
953	ctrls->internal.real_mods&= ~rtrn->internal_mods.mods_clear;
954	ctrls->internal.vmods&= ~rtrn->internal_mods.vmods_clear;
955	ctrls->internal.real_mods|= rtrn->internal_mods.mods;
956	ctrls->internal.vmods|= rtrn->internal_mods.vmods;
957    }
958    mask= 0;
959    (void)XkbVirtualModsToReal(xkb,ctrls->internal.vmods,&mask);
960    ctrls->internal.mask= (ctrls->internal.real_mods|mask);
961
962    if (rtrn->ignore_lock_mods.replace) {
963	ctrls->ignore_lock.real_mods= rtrn->ignore_lock_mods.mods;
964	ctrls->ignore_lock.vmods= rtrn->ignore_lock_mods.vmods;
965    }
966    else {
967	ctrls->ignore_lock.real_mods&= ~rtrn->ignore_lock_mods.mods_clear;
968	ctrls->ignore_lock.vmods&= ~rtrn->ignore_lock_mods.vmods_clear;
969	ctrls->ignore_lock.real_mods|= rtrn->ignore_lock_mods.mods;
970	ctrls->ignore_lock.vmods|= rtrn->ignore_lock_mods.vmods;
971    }
972    mask= 0;
973    (void)XkbVirtualModsToReal(xkb,ctrls->ignore_lock.vmods,&mask);
974    ctrls->ignore_lock.mask= (ctrls->ignore_lock.real_mods|mask);
975
976    if (rtrn->repeat_delay>0)
977	ctrls->repeat_delay= rtrn->repeat_delay;
978    if (rtrn->repeat_interval>0)
979	ctrls->repeat_interval= rtrn->repeat_interval;
980    if (rtrn->slow_keys_delay>0)
981	ctrls->slow_keys_delay= rtrn->slow_keys_delay;
982    if (rtrn->debounce_delay>0)
983	ctrls->debounce_delay= rtrn->debounce_delay;
984    if (rtrn->mk_delay>0)
985	ctrls->mk_delay= rtrn->mk_delay;
986    if (rtrn->mk_interval>0)
987	ctrls->mk_interval= rtrn->mk_interval;
988    if (rtrn->mk_time_to_max>0)
989	ctrls->mk_time_to_max= rtrn->mk_time_to_max;
990    if (rtrn->mk_max_speed>0)
991	ctrls->mk_max_speed= rtrn->mk_max_speed;
992    if (rtrn->mk_curve>0)
993	ctrls->mk_curve= rtrn->mk_curve;
994    if (rtrn->defined&XkbCF_AccessXTimeout && rtrn->ax_timeout > 0)
995	ctrls->ax_timeout= rtrn->ax_timeout;
996
997    /* any value set to both off and on is reset to ignore */
998    if ((off=(rtrn->axt_ctrls_on&rtrn->axt_ctrls_off))!=0)
999	rtrn->axt_ctrls_ignore|= off;
1000
1001    /* ignore takes priority over on and off */
1002    rtrn->axt_ctrls_on&= ~rtrn->axt_ctrls_ignore;
1003    rtrn->axt_ctrls_off&= ~rtrn->axt_ctrls_ignore;
1004
1005    if (!rtrn->replace_axt_ctrls_off) {
1006	 off= (ctrls->axt_ctrls_mask&(~ctrls->axt_ctrls_values));
1007	 off&= ~rtrn->axt_ctrls_on;
1008	 off|= rtrn->axt_ctrls_off;
1009    }
1010    else off= rtrn->axt_ctrls_off;
1011    if (!rtrn->replace_axt_ctrls_on) {
1012	 on= (ctrls->axt_ctrls_mask&ctrls->axt_ctrls_values);
1013	 on&= ~rtrn->axt_ctrls_off;
1014	 on|= rtrn->axt_ctrls_on;
1015    }
1016    else on= rtrn->axt_ctrls_on;
1017    ctrls->axt_ctrls_mask= (on|off)&~rtrn->axt_ctrls_ignore;
1018    ctrls->axt_ctrls_values= on&~rtrn->axt_ctrls_ignore;
1019
1020    /* any value set to both off and on is reset to ignore */
1021    if ((off=(rtrn->axt_opts_on&rtrn->axt_opts_off))!=0)
1022	rtrn->axt_opts_ignore|= off;
1023
1024    /* ignore takes priority over on and off */
1025    rtrn->axt_opts_on&= ~rtrn->axt_opts_ignore;
1026    rtrn->axt_opts_off&= ~rtrn->axt_opts_ignore;
1027
1028    if (rtrn->replace_axt_opts_off) {
1029	 off= (ctrls->axt_opts_mask&(~ctrls->axt_opts_values));
1030	 off&= ~rtrn->axt_opts_on;
1031	 off|= rtrn->axt_opts_off;
1032    }
1033    else off= rtrn->axt_opts_off;
1034    if (!rtrn->replace_axt_opts_on) {
1035	 on= (ctrls->axt_opts_mask&ctrls->axt_opts_values);
1036	 on&= ~rtrn->axt_opts_off;
1037	 on|= rtrn->axt_opts_on;
1038    }
1039    else on= rtrn->axt_opts_on;
1040    ctrls->axt_opts_mask= (unsigned short)((on|off)&~rtrn->axt_ctrls_ignore);
1041    ctrls->axt_opts_values= (unsigned short)(on&~rtrn->axt_ctrls_ignore);
1042
1043    if (rtrn->defined&XkbCF_GroupsWrap) {
1044	int n;
1045	n= XkbNumGroups(ctrls->groups_wrap);
1046	rtrn->groups_wrap= XkbSetNumGroups(rtrn->groups_wrap,n);
1047	ctrls->groups_wrap= rtrn->groups_wrap;
1048    }
1049    return True;
1050}
1051
1052/*ARGSUSED*/
1053static Bool
1054DefaultFinish(	XkbConfigFieldsPtr	fields,
1055		XkbDescPtr		xkb,
1056		XkbConfigRtrnPtr	rtrn,
1057		int			what)
1058{
1059    if ((what==XkbCF_Destroy)||(what==XkbCF_CleanUp))
1060	return DefaultCleanUp(rtrn);
1061    if (what==XkbCF_Check) {
1062	if ((rtrn->symbols==NULL)&&(rtrn->phys_symbols!=NULL))
1063	    rtrn->symbols= _XkbDupString(rtrn->phys_symbols);
1064    }
1065    if ((what==XkbCF_Apply)||(what==XkbCF_Check)) {
1066	if (xkb && xkb->names && (rtrn->num_unbound_mods>0))
1067	    XkbCFBindMods(rtrn,xkb);
1068	XkbCFApplyMods(rtrn,XkbCF_InitialMods,&rtrn->initial_mods);
1069	XkbCFApplyMods(rtrn,XkbCF_InternalMods,&rtrn->internal_mods);
1070	XkbCFApplyMods(rtrn,XkbCF_IgnoreLockMods,&rtrn->ignore_lock_mods);
1071    }
1072    if (what==XkbCF_Apply) {
1073	if (xkb!=NULL) {
1074	    DefaultApplyNames(rtrn,xkb);
1075	    DefaultApplyControls(rtrn,xkb);
1076	    XkbCFBindMods(rtrn,xkb);
1077	}
1078    }
1079    return True;
1080}
1081
1082static XkbConfigFieldRec _XkbCFDfltFields[] = {
1083	{ "rules",	_XkbCF_RulesFile },
1084	{ "model",	_XkbCF_Model },
1085	{ "layout",	_XkbCF_Layout },
1086	{ "variant",	_XkbCF_Variant },
1087	{ "options",	_XkbCF_Options },
1088	{ "keymap",	_XkbCF_Keymap },
1089	{ "keycodes",	_XkbCF_Keycodes },
1090	{ "geometry",	_XkbCF_Geometry },
1091	{ "realsymbols",_XkbCF_PhysSymbols },
1092	{ "actualsymbols",_XkbCF_PhysSymbols },
1093	{ "symbols",	_XkbCF_Symbols },
1094	{ "symbolstouse",_XkbCF_Symbols },
1095	{ "types",	_XkbCF_Types },
1096	{ "compat",	_XkbCF_CompatMap },
1097	{ "modifiers",	_XkbCF_InitialMods },
1098	{ "controls",	_XkbCF_InitialCtrls },
1099	{ "click",	_XkbCF_ClickVolume },
1100	{ "clickvolume",_XkbCF_ClickVolume },
1101	{ "bell",	_XkbCF_BellVolume },
1102	{ "bellvolume",	_XkbCF_BellVolume },
1103	{ "bellpitch",	_XkbCF_BellPitch },
1104	{ "bellduration",_XkbCF_BellDuration },
1105	{ "repeatdelay",_XkbCF_RepeatDelay },
1106	{ "repeatinterval",_XkbCF_RepeatInterval },
1107	{ "slowkeysdelay",_XkbCF_SlowKeysDelay	},
1108	{ "debouncedelay",_XkbCF_DebounceDelay },
1109	{ "mousekeysdelay",_XkbCF_MouseKeysDelay },
1110	{ "mousekeysinterval",_XkbCF_MouseKeysInterval },
1111	{ "mousekeystimetomax",_XkbCF_MouseKeysTimeToMax },
1112	{ "mousekeysmaxspeed",_XkbCF_MouseKeysMaxSpeed },
1113	{ "mousekeyscurve",_XkbCF_MouseKeysCurve },
1114	{ "accessxtimeout",_XkbCF_AccessXTimeout },
1115	{ "axtimeout",_XkbCF_AccessXTimeout },
1116	{ "accessxtimeoutctrlson",_XkbCF_AccessXTimeoutCtrlsOn },
1117	{ "axtctrlson",	_XkbCF_AccessXTimeoutCtrlsOn },
1118	{ "accessxtimeoutctrlsoff",_XkbCF_AccessXTimeoutCtrlsOff },
1119	{ "axtctrlsoff",_XkbCF_AccessXTimeoutCtrlsOff },
1120	{ "accessxtimeoutfeedbackon", _XkbCF_AccessXTimeoutOptsOn },
1121	{ "axtfeedbackon", _XkbCF_AccessXTimeoutOptsOn },
1122	{ "accessxtimeoutfeedbackoff", _XkbCF_AccessXTimeoutOptsOff },
1123	{ "axtfeedbackoff", _XkbCF_AccessXTimeoutOptsOff },
1124	{ "ignorelockmods",_XkbCF_IgnoreLockMods },
1125	{ "ignorelockmodifiers",_XkbCF_IgnoreLockMods },
1126	{ "ignoregrouplock",_XkbCF_IgnoreGroupLock },
1127	{ "internalmods",_XkbCF_InternalMods },
1128	{ "internalmodifiers",_XkbCF_InternalMods },
1129	{ "outofrangegroups",_XkbCF_GroupsWrap },
1130	{ "groups", _XkbCF_GroupsWrap },
1131	{ "feedback", _XkbCF_InitialFeedback },
1132};
1133#define	_XkbCFNumDfltFields (sizeof(_XkbCFDfltFields)/sizeof(XkbConfigFieldRec))
1134
1135static XkbConfigFieldsRec _XkbCFDflts = {
1136	0,			/* cfg_id */
1137	_XkbCFNumDfltFields,	/* num_fields */
1138	_XkbCFDfltFields,	/* fields */
1139	DefaultParser,	/* parser */
1140	DefaultFinish,	/* finish */
1141	NULL,			/* priv */
1142	NULL			/* next */
1143};
1144
1145XkbConfigFieldsPtr	XkbCFDflts= &_XkbCFDflts;
1146
1147/***====================================================================***/
1148
1149XkbConfigFieldsPtr
1150XkbCFDup(XkbConfigFieldsPtr fields)
1151{
1152XkbConfigFieldsPtr	pNew;
1153
1154    pNew= _XkbTypedAlloc(XkbConfigFieldsRec);
1155    if (pNew!=NULL) {
1156	memcpy(pNew,fields,sizeof(XkbConfigFieldsRec));
1157	if ((pNew->fields!=NULL)&&(pNew->num_fields>0)) {
1158	    pNew->fields= _XkbTypedCalloc(pNew->num_fields,XkbConfigFieldRec);
1159	    if (pNew->fields) {
1160		memcpy(fields->fields,pNew->fields,
1161				(pNew->num_fields*sizeof(XkbConfigFieldRec)));
1162	    }
1163	    else {
1164		_XkbFree(pNew);
1165		return NULL;
1166	    }
1167	}
1168	else {
1169	    pNew->num_fields= 0;
1170	    pNew->fields= NULL;
1171	}
1172	pNew->next= NULL;
1173    }
1174    return pNew;
1175}
1176
1177XkbConfigFieldsPtr
1178XkbCFFree(XkbConfigFieldsPtr fields,Bool all)
1179{
1180XkbConfigFieldsPtr	next;
1181
1182    next= NULL;
1183    while (fields!=NULL) {
1184	next= fields->next;
1185	if (fields!=XkbCFDflts) {
1186	    if (fields->fields) {
1187		_XkbFree(fields->fields);
1188		fields->fields= NULL;
1189		fields->num_fields= 0;
1190	    }
1191	    _XkbFree(fields);
1192	}
1193	fields= (all?next:NULL);
1194    }
1195    return next;
1196}
1197
1198Bool
1199XkbCFApplyRtrnValues(	XkbConfigRtrnPtr	rtrn,
1200			XkbConfigFieldsPtr	fields,
1201			XkbDescPtr		xkb)
1202{
1203Bool			ok;
1204
1205    if ((fields==NULL)||(rtrn==NULL)||(xkb==NULL))
1206	return False;
1207    for (ok=True;fields!=NULL;fields=fields->next) {
1208	if (fields->finish!=NULL)
1209	    ok= (*fields->finish)(fields,xkb,rtrn,XkbCF_Apply)&&ok;
1210    }
1211    return ok;
1212}
1213
1214XkbConfigRtrnPrivPtr
1215XkbCFAddPrivate(	XkbConfigRtrnPtr	rtrn,
1216			XkbConfigFieldsPtr	fields,
1217			XPointer		ptr)
1218{
1219XkbConfigRtrnPrivPtr	priv;
1220
1221    if ((rtrn==NULL)||(fields==NULL))
1222	return NULL;
1223    priv= _XkbTypedAlloc(XkbConfigRtrnPrivRec);
1224    if (priv!=NULL) {
1225	priv->cfg_id= 	fields->cfg_id;
1226	priv->priv=	ptr;
1227	priv->next= 	rtrn->priv;
1228	rtrn->priv=	priv;
1229    }
1230    return priv;
1231}
1232
1233void
1234XkbCFFreeRtrn(	XkbConfigRtrnPtr	rtrn,
1235		XkbConfigFieldsPtr	fields,
1236		XkbDescPtr		xkb)
1237{
1238XkbConfigRtrnPrivPtr	tmp,next;
1239
1240    if ((fields==NULL)||(rtrn==NULL))
1241	return;
1242    while (fields!=NULL) {
1243	if (fields->finish!=NULL)
1244	    (*fields->finish)(fields,xkb,rtrn,XkbCF_Destroy);
1245	fields= fields->next;
1246    }
1247    for (tmp=rtrn->priv;tmp!=NULL;tmp=next) {
1248	next= tmp->next;
1249	bzero((char *)tmp,sizeof(XkbConfigRtrnPrivRec));
1250	_XkbFree(tmp);
1251    }
1252    bzero((char *)rtrn,sizeof(XkbConfigRtrnRec));
1253    return;
1254}
1255
1256Bool
1257XkbCFParse(	FILE *			file,
1258		XkbConfigFieldsPtr	fields,
1259		XkbDescPtr		xkb,
1260		XkbConfigRtrnPtr	rtrn)
1261{
1262int			tok;
1263XkbCFScanResultRec	val;
1264XkbConfigFieldsPtr	tmp;
1265
1266    if ((file==NULL)||(fields==NULL)||(rtrn==NULL))
1267	return False;
1268    for (tok=0,tmp=fields;tmp!=NULL;tmp=tmp->next,tok++) {
1269	fields->cfg_id= tok;
1270    }
1271    bzero((char *)rtrn,sizeof(XkbConfigRtrnRec));
1272    rtrn->line= 1;
1273    rtrn->click_volume= -1;
1274    rtrn->bell_volume= -1;
1275    while ((tok=XkbCFScan(file,&val,rtrn))!=XkbCF_EOF) {
1276	if (tok==XkbCF_Ident) {
1277	    Bool		done;
1278	    for (tmp=fields,done=False;(tmp!=NULL)&&(!done);tmp=tmp->next) {
1279		register int 		i;
1280		XkbConfigFieldPtr	f;
1281
1282		for (i=0,f=tmp->fields;(i<tmp->num_fields)&&(!done);i++,f++) {
1283		    if (_XkbStrCaseCmp(val.str,f->field)!=0)
1284			continue;
1285		    if ((*tmp->parser)(file,tmp,f,xkb,rtrn))
1286			 done= True;
1287		    else goto BAILOUT;
1288		}
1289	    }
1290	}
1291	else if ((tok!=XkbCF_EOL)&&(tok!=XkbCF_Semi)) {
1292	    rtrn->error= XkbCF_MissingIdent;
1293	    goto BAILOUT;
1294	}
1295    }
1296    for (tmp=fields;tmp!=NULL;tmp=tmp->next) {
1297	if ((tmp->finish)&&(!(*tmp->finish)(tmp,xkb,rtrn,XkbCF_Check)))
1298	    goto BAILOUT;
1299    }
1300    return True;
1301BAILOUT:
1302    for (tmp=fields;tmp!=NULL;tmp=tmp->next) {
1303	if (tmp->finish)
1304	    (*tmp->finish)(tmp,xkb,rtrn,XkbCF_CleanUp);
1305    }
1306    return False;
1307}
1308
1309/*ARGSUSED*/
1310void
1311XkbCFReportError(FILE *file,char *name,int error,int line)
1312{
1313char *	msg;
1314
1315    switch(error) {
1316	case XkbCF_BadAlloc:
1317	    msg= "allocation failed\n"; break;
1318	case XkbCF_UnterminatedString:
1319	    msg= "unterminated string on line %d"; break;
1320	case XkbCF_MissingIdent:
1321	    msg= "expected identifier on line %d"; break;
1322	case XkbCF_MissingEquals:
1323	    msg= "expected '=' on line %d"; break;
1324	case XkbCF_ExpectedEOS:
1325	    msg= "expected ';' or newline on line %d"; break;
1326	case XkbCF_ExpectedBoolean:
1327	    msg= "expected a boolean value on line %d"; break;
1328	case XkbCF_ExpectedInteger:
1329	    msg= "expected a numeric value on line %d"; break;
1330	case XkbCF_ExpectedString:
1331	    msg= "expected a string on line %d"; break;
1332	case XkbCF_ExpectedModifier:
1333	    msg= "expected a modifier name on line %d"; break;
1334	case XkbCF_ExpectedControl:
1335	    msg= "expected a control name on line %d"; break;
1336	case XkbCF_ExpectedAXOption:
1337	    msg= "expected an AccessX option on line %d"; break;
1338	case XkbCF_ExpectedOperator:
1339	    msg= "expected '+' or '-' on line %d"; break;
1340	case XkbCF_ExpectedOORGroupBehavior:
1341	    msg= "expected wrap, clamp or group number on line %d"; break;
1342	default:
1343	    msg= "unknown error on line %d"; break;
1344    }
1345#ifndef XKB_IN_SERVER
1346    fprintf(file,msg,line);
1347    if (name)	fprintf(file," of %s\n",name);
1348    else	fprintf(file,"\n");
1349#else
1350    ErrorF(msg,line);
1351    if (name)	ErrorF(" of %s\n",name);
1352    else	ErrorF("\n");
1353#endif
1354    return;
1355}
1356