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