compat: remove dead NoAutomatic code
[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 "text.h"
29 #include "expr.h"
30 #include "action.h"
31 #include "vmod.h"
32 #include "include.h"
33
34 /*
35  * The xkb_compat section
36  * =====================
37  * This section is the third to be processesed, after xkb_keycodes and
38  * xkb_types.
39  *
40  * Interpret statements
41  * --------------------
42  * Statements of the form:
43  *      interpret Num_Lock+Any { ... }
44  *
45  * The body of the statment may include statements of the following
46  * forms:
47  *
48  * - action statement:
49  *      action = LockMods(modifiers=NumLock);
50  *
51  * - virtual modifier statement:
52  *      virtualModifier = NumLock;
53  *
54  * - repeat statement:
55  *      repeat = True;
56  *
57  * - useModMapMods statement:
58  *      useModMapMods = level1;
59  *
60  * Indicator map statements
61  * ------------------------
62  * Statements of the form:
63  *      indicator "Shift Lock" { ... }
64  *
65  *   This statement specifies the behavior and binding of the indicator
66  *   with the given name ("Shift Lock" above). The name should have been
67  *   declared previously in the xkb_keycodes section (see Indicator name
68  *   statement), and given an index there. If it wasn't, it is created
69  *   with the next free index.
70  *   The body of the statement describes the conditions of the keyboard
71  *   state which will cause the indicator to be lit. It may include the
72  *   following statements:
73  *
74  * - modifiers statment:
75  *      modifiers = ScrollLock;
76  *
77  *   If the given modifiers are in the required state (see below), the
78  *   led is lit.
79  *
80  * - whichModifierState statment:
81  *      whichModState = Latched + Locked;
82  *
83  *   Can be any combination of:
84  *      base, latched, locked, effective
85  *      any (i.e. all of the above)
86  *      none (i.e. none of the above)
87  *      compat (this is legal, but unused)
88  *   This will cause the respective portion of the modifer state (see
89  *   struct xkb_state) to be matched against the modifiers given in the
90  *   "modifiers" statement.
91  *
92  *   Here's a simple example:
93  *      indicator "Num Lock" {
94  *          modifiers = NumLock;
95  *          whichModState = Locked;
96  *      };
97  *   Whenever the NumLock modifier is locked, the Num Lock indicator
98  *   will light up.
99  *
100  * - groups statment:
101  *      groups = All - group1;
102  *
103  *   If the given groups are in the required state (see below), the led
104  *   is lit.
105  *
106  * - whichGroupState statment:
107  *      whichGroupState = Effective;
108  *
109  *   Can be any combination of:
110  *      base, latched, locked, effective
111  *      any (i.e. all of the above)
112  *      none (i.e. none of the above)
113  *   This will cause the respective portion of the group state (see
114  *   struct xkb_state) to be matched against the groups given in the
115  *   "groups" statement.
116  *
117  *   Note: the above conditions are disjunctive, i.e. if any of them are
118  *   satisfied the led is lit.
119  *
120  * Virtual modifier statements
121  * ---------------------------
122  * Statements of the form:
123  *     virtual_modifiers LControl;
124  *
125  * Can appear in the xkb_types, xkb_compat, xkb_symbols sections.
126  * TODO
127  *
128  * Effect on keymap
129  * ----------------
130  * After all of the xkb_compat sections have been compiled, the following
131  * members of struct xkb_keymap are finalized:
132  *      darray(struct xkb_sym_interpret) sym_interpret;
133  *      struct xkb_indicator_map indicators[XkbNumIndicators];
134  *      char *compat_section_name;
135  * TODO: virtual modifiers.
136  */
137
138 enum si_field {
139     SI_FIELD_VIRTUAL_MOD    = (1 << 0),
140     SI_FIELD_ACTION         = (1 << 1),
141     SI_FIELD_AUTO_REPEAT    = (1 << 2),
142     SI_FIELD_LEVEL_ONE_ONLY = (1 << 3),
143 };
144
145 typedef struct _SymInterpInfo {
146     enum si_field defined;
147     unsigned file_id;
148     enum merge_mode merge;
149     struct list entry;
150
151     struct xkb_sym_interpret interp;
152 } SymInterpInfo;
153
154 enum led_field {
155     LED_FIELD_INDEX      = (1 << 0),
156     LED_FIELD_MODS       = (1 << 1),
157     LED_FIELD_GROUPS     = (1 << 2),
158     LED_FIELD_CTRLS      = (1 << 3),
159     LED_FIELD_EXPLICIT   = (1 << 4),
160     LED_FIELD_DRIVES_KBD = (1 << 5),
161 };
162
163 typedef struct _LEDInfo {
164     enum led_field defined;
165     unsigned file_id;
166     enum merge_mode merge;
167     struct list entry;
168
169     xkb_atom_t name;
170     xkb_led_index_t indicator;
171     unsigned char flags;
172     unsigned char which_mods;
173     xkb_mod_mask_t mods;
174     unsigned char which_groups;
175     uint32_t groups;
176     unsigned int ctrls;
177 } LEDInfo;
178
179 typedef struct _GroupCompatInfo {
180     unsigned file_id;
181     enum merge_mode merge;
182     bool defined;
183     xkb_mod_mask_t mods;
184 } GroupCompatInfo;
185
186 typedef struct _CompatInfo {
187     char *name;
188     unsigned file_id;
189     int errorCount;
190     int nInterps;
191     struct list interps;
192     SymInterpInfo dflt;
193     LEDInfo ledDflt;
194     GroupCompatInfo groupCompat[XkbNumKbdGroups];
195     struct list leds;
196     VModInfo vmods;
197     ActionInfo *act;
198     struct xkb_keymap *keymap;
199 } CompatInfo;
200
201 static const char *
202 siText(SymInterpInfo *si, CompatInfo *info)
203 {
204     static char buf[128];
205
206     if (si == &info->dflt)
207         return "default";
208
209     snprintf(buf, sizeof(buf), "%s+%s(%s)",
210              KeysymText(si->interp.sym),
211              SIMatchText(si->interp.match),
212              ModMaskText(si->interp.mods));
213     return buf;
214 }
215
216 static inline bool
217 ReportSINotArray(CompatInfo *info, SymInterpInfo *si, const char *field)
218 {
219     return ReportNotArray(info->keymap, "symbol interpretation", field,
220                           siText(si, info));
221 }
222
223 static inline bool
224 ReportSIBadType(CompatInfo *info, SymInterpInfo *si, const char *field,
225                 const char *wanted)
226 {
227     return ReportBadType(info->keymap->ctx, "symbol interpretation", field,
228                          siText(si, info), wanted);
229 }
230
231 static inline bool
232 ReportIndicatorBadType(CompatInfo *info, LEDInfo *led,
233                        const char *field, const char *wanted)
234 {
235     return ReportBadType(info->keymap->ctx, "indicator map", field,
236                          xkb_atom_text(info->keymap->ctx, led->name),
237                          wanted);
238 }
239
240 static inline bool
241 ReportIndicatorNotArray(CompatInfo *info, LEDInfo *led,
242                         const char *field)
243 {
244     return ReportNotArray(info->keymap, "indicator map", field,
245                           xkb_atom_text(info->keymap->ctx, led->name));
246 }
247
248 static void
249 ClearIndicatorMapInfo(struct xkb_context *ctx, LEDInfo *info)
250 {
251     info->name = xkb_atom_intern(ctx, "default");
252     info->indicator = XKB_LED_INVALID;
253     info->flags = 0;
254     info->which_mods = 0;
255     info->mods = 0;
256     info->which_groups = info->groups = 0;
257     info->ctrls = 0;
258 }
259
260 static void
261 InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id)
262 {
263     info->keymap = keymap;
264     info->name = NULL;
265     info->file_id = file_id;
266     info->errorCount = 0;
267     info->nInterps = 0;
268     list_init(&info->interps);
269     info->act = NULL;
270     info->dflt.file_id = file_id;
271     info->dflt.defined = 0;
272     info->dflt.merge = MERGE_OVERRIDE;
273     info->dflt.interp.flags = 0;
274     info->dflt.interp.virtual_mod = XkbNoModifier;
275     memset(&info->dflt.interp.act, 0, sizeof(info->dflt.interp.act));
276     info->dflt.interp.act.type = XkbSA_NoAction;
277     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
278     info->ledDflt.file_id = file_id;
279     info->ledDflt.defined = 0;
280     info->ledDflt.merge = MERGE_OVERRIDE;
281     memset(&info->groupCompat[0], 0,
282            XkbNumKbdGroups * sizeof(GroupCompatInfo));
283     list_init(&info->leds);
284     InitVModInfo(&info->vmods, keymap);
285 }
286
287 static void
288 ClearCompatInfo(CompatInfo *info)
289 {
290     SymInterpInfo *si, *next_si;
291     LEDInfo *led, *next_led;
292     struct xkb_keymap *keymap = info->keymap;
293
294     free(info->name);
295     info->name = NULL;
296     info->dflt.defined = 0;
297     info->dflt.merge = MERGE_AUGMENT;
298     info->dflt.interp.flags = 0;
299     info->dflt.interp.virtual_mod = XkbNoModifier;
300     memset(&info->dflt.interp.act, 0, sizeof(info->dflt.interp.act));
301     info->dflt.interp.act.type = XkbSA_NoAction;
302     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
303     info->nInterps = 0;
304     list_foreach_safe(si, next_si, &info->interps, entry)
305         free(si);
306     memset(&info->groupCompat[0], 0,
307            XkbNumKbdGroups * sizeof(GroupCompatInfo));
308     list_foreach_safe(led, next_led, &info->leds, entry)
309         free(led);
310     FreeActionInfo(info->act);
311     info->act = NULL;
312     info->keymap = NULL;
313     ClearVModInfo(&info->vmods, keymap);
314 }
315
316 static SymInterpInfo *
317 NextInterp(CompatInfo *info)
318 {
319     SymInterpInfo *si;
320
321     si = calloc(1, sizeof(*si));
322     if (!si)
323         return NULL;
324
325     list_append(&si->entry, &info->interps);
326     info->nInterps++;
327
328     return si;
329 }
330
331 static SymInterpInfo *
332 FindMatchingInterp(CompatInfo *info, SymInterpInfo *new)
333 {
334     SymInterpInfo *old;
335
336     list_foreach(old, &info->interps, entry)
337         if (old->interp.sym == new->interp.sym &&
338             old->interp.mods == new->interp.mods &&
339             old->interp.match == new->interp.match)
340             return old;
341
342     return NULL;
343 }
344
345 static bool
346 UseNewInterpField(enum si_field field, SymInterpInfo *old, SymInterpInfo *new,
347                   int verbosity, enum si_field *collide)
348 {
349     if (!(old->defined & field))
350         return true;
351
352     if (new->defined & field) {
353         if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
354             *collide |= field;
355
356         if (new->merge != MERGE_AUGMENT)
357             return true;
358     }
359
360     return false;
361 }
362
363 static bool
364 AddInterp(CompatInfo *info, SymInterpInfo *new)
365 {
366     enum si_field collide;
367     SymInterpInfo *old;
368     struct list entry;
369     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
370
371     collide = 0;
372     old = FindMatchingInterp(info, new);
373     if (old != NULL) {
374         if (new->merge == MERGE_REPLACE) {
375             entry = old->entry;
376             if ((old->file_id == new->file_id && verbosity > 0) ||
377                 verbosity > 9)
378                 log_warn(info->keymap->ctx,
379                          "Multiple definitions for \"%s\"; "
380                          "Earlier interpretation ignored\n",
381                          siText(new, info));
382             *old = *new;
383             old->entry = entry;
384             return true;
385         }
386
387         if (UseNewInterpField(SI_FIELD_VIRTUAL_MOD, old, new, verbosity,
388                               &collide)) {
389             old->interp.virtual_mod = new->interp.virtual_mod;
390             old->defined |= SI_FIELD_VIRTUAL_MOD;
391         }
392         if (UseNewInterpField(SI_FIELD_ACTION, old, new, verbosity,
393                               &collide)) {
394             old->interp.act = new->interp.act;
395             old->defined |= SI_FIELD_ACTION;
396         }
397         if (UseNewInterpField(SI_FIELD_AUTO_REPEAT, old, new, verbosity,
398                               &collide)) {
399             old->interp.flags &= ~XkbSI_AutoRepeat;
400             old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
401             old->defined |= SI_FIELD_AUTO_REPEAT;
402         }
403         if (UseNewInterpField(SI_FIELD_LEVEL_ONE_ONLY, old, new, verbosity,
404                               &collide)) {
405             old->interp.match &= ~XkbSI_LevelOneOnly;
406             old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
407             old->defined |= SI_FIELD_LEVEL_ONE_ONLY;
408         }
409
410         if (collide) {
411             log_warn(info->keymap->ctx,
412                      "Multiple interpretations of \"%s\"; "
413                      "Using %s definition for duplicate fields\n",
414                      siText(new, info),
415                      (new->merge != MERGE_AUGMENT ? "last" : "first"));
416         }
417
418         return true;
419     }
420
421     old = new;
422     new = NextInterp(info);
423     if (!new)
424         return false;
425     entry = new->entry;
426     *new = *old;
427     new->entry = entry;
428     return true;
429 }
430
431 static bool
432 AddGroupCompat(CompatInfo *info, xkb_group_index_t group, GroupCompatInfo *new)
433 {
434     GroupCompatInfo *gc;
435     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
436
437     gc = &info->groupCompat[group];
438     if (gc->mods == new->mods)
439         return true;
440
441     if ((gc->file_id == new->file_id && verbosity > 0) || verbosity > 9)
442         log_warn(info->keymap->ctx,
443                  "Compat map for group %u redefined; "
444                  "Using %s definition\n",
445                  group + 1, (new->merge == MERGE_AUGMENT ? "old" : "new"));
446
447     if (new->defined && (new->merge != MERGE_AUGMENT || !gc->defined))
448         *gc = *new;
449
450     return true;
451 }
452
453 /***====================================================================***/
454
455 static bool
456 ResolveStateAndPredicate(ExprDef *expr, unsigned *pred_rtrn,
457                          xkb_mod_mask_t *mods_rtrn, CompatInfo *info)
458 {
459     if (expr == NULL) {
460         *pred_rtrn = XkbSI_AnyOfOrNone;
461         *mods_rtrn = ~0;
462         return true;
463     }
464
465     *pred_rtrn = XkbSI_Exactly;
466     if (expr->op == EXPR_ACTION_DECL) {
467         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
468                                              expr->value.action.name);
469         if (istreq(pred_txt, "noneof"))
470             *pred_rtrn = XkbSI_NoneOf;
471         else if (istreq(pred_txt, "anyofornone"))
472             *pred_rtrn = XkbSI_AnyOfOrNone;
473         else if (istreq(pred_txt, "anyof"))
474             *pred_rtrn = XkbSI_AnyOf;
475         else if (istreq(pred_txt, "allof"))
476             *pred_rtrn = XkbSI_AllOf;
477         else if (istreq(pred_txt, "exactly"))
478             *pred_rtrn = XkbSI_Exactly;
479         else {
480             log_err(info->keymap->ctx,
481                     "Illegal modifier predicate \"%s\"; Ignored\n", pred_txt);
482             return false;
483         }
484         expr = expr->value.action.args;
485     }
486     else if (expr->op == EXPR_IDENT) {
487         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
488                                              expr->value.str);
489         if (pred_txt && istreq(pred_txt, "any")) {
490             *pred_rtrn = XkbSI_AnyOf;
491             *mods_rtrn = 0xff;
492             return true;
493         }
494     }
495
496     return ExprResolveModMask(info->keymap->ctx, expr, mods_rtrn);
497 }
498
499 /***====================================================================***/
500
501 static bool
502 UseNewLEDField(enum led_field field, LEDInfo *old, LEDInfo *new,
503                int verbosity, enum led_field *collide)
504 {
505     if (!(old->defined & field))
506         return true;
507
508     if (new->defined & field) {
509         if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
510             *collide |= field;
511
512         if (new->merge != MERGE_AUGMENT)
513             return true;
514     }
515
516     return false;
517 }
518
519 static bool
520 AddIndicatorMap(CompatInfo *info, LEDInfo *new)
521 {
522     LEDInfo *old;
523     enum led_field collide;
524     struct xkb_context *ctx = info->keymap->ctx;
525     int verbosity = xkb_get_log_verbosity(ctx);
526
527     list_foreach(old, &info->leds, entry) {
528         if (old->name != new->name)
529             continue;
530
531         if (old->mods == new->mods &&
532             old->groups == new->groups &&
533             old->ctrls == new->ctrls &&
534             old->which_mods == new->which_mods &&
535             old->which_groups == new->which_groups) {
536             old->defined |= new->defined;
537             return true;
538         }
539
540         if (new->merge == MERGE_REPLACE) {
541             struct list entry = old->entry;
542             if ((old->file_id == new->file_id && verbosity > 0) ||
543                 verbosity > 9)
544                 log_warn(info->keymap->ctx,
545                          "Map for indicator %s redefined; "
546                          "Earlier definition ignored\n",
547                          xkb_atom_text(ctx, old->name));
548             *old = *new;
549             old->entry = entry;
550             return true;
551         }
552
553         collide = 0;
554         if (UseNewLEDField(LED_FIELD_INDEX, old, new, verbosity,
555                            &collide)) {
556             old->indicator = new->indicator;
557             old->defined |= LED_FIELD_INDEX;
558         }
559         if (UseNewLEDField(LED_FIELD_MODS, old, new, verbosity,
560                            &collide)) {
561             old->which_mods = new->which_mods;
562             old->mods = new->mods;
563             old->defined |= LED_FIELD_MODS;
564         }
565         if (UseNewLEDField(LED_FIELD_GROUPS, old, new, verbosity,
566                            &collide)) {
567             old->which_groups = new->which_groups;
568             old->groups = new->groups;
569             old->defined |= LED_FIELD_GROUPS;
570         }
571         if (UseNewLEDField(LED_FIELD_CTRLS, old, new, verbosity,
572                            &collide)) {
573             old->ctrls = new->ctrls;
574             old->defined |= LED_FIELD_CTRLS;
575         }
576         if (UseNewLEDField(LED_FIELD_EXPLICIT, old, new, verbosity,
577                            &collide)) {
578             old->flags &= ~XkbIM_NoExplicit;
579             old->flags |= (new->flags & XkbIM_NoExplicit);
580             old->defined |= LED_FIELD_EXPLICIT;
581         }
582         if (UseNewLEDField(LED_FIELD_DRIVES_KBD, old, new, verbosity,
583                            &collide)) {
584             old->flags &= ~XkbIM_LEDDrivesKB;
585             old->flags |= (new->flags & XkbIM_LEDDrivesKB);
586             old->defined |= LED_FIELD_DRIVES_KBD;
587         }
588
589         if (collide) {
590             log_warn(info->keymap->ctx,
591                      "Map for indicator %s redefined; "
592                      "Using %s definition for duplicate fields\n",
593                      xkb_atom_text(ctx, old->name),
594                      (new->merge == MERGE_AUGMENT ? "first" : "last"));
595         }
596
597         return true;
598     }
599
600     old = malloc(sizeof(*old));
601     if (!old) {
602         log_wsgo(info->keymap->ctx,
603                  "Couldn't allocate indicator map; "
604                  "Map for indicator %s not compiled\n",
605                  xkb_atom_text(ctx, new->name));
606         return false;
607     }
608
609     *old = *new;
610     list_append(&old->entry, &info->leds);
611
612     return true;
613 }
614
615 static void
616 MergeIncludedCompatMaps(CompatInfo *into, CompatInfo *from,
617                         enum merge_mode merge)
618 {
619     SymInterpInfo *si, *next_si;
620     LEDInfo *led, *next_led;
621     GroupCompatInfo *gcm;
622     xkb_group_index_t i;
623
624     if (from->errorCount > 0) {
625         into->errorCount += from->errorCount;
626         return;
627     }
628
629     if (into->name == NULL) {
630         into->name = from->name;
631         from->name = NULL;
632     }
633
634     list_foreach_safe(si, next_si, &from->interps, entry) {
635         si->merge = (merge == MERGE_DEFAULT ? si->merge : merge);
636         if (!AddInterp(into, si))
637             into->errorCount++;
638     }
639
640     for (i = 0; i < XkbNumKbdGroups; i++) {
641         gcm = &from->groupCompat[i];
642         gcm->merge = (merge == MERGE_DEFAULT ? gcm->merge : merge);
643         if (!AddGroupCompat(into, i, gcm))
644             into->errorCount++;
645     }
646
647     list_foreach_safe(led, next_led, &from->leds, entry) {
648         led->merge = (merge == MERGE_DEFAULT ? led->merge : merge);
649         if (!AddIndicatorMap(into, led))
650             into->errorCount++;
651     }
652 }
653
654 static void
655 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge);
656
657 static bool
658 HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *stmt)
659 {
660     enum merge_mode merge = MERGE_DEFAULT;
661     XkbFile *rtrn;
662     CompatInfo included, next_incl;
663
664     InitCompatInfo(&included, info->keymap, info->file_id);
665     if (stmt->stmt) {
666         free(included.name);
667         included.name = stmt->stmt;
668         stmt->stmt = NULL;
669     }
670
671     for (; stmt; stmt = stmt->next_incl) {
672         if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_COMPAT,
673                                 &rtrn, &merge)) {
674             info->errorCount += 10;
675             ClearCompatInfo(&included);
676             return false;
677         }
678
679         InitCompatInfo(&next_incl, info->keymap, rtrn->id);
680         next_incl.file_id = rtrn->id;
681         next_incl.dflt = info->dflt;
682         next_incl.dflt.file_id = rtrn->id;
683         next_incl.dflt.merge = merge;
684         next_incl.ledDflt.file_id = rtrn->id;
685         next_incl.ledDflt.merge = merge;
686         next_incl.act = info->act;
687
688         HandleCompatMapFile(&next_incl, rtrn, MERGE_OVERRIDE);
689
690         MergeIncludedCompatMaps(&included, &next_incl, merge);
691         if (info->act)
692             next_incl.act = NULL;
693
694         ClearCompatInfo(&next_incl);
695         FreeXkbFile(rtrn);
696     }
697
698     MergeIncludedCompatMaps(info, &included, merge);
699     ClearCompatInfo(&included);
700
701     return (info->errorCount == 0);
702 }
703
704 static const LookupEntry useModMapValues[] = {
705     { "levelone", 1 },
706     { "level1", 1 },
707     { "anylevel", 0 },
708     { "any", 0 },
709     { NULL, 0 }
710 };
711
712 static bool
713 SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
714                ExprDef *arrayNdx, ExprDef *value)
715 {
716     struct xkb_keymap *keymap = info->keymap;
717     xkb_mod_index_t ndx;
718
719     if (istreq(field, "action")) {
720         if (arrayNdx)
721             return ReportSINotArray(info, si, field);
722
723         if (!HandleActionDef(value, keymap, &si->interp.act, info->act))
724             return false;
725
726         si->defined |= SI_FIELD_ACTION;
727     }
728     else if (istreq(field, "virtualmodifier") ||
729              istreq(field, "virtualmod")) {
730         if (arrayNdx)
731             return ReportSINotArray(info, si, field);
732
733         if (!ResolveVirtualModifier(value, keymap, &ndx, &info->vmods))
734             return ReportSIBadType(info, si, field, "virtual modifier");
735
736         si->interp.virtual_mod = ndx;
737         si->defined |= SI_FIELD_VIRTUAL_MOD;
738     }
739     else if (istreq(field, "repeat")) {
740         bool set;
741
742         if (arrayNdx)
743             return ReportSINotArray(info, si, field);
744
745         if (!ExprResolveBoolean(keymap->ctx, value, &set))
746             return ReportSIBadType(info, si, field, "boolean");
747
748         if (set)
749             si->interp.flags |= XkbSI_AutoRepeat;
750         else
751             si->interp.flags &= ~XkbSI_AutoRepeat;
752
753         si->defined |= SI_FIELD_AUTO_REPEAT;
754     }
755     else if (istreq(field, "locking")) {
756         log_dbg(info->keymap->ctx,
757                 "The \"locking\" field in symbol interpretation is unsupported; "
758                 "Ignored\n");
759     }
760     else if (istreq(field, "usemodmap") ||
761              istreq(field, "usemodmapmods")) {
762         unsigned int val;
763
764         if (arrayNdx)
765             return ReportSINotArray(info, si, field);
766
767         if (!ExprResolveEnum(keymap->ctx, value, &val, useModMapValues))
768             return ReportSIBadType(info, si, field, "level specification");
769
770         if (val)
771             si->interp.match |= XkbSI_LevelOneOnly;
772         else
773             si->interp.match &= ~XkbSI_LevelOneOnly;
774
775         si->defined |= SI_FIELD_LEVEL_ONE_ONLY;
776     }
777     else {
778         return ReportBadField(keymap, "symbol interpretation", field,
779                               siText(si, info));
780     }
781
782     return true;
783 }
784
785 static const LookupEntry modComponentNames[] = {
786     {"base", XkbIM_UseBase},
787     {"latched", XkbIM_UseLatched},
788     {"locked", XkbIM_UseLocked},
789     {"effective", XkbIM_UseEffective},
790     {"compat", XkbIM_UseCompat},
791     {"any", XkbIM_UseAnyMods},
792     {"none", 0},
793     {NULL, 0}
794 };
795
796 static const LookupEntry groupComponentNames[] = {
797     {"base", XkbIM_UseBase},
798     {"latched", XkbIM_UseLatched},
799     {"locked", XkbIM_UseLocked},
800     {"effective", XkbIM_UseEffective},
801     {"any", XkbIM_UseAnyGroup},
802     {"none", 0},
803     {NULL, 0}
804 };
805
806 static const LookupEntry groupNames[] = {
807     {"group1", 0x01},
808     {"group2", 0x02},
809     {"group3", 0x04},
810     {"group4", 0x08},
811     {"group5", 0x10},
812     {"group6", 0x20},
813     {"group7", 0x40},
814     {"group8", 0x80},
815     {"none", 0x00},
816     {"all", 0xff},
817     {NULL, 0}
818 };
819
820 static bool
821 SetIndicatorMapField(CompatInfo *info, LEDInfo *led,
822                      const char *field, ExprDef *arrayNdx, ExprDef *value)
823 {
824     bool ok = true;
825     struct xkb_keymap *keymap = info->keymap;
826
827     if (istreq(field, "modifiers") || istreq(field, "mods")) {
828         if (arrayNdx)
829             return ReportIndicatorNotArray(info, led, field);
830
831         if (!ExprResolveVModMask(keymap, value, &led->mods))
832             return ReportIndicatorBadType(info, led, field, "modifier mask");
833
834         led->defined |= LED_FIELD_MODS;
835     }
836     else if (istreq(field, "groups")) {
837         unsigned int mask;
838
839         if (arrayNdx)
840             return ReportIndicatorNotArray(info, led, field);
841
842         if (!ExprResolveMask(keymap->ctx, value, &mask, groupNames))
843             return ReportIndicatorBadType(info, led, field, "group mask");
844
845         led->groups = mask;
846         led->defined |= LED_FIELD_GROUPS;
847     }
848     else if (istreq(field, "controls") || istreq(field, "ctrls")) {
849         unsigned int mask;
850
851         if (arrayNdx)
852             return ReportIndicatorNotArray(info, led, field);
853
854         if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlNames))
855             return ReportIndicatorBadType(info, led, field,
856                                           "controls mask");
857
858         led->ctrls = mask;
859         led->defined |= LED_FIELD_CTRLS;
860     }
861     else if (istreq(field, "allowexplicit")) {
862         bool set;
863
864         if (arrayNdx)
865             return ReportIndicatorNotArray(info, led, field);
866
867         if (!ExprResolveBoolean(keymap->ctx, value, &set))
868             return ReportIndicatorBadType(info, led, field, "boolean");
869
870         if (set)
871             led->flags &= ~XkbIM_NoExplicit;
872         else
873             led->flags |= XkbIM_NoExplicit;
874
875         led->defined |= LED_FIELD_EXPLICIT;
876     }
877     else if (istreq(field, "whichmodstate") ||
878              istreq(field, "whichmodifierstate")) {
879         unsigned int mask;
880
881         if (arrayNdx)
882             return ReportIndicatorNotArray(info, led, field);
883
884         if (!ExprResolveMask(keymap->ctx, value, &mask, modComponentNames))
885             return ReportIndicatorBadType(info, led, field,
886                                           "mask of modifier state components");
887
888         led->which_mods = mask;
889     }
890     else if (istreq(field, "whichgroupstate")) {
891         unsigned mask;
892
893         if (arrayNdx)
894             return ReportIndicatorNotArray(info, led, field);
895
896         if (!ExprResolveMask(keymap->ctx, value, &mask, groupComponentNames))
897             return ReportIndicatorBadType(info, led, field,
898                                           "mask of group state components");
899
900         led->which_groups = mask;
901     }
902     else if (istreq(field, "driveskbd") ||
903              istreq(field, "driveskeyboard") ||
904              istreq(field, "leddriveskbd") ||
905              istreq(field, "leddriveskeyboard") ||
906              istreq(field, "indicatordriveskbd") ||
907              istreq(field, "indicatordriveskeyboard")) {
908         bool set;
909
910         if (arrayNdx)
911             return ReportIndicatorNotArray(info, led, field);
912
913         if (!ExprResolveBoolean(keymap->ctx, value, &set))
914             return ReportIndicatorBadType(info, led, field, "boolean");
915
916         if (set)
917             led->flags |= XkbIM_LEDDrivesKB;
918         else
919             led->flags &= ~XkbIM_LEDDrivesKB;
920
921         led->defined |= LED_FIELD_DRIVES_KBD;
922     }
923     else if (istreq(field, "index")) {
924         int ndx;
925
926         if (arrayNdx)
927             return ReportIndicatorNotArray(info, led, field);
928
929         if (!ExprResolveInteger(keymap->ctx, value, &ndx))
930             return ReportIndicatorBadType(info, led, field,
931                                           "indicator index");
932
933         if (ndx < 1 || ndx > XkbNumIndicators) {
934             log_err(info->keymap->ctx,
935                     "Illegal indicator index %d (range 1..%d); "
936                     "Index definition for %s indicator ignored\n",
937                     ndx, XkbNumIndicators,
938                     xkb_atom_text(keymap->ctx, led->name));
939             return false;
940         }
941
942         led->indicator = (xkb_led_index_t) ndx;
943         led->defined |= LED_FIELD_INDEX;
944     }
945     else {
946         log_err(info->keymap->ctx,
947                 "Unknown field %s in map for %s indicator; "
948                 "Definition ignored\n",
949                 field, xkb_atom_text(keymap->ctx, led->name));
950         ok = false;
951     }
952
953     return ok;
954 }
955
956 static bool
957 HandleInterpVar(CompatInfo *info, VarDef *stmt)
958 {
959     const char *elem, *field;
960     ExprDef *ndx;
961     bool ret;
962
963     if (!ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, &ndx))
964         ret = false;
965     else if (elem && istreq(elem, "interpret"))
966         ret = SetInterpField(info, &info->dflt, field, ndx, stmt->value);
967     else if (elem && istreq(elem, "indicator"))
968         ret = SetIndicatorMapField(info, &info->ledDflt, field, ndx,
969                                    stmt->value);
970     else
971         ret = SetActionField(info->keymap, elem, field, ndx, stmt->value,
972                              &info->act);
973     return ret;
974 }
975
976 static bool
977 HandleInterpBody(CompatInfo *info, VarDef *def, SymInterpInfo *si)
978 {
979     bool ok = true;
980     const char *elem, *field;
981     ExprDef *arrayNdx;
982
983     for (; def; def = (VarDef *) def->common.next) {
984         if (def->name && def->name->op == EXPR_FIELD_REF) {
985             ok = HandleInterpVar(info, def);
986             continue;
987         }
988
989         ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
990                             &arrayNdx);
991         if (!ok)
992             continue;
993
994         ok = SetInterpField(info, si, field, arrayNdx, def->value);
995     }
996
997     return ok;
998 }
999
1000 static bool
1001 HandleInterpDef(CompatInfo *info, InterpDef *def, enum merge_mode merge)
1002 {
1003     unsigned pred, mods;
1004     SymInterpInfo si;
1005
1006     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
1007         log_err(info->keymap->ctx,
1008                 "Couldn't determine matching modifiers; "
1009                 "Symbol interpretation ignored\n");
1010         return false;
1011     }
1012
1013     si = info->dflt;
1014
1015     si.merge = merge = (def->merge == MERGE_DEFAULT ? merge : def->merge);
1016
1017     if (!LookupKeysym(def->sym, &si.interp.sym)) {
1018         log_err(info->keymap->ctx,
1019                 "Could not resolve keysym %s; "
1020                 "Symbol interpretation ignored\n",
1021                 def->sym);
1022         return false;
1023     }
1024
1025     si.interp.match = pred & XkbSI_OpMask;
1026
1027     si.interp.mods = mods;
1028
1029     if (!HandleInterpBody(info, def->def, &si)) {
1030         info->errorCount++;
1031         return false;
1032     }
1033
1034     if (!AddInterp(info, &si)) {
1035         info->errorCount++;
1036         return false;
1037     }
1038
1039     return true;
1040 }
1041
1042 static bool
1043 HandleGroupCompatDef(CompatInfo *info, GroupCompatDef *def,
1044                      enum merge_mode merge)
1045 {
1046     GroupCompatInfo tmp;
1047
1048     merge = (def->merge == MERGE_DEFAULT ? merge : def->merge);
1049
1050     if (def->group < 1 || def->group > XkbNumKbdGroups) {
1051         log_err(info->keymap->ctx,
1052                 "Keyboard group must be in the range 1..%u; "
1053                 "Compatibility map for illegal group %u ignored\n",
1054                 XkbNumKbdGroups, def->group);
1055         return false;
1056     }
1057
1058     tmp.file_id = info->file_id;
1059     tmp.merge = merge;
1060
1061     if (!ExprResolveVModMask(info->keymap, def->def, &tmp.mods)) {
1062         log_err(info->keymap->ctx,
1063                 "Expected a modifier mask in group compatibility definition; "
1064                 "Ignoring illegal compatibility map for group %u\n",
1065                 def->group);
1066         return false;
1067     }
1068
1069     tmp.defined = true;
1070     return AddGroupCompat(info, def->group - 1, &tmp);
1071 }
1072
1073 static bool
1074 HandleIndicatorMapDef(CompatInfo *info, IndicatorMapDef *def,
1075                       enum merge_mode merge)
1076 {
1077     LEDInfo led;
1078     VarDef *var;
1079     bool ok;
1080
1081     if (def->merge != MERGE_DEFAULT)
1082         merge = def->merge;
1083
1084     led = info->ledDflt;
1085     led.merge = merge;
1086     led.name = def->name;
1087
1088     ok = true;
1089     for (var = def->body; var != NULL; var = (VarDef *) var->common.next) {
1090         const char *elem, *field;
1091         ExprDef *arrayNdx;
1092         if (!ExprResolveLhs(info->keymap->ctx, var->name, &elem, &field,
1093                             &arrayNdx)) {
1094             ok = false;
1095             continue;
1096         }
1097
1098         if (elem) {
1099             log_err(info->keymap->ctx,
1100                     "Cannot set defaults for \"%s\" element in indicator map; "
1101                     "Assignment to %s.%s ignored\n", elem, elem, field);
1102             ok = false;
1103         }
1104         else {
1105             ok = SetIndicatorMapField(info, &led, field, arrayNdx,
1106                                       var->value) && ok;
1107         }
1108     }
1109
1110     if (ok)
1111         return AddIndicatorMap(info, &led);
1112
1113     return false;
1114 }
1115
1116 static void
1117 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
1118 {
1119     bool ok;
1120     ParseCommon *stmt;
1121
1122     merge = (merge == MERGE_DEFAULT ? MERGE_AUGMENT : merge);
1123
1124     free(info->name);
1125     info->name = strdup_safe(file->name);
1126
1127     for (stmt = file->defs; stmt; stmt = stmt->next) {
1128         switch (stmt->type) {
1129         case STMT_INCLUDE:
1130             ok = HandleIncludeCompatMap(info, (IncludeStmt *) stmt);
1131             break;
1132         case STMT_INTERP:
1133             ok = HandleInterpDef(info, (InterpDef *) stmt, merge);
1134             break;
1135         case STMT_GROUP_COMPAT:
1136             ok = HandleGroupCompatDef(info, (GroupCompatDef *) stmt, merge);
1137             break;
1138         case STMT_INDICATOR_MAP:
1139             ok = HandleIndicatorMapDef(info, (IndicatorMapDef *) stmt, merge);
1140             break;
1141         case STMT_VAR:
1142             ok = HandleInterpVar(info, (VarDef *) stmt);
1143             break;
1144         case STMT_VMOD:
1145             ok = HandleVModDef((VModDef *) stmt, info->keymap, merge,
1146                                &info->vmods);
1147             break;
1148         default:
1149             log_err(info->keymap->ctx,
1150                     "Interpretation files may not include other types; "
1151                     "Ignoring %s\n", StmtTypeToString(stmt->type));
1152             ok = false;
1153             break;
1154         }
1155
1156         if (!ok)
1157             info->errorCount++;
1158
1159         if (info->errorCount > 10) {
1160             log_err(info->keymap->ctx,
1161                     "Abandoning compatibility map \"%s\"\n", file->topName);
1162             break;
1163         }
1164     }
1165 }
1166
1167 static void
1168 CopyInterps(CompatInfo *info, bool needSymbol, unsigned pred)
1169 {
1170     SymInterpInfo *si;
1171
1172     list_foreach(si, &info->interps, entry) {
1173         if (((si->interp.match & XkbSI_OpMask) != pred) ||
1174             (needSymbol && si->interp.sym == XKB_KEY_NoSymbol) ||
1175             (!needSymbol && si->interp.sym != XKB_KEY_NoSymbol))
1176             continue;
1177
1178         darray_append(info->keymap->sym_interpret, si->interp);
1179     }
1180 }
1181
1182 static void
1183 BindIndicators(CompatInfo *info, struct list *unbound_leds)
1184 {
1185     xkb_led_index_t i;
1186     LEDInfo *led, *next_led;
1187     struct xkb_indicator_map *map;
1188     struct xkb_keymap *keymap = info->keymap;
1189
1190     list_foreach(led, unbound_leds, entry) {
1191         if (led->indicator == XKB_LED_INVALID) {
1192             for (i = 0; i < XkbNumIndicators; i++) {
1193                 if (keymap->indicator_names[i] &&
1194                     streq(keymap->indicator_names[i],
1195                           xkb_atom_text(keymap->ctx, led->name))) {
1196                     led->indicator = i + 1;
1197                     break;
1198                 }
1199             }
1200         }
1201     }
1202
1203     list_foreach(led, unbound_leds, entry) {
1204         if (led->indicator == XKB_LED_INVALID) {
1205             for (i = 0; i < XkbNumIndicators; i++) {
1206                 if (keymap->indicator_names[i] == NULL) {
1207                     keymap->indicator_names[i] =
1208                         xkb_atom_text(keymap->ctx, led->name);
1209                     led->indicator = i + 1;
1210                     break;
1211                 }
1212             }
1213
1214             if (led->indicator == XKB_LED_INVALID) {
1215                 log_err(info->keymap->ctx,
1216                         "No unnamed indicators found; "
1217                         "Virtual indicator map \"%s\" not bound\n",
1218                         xkb_atom_text(keymap->ctx, led->name));
1219                 continue;
1220             }
1221         }
1222     }
1223
1224     list_foreach_safe(led, next_led, unbound_leds, entry) {
1225         if (led->indicator == XKB_LED_INVALID) {
1226             free(led);
1227             continue;
1228         }
1229
1230         if (!streq(keymap->indicator_names[led->indicator - 1],
1231                    xkb_atom_text(keymap->ctx, led->name))) {
1232             const char *old = keymap->indicator_names[led->indicator - 1];
1233             log_err(info->keymap->ctx,
1234                     "Multiple names bound to indicator %d; "
1235                     "Using %s, ignoring %s\n",
1236                     led->indicator, old,
1237                     xkb_atom_text(keymap->ctx, led->name));
1238             free(led);
1239             continue;
1240         }
1241
1242         map = &keymap->indicators[led->indicator - 1];
1243         map->flags = led->flags;
1244         map->which_groups = led->which_groups;
1245         map->groups = led->groups;
1246         map->which_mods = led->which_mods;
1247         map->mods.mods = led->mods;
1248         map->ctrls = led->ctrls;
1249         free(led);
1250     }
1251
1252     list_init(unbound_leds);
1253 }
1254
1255 static bool
1256 CopyIndicatorMapDefs(CompatInfo *info)
1257 {
1258     LEDInfo *led, *next_led;
1259     struct list unbound_leds;
1260     struct xkb_indicator_map *im;
1261     struct xkb_keymap *keymap = info->keymap;
1262
1263     list_init(&unbound_leds);
1264
1265     list_foreach_safe(led, next_led, &info->leds, entry) {
1266         if (led->groups != 0 && led->which_groups == 0)
1267             led->which_groups = XkbIM_UseEffective;
1268
1269         if (led->which_mods == 0 && led->mods)
1270             led->which_mods = XkbIM_UseEffective;
1271
1272         if (led->indicator == XKB_LED_INVALID) {
1273             list_append(&led->entry, &unbound_leds);
1274             continue;
1275         }
1276
1277         im = &keymap->indicators[led->indicator - 1];
1278         im->flags = led->flags;
1279         im->which_groups = led->which_groups;
1280         im->groups = led->groups;
1281         im->which_mods = led->which_mods;
1282         im->mods.mods = led->mods;
1283         im->ctrls = led->ctrls;
1284         keymap->indicator_names[led->indicator - 1] =
1285             xkb_atom_text(keymap->ctx, led->name);
1286         free(led);
1287     }
1288     list_init(&info->leds);
1289
1290     BindIndicators(info, &unbound_leds);
1291
1292     return true;
1293 }
1294
1295 bool
1296 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
1297                  enum merge_mode merge)
1298 {
1299     xkb_group_index_t i;
1300     CompatInfo info;
1301     GroupCompatInfo *gcm;
1302
1303     InitCompatInfo(&info, keymap, file->id);
1304     info.dflt.merge = merge;
1305     info.ledDflt.merge = merge;
1306
1307     HandleCompatMapFile(&info, file, merge);
1308
1309     if (info.errorCount != 0)
1310         goto err_info;
1311
1312     if (info.name)
1313         keymap->compat_section_name = strdup(info.name);
1314
1315     darray_init(keymap->sym_interpret);
1316     if (info.nInterps > 0) {
1317         darray_growalloc(keymap->sym_interpret, info.nInterps);
1318         CopyInterps(&info, true, XkbSI_Exactly);
1319         CopyInterps(&info, true, XkbSI_AllOf | XkbSI_NoneOf);
1320         CopyInterps(&info, true, XkbSI_AnyOf);
1321         CopyInterps(&info, true, XkbSI_AnyOfOrNone);
1322         CopyInterps(&info, false, XkbSI_Exactly);
1323         CopyInterps(&info, false, XkbSI_AllOf | XkbSI_NoneOf);
1324         CopyInterps(&info, false, XkbSI_AnyOf);
1325         CopyInterps(&info, false, XkbSI_AnyOfOrNone);
1326     }
1327
1328     for (i = 0; i < XkbNumKbdGroups; i++) {
1329         gcm = &info.groupCompat[i];
1330         if (gcm->file_id != 0 || gcm->mods != 0)
1331             keymap->groups[i].mods = gcm->mods;
1332     }
1333
1334     if (!CopyIndicatorMapDefs(&info))
1335         info.errorCount++;
1336
1337     ClearCompatInfo(&info);
1338     return true;
1339
1340 err_info:
1341     ClearCompatInfo(&info);
1342     return false;
1343 }
1344
1345 static void
1346 ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
1347 {
1348     xkb_mod_index_t i;
1349     xkb_mod_mask_t vmask = mods->mods >> XkbNumModifiers;
1350
1351     /* The effective mask is only real mods for now. */
1352     mods->mask = mods->mods & 0xff;
1353
1354     for (i = 0; i < XkbNumVirtualMods; i++) {
1355         if (!(vmask & (1 << i)))
1356             continue;
1357         mods->mask |= keymap->vmods[i];
1358     }
1359 }
1360
1361 static void
1362 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
1363                  xkb_mod_mask_t rmodmask)
1364 {
1365     unsigned int flags;
1366     struct xkb_mods *mods;
1367
1368     switch (act->type) {
1369     case XkbSA_SetMods:
1370     case XkbSA_LatchMods:
1371     case XkbSA_LockMods:
1372         flags = act->mods.flags;
1373         mods = &act->mods.mods;
1374         break;
1375
1376     case XkbSA_ISOLock:
1377         flags = act->iso.flags;
1378         mods = &act->iso.mods;
1379         break;
1380
1381     default:
1382         return;
1383     }
1384
1385     if (flags & XkbSA_UseModMapMods) {
1386         /* XXX: what's that. */
1387         mods->mods &= 0xff;
1388         mods->mods |= rmodmask;
1389     }
1390     ComputeEffectiveMask(keymap, mods);
1391 }
1392
1393 /**
1394  * Find an interpretation which applies to this particular level, either by
1395  * finding an exact match for the symbol and modifier combination, or a
1396  * generic XKB_KEY_NoSymbol match.
1397  */
1398 static struct xkb_sym_interpret *
1399 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
1400                  xkb_group_index_t group, xkb_level_index_t level)
1401 {
1402     struct xkb_sym_interpret *ret = NULL;
1403     struct xkb_sym_interpret *interp;
1404     const xkb_keysym_t *syms;
1405     int num_syms;
1406
1407     num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
1408     if (num_syms == 0)
1409         return NULL;
1410
1411     darray_foreach(interp, keymap->sym_interpret) {
1412         uint32_t mods;
1413         bool found;
1414
1415         if ((num_syms > 1 || interp->sym != syms[0]) &&
1416             interp->sym != XKB_KEY_NoSymbol)
1417             continue;
1418
1419         if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
1420             mods = key->modmap;
1421         else
1422             mods = 0;
1423
1424         switch (interp->match & XkbSI_OpMask) {
1425         case XkbSI_NoneOf:
1426             found = !(interp->mods & mods);
1427             break;
1428         case XkbSI_AnyOfOrNone:
1429             found = (!mods || (interp->mods & mods));
1430             break;
1431         case XkbSI_AnyOf:
1432             found = !!(interp->mods & mods);
1433             break;
1434         case XkbSI_AllOf:
1435             found = ((interp->mods & mods) == interp->mods);
1436             break;
1437         case XkbSI_Exactly:
1438             found = (interp->mods == mods);
1439             break;
1440         default:
1441             found = false;
1442             break;
1443         }
1444
1445         if (found && interp->sym != XKB_KEY_NoSymbol)
1446             return interp;
1447         else if (found && !ret)
1448             ret = interp;
1449     }
1450
1451     return ret;
1452 }
1453
1454 static bool
1455 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
1456 {
1457 #define INTERP_SIZE (8 * 4)
1458     struct xkb_sym_interpret *interps[INTERP_SIZE];
1459     xkb_mod_mask_t vmodmask = 0;
1460     int num_acts = 0;
1461     xkb_group_index_t group;
1462     xkb_level_index_t level;
1463     unsigned int i;
1464
1465     /* If we've been told not to bind interps to this key, then don't. */
1466     if (key->explicit & XkbExplicitInterpretMask)
1467         return true;
1468
1469     for (i = 0; i < INTERP_SIZE; i++)
1470         interps[i] = NULL;
1471
1472     for (group = 0; group < key->num_groups; group++) {
1473         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1474              level++) {
1475             i = (group * key->width) + level;
1476             if (i >= INTERP_SIZE) /* XXX FIXME */
1477                 return false;
1478             interps[i] = FindInterpForKey(keymap, key, group, level);
1479             if (interps[i])
1480                 num_acts++;
1481         }
1482     }
1483
1484     if (num_acts && !key->actions) {
1485         key->actions = calloc(key->num_groups * key->width,
1486                               sizeof(*key->actions));
1487         if (!key->actions)
1488             return false;
1489     }
1490
1491     for (group = 0; group < key->num_groups; group++) {
1492         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1493              level++) {
1494             struct xkb_sym_interpret *interp;
1495
1496             i = (group * key->width) + level;
1497             interp = interps[i];
1498
1499             /* Infer default key behaviours from the base level. */
1500             if (group == 0 && level == 0) {
1501                 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
1502                     (!interp || (interp->flags & XkbSI_AutoRepeat)))
1503                     key->repeats = true;
1504             }
1505
1506             if (!interp)
1507                 continue;
1508
1509             if ((group == 0 && level == 0) ||
1510                 !(interp->match & XkbSI_LevelOneOnly)) {
1511                 if (interp->virtual_mod != XkbNoModifier)
1512                     vmodmask |= (1 << interp->virtual_mod);
1513             }
1514
1515             key->actions[i] = interp->act;
1516         }
1517     }
1518
1519     if (!(key->explicit & XkbExplicitVModMapMask))
1520         key->vmodmap = vmodmask;
1521
1522     return true;
1523 #undef INTERP_SIZE
1524 }
1525
1526 /**
1527  * This collects a bunch of disparate functions which was done in the server
1528  * at various points that really should've been done within xkbcomp.  Turns out
1529  * your actions and types are a lot more useful when any of your modifiers
1530  * other than Shift actually do something ...
1531  */
1532 bool
1533 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
1534 {
1535     xkb_mod_index_t vmod;
1536     xkb_group_index_t grp;
1537     xkb_led_index_t led;
1538     unsigned int i, j;
1539     struct xkb_key *key;
1540
1541     /* Find all the interprets for the key and bind them to actions,
1542      * which will also update the vmodmap. */
1543     xkb_foreach_key(key, keymap)
1544         if (!ApplyInterpsToKey(keymap, key))
1545             return false;
1546
1547     /* Update keymap->vmods, the virtual -> real mod mapping. */
1548     for (vmod = 0; vmod < XkbNumVirtualMods; vmod++)
1549         keymap->vmods[vmod] = 0;
1550
1551     xkb_foreach_key(key, keymap) {
1552         if (!key->vmodmap)
1553             continue;
1554
1555         for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) {
1556             if (!(key->vmodmap & (1 << vmod)))
1557                 continue;
1558             keymap->vmods[vmod] |= key->modmap;
1559         }
1560     }
1561
1562     /* Now update the level masks for all the types to reflect the vmods. */
1563     for (i = 0; i < keymap->num_types; i++) {
1564         ComputeEffectiveMask(keymap, &keymap->types[i].mods);
1565
1566         for (j = 0; j < keymap->types[i].num_entries; j++) {
1567             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].mods);
1568             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].preserve);
1569         }
1570     }
1571
1572     /* Update action modifiers. */
1573     xkb_foreach_key(key, keymap) {
1574         if (!key->actions)
1575             continue;
1576
1577         for (i = 0; i < key->num_groups * key->width; i++)
1578             UpdateActionMods(keymap, &key->actions[i], key->modmap);
1579     }
1580
1581     /* Update group modifiers. */
1582     for (grp = 0; grp < XkbNumKbdGroups; grp++)
1583         ComputeEffectiveMask(keymap, &keymap->groups[grp]);
1584
1585     /* Update vmod -> indicator maps. */
1586     for (led = 0; led < XkbNumIndicators; led++)
1587         ComputeEffectiveMask(keymap, &keymap->indicators[led].mods);
1588
1589     return true;
1590 }