Don't leak KeyNamesInfo
[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         FreeXKBFile(rtrn);
430     }
431     else
432     {
433         info->errorCount += 10;
434         return False;
435     }
436     if ((stmt->next != NULL) && (included.errorCount < 1))
437     {
438         IncludeStmt *next;
439         unsigned op;
440         CompatInfo next_incl;
441
442         for (next = stmt->next; next != NULL; next = next->next)
443         {
444             if ((next->file == NULL) && (next->map == NULL))
445             {
446                 haveSelf = True;
447                 MergeIncludedCompatMaps(&included, info, next->merge);
448                 ClearCompatInfo(info, xkb);
449             }
450             else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
451             {
452                 InitCompatInfo(&next_incl, xkb);
453                 next_incl.fileID = rtrn->id;
454                 next_incl.dflt = info->dflt;
455                 next_incl.dflt.defs.fileID = rtrn->id;
456                 next_incl.dflt.defs.merge = op;
457                 next_incl.ledDflt.defs.fileID = rtrn->id;
458                 next_incl.ledDflt.defs.merge = op;
459                 next_incl.act = info->act;
460                 (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
461                 MergeIncludedCompatMaps(&included, &next_incl, op);
462                 ClearCompatInfo(&next_incl, xkb);
463                 FreeXKBFile(rtrn);
464             }
465             else
466             {
467                 info->errorCount += 10;
468                 return False;
469             }
470         }
471     }
472     if (haveSelf)
473         *info = included;
474     else
475     {
476         MergeIncludedCompatMaps(info, &included, newMerge);
477         ClearCompatInfo(&included, xkb);
478     }
479     return (info->errorCount == 0);
480 }
481
482 static const LookupEntry useModMapValues[] = {
483     {"levelone", 1},
484     {"level1", 1},
485     {"anylevel", 0},
486     {"any", 0},
487     {NULL, 0}
488 };
489
490 static int
491 SetInterpField(SymInterpInfo * si,
492                struct xkb_desc * xkb,
493                char *field,
494                ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
495 {
496     int ok = 1;
497     ExprResult tmp;
498
499     if (uStrCaseCmp(field, "action") == 0)
500     {
501         if (arrayNdx != NULL)
502             return ReportSINotArray(si, field, info);
503         ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
504                              info->act);
505         if (ok)
506             si->defs.defined |= _SI_Action;
507     }
508     else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
509              (uStrCaseCmp(field, "virtualmod") == 0))
510     {
511         if (arrayNdx != NULL)
512             return ReportSINotArray(si, field, info);
513         ok = ResolveVirtualModifier(value, xkb, &tmp, &info->vmods);
514         if (ok)
515         {
516             si->interp.virtual_mod = tmp.uval;
517             si->defs.defined |= _SI_VirtualMod;
518         }
519         else
520             return ReportSIBadType(si, field, "virtual modifier", info);
521     }
522     else if (uStrCaseCmp(field, "repeat") == 0)
523     {
524         if (arrayNdx != NULL)
525             return ReportSINotArray(si, field, info);
526         ok = ExprResolveBoolean(value, &tmp);
527         if (ok)
528         {
529             if (tmp.uval)
530                 si->interp.flags |= XkbSI_AutoRepeat;
531             else
532                 si->interp.flags &= ~XkbSI_AutoRepeat;
533             si->defs.defined |= _SI_AutoRepeat;
534         }
535         else
536             return ReportSIBadType(si, field, "boolean", info);
537     }
538     else if (uStrCaseCmp(field, "locking") == 0)
539     {
540         if (arrayNdx != NULL)
541             return ReportSINotArray(si, field, info);
542         ok = ExprResolveBoolean(value, &tmp);
543         if (ok)
544         {
545             if (tmp.uval)
546                 si->interp.flags |= XkbSI_LockingKey;
547             else
548                 si->interp.flags &= ~XkbSI_LockingKey;
549             si->defs.defined |= _SI_LockingKey;
550         }
551         else
552             return ReportSIBadType(si, field, "boolean", info);
553     }
554     else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
555              (uStrCaseCmp(field, "usemodmapmods") == 0))
556     {
557         if (arrayNdx != NULL)
558             return ReportSINotArray(si, field, info);
559         ok = ExprResolveEnum(value, &tmp, useModMapValues);
560         if (ok)
561         {
562             if (tmp.uval)
563                 si->interp.match |= XkbSI_LevelOneOnly;
564             else
565                 si->interp.match &= ~XkbSI_LevelOneOnly;
566             si->defs.defined |= _SI_LevelOneOnly;
567         }
568         else
569             return ReportSIBadType(si, field, "level specification", info);
570     }
571     else
572     {
573         ok = ReportBadField("symbol interpretation", field, siText(si, info));
574     }
575     return ok;
576 }
577
578 static int
579 HandleInterpVar(VarDef * stmt, struct xkb_desc * xkb, CompatInfo * info)
580 {
581     ExprResult elem, field;
582     ExprDef *ndx;
583     int ret;
584
585     if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
586         ret = 0;               /* internal error, already reported */
587     else if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
588         ret = SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
589                               info);
590     else if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
591         ret = SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
592                                   stmt->value);
593     else
594         ret = SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
595                             &info->act);
596     free(elem.str);
597     free(field.str);
598     return ret;
599 }
600
601 static int
602 HandleInterpBody(VarDef * def, struct xkb_desc * xkb, SymInterpInfo * si,
603                  CompatInfo * info)
604 {
605     int ok = 1;
606     ExprResult tmp, field;
607     ExprDef *arrayNdx;
608
609     for (; def != NULL; def = (VarDef *) def->common.next)
610     {
611         if ((def->name) && (def->name->type == ExprFieldRef))
612         {
613             ok = HandleInterpVar(def, xkb, info);
614             continue;
615         }
616         ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
617         if (ok) {
618             ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
619                                 info);
620             free(field.str);
621         }
622     }
623     return ok;
624 }
625
626 static int
627 HandleInterpDef(InterpDef * def, struct xkb_desc * xkb, unsigned merge,
628                 CompatInfo * info)
629 {
630     unsigned pred, mods;
631     SymInterpInfo si;
632
633     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
634     {
635         ERROR("Couldn't determine matching modifiers\n");
636         ACTION("Symbol interpretation ignored\n");
637         return False;
638     }
639     if (def->merge != MergeDefault)
640         merge = def->merge;
641
642     si = info->dflt;
643     si.defs.merge = merge;
644     if (!LookupKeysym(def->sym, &si.interp.sym))
645     {
646         WARN("Could not resolve keysym %s\n", def->sym);
647         info->errorCount++;
648         return False;
649     }
650     si.interp.match = pred & XkbSI_OpMask;
651     si.interp.mods = mods;
652     if (!HandleInterpBody(def->def, xkb, &si, info))
653     {
654         info->errorCount++;
655         return False;
656     }
657
658     if (!AddInterp(info, &si))
659     {
660         info->errorCount++;
661         return False;
662     }
663     return True;
664 }
665
666 static int
667 HandleGroupCompatDef(GroupCompatDef * def,
668                      struct xkb_desc * xkb, unsigned merge, CompatInfo * info)
669 {
670     ExprResult val;
671     GroupCompatInfo tmp;
672
673     if (def->merge != MergeDefault)
674         merge = def->merge;
675     if (!XkbIsLegalGroup(def->group - 1))
676     {
677         ERROR("Keyboard group must be in the range 1..%d\n",
678                XkbNumKbdGroups + 1);
679         ACTION("Compatibility map for illegal group %d ignored\n",
680                 def->group);
681         return False;
682     }
683     tmp.fileID = info->fileID;
684     tmp.merge = merge;
685     if (!ExprResolveVModMask(def->def, &val, xkb))
686     {
687         ERROR("Expected a modifier mask in group compatibility definition\n");
688         ACTION("Ignoring illegal compatibility map for group %d\n",
689                 def->group);
690         return False;
691     }
692     tmp.real_mods = val.uval & 0xff;
693     tmp.vmods = (val.uval >> 8) & 0xffff;
694     return AddGroupCompat(info, def->group - 1, &tmp);
695 }
696
697 static void
698 HandleCompatMapFile(XkbFile * file,
699                     struct xkb_desc * xkb, unsigned merge, CompatInfo * info)
700 {
701     ParseCommon *stmt;
702
703     if (merge == MergeDefault)
704         merge = MergeAugment;
705     free(info->name);
706     info->name = _XkbDupString(file->name);
707     stmt = file->defs;
708     while (stmt)
709     {
710         switch (stmt->stmtType)
711         {
712         case StmtInclude:
713             if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
714                                         HandleCompatMapFile))
715                 info->errorCount++;
716             break;
717         case StmtInterpDef:
718             if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
719                 info->errorCount++;
720             break;
721         case StmtGroupCompatDef:
722             if (!HandleGroupCompatDef
723                 ((GroupCompatDef *) stmt, xkb, merge, info))
724                 info->errorCount++;
725             break;
726         case StmtIndicatorMapDef:
727         {
728             LEDInfo *rtrn;
729             rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
730                                          &info->ledDflt, info->leds, merge);
731             if (rtrn != NULL)
732                 info->leds = rtrn;
733             else
734                 info->errorCount++;
735         }
736             break;
737         case StmtVarDef:
738             if (!HandleInterpVar((VarDef *) stmt, xkb, info))
739                 info->errorCount++;
740             break;
741         case StmtVModDef:
742             if (!HandleVModDef((VModDef *) stmt, xkb, merge, &info->vmods))
743                 info->errorCount++;
744             break;
745         case StmtKeycodeDef:
746             ERROR("Interpretation files may not include other types\n");
747             ACTION("Ignoring definition of key name\n");
748             info->errorCount++;
749             break;
750         default:
751             WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
752                   stmt->stmtType);
753             break;
754         }
755         stmt = stmt->next;
756         if (info->errorCount > 10)
757         {
758 #ifdef NOISY
759             ERROR("Too many errors\n");
760 #endif
761             ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
762             break;
763         }
764     }
765 }
766
767 static void
768 CopyInterps(CompatInfo * info,
769             struct xkb_compat_map * compat, Bool needSymbol, unsigned pred)
770 {
771     SymInterpInfo *si;
772
773     for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
774     {
775         if (((si->interp.match & XkbSI_OpMask) != pred) ||
776             (needSymbol && (si->interp.sym == NoSymbol)) ||
777             ((!needSymbol) && (si->interp.sym != NoSymbol)))
778             continue;
779         if (compat->num_si >= compat->size_si)
780         {
781             WSGO("No room to merge symbol interpretations\n");
782             ACTION("Symbol interpretations lost\n");
783             return;
784         }
785         compat->sym_interpret[compat->num_si++] = si->interp;
786     }
787 }
788
789 Bool
790 CompileCompatMap(XkbFile *file, struct xkb_desc * xkb, unsigned merge,
791                  LEDInfoPtr *unboundLEDs)
792 {
793     int i;
794     CompatInfo info;
795     GroupCompatInfo *gcm;
796
797     InitCompatInfo(&info, xkb);
798     info.dflt.defs.merge = merge;
799     info.ledDflt.defs.merge = merge;
800     HandleCompatMapFile(file, xkb, merge, &info);
801
802     if (info.errorCount == 0)
803     {
804         int size;
805         if (XkbcAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
806             Success)
807         {
808             WSGO("Couldn't allocate compatibility map\n");
809             return False;
810         }
811         if (info.name != NULL)
812         {
813             if (XkbcAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
814                 xkb->names->compat =
815                     xkb_intern_atom(info.name);
816             else
817             {
818                 WSGO("Couldn't allocate space for compat name\n");
819                 ACTION("Name \"%s\" (from %s) NOT assigned\n",
820                         scanFile, info.name);
821             }
822         }
823         size = info.nInterps * sizeof(struct xkb_sym_interpret);
824         if (size > 0)
825         {
826             CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
827             CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
828             CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
829             CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
830             CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
831             CopyInterps(&info, xkb->compat, False,
832                         XkbSI_AllOf | XkbSI_NoneOf);
833             CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
834             CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
835         }
836         for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
837              i++, gcm++)
838         {
839             if ((gcm->fileID != 0) || (gcm->real_mods != 0)
840                 || (gcm->vmods != 0))
841             {
842                 xkb->compat->groups[i].mask = gcm->real_mods;
843                 xkb->compat->groups[i].real_mods = gcm->real_mods;
844                 xkb->compat->groups[i].vmods = gcm->vmods;
845             }
846         }
847         if (info.leds != NULL)
848         {
849             if (!CopyIndicatorMapDefs(xkb, info.leds, unboundLEDs))
850                 info.errorCount++;
851             info.leds = NULL;
852         }
853         ClearCompatInfo(&info, xkb);
854         return True;
855     }
856     free(info.interps);
857     return False;
858 }