compat: use darray for sym_interprets
[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 "xkbcomp-priv.h"
28 #include "parseutils.h"
29 #include "action.h"
30 #include "indicators.h"
31 #include "vmod.h"
32
33 typedef struct _SymInterpInfo
34 {
35     CommonInfo defs;
36     struct xkb_sym_interpret interp;
37 } SymInterpInfo;
38
39 #define _SI_VirtualMod          (1<<0)
40 #define _SI_Action              (1<<1)
41 #define _SI_AutoRepeat          (1<<2)
42 #define _SI_LockingKey          (1<<3)
43 #define _SI_LevelOneOnly        (1<<4)
44
45 typedef struct _GroupCompatInfo
46 {
47     unsigned char fileID;
48     unsigned char merge;
49     bool defined;
50     unsigned char real_mods;
51     xkb_atom_t vmods;
52 } GroupCompatInfo;
53
54 typedef struct _CompatInfo
55 {
56     char *name;
57     unsigned fileID;
58     int errorCount;
59     int nInterps;
60     SymInterpInfo *interps;
61     SymInterpInfo dflt;
62     LEDInfo ledDflt;
63     GroupCompatInfo groupCompat[XkbNumKbdGroups];
64     LEDInfo *leds;
65     VModInfo vmods;
66     ActionInfo *act;
67     struct xkb_keymap *keymap;
68 } CompatInfo;
69
70 /***====================================================================***/
71
72 #define ReportSINotArray(si,f,i) \
73         ReportNotArray("symbol interpretation",(f),siText((si),(i)))
74 #define ReportSIBadType(si,f,w,i) \
75         ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
76
77 /***====================================================================***/
78
79 static const char *
80 siText(SymInterpInfo * si, CompatInfo * info)
81 {
82     static char buf[128];
83
84     if (si == &info->dflt)
85     {
86         snprintf(buf, sizeof(buf), "default");
87     }
88     else
89     {
90         snprintf(buf, sizeof(buf), "%s+%s(%s)",
91                 XkbcKeysymText(si->interp.sym),
92                 XkbcSIMatchText(si->interp.match),
93                 XkbcModMaskText(si->interp.mods, false));
94     }
95     return buf;
96 }
97
98 static void
99 InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap)
100 {
101     unsigned int i;
102
103     info->keymap = keymap;
104     info->name = NULL;
105     info->fileID = 0;
106     info->errorCount = 0;
107     info->nInterps = 0;
108     info->interps = NULL;
109     info->act = NULL;
110     info->dflt.defs.fileID = info->fileID;
111     info->dflt.defs.defined = 0;
112     info->dflt.defs.merge = MergeOverride;
113     info->dflt.interp.flags = 0;
114     info->dflt.interp.virtual_mod = XkbNoModifier;
115     info->dflt.interp.act.type = XkbSA_NoAction;
116     for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
117         info->dflt.interp.act.any.data[i] = 0;
118     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
119     info->ledDflt.defs.fileID = info->fileID;
120     info->ledDflt.defs.defined = 0;
121     info->ledDflt.defs.merge = MergeOverride;
122     memset(&info->groupCompat[0], 0,
123            XkbNumKbdGroups * sizeof(GroupCompatInfo));
124     info->leds = NULL;
125     InitVModInfo(&info->vmods, keymap);
126 }
127
128 static void
129 ClearCompatInfo(CompatInfo *info, struct xkb_keymap *keymap)
130 {
131     unsigned int i;
132     ActionInfo *next;
133
134     free(info->name);
135     info->name = NULL;
136     info->dflt.defs.defined = 0;
137     info->dflt.defs.merge = MergeAugment;
138     info->dflt.interp.flags = 0;
139     info->dflt.interp.virtual_mod = XkbNoModifier;
140     info->dflt.interp.act.type = XkbSA_NoAction;
141     for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
142         info->dflt.interp.act.any.data[i] = 0;
143     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
144     info->nInterps = 0;
145     info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
146     memset(&info->groupCompat[0], 0,
147            XkbNumKbdGroups * sizeof(GroupCompatInfo));
148     info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
149     while (info->act) {
150             next = info->act->next;
151             free(info->act);
152             info->act = next;
153     }
154     ClearVModInfo(&info->vmods, keymap);
155 }
156
157 static SymInterpInfo *
158 NextInterp(CompatInfo * info)
159 {
160     SymInterpInfo *si;
161
162     si = uTypedAlloc(SymInterpInfo);
163     if (si)
164     {
165         memset(si, 0, sizeof(SymInterpInfo));
166         info->interps =
167             (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
168                                             (CommonInfo *) si);
169         info->nInterps++;
170     }
171     return si;
172 }
173
174 static SymInterpInfo *
175 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
176 {
177     SymInterpInfo *old;
178
179     for (old = info->interps; old != NULL;
180          old = (SymInterpInfo *) old->defs.next)
181     {
182         if ((old->interp.sym == new->interp.sym) &&
183             (old->interp.mods == new->interp.mods) &&
184             (old->interp.match == new->interp.match))
185         {
186             return old;
187         }
188     }
189     return NULL;
190 }
191
192 static bool
193 AddInterp(CompatInfo * info, SymInterpInfo * new)
194 {
195     unsigned collide;
196     SymInterpInfo *old;
197
198     collide = 0;
199     old = FindMatchingInterp(info, new);
200     if (old != NULL)
201     {
202         if (new->defs.merge == MergeReplace)
203         {
204             SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
205             if (((old->defs.fileID == new->defs.fileID)
206                  && (warningLevel > 0)) || (warningLevel > 9))
207             {
208                 WARN("Multiple definitions for \"%s\"\n", siText(new, info));
209                 ACTION("Earlier interpretation ignored\n");
210             }
211             *old = *new;
212             old->defs.next = &next->defs;
213             return true;
214         }
215         if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
216         {
217             old->interp.virtual_mod = new->interp.virtual_mod;
218             old->defs.defined |= _SI_VirtualMod;
219         }
220         if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
221         {
222             old->interp.act = new->interp.act;
223             old->defs.defined |= _SI_Action;
224         }
225         if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
226         {
227             old->interp.flags &= ~XkbSI_AutoRepeat;
228             old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
229             old->defs.defined |= _SI_AutoRepeat;
230         }
231         if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
232         {
233             old->interp.flags &= ~XkbSI_LockingKey;
234             old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
235             old->defs.defined |= _SI_LockingKey;
236         }
237         if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
238         {
239             old->interp.match &= ~XkbSI_LevelOneOnly;
240             old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
241             old->defs.defined |= _SI_LevelOneOnly;
242         }
243         if (collide)
244         {
245             WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
246             ACTION("Using %s definition for duplicate fields\n",
247                     (new->defs.merge != MergeAugment ? "last" : "first"));
248         }
249         return true;
250     }
251     old = new;
252     if ((new = NextInterp(info)) == NULL)
253         return false;
254     *new = *old;
255     new->defs.next = NULL;
256     return true;
257 }
258
259 static bool
260 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
261 {
262     GroupCompatInfo *gc;
263     unsigned merge;
264
265     merge = newGC->merge;
266     gc = &info->groupCompat[group];
267     if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
268     {
269         return true;
270     }
271     if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
272         || (warningLevel > 9))
273     {
274         WARN("Compat map for group %d redefined\n", group + 1);
275         ACTION("Using %s definition\n",
276                 (merge == MergeAugment ? "old" : "new"));
277     }
278     if (newGC->defined && (merge != MergeAugment || !gc->defined))
279         *gc = *newGC;
280     return true;
281 }
282
283 /***====================================================================***/
284
285 static bool
286 ResolveStateAndPredicate(ExprDef * expr,
287                          unsigned *pred_rtrn,
288                          unsigned *mods_rtrn, CompatInfo * info)
289 {
290     ExprResult result;
291
292     if (expr == NULL)
293     {
294         *pred_rtrn = XkbSI_AnyOfOrNone;
295         *mods_rtrn = ~0;
296         return true;
297     }
298
299     *pred_rtrn = XkbSI_Exactly;
300     if (expr->op == ExprActionDecl)
301     {
302         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
303                                              expr->value.action.name);
304         if (strcasecmp(pred_txt, "noneof") == 0)
305             *pred_rtrn = XkbSI_NoneOf;
306         else if (strcasecmp(pred_txt, "anyofornone") == 0)
307             *pred_rtrn = XkbSI_AnyOfOrNone;
308         else if (strcasecmp(pred_txt, "anyof") == 0)
309             *pred_rtrn = XkbSI_AnyOf;
310         else if (strcasecmp(pred_txt, "allof") == 0)
311             *pred_rtrn = XkbSI_AllOf;
312         else if (strcasecmp(pred_txt, "exactly") == 0)
313             *pred_rtrn = XkbSI_Exactly;
314         else
315         {
316             ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
317             ACTION("Ignored\n");
318             return false;
319         }
320         expr = expr->value.action.args;
321     }
322     else if (expr->op == ExprIdent)
323     {
324         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
325                                              expr->value.str);
326         if ((pred_txt) && (strcasecmp(pred_txt, "any") == 0))
327         {
328             *pred_rtrn = XkbSI_AnyOf;
329             *mods_rtrn = 0xff;
330             return true;
331         }
332     }
333
334     if (ExprResolveModMask(info->keymap->ctx, expr, &result))
335     {
336         *mods_rtrn = result.uval;
337         return true;
338     }
339     return false;
340 }
341
342 /***====================================================================***/
343
344 static void
345 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
346 {
347     SymInterpInfo *si;
348     LEDInfo *led, *rtrn, *next;
349     GroupCompatInfo *gcm;
350     int i;
351
352     if (from->errorCount > 0)
353     {
354         into->errorCount += from->errorCount;
355         return;
356     }
357     if (into->name == NULL)
358     {
359         into->name = from->name;
360         from->name = NULL;
361     }
362     for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
363     {
364         if (merge != MergeDefault)
365             si->defs.merge = merge;
366         if (!AddInterp(into, si))
367             into->errorCount++;
368     }
369     for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
370     {
371         if (merge != MergeDefault)
372             gcm->merge = merge;
373         if (!AddGroupCompat(into, i, gcm))
374             into->errorCount++;
375     }
376     for (led = from->leds; led != NULL; led = next)
377     {
378         next = (LEDInfo *) led->defs.next;
379         if (merge != MergeDefault)
380             led->defs.merge = merge;
381         rtrn = AddIndicatorMap(from->keymap, into->leds, led);
382         if (rtrn != NULL)
383             into->leds = rtrn;
384         else
385             into->errorCount++;
386     }
387 }
388
389 static void
390 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap, unsigned merge,
391                     CompatInfo *info);
392
393 static bool
394 HandleIncludeCompatMap(IncludeStmt *stmt, struct xkb_keymap *keymap,
395                        CompatInfo *info)
396 {
397     unsigned newMerge;
398     XkbFile *rtrn;
399     CompatInfo included;
400     bool haveSelf;
401
402     haveSelf = false;
403     if ((stmt->file == NULL) && (stmt->map == NULL))
404     {
405         haveSelf = true;
406         included = *info;
407         memset(info, 0, sizeof(CompatInfo));
408     }
409     else if (ProcessIncludeFile(keymap->ctx, stmt, XkmCompatMapIndex, &rtrn,
410                                 &newMerge))
411     {
412         InitCompatInfo(&included, keymap);
413         included.fileID = rtrn->id;
414         included.dflt = info->dflt;
415         included.dflt.defs.fileID = rtrn->id;
416         included.dflt.defs.merge = newMerge;
417         included.ledDflt.defs.fileID = rtrn->id;
418         included.ledDflt.defs.merge = newMerge;
419         included.act = info->act;
420         HandleCompatMapFile(rtrn, keymap, MergeOverride, &included);
421         if (stmt->stmt != NULL)
422         {
423             free(included.name);
424             included.name = stmt->stmt;
425             stmt->stmt = NULL;
426         }
427         if (info->act != NULL)
428                 included.act = NULL;
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, keymap);
449             }
450             else if (ProcessIncludeFile(keymap->ctx, next, XkmCompatMapIndex,
451                                         &rtrn, &op))
452             {
453                 InitCompatInfo(&next_incl, keymap);
454                 next_incl.fileID = rtrn->id;
455                 next_incl.dflt = info->dflt;
456                 next_incl.dflt.defs.fileID = rtrn->id;
457                 next_incl.dflt.defs.merge = op;
458                 next_incl.ledDflt.defs.fileID = rtrn->id;
459                 next_incl.ledDflt.defs.merge = op;
460                 next_incl.act = info->act;
461                 HandleCompatMapFile(rtrn, keymap, MergeOverride, &next_incl);
462                 MergeIncludedCompatMaps(&included, &next_incl, op);
463                 if (info->act != NULL)
464                         next_incl.act = NULL;
465                 ClearCompatInfo(&next_incl, keymap);
466                 FreeXKBFile(rtrn);
467             }
468             else
469             {
470                 info->errorCount += 10;
471                 return false;
472             }
473         }
474     }
475     if (haveSelf)
476         *info = included;
477     else
478     {
479         MergeIncludedCompatMaps(info, &included, newMerge);
480         ClearCompatInfo(&included, keymap);
481     }
482     return (info->errorCount == 0);
483 }
484
485 static const LookupEntry useModMapValues[] = {
486     {"levelone", 1},
487     {"level1", 1},
488     {"anylevel", 0},
489     {"any", 0},
490     {NULL, 0}
491 };
492
493 static int
494 SetInterpField(SymInterpInfo *si, struct xkb_keymap *keymap, char *field,
495                ExprDef *arrayNdx, ExprDef *value, CompatInfo *info)
496 {
497     int ok = 1;
498     ExprResult tmp;
499
500     if (strcasecmp(field, "action") == 0)
501     {
502         if (arrayNdx != NULL)
503             return ReportSINotArray(si, field, info);
504         ok = HandleActionDef(value, keymap, &si->interp.act.any, info->act);
505         if (ok)
506             si->defs.defined |= _SI_Action;
507     }
508     else if ((strcasecmp(field, "virtualmodifier") == 0) ||
509              (strcasecmp(field, "virtualmod") == 0))
510     {
511         if (arrayNdx != NULL)
512             return ReportSINotArray(si, field, info);
513         ok = ResolveVirtualModifier(value, keymap, &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 (strcasecmp(field, "repeat") == 0)
523     {
524         if (arrayNdx != NULL)
525             return ReportSINotArray(si, field, info);
526         ok = ExprResolveBoolean(keymap->ctx, 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 (strcasecmp(field, "locking") == 0)
539     {
540         if (arrayNdx != NULL)
541             return ReportSINotArray(si, field, info);
542         ok = ExprResolveBoolean(keymap->ctx, 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 ((strcasecmp(field, "usemodmap") == 0) ||
555              (strcasecmp(field, "usemodmapmods") == 0))
556     {
557         if (arrayNdx != NULL)
558             return ReportSINotArray(si, field, info);
559         ok = ExprResolveEnum(keymap->ctx, 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_keymap *keymap, CompatInfo * info)
580 {
581     ExprResult elem, field;
582     ExprDef *ndx;
583     int ret;
584
585     if (ExprResolveLhs(keymap, stmt->name, &elem, &field, &ndx) == 0)
586         ret = 0;               /* internal error, already reported */
587     else if (elem.str && (strcasecmp(elem.str, "interpret") == 0))
588         ret = SetInterpField(&info->dflt, keymap, field.str, ndx, stmt->value,
589                               info);
590     else if (elem.str && (strcasecmp(elem.str, "indicator") == 0))
591         ret = SetIndicatorMapField(&info->ledDflt, keymap, field.str, ndx,
592                                   stmt->value);
593     else
594         ret = SetActionField(keymap, 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_keymap *keymap, 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, keymap, info);
614             continue;
615         }
616         ok = ExprResolveLhs(keymap, def->name, &tmp, &field, &arrayNdx);
617         if (ok) {
618             ok = SetInterpField(si, keymap, 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_keymap *keymap, 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         ERROR("Could not resolve keysym %s\n", def->sym);
647         ACTION("Symbol interpretation ignored\n");
648         return false;
649     }
650     si.interp.match = pred & XkbSI_OpMask;
651     si.interp.mods = mods;
652     if (!HandleInterpBody(def->def, keymap, &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, struct xkb_keymap *keymap,
668                      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, keymap))
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     tmp.defined = true;
695     return AddGroupCompat(info, def->group - 1, &tmp);
696 }
697
698 static void
699 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap, unsigned merge,
700                     CompatInfo *info)
701 {
702     ParseCommon *stmt;
703
704     if (merge == MergeDefault)
705         merge = MergeAugment;
706     free(info->name);
707     info->name = uDupString(file->name);
708     stmt = file->defs;
709     while (stmt)
710     {
711         switch (stmt->stmtType)
712         {
713         case StmtInclude:
714             if (!HandleIncludeCompatMap((IncludeStmt *) stmt, keymap, info))
715                 info->errorCount++;
716             break;
717         case StmtInterpDef:
718             if (!HandleInterpDef((InterpDef *) stmt, keymap, merge, info))
719                 info->errorCount++;
720             break;
721         case StmtGroupCompatDef:
722             if (!HandleGroupCompatDef
723                 ((GroupCompatDef *) stmt, keymap, merge, info))
724                 info->errorCount++;
725             break;
726         case StmtIndicatorMapDef:
727         {
728             LEDInfo *rtrn;
729             rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, keymap,
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, keymap, info))
739                 info->errorCount++;
740             break;
741         case StmtVModDef:
742             if (!HandleVModDef((VModDef *) stmt, keymap, 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 == XKB_KEY_NoSymbol)) ||
777             ((!needSymbol) && (si->interp.sym != XKB_KEY_NoSymbol)))
778             continue;
779         darray_append(compat->sym_interpret, si->interp);
780     }
781 }
782
783 bool
784 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap, unsigned merge,
785                  LEDInfoPtr *unboundLEDs)
786 {
787     int i;
788     CompatInfo info;
789     GroupCompatInfo *gcm;
790
791     InitCompatInfo(&info, keymap);
792     info.dflt.defs.merge = merge;
793     info.ledDflt.defs.merge = merge;
794
795     HandleCompatMapFile(file, keymap, merge, &info);
796
797     if (info.errorCount != 0)
798         goto err_info;
799
800     if (XkbcAllocCompatMap(keymap, info.nInterps) != Success) {
801         WSGO("Couldn't allocate compatibility map\n");
802         goto err_info;
803     }
804
805     if (info.nInterps > 0) {
806         CopyInterps(&info, keymap->compat, true, XkbSI_Exactly);
807         CopyInterps(&info, keymap->compat, true, XkbSI_AllOf | XkbSI_NoneOf);
808         CopyInterps(&info, keymap->compat, true, XkbSI_AnyOf);
809         CopyInterps(&info, keymap->compat, true, XkbSI_AnyOfOrNone);
810         CopyInterps(&info, keymap->compat, false, XkbSI_Exactly);
811         CopyInterps(&info, keymap->compat, false, XkbSI_AllOf | XkbSI_NoneOf);
812         CopyInterps(&info, keymap->compat, false, XkbSI_AnyOf);
813         CopyInterps(&info, keymap->compat, false, XkbSI_AnyOfOrNone);
814     }
815
816     for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++) {
817         if ((gcm->fileID != 0) || (gcm->real_mods != 0) || (gcm->vmods != 0)) {
818             keymap->compat->groups[i].mask = gcm->real_mods;
819             keymap->compat->groups[i].real_mods = gcm->real_mods;
820             keymap->compat->groups[i].vmods = gcm->vmods;
821         }
822     }
823
824     if (info.leds != NULL) {
825         if (!CopyIndicatorMapDefs(keymap, info.leds, unboundLEDs))
826             info.errorCount++;
827         info.leds = NULL;
828     }
829
830     ClearCompatInfo(&info, keymap);
831     return true;
832
833 err_info:
834     ClearCompatInfo(&info, keymap);
835     return false;
836 }
837
838 static uint32_t
839 VModsToReal(struct xkb_keymap *keymap, uint32_t vmodmask)
840 {
841     uint32_t ret = 0;
842     int i;
843
844     if (!vmodmask)
845         return 0;
846
847     for (i = 0; i < XkbNumVirtualMods; i++) {
848         if (!(vmodmask & (1 << i)))
849             continue;
850         ret |= keymap->server->vmods[i];
851     }
852
853     return ret;
854 }
855
856 static void
857 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
858                  uint32_t rmodmask)
859 {
860     switch (act->type) {
861     case XkbSA_SetMods:
862     case XkbSA_LatchMods:
863     case XkbSA_LockMods:
864         if (act->mods.flags & XkbSA_UseModMapMods)
865             act->mods.real_mods = rmodmask;
866         act->mods.mask = act->mods.real_mods;
867         act->mods.mask |= VModsToReal(keymap, act->mods.vmods);
868         break;
869     case XkbSA_ISOLock:
870         if (act->iso.flags & XkbSA_UseModMapMods)
871             act->iso.real_mods = rmodmask;
872         act->iso.mask = act->iso.real_mods;
873         act->iso.mask |= VModsToReal(keymap, act->iso.vmods);
874         break;
875     default:
876         break;
877     }
878 }
879
880 /**
881  * Find an interpretation which applies to this particular level, either by
882  * finding an exact match for the symbol and modifier combination, or a
883  * generic XKB_KEY_NoSymbol match.
884  */
885 static struct xkb_sym_interpret *
886 FindInterpForKey(struct xkb_keymap *keymap, xkb_keycode_t key,
887                  uint32_t group, uint32_t level)
888 {
889     struct xkb_sym_interpret *ret = NULL;
890     struct xkb_sym_interpret *interp;
891     const xkb_keysym_t *syms;
892     int num_syms;
893
894     num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
895     if (num_syms == 0)
896         return NULL;
897
898     darray_foreach(interp, keymap->compat->sym_interpret) {
899         uint32_t mods;
900         bool found;
901
902         if ((num_syms > 1 || interp->sym != syms[0]) &&
903             interp->sym != XKB_KEY_NoSymbol)
904             continue;
905
906         if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
907             mods = keymap->map->modmap[key];
908         else
909             mods = 0;
910
911         switch (interp->match & XkbSI_OpMask) {
912         case XkbSI_NoneOf:
913             found = !(interp->mods & mods);
914             break;
915         case XkbSI_AnyOfOrNone:
916             found = (!mods || (interp->mods & mods));
917             break;
918         case XkbSI_AnyOf:
919             found = !!(interp->mods & mods);
920             break;
921         case XkbSI_AllOf:
922             found = ((interp->mods & mods) == mods);
923             break;
924         case XkbSI_Exactly:
925             found = (interp->mods == mods);
926             break;
927         default:
928             found = false;
929             break;
930         }
931
932         if (found && interp->sym != XKB_KEY_NoSymbol)
933             return interp;
934         else if (found && !ret)
935             ret = interp;
936     }
937
938     return ret;
939 }
940
941 /**
942  */
943 static bool
944 ApplyInterpsToKey(struct xkb_keymap *keymap, xkb_keycode_t key)
945 {
946 #define INTERP_SIZE (8 * 4)
947     struct xkb_sym_interpret *interps[INTERP_SIZE];
948     union xkb_action *acts;
949     uint32_t vmodmask = 0;
950     int num_acts = 0;
951     int group, level;
952     int width = XkbKeyGroupsWidth(keymap, key);
953     int i;
954
955     /* If we've been told not to bind interps to this key, then don't. */
956     if (keymap->server->explicit[key] & XkbExplicitInterpretMask)
957         return true;
958
959     for (i = 0; i < INTERP_SIZE; i++)
960         interps[i] = NULL;
961
962     for (group = 0; group < XkbKeyNumGroups(keymap, key); group++) {
963         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); level++) {
964             i = (group * width) + level;
965             if (i >= INTERP_SIZE) /* XXX FIXME */
966                 return false;
967             interps[i] = FindInterpForKey(keymap, key, group, level);
968             if (interps[i])
969                 num_acts++;
970         }
971     }
972
973     if (num_acts)
974         num_acts = XkbKeyNumGroups(keymap, key) * width;
975     acts = XkbcResizeKeyActions(keymap, key, num_acts);
976     if (!num_acts)
977         return true;
978     else if (!acts)
979         return false;
980
981     for (group = 0; group < XkbKeyNumGroups(keymap, key); group++) {
982         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); level++) {
983             struct xkb_sym_interpret *interp;
984
985             i = (group * width) + level;
986             interp = interps[i];
987
988             /* Infer default key behaviours from the base level. */
989             if (group == 0 && level == 0) {
990                 if (!(keymap->server->explicit[key] & XkbExplicitAutoRepeatMask) &&
991                     (!interp || interp->flags & XkbSI_AutoRepeat))
992                     keymap->ctrls->per_key_repeat[key / 8] |= (1 << (key % 8));
993                 if (!(keymap->server->explicit[key] & XkbExplicitBehaviorMask) &&
994                     interp && (interp->flags & XkbSI_LockingKey))
995                     keymap->server->behaviors[key].type = XkbKB_Lock;
996             }
997
998             if (!interp)
999                 continue;
1000
1001             if ((group == 0 && level == 0) ||
1002                 !(interp->match & XkbSI_LevelOneOnly)) {
1003                 if (interp->virtual_mod != XkbNoModifier)
1004                     vmodmask |= (1 << interp->virtual_mod);
1005             }
1006             acts[i] = interp->act;
1007         }
1008     }
1009
1010     if (!(keymap->server->explicit[key] & XkbExplicitVModMapMask))
1011         keymap->server->vmodmap[key] = vmodmask;
1012
1013     return true;
1014 #undef INTERP_SIZE
1015 }
1016
1017 /**
1018  * This collects a bunch of disparate functions which was done in the server
1019  * at various points that really should've been done within xkbcomp.  Turns out
1020  * your actions and types are a lot more useful when any of your modifiers
1021  * other than Shift actually do something ...
1022  */
1023 bool
1024 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
1025 {
1026     xkb_keycode_t key;
1027     int i;
1028
1029     /* Find all the interprets for the key and bind them to actions,
1030      * which will also update the vmodmap. */
1031     for (key = keymap->min_key_code; key <= keymap->max_key_code; key++)
1032         if (!ApplyInterpsToKey(keymap, key))
1033             return false;
1034
1035     /* Update keymap->server->vmods, the virtual -> real mod mapping. */
1036     for (i = 0; i < XkbNumVirtualMods; i++)
1037         keymap->server->vmods[i] = 0;
1038     for (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
1039         if (!keymap->server->vmodmap[key])
1040             continue;
1041         for (i = 0; i < XkbNumVirtualMods; i++) {
1042             if (!(keymap->server->vmodmap[key] & (1 << i)))
1043                 continue;
1044             keymap->server->vmods[i] |= keymap->map->modmap[key];
1045         }
1046     }
1047
1048     /* Now update the level masks for all the types to reflect the vmods. */
1049     for (i = 0; i < keymap->map->num_types; i++) {
1050         struct xkb_key_type *type = &keymap->map->types[i];
1051         uint32_t mask = 0;
1052         int j;
1053         type->mods.mask = type->mods.real_mods;
1054         type->mods.mask |= VModsToReal(keymap, type->mods.vmods);
1055         for (j = 0; j < XkbNumVirtualMods; j++) {
1056             if (!(type->mods.vmods & (1 << j)))
1057                 continue;
1058             mask |= keymap->server->vmods[j];
1059         }
1060         for (j = 0; j < type->map_count; j++) {
1061             struct xkb_mods *mods = &type->map[j].mods;
1062             mods->mask = mods->real_mods | VModsToReal(keymap, mods->vmods);
1063         }
1064     }
1065
1066     /* Update action modifiers. */
1067     for (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
1068         union xkb_action *acts = XkbKeyActionsPtr(keymap, key);
1069         for (i = 0; i < XkbKeyNumActions(keymap, key); i++) {
1070             if (acts[i].any.type == XkbSA_NoAction)
1071                 continue;
1072             UpdateActionMods(keymap, &acts[i], keymap->map->modmap[key]);
1073         }
1074     }
1075
1076     /* Update group modifiers. */
1077     for (i = 0; i < XkbNumKbdGroups; i++) {
1078         struct xkb_mods *group = &keymap->compat->groups[i];
1079         group->mask = group->real_mods | VModsToReal(keymap, group->vmods);
1080     }
1081
1082     /* Update vmod -> indicator maps. */
1083     for (i = 0; i < XkbNumIndicators; i++) {
1084         struct xkb_mods *led = &keymap->indicators->maps[i].mods;
1085         led->mask = led->real_mods | VModsToReal(keymap, led->vmods);
1086     }
1087
1088     return true;
1089 }