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