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