upload tizen2.0 source
[framework/uifw/xorg/util/x11-xkb-utils.git] / xkbcomp / compat.c
1 /************************************************************
2  Copyright (c) 1994 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 #include <X11/Xos.h>
28 #include "xkbcomp.h"
29 #include "tokens.h"
30 #include "expr.h"
31 #include "vmod.h"
32 #include "misc.h"
33 #include "indicators.h"
34 #include "action.h"
35 #include "compat.h"
36
37 typedef struct _SymInterpInfo
38 {
39     CommonInfo defs;
40     XkbSymInterpretRec interp;
41 } SymInterpInfo;
42
43 #define _SI_VirtualMod          (1<<0)
44 #define _SI_Action              (1<<1)
45 #define _SI_AutoRepeat          (1<<2)
46 #define _SI_LockingKey          (1<<3)
47 #define _SI_LevelOneOnly        (1<<4)
48
49 typedef struct _GroupCompatInfo
50 {
51     unsigned char fileID;
52     unsigned char merge;
53     Bool defined;
54     unsigned char real_mods;
55     unsigned short vmods;
56 } GroupCompatInfo;
57
58 typedef struct _CompatInfo
59 {
60     char *name;
61     unsigned fileID;
62     int errorCount;
63     int nInterps;
64     SymInterpInfo *interps;
65     SymInterpInfo dflt;
66     LEDInfo ledDflt;
67     GroupCompatInfo groupCompat[XkbNumKbdGroups];
68     LEDInfo *leds;
69     VModInfo vmods;
70     ActionInfo *act;
71     XkbDescPtr xkb;
72 } CompatInfo;
73
74 /***====================================================================***/
75
76 #define ReportSINotArray(si,f,i) \
77         ReportNotArray("symbol interpretation",(f),siText((si),(i)))
78 #define ReportSIBadType(si,f,w,i) \
79         ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
80
81 /***====================================================================***/
82
83 static char *
84 siText(SymInterpInfo * si, CompatInfo * info)
85 {
86     static char buf[128];
87
88     if (si == &info->dflt)
89     {
90         snprintf(buf, sizeof(buf), "default");
91     }
92     else
93     {
94         snprintf(buf, sizeof(buf), "%s+%s(%s)", 
95                 XkbKeysymText(si->interp.sym, XkbMessage),
96                 XkbSIMatchText(si->interp.match, XkbMessage),
97                 XkbModMaskText(si->interp.mods, XkbMessage));
98     }
99     return buf;
100 }
101
102 static void
103 InitCompatInfo(CompatInfo * info, XkbDescPtr xkb)
104 {
105     register int i;
106
107     info->xkb = xkb;
108     info->name = NULL;
109     info->fileID = 0;
110     info->errorCount = 0;
111     info->nInterps = 0;
112     info->interps = NULL;
113     info->act = NULL;
114     info->dflt.defs.fileID = info->fileID;
115     info->dflt.defs.defined = 0;
116     info->dflt.defs.merge = MergeOverride;
117     info->dflt.interp.flags = 0;
118     info->dflt.interp.virtual_mod = XkbNoModifier;
119     info->dflt.interp.act.type = XkbSA_NoAction;
120     for (i = 0; i < XkbAnyActionDataSize; i++)
121     {
122         info->dflt.interp.act.data[i] = 0;
123     }
124     ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
125     info->ledDflt.defs.fileID = info->fileID;
126     info->ledDflt.defs.defined = 0;
127     info->ledDflt.defs.merge = MergeOverride;
128     bzero((char *) &info->groupCompat[0],
129           XkbNumKbdGroups * sizeof(GroupCompatInfo));
130     info->leds = NULL;
131     InitVModInfo(&info->vmods, xkb);
132     return;
133 }
134
135 static void
136 ClearCompatInfo(CompatInfo * info, XkbDescPtr xkb)
137 {
138     register int i;
139
140     if (info->name != NULL)
141         uFree(info->name);
142     info->name = NULL;
143     info->dflt.defs.defined = 0;
144     info->dflt.defs.merge = MergeAugment;
145     info->dflt.interp.flags = 0;
146     info->dflt.interp.virtual_mod = XkbNoModifier;
147     info->dflt.interp.act.type = XkbSA_NoAction;
148     for (i = 0; i < XkbAnyActionDataSize; i++)
149     {
150         info->dflt.interp.act.data[i] = 0;
151     }
152     ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
153     info->nInterps = 0;
154     info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
155     bzero((char *) &info->groupCompat[0],
156           XkbNumKbdGroups * sizeof(GroupCompatInfo));
157     info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
158     /* 3/30/94 (ef) -- XXX! Should free action info here */
159     ClearVModInfo(&info->vmods, xkb);
160     return;
161 }
162
163 static SymInterpInfo *
164 NextInterp(CompatInfo * info)
165 {
166     SymInterpInfo *si;
167
168     si = uTypedAlloc(SymInterpInfo);
169     if (si)
170     {
171         bzero((char *) si, sizeof(SymInterpInfo));
172         info->interps =
173             (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
174                                             (CommonInfo *) si);
175         info->nInterps++;
176     }
177     return si;
178 }
179
180 static SymInterpInfo *
181 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
182 {
183     SymInterpInfo *old;
184
185     for (old = info->interps; old != NULL;
186          old = (SymInterpInfo *) old->defs.next)
187     {
188         if ((old->interp.sym == new->interp.sym) &&
189             (old->interp.mods == new->interp.mods) &&
190             (old->interp.match == new->interp.match))
191         {
192             return old;
193         }
194     }
195     return NULL;
196 }
197
198 static Bool
199 AddInterp(CompatInfo * info, SymInterpInfo * new)
200 {
201     unsigned collide;
202     SymInterpInfo *old;
203
204     collide = 0;
205     old = FindMatchingInterp(info, new);
206     if (old != NULL)
207     {
208         if (new->defs.merge == MergeReplace)
209         {
210             SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
211             if (((old->defs.fileID == new->defs.fileID)
212                  && (warningLevel > 0)) || (warningLevel > 9))
213             {
214                 WARN1("Multiple definitions for \"%s\"\n", siText(new, info));
215                 ACTION("Earlier interpretation ignored\n");
216             }
217             *old = *new;
218             old->defs.next = &next->defs;
219             return True;
220         }
221         if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
222         {
223             old->interp.virtual_mod = new->interp.virtual_mod;
224             old->defs.defined |= _SI_VirtualMod;
225         }
226         if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
227         {
228             old->interp.act = new->interp.act;
229             old->defs.defined |= _SI_Action;
230         }
231         if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
232         {
233             old->interp.flags &= ~XkbSI_AutoRepeat;
234             old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
235             old->defs.defined |= _SI_AutoRepeat;
236         }
237         if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
238         {
239             old->interp.flags &= ~XkbSI_LockingKey;
240             old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
241             old->defs.defined |= _SI_LockingKey;
242         }
243         if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
244         {
245             old->interp.match &= ~XkbSI_LevelOneOnly;
246             old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
247             old->defs.defined |= _SI_LevelOneOnly;
248         }
249         if (collide)
250         {
251             WARN1("Multiple interpretations of \"%s\"\n", siText(new, info));
252             ACTION1("Using %s definition for duplicate fields\n",
253                     (new->defs.merge != MergeAugment ? "last" : "first"));
254         }
255         return True;
256     }
257     old = new;
258     if ((new = NextInterp(info)) == NULL)
259         return False;
260     *new = *old;
261     new->defs.next = NULL;
262     return True;
263 }
264
265 static Bool
266 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
267 {
268     GroupCompatInfo *gc;
269     unsigned merge;
270
271     merge = newGC->merge;
272     gc = &info->groupCompat[group];
273     if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
274     {
275         return True;
276     }
277     if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
278         || (warningLevel > 9))
279     {
280         WARN1("Compat map for group %d redefined\n", group + 1);
281         ACTION1("Using %s definition\n",
282                 (merge == MergeAugment ? "old" : "new"));
283     }
284     if(newGC->defined && (merge != MergeAugment || !gc->defined))
285         *gc = *newGC;
286     return True;
287 }
288
289 /***====================================================================***/
290
291 static Bool
292 ResolveStateAndPredicate(ExprDef * expr,
293                          unsigned *pred_rtrn,
294                          unsigned *mods_rtrn, CompatInfo * info)
295 {
296     ExprResult result;
297
298     if (expr == NULL)
299     {
300         *pred_rtrn = XkbSI_AnyOfOrNone;
301         *mods_rtrn = ~0;
302         return True;
303     }
304
305     *pred_rtrn = XkbSI_Exactly;
306     if (expr->op == ExprActionDecl)
307     {
308         char *pred_txt =
309             XkbAtomText(NULL, expr->value.action.name, XkbMessage);
310         if (uStrCaseCmp(pred_txt, "noneof") == 0)
311             *pred_rtrn = XkbSI_NoneOf;
312         else if (uStrCaseCmp(pred_txt, "anyofornone") == 0)
313             *pred_rtrn = XkbSI_AnyOfOrNone;
314         else if (uStrCaseCmp(pred_txt, "anyof") == 0)
315             *pred_rtrn = XkbSI_AnyOf;
316         else if (uStrCaseCmp(pred_txt, "allof") == 0)
317             *pred_rtrn = XkbSI_AllOf;
318         else if (uStrCaseCmp(pred_txt, "exactly") == 0)
319             *pred_rtrn = XkbSI_Exactly;
320         else
321         {
322             ERROR1("Illegal modifier predicate \"%s\"\n", pred_txt);
323             ACTION("Ignored\n");
324             return False;
325         }
326         expr = expr->value.action.args;
327     }
328     else if (expr->op == ExprIdent)
329     {
330         char *pred_txt = XkbAtomText(NULL, expr->value.str, XkbMessage);
331         if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0))
332         {
333             *pred_rtrn = XkbSI_AnyOf;
334             *mods_rtrn = 0xff;
335             return True;
336         }
337     }
338
339     if (ExprResolveModMask(expr, &result, NULL, NULL))
340     {
341         *mods_rtrn = result.uval;
342         return True;
343     }
344     return False;
345 }
346
347 /***====================================================================***/
348
349 static void
350 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
351 {
352     SymInterpInfo *si;
353     LEDInfo *led, *rtrn, *next;
354     GroupCompatInfo *gcm;
355     register int i;
356
357     if (from->errorCount > 0)
358     {
359         into->errorCount += from->errorCount;
360         return;
361     }
362     if (into->name == NULL)
363     {
364         into->name = from->name;
365         from->name = NULL;
366     }
367     for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
368     {
369         if (merge != MergeDefault)
370             si->defs.merge = merge;
371         if (!AddInterp(into, si))
372             into->errorCount++;
373     }
374     for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
375     {
376         if (merge != MergeDefault)
377             gcm->merge = merge;
378         if (!AddGroupCompat(into, i, gcm))
379             into->errorCount++;
380     }
381     for (led = from->leds; led != NULL; led = next)
382     {
383         next = (LEDInfo *) led->defs.next;
384         if (merge != MergeDefault)
385             led->defs.merge = merge;
386         rtrn = AddIndicatorMap(into->leds, led);
387         if (rtrn != NULL)
388             into->leds = rtrn;
389         else
390             into->errorCount++;
391     }
392     return;
393 }
394
395 typedef void (*FileHandler) (XkbFile * /* rtrn */ ,
396                              XkbDescPtr /* xkb */ ,
397                              unsigned /* merge */ ,
398                              CompatInfo *       /* info */
399     );
400
401 static Bool
402 HandleIncludeCompatMap(IncludeStmt * stmt,
403                        XkbDescPtr xkb, CompatInfo * info, FileHandler hndlr)
404 {
405     unsigned newMerge;
406     XkbFile *rtrn;
407     CompatInfo included;
408     Bool haveSelf;
409
410     haveSelf = False;
411     if ((stmt->file == NULL) && (stmt->map == NULL))
412     {
413         haveSelf = True;
414         included = *info;
415         bzero(info, sizeof(CompatInfo));
416     }
417     else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
418     {
419         InitCompatInfo(&included, xkb);
420         included.fileID = rtrn->id;
421         included.dflt = info->dflt;
422         included.dflt.defs.fileID = rtrn->id;
423         included.dflt.defs.merge = newMerge;
424         included.ledDflt.defs.fileID = rtrn->id;
425         included.ledDflt.defs.merge = newMerge;
426         included.act = info->act;
427         (*hndlr) (rtrn, xkb, MergeOverride, &included);
428         if (stmt->stmt != NULL)
429         {
430             if (included.name != NULL)
431                 uFree(included.name);
432             included.name = stmt->stmt;
433             stmt->stmt = NULL;
434         }
435     }
436     else
437     {
438         info->errorCount += 10;
439         return False;
440     }
441     if ((stmt->next != NULL) && (included.errorCount < 1))
442     {
443         IncludeStmt *next;
444         unsigned op;
445         CompatInfo next_incl;
446
447         for (next = stmt->next; next != NULL; next = next->next)
448         {
449             if ((next->file == NULL) && (next->map == NULL))
450             {
451                 haveSelf = True;
452                 MergeIncludedCompatMaps(&included, info, next->merge);
453                 ClearCompatInfo(info, xkb);
454             }
455             else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
456             {
457                 InitCompatInfo(&next_incl, xkb);
458                 next_incl.fileID = rtrn->id;
459                 next_incl.dflt = info->dflt;
460                 next_incl.dflt.defs.fileID = rtrn->id;
461                 next_incl.dflt.defs.merge = op;
462                 next_incl.ledDflt.defs.fileID = rtrn->id;
463                 next_incl.ledDflt.defs.merge = op;
464                 next_incl.act = info->act;
465                 (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
466                 MergeIncludedCompatMaps(&included, &next_incl, op);
467                 ClearCompatInfo(&next_incl, xkb);
468             }
469             else
470             {
471                 info->errorCount += 10;
472                 return False;
473             }
474         }
475     }
476     if (haveSelf)
477         *info = included;
478     else
479     {
480         MergeIncludedCompatMaps(info, &included, newMerge);
481         ClearCompatInfo(&included, xkb);
482     }
483     return (info->errorCount == 0);
484 }
485
486 static LookupEntry useModMapValues[] = {
487     {"levelone", 1},
488     {"level1", 1},
489     {"anylevel", 0},
490     {"any", 0},
491     {NULL, 0}
492 };
493
494 static int
495 SetInterpField(SymInterpInfo * si,
496                XkbDescPtr xkb,
497                char *field,
498                ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
499 {
500     int ok = 1;
501     ExprResult tmp;
502
503     if (uStrCaseCmp(field, "action") == 0)
504     {
505         if (arrayNdx != NULL)
506             return ReportSINotArray(si, field, info);
507         ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
508                              info->act);
509         if (ok)
510             si->defs.defined |= _SI_Action;
511     }
512     else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
513              (uStrCaseCmp(field, "virtualmod") == 0))
514     {
515         if (arrayNdx != NULL)
516             return ReportSINotArray(si, field, info);
517         ok = ResolveVirtualModifier(value, &tmp, &info->vmods);
518         if (ok)
519         {
520             si->interp.virtual_mod = tmp.uval;
521             si->defs.defined |= _SI_VirtualMod;
522         }
523         else
524             return ReportSIBadType(si, field, "virtual modifier", info);
525     }
526     else if (uStrCaseCmp(field, "repeat") == 0)
527     {
528         if (arrayNdx != NULL)
529             return ReportSINotArray(si, field, info);
530         ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
531         if (ok)
532         {
533             if (tmp.uval)
534                 si->interp.flags |= XkbSI_AutoRepeat;
535             else
536                 si->interp.flags &= ~XkbSI_AutoRepeat;
537             si->defs.defined |= _SI_AutoRepeat;
538         }
539         else
540             return ReportSIBadType(si, field, "boolean", info);
541     }
542     else if (uStrCaseCmp(field, "locking") == 0)
543     {
544         if (arrayNdx != NULL)
545             return ReportSINotArray(si, field, info);
546         ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
547         if (ok)
548         {
549             if (tmp.uval)
550                 si->interp.flags |= XkbSI_LockingKey;
551             else
552                 si->interp.flags &= ~XkbSI_LockingKey;
553             si->defs.defined |= _SI_LockingKey;
554         }
555         else
556             return ReportSIBadType(si, field, "boolean", info);
557     }
558     else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
559              (uStrCaseCmp(field, "usemodmapmods") == 0))
560     {
561         if (arrayNdx != NULL)
562             return ReportSINotArray(si, field, info);
563         ok = ExprResolveEnum(value, &tmp, useModMapValues);
564         if (ok)
565         {
566             if (tmp.uval)
567                 si->interp.match |= XkbSI_LevelOneOnly;
568             else
569                 si->interp.match &= ~XkbSI_LevelOneOnly;
570             si->defs.defined |= _SI_LevelOneOnly;
571         }
572         else
573             return ReportSIBadType(si, field, "level specification", info);
574     }
575     else
576     {
577         ok = ReportBadField("symbol interpretation", field, siText(si, info));
578     }
579     return ok;
580 }
581
582 LookupEntry groupNames[] = {
583     {"group1", 0x01}
584     ,
585     {"group2", 0x02}
586     ,
587     {"group3", 0x04}
588     ,
589     {"group4", 0x08}
590     ,
591     {"group5", 0x10}
592     ,
593     {"group6", 0x20}
594     ,
595     {"group7", 0x40}
596     ,
597     {"group8", 0x80}
598     ,
599     {"none", 0x00}
600     ,
601     {"all", 0xff}
602     ,
603     {NULL, 0}
604 };
605
606 static int
607 HandleInterpVar(VarDef * stmt, XkbDescPtr xkb, CompatInfo * info)
608 {
609     ExprResult elem, field;
610     ExprDef *ndx;
611
612     if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
613         return 0;               /* internal error, already reported */
614     if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
615         return SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
616                               info);
617     if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
618     {
619         return SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
620                                     stmt->value);
621     }
622     return SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
623                           &info->act);
624 }
625
626 static int
627 HandleInterpBody(VarDef * def, XkbDescPtr xkb, SymInterpInfo * si,
628                  CompatInfo * info)
629 {
630     int ok = 1;
631     ExprResult tmp, field;
632     ExprDef *arrayNdx;
633
634     for (; def != NULL; def = (VarDef *) def->common.next)
635     {
636         if ((def->name) && (def->name->type == ExprFieldRef))
637         {
638             ok = HandleInterpVar(def, xkb, info);
639             continue;
640         }
641         ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
642         if (ok)
643             ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
644                                 info);
645     }
646     return ok;
647 }
648
649 static int
650 HandleInterpDef(InterpDef * def, XkbDescPtr xkb, unsigned merge,
651                 CompatInfo * info)
652 {
653     unsigned pred, mods;
654     SymInterpInfo si;
655
656     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
657     {
658         ERROR("Couldn't determine matching modifiers\n");
659         ACTION("Symbol interpretation ignored\n");
660         return True;
661     }
662     if (def->ignore)
663     {
664         ERROR("Couldn't lookup keysym\n");
665         ACTION("Symbol interpretation ignored\n");
666         return True;
667     }
668
669     if (def->merge != MergeDefault)
670         merge = def->merge;
671
672     si = info->dflt;
673     si.defs.merge = merge;
674     si.interp.sym = def->sym;
675     si.interp.match = pred & XkbSI_OpMask;
676     si.interp.mods = mods;
677     if (!HandleInterpBody(def->def, xkb, &si, info))
678     {
679         info->errorCount++;
680         return False;
681     }
682
683     if (!AddInterp(info, &si))
684     {
685         info->errorCount++;
686         return False;
687     }
688     return True;
689 }
690
691 static int
692 HandleGroupCompatDef(GroupCompatDef * def,
693                      XkbDescPtr xkb, unsigned merge, CompatInfo * info)
694 {
695     ExprResult val;
696     GroupCompatInfo tmp;
697
698     if (def->merge != MergeDefault)
699         merge = def->merge;
700     if (!XkbIsLegalGroup(def->group - 1))
701     {
702         ERROR1("Keyboard group must be in the range 1..%d\n",
703                XkbNumKbdGroups + 1);
704         ACTION1("Compatibility map for illegal group %d ignored\n",
705                 def->group);
706         return False;
707     }
708     tmp.fileID = info->fileID;
709     tmp.merge = merge;
710     if (!ExprResolveModMask(def->def, &val, LookupVModMask, (XPointer) xkb))
711     {
712         ERROR("Expected a modifier mask in group compatibility definition\n");
713         ACTION1("Ignoring illegal compatibility map for group %d\n",
714                 def->group);
715         return False;
716     }
717     tmp.real_mods = val.uval & 0xff;
718     tmp.vmods = (val.uval >> 8) & 0xffff;
719     tmp.defined = True;
720     return AddGroupCompat(info, def->group - 1, &tmp);
721 }
722
723 static void
724 HandleCompatMapFile(XkbFile * file,
725                     XkbDescPtr xkb, unsigned merge, CompatInfo * info)
726 {
727     ParseCommon *stmt;
728
729     if (merge == MergeDefault)
730         merge = MergeAugment;
731     info->name = uStringDup(file->name);
732     stmt = file->defs;
733     while (stmt)
734     {
735         switch (stmt->stmtType)
736         {
737         case StmtInclude:
738             if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
739                                         HandleCompatMapFile))
740                 info->errorCount++;
741             break;
742         case StmtInterpDef:
743             if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
744                 info->errorCount++;
745             break;
746         case StmtGroupCompatDef:
747             if (!HandleGroupCompatDef
748                 ((GroupCompatDef *) stmt, xkb, merge, info))
749                 info->errorCount++;
750             break;
751         case StmtIndicatorMapDef:
752         {
753             LEDInfo *rtrn;
754             rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
755                                          &info->ledDflt, info->leds, merge);
756             if (rtrn != NULL)
757                 info->leds = rtrn;
758             else
759                 info->errorCount++;
760         }
761             break;
762         case StmtVarDef:
763             if (!HandleInterpVar((VarDef *) stmt, xkb, info))
764                 info->errorCount++;
765             break;
766         case StmtVModDef:
767             if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
768                 info->errorCount++;
769             break;
770         case StmtKeycodeDef:
771             ERROR("Interpretation files may not include other types\n");
772             ACTION("Ignoring definition of key name\n");
773             info->errorCount++;
774             break;
775         default:
776             WSGO1("Unexpected statement type %d in HandleCompatMapFile\n",
777                   stmt->stmtType);
778             break;
779         }
780         stmt = stmt->next;
781         if (info->errorCount > 10)
782         {
783 #ifdef NOISY
784             ERROR("Too many errors\n");
785 #endif
786             ACTION1("Abandoning compatibility map \"%s\"\n", file->topName);
787             break;
788         }
789     }
790     return;
791 }
792
793 static void
794 CopyInterps(CompatInfo * info,
795             XkbCompatMapPtr compat, Bool needSymbol, unsigned pred)
796 {
797     SymInterpInfo *si;
798
799     for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
800     {
801         if (((si->interp.match & XkbSI_OpMask) != pred) ||
802             (needSymbol && (si->interp.sym == NoSymbol)) ||
803             ((!needSymbol) && (si->interp.sym != NoSymbol)))
804             continue;
805         if (compat->num_si >= compat->size_si)
806         {
807             WSGO("No room to merge symbol interpretations\n");
808             ACTION("Symbol interpretations lost\n");
809             return;
810         }
811         compat->sym_interpret[compat->num_si++] = si->interp;
812     }
813     return;
814 }
815
816 Bool
817 CompileCompatMap(XkbFile * file,
818                  XkbFileInfo * result, unsigned merge, LEDInfo ** unboundLEDs)
819 {
820     int i;
821     CompatInfo info;
822     XkbDescPtr xkb;
823     GroupCompatInfo *gcm;
824
825     xkb = result->xkb;
826     InitCompatInfo(&info, xkb);
827     info.dflt.defs.merge = merge;
828     info.ledDflt.defs.merge = merge;
829     HandleCompatMapFile(file, xkb, merge, &info);
830
831     if (info.errorCount == 0)
832     {
833         int size;
834         if (XkbAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
835             Success)
836         {
837             WSGO("Couldn't allocate compatibility map\n");
838             ACTION("Exiting\n");
839             return False;
840         }
841         if (info.name != NULL)
842         {
843             if (XkbAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
844                 xkb->names->compat =
845                     XkbInternAtom(xkb->dpy, info.name, False);
846             else
847             {
848                 WSGO("Couldn't allocate space for compat name\n");
849                 ACTION2("Name \"%s\" (from %s) NOT assigned\n",
850                         scanFile, info.name);
851             }
852         }
853         size = info.nInterps * sizeof(XkbSymInterpretRec);
854         if (size > 0)
855         {
856             CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
857             CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
858             CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
859             CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
860             CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
861             CopyInterps(&info, xkb->compat, False,
862                         XkbSI_AllOf | XkbSI_NoneOf);
863             CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
864             CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
865         }
866         for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
867              i++, gcm++)
868         {
869             if ((gcm->fileID != 0) || (gcm->real_mods != 0)
870                 || (gcm->vmods != 0))
871             {
872                 xkb->compat->groups[i].mask = gcm->real_mods;
873                 xkb->compat->groups[i].real_mods = gcm->real_mods;
874                 xkb->compat->groups[i].vmods = gcm->vmods;
875             }
876         }
877         if (info.leds != NULL)
878         {
879             if (!CopyIndicatorMapDefs(result, info.leds, unboundLEDs))
880                 info.errorCount++;
881             info.leds = NULL;
882         }
883         ClearCompatInfo(&info, xkb);
884         return True;
885     }
886     if (info.interps != NULL)
887         uFree(info.interps);
888     return False;
889 }