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