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