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