bad5cc29f19b1924839fbf2a63f136fa1dae7440
[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 "tokens.h"
32 #include "expr.h"
33 #include "vmod.h"
34 #include "misc.h"
35 #include "indicators.h"
36 #include "action.h"
37 #include "compat.h"
38 #include "parseutils.h"
39
40 typedef struct _SymInterpInfo
41 {
42     CommonInfo defs;
43     struct xkb_sym_interpret interp;
44 } SymInterpInfo;
45
46 #define _SI_VirtualMod          (1<<0)
47 #define _SI_Action              (1<<1)
48 #define _SI_AutoRepeat          (1<<2)
49 #define _SI_LockingKey          (1<<3)
50 #define _SI_LevelOneOnly        (1<<4)
51
52 typedef struct _GroupCompatInfo
53 {
54     unsigned char fileID;
55     unsigned char merge;
56     unsigned char real_mods;
57     uint32_t vmods;
58 } GroupCompatInfo;
59
60 typedef struct _CompatInfo
61 {
62     char *name;
63     unsigned fileID;
64     int errorCount;
65     int nInterps;
66     SymInterpInfo *interps;
67     SymInterpInfo dflt;
68     LEDInfo ledDflt;
69     GroupCompatInfo groupCompat[XkbNumKbdGroups];
70     LEDInfo *leds;
71     VModInfo vmods;
72     ActionInfo *act;
73     struct xkb_desc * xkb;
74 } CompatInfo;
75
76 /***====================================================================***/
77
78 #define ReportSINotArray(si,f,i) \
79         ReportNotArray("symbol interpretation",(f),siText((si),(i)))
80 #define ReportSIBadType(si,f,w,i) \
81         ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
82
83 /***====================================================================***/
84
85 static char *
86 siText(SymInterpInfo * si, CompatInfo * info)
87 {
88     static char buf[128];
89
90     if (si == &info->dflt)
91     {
92         snprintf(buf, sizeof(buf), "default");
93     }
94     else
95     {
96         snprintf(buf, sizeof(buf), "%s+%s(%s)",
97                 XkbcKeysymText(si->interp.sym),
98                 XkbcSIMatchText(si->interp.match),
99                 XkbcModMaskText(si->interp.mods, False));
100     }
101     return buf;
102 }
103
104 static void
105 InitCompatInfo(CompatInfo * info, struct xkb_desc * xkb)
106 {
107     register int i;
108
109     info->xkb = xkb;
110     info->name = NULL;
111     info->fileID = 0;
112     info->errorCount = 0;
113     info->nInterps = 0;
114     info->interps = NULL;
115     info->act = NULL;
116     info->dflt.defs.fileID = info->fileID;
117     info->dflt.defs.defined = 0;
118     info->dflt.defs.merge = MergeOverride;
119     info->dflt.interp.flags = 0;
120     info->dflt.interp.virtual_mod = XkbNoModifier;
121     info->dflt.interp.act.type = XkbSA_NoAction;
122     for (i = 0; i < sizeof info->dflt.interp.act.data; i++)
123     {
124         info->dflt.interp.act.data[i] = 0;
125     }
126     ClearIndicatorMapInfo(&info->ledDflt);
127     info->ledDflt.defs.fileID = info->fileID;
128     info->ledDflt.defs.defined = 0;
129     info->ledDflt.defs.merge = MergeOverride;
130     bzero((char *) &info->groupCompat[0],
131           XkbNumKbdGroups * sizeof(GroupCompatInfo));
132     info->leds = NULL;
133     InitVModInfo(&info->vmods, xkb);
134     return;
135 }
136
137 static void
138 ClearCompatInfo(CompatInfo * info, struct xkb_desc * xkb)
139 {
140     register int i;
141
142     if (info->name != NULL)
143         free(info->name);
144     info->name = NULL;
145     info->dflt.defs.defined = 0;
146     info->dflt.defs.merge = MergeAugment;
147     info->dflt.interp.flags = 0;
148     info->dflt.interp.virtual_mod = XkbNoModifier;
149     info->dflt.interp.act.type = XkbSA_NoAction;
150     for (i = 0; i < sizeof info->dflt.interp.act.data; i++)
151     {
152         info->dflt.interp.act.data[i] = 0;
153     }
154     ClearIndicatorMapInfo(&info->ledDflt);
155     info->nInterps = 0;
156     info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
157     bzero((char *) &info->groupCompat[0],
158           XkbNumKbdGroups * sizeof(GroupCompatInfo));
159     info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
160     /* 3/30/94 (ef) -- XXX! Should free action info here */
161     ClearVModInfo(&info->vmods, xkb);
162     return;
163 }
164
165 static SymInterpInfo *
166 NextInterp(CompatInfo * info)
167 {
168     SymInterpInfo *si;
169
170     si = uTypedAlloc(SymInterpInfo);
171     if (si)
172     {
173         bzero((char *) si, 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, NULL, NULL))
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     register 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     return;
394 }
395
396 typedef void (*FileHandler) (XkbFile * /* rtrn */ ,
397                              struct xkb_desc * /* xkb */ ,
398                              unsigned /* merge */ ,
399                              CompatInfo *       /* info */
400     );
401
402 static Bool
403 HandleIncludeCompatMap(IncludeStmt * stmt,
404                        struct xkb_desc * xkb, CompatInfo * info, FileHandler hndlr)
405 {
406     unsigned newMerge;
407     XkbFile *rtrn;
408     CompatInfo included;
409     Bool haveSelf;
410
411     haveSelf = False;
412     if ((stmt->file == NULL) && (stmt->map == NULL))
413     {
414         haveSelf = True;
415         included = *info;
416         bzero(info, sizeof(CompatInfo));
417     }
418     else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
419     {
420         InitCompatInfo(&included, xkb);
421         included.fileID = rtrn->id;
422         included.dflt = info->dflt;
423         included.dflt.defs.fileID = rtrn->id;
424         included.dflt.defs.merge = newMerge;
425         included.ledDflt.defs.fileID = rtrn->id;
426         included.ledDflt.defs.merge = newMerge;
427         included.act = info->act;
428         (*hndlr) (rtrn, xkb, MergeOverride, &included);
429         if (stmt->stmt != NULL)
430         {
431             if (included.name != NULL)
432                 free(included.name);
433             included.name = stmt->stmt;
434             stmt->stmt = NULL;
435         }
436     }
437     else
438     {
439         info->errorCount += 10;
440         return False;
441     }
442     if ((stmt->next != NULL) && (included.errorCount < 1))
443     {
444         IncludeStmt *next;
445         unsigned op;
446         CompatInfo next_incl;
447
448         for (next = stmt->next; next != NULL; next = next->next)
449         {
450             if ((next->file == NULL) && (next->map == NULL))
451             {
452                 haveSelf = True;
453                 MergeIncludedCompatMaps(&included, info, next->merge);
454                 ClearCompatInfo(info, xkb);
455             }
456             else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
457             {
458                 InitCompatInfo(&next_incl, xkb);
459                 next_incl.fileID = rtrn->id;
460                 next_incl.dflt = info->dflt;
461                 next_incl.dflt.defs.fileID = rtrn->id;
462                 next_incl.dflt.defs.merge = op;
463                 next_incl.ledDflt.defs.fileID = rtrn->id;
464                 next_incl.ledDflt.defs.merge = op;
465                 next_incl.act = info->act;
466                 (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
467                 MergeIncludedCompatMaps(&included, &next_incl, op);
468                 ClearCompatInfo(&next_incl, xkb);
469             }
470             else
471             {
472                 info->errorCount += 10;
473                 return False;
474             }
475         }
476     }
477     if (haveSelf)
478         *info = included;
479     else
480     {
481         MergeIncludedCompatMaps(info, &included, newMerge);
482         ClearCompatInfo(&included, xkb);
483     }
484     return (info->errorCount == 0);
485 }
486
487 static LookupEntry useModMapValues[] = {
488     {"levelone", 1},
489     {"level1", 1},
490     {"anylevel", 0},
491     {"any", 0},
492     {NULL, 0}
493 };
494
495 static int
496 SetInterpField(SymInterpInfo * si,
497                struct xkb_desc * xkb,
498                char *field,
499                ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
500 {
501     int ok = 1;
502     ExprResult tmp;
503
504     if (uStrCaseCmp(field, "action") == 0)
505     {
506         if (arrayNdx != NULL)
507             return ReportSINotArray(si, field, info);
508         ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
509                              info->act);
510         if (ok)
511             si->defs.defined |= _SI_Action;
512     }
513     else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
514              (uStrCaseCmp(field, "virtualmod") == 0))
515     {
516         if (arrayNdx != NULL)
517             return ReportSINotArray(si, field, info);
518         ok = ResolveVirtualModifier(value, xkb, &tmp, &info->vmods);
519         if (ok)
520         {
521             si->interp.virtual_mod = tmp.uval;
522             si->defs.defined |= _SI_VirtualMod;
523         }
524         else
525             return ReportSIBadType(si, field, "virtual modifier", info);
526     }
527     else if (uStrCaseCmp(field, "repeat") == 0)
528     {
529         if (arrayNdx != NULL)
530             return ReportSINotArray(si, field, info);
531         ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
532         if (ok)
533         {
534             if (tmp.uval)
535                 si->interp.flags |= XkbSI_AutoRepeat;
536             else
537                 si->interp.flags &= ~XkbSI_AutoRepeat;
538             si->defs.defined |= _SI_AutoRepeat;
539         }
540         else
541             return ReportSIBadType(si, field, "boolean", info);
542     }
543     else if (uStrCaseCmp(field, "locking") == 0)
544     {
545         if (arrayNdx != NULL)
546             return ReportSINotArray(si, field, info);
547         ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
548         if (ok)
549         {
550             if (tmp.uval)
551                 si->interp.flags |= XkbSI_LockingKey;
552             else
553                 si->interp.flags &= ~XkbSI_LockingKey;
554             si->defs.defined |= _SI_LockingKey;
555         }
556         else
557             return ReportSIBadType(si, field, "boolean", info);
558     }
559     else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
560              (uStrCaseCmp(field, "usemodmapmods") == 0))
561     {
562         if (arrayNdx != NULL)
563             return ReportSINotArray(si, field, info);
564         ok = ExprResolveEnum(value, &tmp, useModMapValues);
565         if (ok)
566         {
567             if (tmp.uval)
568                 si->interp.match |= XkbSI_LevelOneOnly;
569             else
570                 si->interp.match &= ~XkbSI_LevelOneOnly;
571             si->defs.defined |= _SI_LevelOneOnly;
572         }
573         else
574             return ReportSIBadType(si, field, "level specification", info);
575     }
576     else
577     {
578         ok = ReportBadField("symbol interpretation", field, siText(si, info));
579     }
580     return ok;
581 }
582
583 LookupEntry groupNames[] = {
584     {"group1", 0x01}
585     ,
586     {"group2", 0x02}
587     ,
588     {"group3", 0x04}
589     ,
590     {"group4", 0x08}
591     ,
592     {"group5", 0x10}
593     ,
594     {"group6", 0x20}
595     ,
596     {"group7", 0x40}
597     ,
598     {"group8", 0x80}
599     ,
600     {"none", 0x00}
601     ,
602     {"all", 0xff}
603     ,
604     {NULL, 0}
605 };
606
607 static int
608 HandleInterpVar(VarDef * stmt, struct xkb_desc * xkb, CompatInfo * info)
609 {
610     ExprResult elem, field;
611     ExprDef *ndx;
612     int ret;
613
614     if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
615         ret = 0;               /* internal error, already reported */
616     else if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
617         ret = SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
618                               info);
619     else if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
620         ret = SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
621                                   stmt->value);
622     else
623         ret = SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
624                             &info->act);
625     free(elem.str);
626     free(field.str);
627     return ret;
628 }
629
630 static int
631 HandleInterpBody(VarDef * def, struct xkb_desc * xkb, SymInterpInfo * si,
632                  CompatInfo * info)
633 {
634     int ok = 1;
635     ExprResult tmp, field;
636     ExprDef *arrayNdx;
637
638     for (; def != NULL; def = (VarDef *) def->common.next)
639     {
640         if ((def->name) && (def->name->type == ExprFieldRef))
641         {
642             ok = HandleInterpVar(def, xkb, info);
643             continue;
644         }
645         ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
646         if (ok)
647             ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
648                                 info);
649     }
650     return ok;
651 }
652
653 static int
654 HandleInterpDef(InterpDef * def, struct xkb_desc * xkb, unsigned merge,
655                 CompatInfo * info)
656 {
657     unsigned pred, mods;
658     SymInterpInfo si;
659
660     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
661     {
662         ERROR("Couldn't determine matching modifiers\n");
663         ACTION("Symbol interpretation ignored\n");
664         return False;
665     }
666     if (def->merge != MergeDefault)
667         merge = def->merge;
668
669     si = info->dflt;
670     si.defs.merge = merge;
671     if (!LookupKeysym(def->sym, &si.interp.sym))
672     {
673         WARN("Could not resolve keysym %s\n", def->sym);
674         info->errorCount++;
675         return False;
676     }
677     si.interp.match = pred & XkbSI_OpMask;
678     si.interp.mods = mods;
679     if (!HandleInterpBody(def->def, xkb, &si, info))
680     {
681         info->errorCount++;
682         return False;
683     }
684
685     if (!AddInterp(info, &si))
686     {
687         info->errorCount++;
688         return False;
689     }
690     return True;
691 }
692
693 static int
694 HandleGroupCompatDef(GroupCompatDef * def,
695                      struct xkb_desc * xkb, unsigned merge, CompatInfo * info)
696 {
697     ExprResult val;
698     GroupCompatInfo tmp;
699
700     if (def->merge != MergeDefault)
701         merge = def->merge;
702     if (!XkbIsLegalGroup(def->group - 1))
703     {
704         ERROR("Keyboard group must be in the range 1..%d\n",
705                XkbNumKbdGroups + 1);
706         ACTION("Compatibility map for illegal group %d ignored\n",
707                 def->group);
708         return False;
709     }
710     tmp.fileID = info->fileID;
711     tmp.merge = merge;
712     if (!ExprResolveModMask(def->def, &val, LookupVModMask, (char *) xkb))
713     {
714         ERROR("Expected a modifier mask in group compatibility definition\n");
715         ACTION("Ignoring illegal compatibility map for group %d\n",
716                 def->group);
717         return False;
718     }
719     tmp.real_mods = val.uval & 0xff;
720     tmp.vmods = (val.uval >> 8) & 0xffff;
721     return AddGroupCompat(info, def->group - 1, &tmp);
722 }
723
724 static void
725 HandleCompatMapFile(XkbFile * file,
726                     struct xkb_desc * xkb, unsigned merge, CompatInfo * info)
727 {
728     ParseCommon *stmt;
729
730     if (merge == MergeDefault)
731         merge = MergeAugment;
732     info->name = _XkbDupString(file->name);
733     stmt = file->defs;
734     while (stmt)
735     {
736         switch (stmt->stmtType)
737         {
738         case StmtInclude:
739             if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
740                                         HandleCompatMapFile))
741                 info->errorCount++;
742             break;
743         case StmtInterpDef:
744             if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
745                 info->errorCount++;
746             break;
747         case StmtGroupCompatDef:
748             if (!HandleGroupCompatDef
749                 ((GroupCompatDef *) stmt, xkb, merge, info))
750                 info->errorCount++;
751             break;
752         case StmtIndicatorMapDef:
753         {
754             LEDInfo *rtrn;
755             rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
756                                          &info->ledDflt, info->leds, merge);
757             if (rtrn != NULL)
758                 info->leds = rtrn;
759             else
760                 info->errorCount++;
761         }
762             break;
763         case StmtVarDef:
764             if (!HandleInterpVar((VarDef *) stmt, xkb, info))
765                 info->errorCount++;
766             break;
767         case StmtVModDef:
768             if (!HandleVModDef((VModDef *) stmt, xkb, merge, &info->vmods))
769                 info->errorCount++;
770             break;
771         case StmtKeycodeDef:
772             ERROR("Interpretation files may not include other types\n");
773             ACTION("Ignoring definition of key name\n");
774             info->errorCount++;
775             break;
776         default:
777             WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
778                   stmt->stmtType);
779             break;
780         }
781         stmt = stmt->next;
782         if (info->errorCount > 10)
783         {
784 #ifdef NOISY
785             ERROR("Too many errors\n");
786 #endif
787             ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
788             break;
789         }
790     }
791     return;
792 }
793
794 static void
795 CopyInterps(CompatInfo * info,
796             struct xkb_compat_map * compat, Bool needSymbol, unsigned pred)
797 {
798     SymInterpInfo *si;
799
800     for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
801     {
802         if (((si->interp.match & XkbSI_OpMask) != pred) ||
803             (needSymbol && (si->interp.sym == NoSymbol)) ||
804             ((!needSymbol) && (si->interp.sym != NoSymbol)))
805             continue;
806         if (compat->num_si >= compat->size_si)
807         {
808             WSGO("No room to merge symbol interpretations\n");
809             ACTION("Symbol interpretations lost\n");
810             return;
811         }
812         compat->sym_interpret[compat->num_si++] = si->interp;
813     }
814     return;
815 }
816
817 Bool
818 CompileCompatMap(XkbFile *file, struct xkb_desc * xkb, unsigned merge,
819                  LEDInfoPtr *unboundLEDs)
820 {
821     int i;
822     CompatInfo info;
823     GroupCompatInfo *gcm;
824
825     InitCompatInfo(&info, xkb);
826     info.dflt.defs.merge = merge;
827     info.ledDflt.defs.merge = merge;
828     HandleCompatMapFile(file, xkb, merge, &info);
829
830     if (info.errorCount == 0)
831     {
832         int size;
833         if (XkbcAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
834             Success)
835         {
836             WSGO("Couldn't allocate compatibility map\n");
837             return False;
838         }
839         if (info.name != NULL)
840         {
841             if (XkbcAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
842                 xkb->names->compat =
843                     xkb_intern_atom(info.name);
844             else
845             {
846                 WSGO("Couldn't allocate space for compat name\n");
847                 ACTION("Name \"%s\" (from %s) NOT assigned\n",
848                         scanFile, info.name);
849             }
850         }
851         size = info.nInterps * sizeof(struct xkb_sym_interpret);
852         if (size > 0)
853         {
854             CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
855             CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
856             CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
857             CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
858             CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
859             CopyInterps(&info, xkb->compat, False,
860                         XkbSI_AllOf | XkbSI_NoneOf);
861             CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
862             CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
863         }
864         for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
865              i++, gcm++)
866         {
867             if ((gcm->fileID != 0) || (gcm->real_mods != 0)
868                 || (gcm->vmods != 0))
869             {
870                 xkb->compat->groups[i].mask = gcm->real_mods;
871                 xkb->compat->groups[i].real_mods = gcm->real_mods;
872                 xkb->compat->groups[i].vmods = gcm->vmods;
873             }
874         }
875         if (info.leds != NULL)
876         {
877             if (!CopyIndicatorMapDefs(xkb, info.leds, unboundLEDs))
878                 info.errorCount++;
879             info.leds = NULL;
880         }
881         ClearCompatInfo(&info, xkb);
882         return True;
883     }
884     if (info.interps != NULL)
885         free(info.interps);
886     return False;
887 }