Pass around xkb_key's instead of keycodes
[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 "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     CommonInfo defs;
35     struct xkb_sym_interpret interp;
36 } SymInterpInfo;
37
38 #define _SI_VirtualMod   (1 << 0)
39 #define _SI_Action       (1 << 1)
40 #define _SI_AutoRepeat   (1 << 2)
41 #define _SI_LockingKey   (1 << 3)
42 #define _SI_LevelOneOnly (1 << 4)
43
44 typedef struct _GroupCompatInfo {
45     unsigned file_id;
46     enum merge_mode merge;
47     bool defined;
48     unsigned char real_mods;
49     xkb_atom_t vmods;
50 } GroupCompatInfo;
51
52 typedef struct _CompatInfo {
53     char *name;
54     unsigned file_id;
55     int errorCount;
56     int nInterps;
57     SymInterpInfo *interps;
58     SymInterpInfo dflt;
59     LEDInfo ledDflt;
60     GroupCompatInfo groupCompat[XkbNumKbdGroups];
61     LEDInfo *leds;
62     VModInfo vmods;
63     ActionInfo *act;
64     struct xkb_keymap *keymap;
65 } CompatInfo;
66
67 /***====================================================================***/
68
69 #define ReportSINotArray(si, f, i) \
70     ReportNotArray("symbol interpretation", (f), siText((si), (i)))
71 #define ReportSIBadType(si, f, w, i) \
72     ReportBadType("symbol interpretation", (f), siText((si), (i)), (w))
73
74 /***====================================================================***/
75
76 static const char *
77 siText(SymInterpInfo * si, CompatInfo * info)
78 {
79     static char buf[128];
80
81     if (si == &info->dflt) {
82         snprintf(buf, sizeof(buf), "default");
83     }
84     else {
85         snprintf(buf, sizeof(buf), "%s+%s(%s)",
86                  XkbcKeysymText(si->interp.sym),
87                  XkbcSIMatchText(si->interp.match),
88                  XkbcModMaskText(si->interp.mods, false));
89     }
90     return buf;
91 }
92
93 static void
94 InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id)
95 {
96     unsigned int i;
97
98     info->keymap = keymap;
99     info->name = NULL;
100     info->file_id = file_id;
101     info->errorCount = 0;
102     info->nInterps = 0;
103     info->interps = NULL;
104     info->act = NULL;
105     info->dflt.defs.file_id = file_id;
106     info->dflt.defs.defined = 0;
107     info->dflt.defs.merge = MERGE_OVERRIDE;
108     info->dflt.interp.flags = 0;
109     info->dflt.interp.virtual_mod = XkbNoModifier;
110     info->dflt.interp.act.type = XkbSA_NoAction;
111     for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
112         info->dflt.interp.act.any.data[i] = 0;
113     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
114     info->ledDflt.defs.file_id = file_id;
115     info->ledDflt.defs.defined = 0;
116     info->ledDflt.defs.merge = MERGE_OVERRIDE;
117     memset(&info->groupCompat[0], 0,
118            XkbNumKbdGroups * sizeof(GroupCompatInfo));
119     info->leds = NULL;
120     InitVModInfo(&info->vmods, keymap);
121 }
122
123 static void
124 ClearCompatInfo(CompatInfo *info, struct xkb_keymap *keymap)
125 {
126     unsigned int i;
127     ActionInfo *next;
128
129     free(info->name);
130     info->name = NULL;
131     info->dflt.defs.defined = 0;
132     info->dflt.defs.merge = MERGE_AUGMENT;
133     info->dflt.interp.flags = 0;
134     info->dflt.interp.virtual_mod = XkbNoModifier;
135     info->dflt.interp.act.type = XkbSA_NoAction;
136     for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
137         info->dflt.interp.act.any.data[i] = 0;
138     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
139     info->nInterps = 0;
140     info->interps = ClearCommonInfo(&info->interps->defs);
141     memset(&info->groupCompat[0], 0,
142            XkbNumKbdGroups * sizeof(GroupCompatInfo));
143     info->leds = ClearCommonInfo(&info->leds->defs);
144     while (info->act) {
145         next = info->act->next;
146         free(info->act);
147         info->act = next;
148     }
149     ClearVModInfo(&info->vmods, keymap);
150 }
151
152 static SymInterpInfo *
153 NextInterp(CompatInfo * info)
154 {
155     SymInterpInfo *si;
156
157     si = uTypedAlloc(SymInterpInfo);
158     if (si) {
159         memset(si, 0, sizeof(SymInterpInfo));
160         info->interps = AddCommonInfo(&info->interps->defs, &si->defs);
161         info->nInterps++;
162     }
163     return si;
164 }
165
166 static SymInterpInfo *
167 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
168 {
169     SymInterpInfo *old;
170
171     for (old = info->interps; old != NULL;
172          old = (SymInterpInfo *) old->defs.next) {
173         if ((old->interp.sym == new->interp.sym) &&
174             (old->interp.mods == new->interp.mods) &&
175             (old->interp.match == new->interp.match)) {
176             return old;
177         }
178     }
179     return NULL;
180 }
181
182 static bool
183 AddInterp(CompatInfo * info, SymInterpInfo * new)
184 {
185     unsigned collide;
186     SymInterpInfo *old;
187
188     collide = 0;
189     old = FindMatchingInterp(info, new);
190     if (old != NULL) {
191         if (new->defs.merge == MERGE_REPLACE) {
192             SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
193             if (((old->defs.file_id == new->defs.file_id)
194                  && (warningLevel > 0)) || (warningLevel > 9)) {
195                 WARN("Multiple definitions for \"%s\"\n", siText(new, info));
196                 ACTION("Earlier interpretation ignored\n");
197             }
198             *old = *new;
199             old->defs.next = &next->defs;
200             return true;
201         }
202         if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide)) {
203             old->interp.virtual_mod = new->interp.virtual_mod;
204             old->defs.defined |= _SI_VirtualMod;
205         }
206         if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide)) {
207             old->interp.act = new->interp.act;
208             old->defs.defined |= _SI_Action;
209         }
210         if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide)) {
211             old->interp.flags &= ~XkbSI_AutoRepeat;
212             old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
213             old->defs.defined |= _SI_AutoRepeat;
214         }
215         if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide)) {
216             old->interp.flags &= ~XkbSI_LockingKey;
217             old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
218             old->defs.defined |= _SI_LockingKey;
219         }
220         if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs,
221                         &collide)) {
222             old->interp.match &= ~XkbSI_LevelOneOnly;
223             old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
224             old->defs.defined |= _SI_LevelOneOnly;
225         }
226         if (collide) {
227             WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
228             ACTION("Using %s definition for duplicate fields\n",
229                    (new->defs.merge != MERGE_AUGMENT ? "last" : "first"));
230         }
231         return true;
232     }
233     old = new;
234     if ((new = NextInterp(info)) == NULL)
235         return false;
236     *new = *old;
237     new->defs.next = NULL;
238     return true;
239 }
240
241 static bool
242 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
243 {
244     GroupCompatInfo *gc;
245     enum merge_mode merge;
246
247     merge = newGC->merge;
248     gc = &info->groupCompat[group];
249     if (((gc->real_mods == newGC->real_mods) &&
250          (gc->vmods == newGC->vmods))) {
251         return true;
252     }
253     if (((gc->file_id == newGC->file_id) && (warningLevel > 0))
254         || (warningLevel > 9)) {
255         WARN("Compat map for group %d redefined\n", group + 1);
256         ACTION("Using %s definition\n",
257                (merge == MERGE_AUGMENT ? "old" : "new"));
258     }
259     if (newGC->defined && (merge != MERGE_AUGMENT || !gc->defined))
260         *gc = *newGC;
261     return true;
262 }
263
264 /***====================================================================***/
265
266 static bool
267 ResolveStateAndPredicate(ExprDef * expr,
268                          unsigned *pred_rtrn,
269                          unsigned *mods_rtrn, CompatInfo * info)
270 {
271     ExprResult result;
272
273     if (expr == NULL) {
274         *pred_rtrn = XkbSI_AnyOfOrNone;
275         *mods_rtrn = ~0;
276         return true;
277     }
278
279     *pred_rtrn = XkbSI_Exactly;
280     if (expr->op == ExprActionDecl) {
281         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
282                                              expr->value.action.name);
283         if (strcasecmp(pred_txt, "noneof") == 0)
284             *pred_rtrn = XkbSI_NoneOf;
285         else if (strcasecmp(pred_txt, "anyofornone") == 0)
286             *pred_rtrn = XkbSI_AnyOfOrNone;
287         else if (strcasecmp(pred_txt, "anyof") == 0)
288             *pred_rtrn = XkbSI_AnyOf;
289         else if (strcasecmp(pred_txt, "allof") == 0)
290             *pred_rtrn = XkbSI_AllOf;
291         else if (strcasecmp(pred_txt, "exactly") == 0)
292             *pred_rtrn = XkbSI_Exactly;
293         else {
294             ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
295             ACTION("Ignored\n");
296             return false;
297         }
298         expr = expr->value.action.args;
299     }
300     else if (expr->op == ExprIdent) {
301         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
302                                              expr->value.str);
303         if ((pred_txt) && (strcasecmp(pred_txt, "any") == 0)) {
304             *pred_rtrn = XkbSI_AnyOf;
305             *mods_rtrn = 0xff;
306             return true;
307         }
308     }
309
310     if (ExprResolveModMask(info->keymap->ctx, expr, &result)) {
311         *mods_rtrn = result.uval;
312         return true;
313     }
314     return false;
315 }
316
317 /***====================================================================***/
318
319 static void
320 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from,
321                         enum merge_mode merge)
322 {
323     SymInterpInfo *si;
324     LEDInfo *led, *rtrn, *next;
325     GroupCompatInfo *gcm;
326     int i;
327
328     if (from->errorCount > 0) {
329         into->errorCount += from->errorCount;
330         return;
331     }
332     if (into->name == NULL) {
333         into->name = from->name;
334         from->name = NULL;
335     }
336     for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next) {
337         if (merge != MERGE_DEFAULT)
338             si->defs.merge = merge;
339         if (!AddInterp(into, si))
340             into->errorCount++;
341     }
342     for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++,
343          gcm++) {
344         if (merge != MERGE_DEFAULT)
345             gcm->merge = merge;
346         if (!AddGroupCompat(into, i, gcm))
347             into->errorCount++;
348     }
349     for (led = from->leds; led != NULL; led = next) {
350         next = (LEDInfo *) led->defs.next;
351         if (merge != MERGE_DEFAULT)
352             led->defs.merge = merge;
353         rtrn = AddIndicatorMap(from->keymap, into->leds, led);
354         if (rtrn != NULL)
355             into->leds = rtrn;
356         else
357             into->errorCount++;
358     }
359 }
360
361 static void
362 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap,
363                     enum merge_mode merge,
364                     CompatInfo *info);
365
366 static bool
367 HandleIncludeCompatMap(IncludeStmt *stmt, struct xkb_keymap *keymap,
368                        CompatInfo *info)
369 {
370     enum merge_mode newMerge;
371     XkbFile *rtrn;
372     CompatInfo included;
373     bool haveSelf;
374
375     haveSelf = false;
376     if ((stmt->file == NULL) && (stmt->map == NULL)) {
377         haveSelf = true;
378         included = *info;
379         memset(info, 0, sizeof(CompatInfo));
380     }
381     else if (ProcessIncludeFile(keymap->ctx, stmt, FILE_TYPE_COMPAT, &rtrn,
382                                 &newMerge)) {
383         InitCompatInfo(&included, keymap, rtrn->id);
384         included.dflt = info->dflt;
385         included.dflt.defs.merge = newMerge;
386         included.ledDflt.defs.merge = newMerge;
387         included.act = info->act;
388         HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &included);
389         if (stmt->stmt != NULL) {
390             free(included.name);
391             included.name = stmt->stmt;
392             stmt->stmt = NULL;
393         }
394         if (info->act != NULL)
395             included.act = NULL;
396         FreeXKBFile(rtrn);
397     }
398     else {
399         info->errorCount += 10;
400         return false;
401     }
402     if ((stmt->next != NULL) && (included.errorCount < 1)) {
403         IncludeStmt *next;
404         unsigned op;
405         CompatInfo next_incl;
406
407         for (next = stmt->next; next != NULL; next = next->next) {
408             if ((next->file == NULL) && (next->map == NULL)) {
409                 haveSelf = true;
410                 MergeIncludedCompatMaps(&included, info, next->merge);
411                 ClearCompatInfo(info, keymap);
412             }
413             else if (ProcessIncludeFile(keymap->ctx, next, FILE_TYPE_COMPAT,
414                                         &rtrn, &op)) {
415                 InitCompatInfo(&next_incl, keymap, rtrn->id);
416                 next_incl.file_id = rtrn->id;
417                 next_incl.dflt = info->dflt;
418                 next_incl.dflt.defs.file_id = rtrn->id;
419                 next_incl.dflt.defs.merge = op;
420                 next_incl.ledDflt.defs.file_id = rtrn->id;
421                 next_incl.ledDflt.defs.merge = op;
422                 next_incl.act = info->act;
423                 HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &next_incl);
424                 MergeIncludedCompatMaps(&included, &next_incl, op);
425                 if (info->act != NULL)
426                     next_incl.act = NULL;
427                 ClearCompatInfo(&next_incl, keymap);
428                 FreeXKBFile(rtrn);
429             }
430             else {
431                 info->errorCount += 10;
432                 return false;
433             }
434         }
435     }
436     if (haveSelf)
437         *info = included;
438     else {
439         MergeIncludedCompatMaps(info, &included, newMerge);
440         ClearCompatInfo(&included, keymap);
441     }
442     return (info->errorCount == 0);
443 }
444
445 static const LookupEntry useModMapValues[] = {
446     { "levelone", 1 },
447     { "level1", 1 },
448     { "anylevel", 0 },
449     { "any", 0 },
450     { NULL, 0 }
451 };
452
453 static int
454 SetInterpField(SymInterpInfo *si, struct xkb_keymap *keymap, char *field,
455                ExprDef *arrayNdx, ExprDef *value, CompatInfo *info)
456 {
457     int ok = 1;
458     ExprResult tmp;
459
460     if (strcasecmp(field, "action") == 0) {
461         if (arrayNdx != NULL)
462             return ReportSINotArray(si, field, info);
463         ok = HandleActionDef(value, keymap, &si->interp.act.any, info->act);
464         if (ok)
465             si->defs.defined |= _SI_Action;
466     }
467     else if ((strcasecmp(field, "virtualmodifier") == 0) ||
468              (strcasecmp(field, "virtualmod") == 0)) {
469         if (arrayNdx != NULL)
470             return ReportSINotArray(si, field, info);
471         ok = ResolveVirtualModifier(value, keymap, &tmp, &info->vmods);
472         if (ok) {
473             si->interp.virtual_mod = tmp.uval;
474             si->defs.defined |= _SI_VirtualMod;
475         }
476         else
477             return ReportSIBadType(si, field, "virtual modifier", info);
478     }
479     else if (strcasecmp(field, "repeat") == 0) {
480         if (arrayNdx != NULL)
481             return ReportSINotArray(si, field, info);
482         ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
483         if (ok) {
484             if (tmp.uval)
485                 si->interp.flags |= XkbSI_AutoRepeat;
486             else
487                 si->interp.flags &= ~XkbSI_AutoRepeat;
488             si->defs.defined |= _SI_AutoRepeat;
489         }
490         else
491             return ReportSIBadType(si, field, "boolean", info);
492     }
493     else if (strcasecmp(field, "locking") == 0) {
494         if (arrayNdx != NULL)
495             return ReportSINotArray(si, field, info);
496         ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
497         if (ok) {
498             if (tmp.uval)
499                 si->interp.flags |= XkbSI_LockingKey;
500             else
501                 si->interp.flags &= ~XkbSI_LockingKey;
502             si->defs.defined |= _SI_LockingKey;
503         }
504         else
505             return ReportSIBadType(si, field, "boolean", info);
506     }
507     else if ((strcasecmp(field, "usemodmap") == 0) ||
508              (strcasecmp(field, "usemodmapmods") == 0)) {
509         if (arrayNdx != NULL)
510             return ReportSINotArray(si, field, info);
511         ok = ExprResolveEnum(keymap->ctx, value, &tmp, useModMapValues);
512         if (ok) {
513             if (tmp.uval)
514                 si->interp.match |= XkbSI_LevelOneOnly;
515             else
516                 si->interp.match &= ~XkbSI_LevelOneOnly;
517             si->defs.defined |= _SI_LevelOneOnly;
518         }
519         else
520             return ReportSIBadType(si, field, "level specification", info);
521     }
522     else {
523         ok = ReportBadField("symbol interpretation", field, siText(si, info));
524     }
525     return ok;
526 }
527
528 static int
529 HandleInterpVar(VarDef * stmt, struct xkb_keymap *keymap, CompatInfo * info)
530 {
531     ExprResult elem, field;
532     ExprDef *ndx;
533     int ret;
534
535     if (ExprResolveLhs(keymap, stmt->name, &elem, &field, &ndx) == 0)
536         ret = 0;               /* internal error, already reported */
537     else if (elem.str && (strcasecmp(elem.str, "interpret") == 0))
538         ret = SetInterpField(&info->dflt, keymap, field.str, ndx, stmt->value,
539                              info);
540     else if (elem.str && (strcasecmp(elem.str, "indicator") == 0))
541         ret = SetIndicatorMapField(&info->ledDflt, keymap, field.str, ndx,
542                                    stmt->value);
543     else
544         ret = SetActionField(keymap, elem.str, field.str, ndx, stmt->value,
545                              &info->act);
546     free(elem.str);
547     free(field.str);
548     return ret;
549 }
550
551 static int
552 HandleInterpBody(VarDef *def, struct xkb_keymap *keymap, SymInterpInfo *si,
553                  CompatInfo *info)
554 {
555     int ok = 1;
556     ExprResult tmp, field;
557     ExprDef *arrayNdx;
558
559     for (; def != NULL; def = (VarDef *) def->common.next) {
560         if ((def->name) && (def->name->type == ExprFieldRef)) {
561             ok = HandleInterpVar(def, keymap, info);
562             continue;
563         }
564         ok = ExprResolveLhs(keymap, def->name, &tmp, &field, &arrayNdx);
565         if (ok) {
566             ok = SetInterpField(si, keymap, field.str, arrayNdx, def->value,
567                                 info);
568             free(field.str);
569         }
570     }
571     return ok;
572 }
573
574 static int
575 HandleInterpDef(InterpDef *def, struct xkb_keymap *keymap,
576                 enum merge_mode merge,
577                 CompatInfo *info)
578 {
579     unsigned pred, mods;
580     SymInterpInfo si;
581
582     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
583         ERROR("Couldn't determine matching modifiers\n");
584         ACTION("Symbol interpretation ignored\n");
585         return false;
586     }
587     if (def->merge != MERGE_DEFAULT)
588         merge = def->merge;
589
590     si = info->dflt;
591     si.defs.merge = merge;
592     if (!LookupKeysym(def->sym, &si.interp.sym)) {
593         ERROR("Could not resolve keysym %s\n", def->sym);
594         ACTION("Symbol interpretation ignored\n");
595         return false;
596     }
597     si.interp.match = pred & XkbSI_OpMask;
598     si.interp.mods = mods;
599     if (!HandleInterpBody(def->def, keymap, &si, info)) {
600         info->errorCount++;
601         return false;
602     }
603
604     if (!AddInterp(info, &si)) {
605         info->errorCount++;
606         return false;
607     }
608     return true;
609 }
610
611 static int
612 HandleGroupCompatDef(GroupCompatDef *def, struct xkb_keymap *keymap,
613                      enum merge_mode merge, CompatInfo *info)
614 {
615     ExprResult val;
616     GroupCompatInfo tmp;
617
618     if (def->merge != MERGE_DEFAULT)
619         merge = def->merge;
620     if (!XkbIsLegalGroup(def->group - 1)) {
621         ERROR("Keyboard group must be in the range 1..%d\n",
622               XkbNumKbdGroups + 1);
623         ACTION("Compatibility map for illegal group %d ignored\n",
624                def->group);
625         return false;
626     }
627     tmp.file_id = info->file_id;
628     tmp.merge = merge;
629     if (!ExprResolveVModMask(def->def, &val, keymap)) {
630         ERROR("Expected a modifier mask in group compatibility definition\n");
631         ACTION("Ignoring illegal compatibility map for group %d\n",
632                def->group);
633         return false;
634     }
635     tmp.real_mods = val.uval & 0xff;
636     tmp.vmods = (val.uval >> 8) & 0xffff;
637     tmp.defined = true;
638     return AddGroupCompat(info, def->group - 1, &tmp);
639 }
640
641 static void
642 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap,
643                     enum merge_mode merge,
644                     CompatInfo *info)
645 {
646     ParseCommon *stmt;
647     LEDInfo *leds;
648
649     if (merge == MERGE_DEFAULT)
650         merge = MERGE_AUGMENT;
651     free(info->name);
652     info->name = uDupString(file->name);
653     stmt = file->defs;
654     while (stmt)
655     {
656         switch (stmt->stmtType) {
657         case StmtInclude:
658             if (!HandleIncludeCompatMap((IncludeStmt *) stmt, keymap, info))
659                 info->errorCount++;
660             break;
661         case StmtInterpDef:
662             if (!HandleInterpDef((InterpDef *) stmt, keymap, merge, info))
663                 info->errorCount++;
664             break;
665         case StmtGroupCompatDef:
666             if (!HandleGroupCompatDef
667                     ((GroupCompatDef *) stmt, keymap, merge, info))
668                 info->errorCount++;
669             break;
670         case StmtIndicatorMapDef:
671             leds = HandleIndicatorMapDef((IndicatorMapDef *) stmt, keymap,
672                                          &info->ledDflt, info->leds, merge);
673             if (leds != NULL)
674                 info->leds = leds;
675             else
676                 info->errorCount++;
677         break;
678         case StmtVarDef:
679             if (!HandleInterpVar((VarDef *) stmt, keymap, info))
680                 info->errorCount++;
681             break;
682         case StmtVModDef:
683             if (!HandleVModDef((VModDef *) stmt, keymap, merge, &info->vmods))
684                 info->errorCount++;
685             break;
686         case StmtKeycodeDef:
687             ERROR("Interpretation files may not include other types\n");
688             ACTION("Ignoring definition of key name\n");
689             info->errorCount++;
690             break;
691         default:
692             WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
693                  stmt->stmtType);
694             break;
695         }
696         stmt = stmt->next;
697         if (info->errorCount > 10) {
698 #ifdef NOISY
699             ERROR("Too many errors\n");
700 #endif
701             ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
702             break;
703         }
704     }
705 }
706
707 static void
708 CopyInterps(CompatInfo *info, struct xkb_keymap *keymap,
709             bool needSymbol, unsigned pred)
710 {
711     SymInterpInfo *si;
712
713     for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next) {
714         if (((si->interp.match & XkbSI_OpMask) != pred) ||
715             (needSymbol && (si->interp.sym == XKB_KEY_NoSymbol)) ||
716             ((!needSymbol) && (si->interp.sym != XKB_KEY_NoSymbol)))
717             continue;
718         darray_append(keymap->sym_interpret, si->interp);
719     }
720 }
721
722 bool
723 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
724                  enum merge_mode merge)
725 {
726     int i;
727     CompatInfo info;
728     GroupCompatInfo *gcm;
729
730     InitCompatInfo(&info, keymap, file->id);
731     info.dflt.defs.merge = merge;
732     info.ledDflt.defs.merge = merge;
733
734     HandleCompatMapFile(file, keymap, merge, &info);
735
736     if (info.errorCount != 0)
737         goto err_info;
738
739     darray_init(keymap->sym_interpret);
740     darray_growalloc(keymap->sym_interpret, info.nInterps);
741
742     if (info.name)
743         keymap->compat_section_name = strdup(info.name);
744
745     if (info.nInterps > 0) {
746         CopyInterps(&info, keymap, true, XkbSI_Exactly);
747         CopyInterps(&info, keymap, true, XkbSI_AllOf | XkbSI_NoneOf);
748         CopyInterps(&info, keymap, true, XkbSI_AnyOf);
749         CopyInterps(&info, keymap, true, XkbSI_AnyOfOrNone);
750         CopyInterps(&info, keymap, false, XkbSI_Exactly);
751         CopyInterps(&info, keymap, false, XkbSI_AllOf | XkbSI_NoneOf);
752         CopyInterps(&info, keymap, false, XkbSI_AnyOf);
753         CopyInterps(&info, keymap, false, XkbSI_AnyOfOrNone);
754     }
755
756     for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
757          i++, gcm++) {
758         if (gcm->file_id != 0 || gcm->real_mods != 0 || gcm->vmods != 0) {
759             keymap->groups[i].mask = gcm->real_mods;
760             keymap->groups[i].real_mods = gcm->real_mods;
761             keymap->groups[i].vmods = gcm->vmods;
762         }
763     }
764
765     if (info.leds != NULL) {
766         if (!CopyIndicatorMapDefs(keymap, info.leds))
767             info.errorCount++;
768         info.leds = NULL;
769     }
770
771     ClearCompatInfo(&info, keymap);
772     return true;
773
774 err_info:
775     ClearCompatInfo(&info, keymap);
776     return false;
777 }
778
779 uint32_t
780 VModsToReal(struct xkb_keymap *keymap, uint32_t vmodmask)
781 {
782     uint32_t ret = 0;
783     int i;
784
785     if (!vmodmask)
786         return 0;
787
788     for (i = 0; i < XkbNumVirtualMods; i++) {
789         if (!(vmodmask & (1 << i)))
790             continue;
791         ret |= keymap->vmods[i];
792     }
793
794     return ret;
795 }
796
797 static void
798 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
799                  uint32_t rmodmask)
800 {
801     switch (act->type) {
802     case XkbSA_SetMods:
803     case XkbSA_LatchMods:
804     case XkbSA_LockMods:
805         if (act->mods.flags & XkbSA_UseModMapMods)
806             act->mods.real_mods = rmodmask;
807         act->mods.mask = act->mods.real_mods;
808         act->mods.mask |= VModsToReal(keymap, act->mods.vmods);
809         break;
810
811     case XkbSA_ISOLock:
812         if (act->iso.flags & XkbSA_UseModMapMods)
813             act->iso.real_mods = rmodmask;
814         act->iso.mask = act->iso.real_mods;
815         act->iso.mask |= VModsToReal(keymap, act->iso.vmods);
816         break;
817
818     default:
819         break;
820     }
821 }
822
823 /**
824  * Find an interpretation which applies to this particular level, either by
825  * finding an exact match for the symbol and modifier combination, or a
826  * generic XKB_KEY_NoSymbol match.
827  */
828 static struct xkb_sym_interpret *
829 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
830                  uint32_t group, uint32_t level)
831 {
832     struct xkb_sym_interpret *ret = NULL;
833     struct xkb_sym_interpret *interp;
834     const xkb_keysym_t *syms;
835     int num_syms;
836
837     num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
838     if (num_syms == 0)
839         return NULL;
840
841     darray_foreach(interp, keymap->sym_interpret) {
842         uint32_t mods;
843         bool found;
844
845         if ((num_syms > 1 || interp->sym != syms[0]) &&
846             interp->sym != XKB_KEY_NoSymbol)
847             continue;
848
849         if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
850             mods = key->modmap;
851         else
852             mods = 0;
853
854         switch (interp->match & XkbSI_OpMask) {
855         case XkbSI_NoneOf:
856             found = !(interp->mods & mods);
857             break;
858         case XkbSI_AnyOfOrNone:
859             found = (!mods || (interp->mods & mods));
860             break;
861         case XkbSI_AnyOf:
862             found = !!(interp->mods & mods);
863             break;
864         case XkbSI_AllOf:
865             found = ((interp->mods & mods) == interp->mods);
866             break;
867         case XkbSI_Exactly:
868             found = (interp->mods == mods);
869             break;
870         default:
871             found = false;
872             break;
873         }
874
875         if (found && interp->sym != XKB_KEY_NoSymbol)
876             return interp;
877         else if (found && !ret)
878             ret = interp;
879     }
880
881     return ret;
882 }
883
884 /**
885  */
886 static bool
887 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
888 {
889 #define INTERP_SIZE (8 * 4)
890     struct xkb_sym_interpret *interps[INTERP_SIZE];
891     union xkb_action *acts;
892     uint32_t vmodmask = 0;
893     int num_acts = 0;
894     int group, level;
895     int i;
896
897     /* If we've been told not to bind interps to this key, then don't. */
898     if (key->explicit & XkbExplicitInterpretMask)
899         return true;
900
901     for (i = 0; i < INTERP_SIZE; i++)
902         interps[i] = NULL;
903
904     for (group = 0; group < key->num_groups; group++) {
905         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
906              level++) {
907             i = (group * key->width) + level;
908             if (i >= INTERP_SIZE) /* XXX FIXME */
909                 return false;
910             interps[i] = FindInterpForKey(keymap, key, group, level);
911             if (interps[i])
912                 num_acts++;
913         }
914     }
915
916     if (num_acts)
917         num_acts = key->num_groups * key->width;
918     acts = XkbcResizeKeyActions(keymap, key, num_acts);
919     if (num_acts && !acts)
920         return false;
921
922     for (group = 0; group < key->num_groups; group++) {
923         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
924              level++) {
925             struct xkb_sym_interpret *interp;
926
927             i = (group * key->width) + level;
928             interp = interps[i];
929
930             /* Infer default key behaviours from the base level. */
931             if (group == 0 && level == 0) {
932                 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
933                     (!interp || interp->flags & XkbSI_AutoRepeat))
934                     key->repeats = true;
935                 if (!(key->explicit & XkbExplicitBehaviorMask) &&
936                     interp && (interp->flags & XkbSI_LockingKey))
937                     key->behavior.type = XkbKB_Lock;
938             }
939
940             if (!interp)
941                 continue;
942
943             if ((group == 0 && level == 0) ||
944                 !(interp->match & XkbSI_LevelOneOnly)) {
945                 if (interp->virtual_mod != XkbNoModifier)
946                     vmodmask |= (1 << interp->virtual_mod);
947             }
948             acts[i] = interp->act;
949         }
950     }
951
952     if (!(key->explicit & XkbExplicitVModMapMask))
953         key->vmodmap = vmodmask;
954
955     return true;
956 #undef INTERP_SIZE
957 }
958
959 /**
960  * This collects a bunch of disparate functions which was done in the server
961  * at various points that really should've been done within xkbcomp.  Turns out
962  * your actions and types are a lot more useful when any of your modifiers
963  * other than Shift actually do something ...
964  */
965 bool
966 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
967 {
968     struct xkb_key *key;
969     int i;
970     struct xkb_key_type *type;
971     struct xkb_kt_map_entry *entry;
972
973     /* Find all the interprets for the key and bind them to actions,
974      * which will also update the vmodmap. */
975     xkb_foreach_key(key, keymap)
976         if (!ApplyInterpsToKey(keymap, key))
977             return false;
978
979     /* Update keymap->vmods, the virtual -> real mod mapping. */
980     for (i = 0; i < XkbNumVirtualMods; i++)
981         keymap->vmods[i] = 0;
982     xkb_foreach_key(key, keymap) {
983         if (!key->vmodmap)
984             continue;
985
986         for (i = 0; i < XkbNumVirtualMods; i++) {
987             if (!(key->vmodmap & (1 << i)))
988                 continue;
989             keymap->vmods[i] |= key->modmap;
990         }
991     }
992
993     /* Now update the level masks for all the types to reflect the vmods. */
994     darray_foreach(type, keymap->types) {
995         uint32_t mask = 0;
996         int j;
997         type->mods.mask = type->mods.real_mods;
998         type->mods.mask |= VModsToReal(keymap, type->mods.vmods);
999         for (j = 0; j < XkbNumVirtualMods; j++) {
1000             if (!(type->mods.vmods & (1 << j)))
1001                 continue;
1002             mask |= keymap->vmods[j];
1003         }
1004
1005         darray_foreach(entry, type->map)
1006         entry->mods.mask = entry->mods.real_mods |
1007                            VModsToReal(keymap, entry->mods.vmods);
1008     }
1009
1010     /* Update action modifiers. */
1011     xkb_foreach_key(key, keymap) {
1012         union xkb_action *acts = XkbKeyActionsPtr(keymap, key);
1013         for (i = 0; i < XkbKeyNumActions(key); i++) {
1014             if (acts[i].any.type == XkbSA_NoAction)
1015                 continue;
1016             UpdateActionMods(keymap, &acts[i], key->modmap);
1017         }
1018     }
1019
1020     /* Update group modifiers. */
1021     for (i = 0; i < XkbNumKbdGroups; i++) {
1022         struct xkb_mods *group = &keymap->groups[i];
1023         group->mask = group->real_mods | VModsToReal(keymap, group->vmods);
1024     }
1025
1026     /* Update vmod -> indicator maps. */
1027     for (i = 0; i < XkbNumIndicators; i++) {
1028         struct xkb_mods *led = &keymap->indicators[i].mods;
1029         led->mask = led->real_mods | VModsToReal(keymap, led->vmods);
1030     }
1031
1032     return true;
1033 }