xkbcomp: use new log functions
[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     unsigned short 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                  XkbcKeysymText(si->interp.sym),
108                  XkbcSIMatchText(si->interp.match),
109                  XkbcModMaskText(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                          unsigned *mods_rtrn, CompatInfo * info)
370 {
371     ExprResult result;
372
373     if (expr == NULL) {
374         *pred_rtrn = XkbSI_AnyOfOrNone;
375         *mods_rtrn = ~0;
376         return true;
377     }
378
379     *pred_rtrn = XkbSI_Exactly;
380     if (expr->op == ExprActionDecl) {
381         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
382                                              expr->value.action.name);
383         if (strcasecmp(pred_txt, "noneof") == 0)
384             *pred_rtrn = XkbSI_NoneOf;
385         else if (strcasecmp(pred_txt, "anyofornone") == 0)
386             *pred_rtrn = XkbSI_AnyOfOrNone;
387         else if (strcasecmp(pred_txt, "anyof") == 0)
388             *pred_rtrn = XkbSI_AnyOf;
389         else if (strcasecmp(pred_txt, "allof") == 0)
390             *pred_rtrn = XkbSI_AllOf;
391         else if (strcasecmp(pred_txt, "exactly") == 0)
392             *pred_rtrn = XkbSI_Exactly;
393         else {
394             log_err(info->keymap->ctx,
395                     "Illegal modifier predicate \"%s\"; Ignored\n", pred_txt);
396             return false;
397         }
398         expr = expr->value.action.args;
399     }
400     else if (expr->op == ExprIdent) {
401         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
402                                              expr->value.str);
403         if ((pred_txt) && (strcasecmp(pred_txt, "any") == 0)) {
404             *pred_rtrn = XkbSI_AnyOf;
405             *mods_rtrn = 0xff;
406             return true;
407         }
408     }
409
410     if (ExprResolveModMask(info->keymap->ctx, expr, &result)) {
411         *mods_rtrn = result.uval;
412         return true;
413     }
414     return false;
415 }
416
417 /***====================================================================***/
418
419 static bool
420 UseNewLEDField(unsigned field, LEDInfo *old, LEDInfo *new,
421                int verbosity, unsigned *collide)
422 {
423     if (!(old->defined & field))
424         return true;
425
426     if (new->defined & field) {
427         if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
428             *collide |= field;
429
430         if (new->merge != MERGE_AUGMENT)
431             return true;
432     }
433
434     return false;
435 }
436
437 static bool
438 AddIndicatorMap(CompatInfo *info, LEDInfo *new)
439 {
440     LEDInfo *old;
441     unsigned collide;
442     struct xkb_context *ctx = info->keymap->ctx;
443     int verbosity = xkb_get_log_verbosity(ctx);
444
445     list_foreach(old, &info->leds, entry) {
446         if (old->name == new->name) {
447             if ((old->real_mods == new->real_mods) &&
448                 (old->vmods == new->vmods) &&
449                 (old->groups == new->groups) &&
450                 (old->ctrls == new->ctrls) &&
451                 (old->which_mods == new->which_mods) &&
452                 (old->which_groups == new->which_groups)) {
453                 old->defined |= new->defined;
454                 return true;
455             }
456
457             if (new->merge == MERGE_REPLACE) {
458                 struct list entry = old->entry;
459                 if ((old->file_id == new->file_id && verbosity > 0) ||
460                     verbosity > 9)
461                     log_warn(info->keymap->ctx,
462                              "Map for indicator %s redefined; "
463                              "Earlier definition ignored\n",
464                              xkb_atom_text(ctx, old->name));
465                 *old = *new;
466                 old->entry = entry;
467                 return true;
468             }
469
470             collide = 0;
471             if (UseNewLEDField(_LED_Index, old, new, verbosity,
472                                &collide)) {
473                 old->indicator = new->indicator;
474                 old->defined |= _LED_Index;
475             }
476             if (UseNewLEDField(_LED_Mods, old, new, verbosity,
477                                &collide)) {
478                 old->which_mods = new->which_mods;
479                 old->real_mods = new->real_mods;
480                 old->vmods = new->vmods;
481                 old->defined |= _LED_Mods;
482             }
483             if (UseNewLEDField(_LED_Groups, old, new, verbosity,
484                                &collide)) {
485                 old->which_groups = new->which_groups;
486                 old->groups = new->groups;
487                 old->defined |= _LED_Groups;
488             }
489             if (UseNewLEDField(_LED_Ctrls, old, new, verbosity,
490                                &collide)) {
491                 old->ctrls = new->ctrls;
492                 old->defined |= _LED_Ctrls;
493             }
494             if (UseNewLEDField(_LED_Explicit, old, new, verbosity,
495                                &collide)) {
496                 old->flags &= ~XkbIM_NoExplicit;
497                 old->flags |= (new->flags & XkbIM_NoExplicit);
498                 old->defined |= _LED_Explicit;
499             }
500             if (UseNewLEDField(_LED_Automatic, old, new, verbosity,
501                                &collide)) {
502                 old->flags &= ~XkbIM_NoAutomatic;
503                 old->flags |= (new->flags & XkbIM_NoAutomatic);
504                 old->defined |= _LED_Automatic;
505             }
506             if (UseNewLEDField(_LED_DrivesKbd, old, new, verbosity,
507                                &collide)) {
508                 old->flags &= ~XkbIM_LEDDrivesKB;
509                 old->flags |= (new->flags & XkbIM_LEDDrivesKB);
510                 old->defined |= _LED_DrivesKbd;
511             }
512
513             if (collide) {
514                 log_warn(info->keymap->ctx,
515                          "Map for indicator %s redefined; "
516                          "Using %s definition for duplicate fields\n",
517                          xkb_atom_text(ctx, old->name),
518                          (new->merge == MERGE_AUGMENT ? "first" : "last"));
519             }
520
521             return true;
522         }
523     }
524
525     /* new definition */
526     old = malloc(sizeof(*old));
527     if (!old) {
528         log_wsgo(info->keymap->ctx,
529                  "Couldn't allocate indicator map; "
530                  "Map for indicator %s not compiled\n",
531                  xkb_atom_text(ctx, new->name));
532         return false;
533     }
534
535     *old = *new;
536     list_append(&old->entry, &info->leds);
537
538     return true;
539 }
540
541 static void
542 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from,
543                         enum merge_mode merge)
544 {
545     SymInterpInfo *si;
546     LEDInfo *led, *next_led;
547     GroupCompatInfo *gcm;
548     xkb_group_index_t i;
549
550     if (from->errorCount > 0) {
551         into->errorCount += from->errorCount;
552         return;
553     }
554     if (into->name == NULL) {
555         into->name = from->name;
556         from->name = NULL;
557     }
558
559     list_foreach(si, &from->interps, entry) {
560         if (merge != MERGE_DEFAULT)
561             si->merge = merge;
562         if (!AddInterp(into, si))
563             into->errorCount++;
564     }
565
566     for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups;
567          i++, gcm++) {
568         if (merge != MERGE_DEFAULT)
569             gcm->merge = merge;
570         if (!AddGroupCompat(into, i, gcm))
571             into->errorCount++;
572     }
573
574     list_foreach_safe(led, next_led, &from->leds, entry) {
575         led->merge = (merge == MERGE_DEFAULT ? led->merge : merge);
576         if (!AddIndicatorMap(into, led))
577             into->errorCount++;
578     }
579 }
580
581 static void
582 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge);
583
584 static bool
585 HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *stmt)
586 {
587     enum merge_mode merge = MERGE_DEFAULT;
588     XkbFile *rtrn;
589     CompatInfo included, next_incl;
590
591     InitCompatInfo(&included, info->keymap, info->file_id);
592     if (stmt->stmt) {
593         free(included.name);
594         included.name = stmt->stmt;
595         stmt->stmt = NULL;
596     }
597
598     for (; stmt; stmt = stmt->next) {
599         if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_COMPAT,
600                                 &rtrn, &merge)) {
601             info->errorCount += 10;
602             ClearCompatInfo(&included);
603             return false;
604         }
605
606         InitCompatInfo(&next_incl, info->keymap, rtrn->id);
607         next_incl.file_id = rtrn->id;
608         next_incl.dflt = info->dflt;
609         next_incl.dflt.file_id = rtrn->id;
610         next_incl.dflt.merge = merge;
611         next_incl.ledDflt.file_id = rtrn->id;
612         next_incl.ledDflt.merge = merge;
613         next_incl.act = info->act;
614
615         HandleCompatMapFile(&next_incl, rtrn, MERGE_OVERRIDE);
616
617         MergeIncludedCompatMaps(&included, &next_incl, merge);
618         if (info->act)
619             next_incl.act = NULL;
620
621         ClearCompatInfo(&next_incl);
622         FreeXKBFile(rtrn);
623     }
624
625     MergeIncludedCompatMaps(info, &included, merge);
626     ClearCompatInfo(&included);
627
628     return (info->errorCount == 0);
629 }
630
631 static const LookupEntry useModMapValues[] = {
632     { "levelone", 1 },
633     { "level1", 1 },
634     { "anylevel", 0 },
635     { "any", 0 },
636     { NULL, 0 }
637 };
638
639 static int
640 SetInterpField(CompatInfo *info, SymInterpInfo *si, char *field,
641                ExprDef *arrayNdx, ExprDef *value)
642 {
643     int ok = 1;
644     ExprResult tmp;
645     struct xkb_keymap *keymap = info->keymap;
646
647     if (strcasecmp(field, "action") == 0) {
648         if (arrayNdx != NULL)
649             return ReportSINotArray(info, si, field);
650         ok = HandleActionDef(value, keymap, &si->interp.act.any,
651                              info->act);
652         if (ok)
653             si->defined |= _SI_Action;
654     }
655     else if ((strcasecmp(field, "virtualmodifier") == 0) ||
656              (strcasecmp(field, "virtualmod") == 0)) {
657         if (arrayNdx != NULL)
658             return ReportSINotArray(info, si, field);
659         ok = ResolveVirtualModifier(value, keymap, &tmp, &info->vmods);
660         if (ok) {
661             si->interp.virtual_mod = tmp.uval;
662             si->defined |= _SI_VirtualMod;
663         }
664         else
665             return ReportSIBadType(info, si, field, "virtual modifier");
666     }
667     else if (strcasecmp(field, "repeat") == 0) {
668         if (arrayNdx != NULL)
669             return ReportSINotArray(info, si, field);
670         ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
671         if (ok) {
672             if (tmp.uval)
673                 si->interp.flags |= XkbSI_AutoRepeat;
674             else
675                 si->interp.flags &= ~XkbSI_AutoRepeat;
676             si->defined |= _SI_AutoRepeat;
677         }
678         else
679             return ReportSIBadType(info, si, field, "boolean");
680     }
681     else if (strcasecmp(field, "locking") == 0) {
682         if (arrayNdx != NULL)
683             return ReportSINotArray(info, si, field);
684         ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
685         if (ok) {
686             if (tmp.uval)
687                 si->interp.flags |= XkbSI_LockingKey;
688             else
689                 si->interp.flags &= ~XkbSI_LockingKey;
690             si->defined |= _SI_LockingKey;
691         }
692         else
693             return ReportSIBadType(info, si, field, "boolean");
694     }
695     else if ((strcasecmp(field, "usemodmap") == 0) ||
696              (strcasecmp(field, "usemodmapmods") == 0)) {
697         if (arrayNdx != NULL)
698             return ReportSINotArray(info, si, field);
699         ok = ExprResolveEnum(keymap->ctx, value, &tmp, useModMapValues);
700         if (ok) {
701             if (tmp.uval)
702                 si->interp.match |= XkbSI_LevelOneOnly;
703             else
704                 si->interp.match &= ~XkbSI_LevelOneOnly;
705             si->defined |= _SI_LevelOneOnly;
706         }
707         else
708             return ReportSIBadType(info, si, field, "level specification");
709     }
710     else {
711         ok = ReportBadField(keymap, "symbol interpretation", field,
712                             siText(si, info));
713     }
714     return ok;
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                      char *field, ExprDef *arrayNdx, ExprDef *value)
754 {
755     ExprResult rtrn;
756     bool ok = true;
757     struct xkb_keymap *keymap = info->keymap;
758
759     if (strcasecmp(field, "modifiers") == 0 || strcasecmp(field, "mods") == 0) {
760         if (arrayNdx != NULL)
761             return ReportIndicatorNotArray(info, led, field);
762
763         if (!ExprResolveVModMask(keymap, value, &rtrn))
764             return ReportIndicatorBadType(info, led, field, "modifier mask");
765
766         led->real_mods = rtrn.uval & 0xff;
767         led->vmods = (rtrn.uval >> 8) & 0xff;
768         led->defined |= _LED_Mods;
769     }
770     else if (strcasecmp(field, "groups") == 0) {
771         if (arrayNdx != NULL)
772             return ReportIndicatorNotArray(info, led, field);
773
774         if (!ExprResolveMask(keymap->ctx, value, &rtrn, groupNames))
775             return ReportIndicatorBadType(info, led, field, "group mask");
776
777         led->groups = rtrn.uval;
778         led->defined |= _LED_Groups;
779     }
780     else if (strcasecmp(field, "controls") == 0 ||
781              strcasecmp(field, "ctrls") == 0) {
782         if (arrayNdx != NULL)
783             return ReportIndicatorNotArray(info, led, field);
784
785         if (!ExprResolveMask(keymap->ctx, value, &rtrn, ctrlNames))
786             return ReportIndicatorBadType(info, led, field,
787                                           "controls mask");
788
789         led->ctrls = rtrn.uval;
790         led->defined |= _LED_Ctrls;
791     }
792     else if (strcasecmp(field, "allowexplicit") == 0) {
793         if (arrayNdx != NULL)
794             return ReportIndicatorNotArray(info, led, field);
795
796         if (!ExprResolveBoolean(keymap->ctx, value, &rtrn))
797             return ReportIndicatorBadType(info, led, field, "boolean");
798
799         if (rtrn.uval)
800             led->flags &= ~XkbIM_NoExplicit;
801         else
802             led->flags |= XkbIM_NoExplicit;
803         led->defined |= _LED_Explicit;
804     }
805     else if (strcasecmp(field, "whichmodstate") == 0 ||
806              strcasecmp(field, "whichmodifierstate") == 0) {
807         if (arrayNdx != NULL)
808             return ReportIndicatorNotArray(info, led, field);
809
810         if (!ExprResolveMask(keymap->ctx, value, &rtrn, modComponentNames))
811             return ReportIndicatorBadType(info, led, field,
812                                           "mask of modifier state components");
813
814         led->which_mods = rtrn.uval;
815     }
816     else if (strcasecmp(field, "whichgroupstate") == 0) {
817         if (arrayNdx != NULL)
818             return ReportIndicatorNotArray(info, led, field);
819
820         if (!ExprResolveMask(keymap->ctx, value, &rtrn, groupComponentNames))
821             return ReportIndicatorBadType(info, led, field,
822                                           "mask of group state components");
823
824         led->which_groups = rtrn.uval;
825     }
826     else if (strcasecmp(field, "driveskbd") == 0 ||
827              strcasecmp(field, "driveskeyboard") == 0 ||
828              strcasecmp(field, "leddriveskbd") == 0 ||
829              strcasecmp(field, "leddriveskeyboard") == 0 ||
830              strcasecmp(field, "indicatordriveskbd") == 0 ||
831              strcasecmp(field, "indicatordriveskeyboard") == 0) {
832         if (arrayNdx != NULL)
833             return ReportIndicatorNotArray(info, led, field);
834
835         if (!ExprResolveBoolean(keymap->ctx, value, &rtrn))
836             return ReportIndicatorBadType(info, led, field, "boolean");
837
838         if (rtrn.uval)
839             led->flags |= XkbIM_LEDDrivesKB;
840         else
841             led->flags &= ~XkbIM_LEDDrivesKB;
842         led->defined |= _LED_DrivesKbd;
843     }
844     else if (strcasecmp(field, "index") == 0) {
845         if (arrayNdx != NULL)
846             return ReportIndicatorNotArray(info, led, field);
847
848         if (!ExprResolveInteger(keymap->ctx, value, &rtrn))
849             return ReportIndicatorBadType(info, led, field,
850                                           "indicator index");
851
852         if (rtrn.uval < 1 || rtrn.uval > 32) {
853             log_err(info->keymap->ctx,
854                     "Illegal indicator index %d (range 1..%d); "
855                     "Index definition for %s indicator ignored\n",
856                     rtrn.uval, XkbNumIndicators,
857                     xkb_atom_text(keymap->ctx, led->name));
858             return false;
859         }
860
861         led->indicator = rtrn.uval;
862         led->defined |= _LED_Index;
863     }
864     else {
865         log_err(info->keymap->ctx,
866                 "Unknown field %s in map for %s indicator; "
867                 "Definition ignored\n",
868                 field, xkb_atom_text(keymap->ctx, led->name));
869         ok = false;
870     }
871
872     return ok;
873 }
874
875 static int
876 HandleInterpVar(CompatInfo *info, VarDef *stmt)
877 {
878     ExprResult elem, field;
879     ExprDef *ndx;
880     int ret;
881
882     if (ExprResolveLhs(info->keymap, stmt->name, &elem, &field, &ndx) == 0)
883         ret = 0;               /* internal error, already reported */
884     else if (elem.str && (strcasecmp(elem.str, "interpret") == 0))
885         ret = SetInterpField(info, &info->dflt, field.str, ndx, stmt->value);
886     else if (elem.str && (strcasecmp(elem.str, "indicator") == 0))
887         ret = SetIndicatorMapField(info, &info->ledDflt, field.str, ndx,
888                                    stmt->value);
889     else
890         ret = SetActionField(info->keymap, elem.str, field.str, ndx,
891                              stmt->value, &info->act);
892     free(elem.str);
893     free(field.str);
894     return ret;
895 }
896
897 static int
898 HandleInterpBody(CompatInfo *info, VarDef *def, SymInterpInfo *si)
899 {
900     int ok = 1;
901     ExprResult tmp, field;
902     ExprDef *arrayNdx;
903
904     for (; def != NULL; def = (VarDef *) def->common.next) {
905         if ((def->name) && (def->name->type == ExprFieldRef)) {
906             ok = HandleInterpVar(info, def);
907             continue;
908         }
909         ok = ExprResolveLhs(info->keymap, def->name, &tmp, &field, &arrayNdx);
910         if (ok) {
911             ok = SetInterpField(info, si, field.str, arrayNdx, def->value);
912             free(field.str);
913         }
914     }
915     return ok;
916 }
917
918 static int
919 HandleInterpDef(CompatInfo *info, InterpDef *def, enum merge_mode merge)
920 {
921     unsigned pred, mods;
922     SymInterpInfo si;
923
924     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
925         log_err(info->keymap->ctx,
926                 "Couldn't determine matching modifiers; "
927                 "Symbol interpretation ignored\n");
928         return false;
929     }
930     if (def->merge != MERGE_DEFAULT)
931         merge = def->merge;
932
933     si = info->dflt;
934     si.merge = merge;
935     if (!LookupKeysym(def->sym, &si.interp.sym)) {
936         log_err(info->keymap->ctx,
937                 "Could not resolve keysym %s; "
938                 "Symbol interpretation ignored\n",
939                 def->sym);
940         return false;
941     }
942     si.interp.match = pred & XkbSI_OpMask;
943     si.interp.mods = mods;
944     if (!HandleInterpBody(info, def->def, &si)) {
945         info->errorCount++;
946         return false;
947     }
948
949     if (!AddInterp(info, &si)) {
950         info->errorCount++;
951         return false;
952     }
953     return true;
954 }
955
956 static int
957 HandleGroupCompatDef(CompatInfo *info, GroupCompatDef *def,
958                      enum merge_mode merge)
959 {
960     ExprResult val;
961     GroupCompatInfo tmp;
962
963     if (def->merge != MERGE_DEFAULT)
964         merge = def->merge;
965     if (def->group < 1 || def->group > XkbNumKbdGroups) {
966         log_err(info->keymap->ctx,
967                 "Keyboard group must be in the range 1..%u; "
968                 "Compatibility map for illegal group %u ignored\n",
969                 XkbNumKbdGroups, def->group);
970         return false;
971     }
972     tmp.file_id = info->file_id;
973     tmp.merge = merge;
974     if (!ExprResolveVModMask(info->keymap, def->def, &val)) {
975         log_err(info->keymap->ctx,
976                 "Expected a modifier mask in group compatibility definition; "
977                 "Ignoring illegal compatibility map for group %u\n",
978                 def->group);
979         return false;
980     }
981     tmp.real_mods = val.uval & 0xff;
982     tmp.vmods = (val.uval >> 8) & 0xffff;
983     tmp.defined = true;
984     return AddGroupCompat(info, def->group - 1, &tmp);
985 }
986
987 static bool
988 HandleIndicatorMapDef(CompatInfo *info, IndicatorMapDef *def,
989                       enum merge_mode merge)
990 {
991     LEDInfo led;
992     VarDef *var;
993     bool ok;
994
995     if (def->merge != MERGE_DEFAULT)
996         merge = def->merge;
997
998     led = info->ledDflt;
999     led.merge = merge;
1000     led.name = def->name;
1001
1002     ok = true;
1003     for (var = def->body; var != NULL; var = (VarDef *) var->common.next) {
1004         ExprResult elem, field;
1005         ExprDef *arrayNdx;
1006         if (!ExprResolveLhs(info->keymap, var->name, &elem, &field,
1007                             &arrayNdx)) {
1008             ok = false;
1009             continue;
1010         }
1011
1012         if (elem.str != NULL) {
1013             log_err(info->keymap->ctx,
1014                     "Cannot set defaults for \"%s\" element in indicator map; "
1015                     "Assignment to %s.%s ignored\n",
1016                     elem.str, elem.str, field.str);
1017             ok = false;
1018         }
1019         else {
1020             ok = SetIndicatorMapField(info, &led, field.str, arrayNdx,
1021                                       var->value) && ok;
1022         }
1023         free(elem.str);
1024         free(field.str);
1025     }
1026
1027     if (ok)
1028         return AddIndicatorMap(info, &led);
1029
1030     return false;
1031 }
1032
1033 static void
1034 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
1035 {
1036     ParseCommon *stmt;
1037
1038     if (merge == MERGE_DEFAULT)
1039         merge = MERGE_AUGMENT;
1040     free(info->name);
1041     info->name = uDupString(file->name);
1042     stmt = file->defs;
1043     while (stmt)
1044     {
1045         switch (stmt->stmtType) {
1046         case StmtInclude:
1047             if (!HandleIncludeCompatMap(info, (IncludeStmt *) stmt))
1048                 info->errorCount++;
1049             break;
1050         case StmtInterpDef:
1051             if (!HandleInterpDef(info, (InterpDef *) stmt, merge))
1052                 info->errorCount++;
1053             break;
1054         case StmtGroupCompatDef:
1055             if (!HandleGroupCompatDef(info, (GroupCompatDef *) stmt, merge))
1056                 info->errorCount++;
1057             break;
1058         case StmtIndicatorMapDef:
1059             if (!HandleIndicatorMapDef(info, (IndicatorMapDef *) stmt, merge))
1060                 info->errorCount++;
1061             break;
1062         case StmtVarDef:
1063             if (!HandleInterpVar(info, (VarDef *) stmt))
1064                 info->errorCount++;
1065             break;
1066         case StmtVModDef:
1067             if (!HandleVModDef((VModDef *) stmt, info->keymap, merge,
1068                                &info->vmods))
1069                 info->errorCount++;
1070             break;
1071         case StmtKeycodeDef:
1072             log_err(info->keymap->ctx,
1073                     "Interpretation files may not include other types; "
1074                     "Ignoring definition of key name\n");
1075             info->errorCount++;
1076             break;
1077         default:
1078             log_wsgo(info->keymap->ctx,
1079                      "Unexpected statement type %d in HandleCompatMapFile\n",
1080                      stmt->stmtType);
1081             break;
1082         }
1083         stmt = stmt->next;
1084         if (info->errorCount > 10) {
1085             log_err(info->keymap->ctx,
1086                     "Abandoning compatibility map \"%s\"\n", file->topName);
1087             break;
1088         }
1089     }
1090 }
1091
1092 static void
1093 CopyInterps(CompatInfo *info, bool needSymbol, unsigned pred)
1094 {
1095     SymInterpInfo *si;
1096
1097     list_foreach(si, &info->interps, entry) {
1098         if (((si->interp.match & XkbSI_OpMask) != pred) ||
1099             (needSymbol && si->interp.sym == XKB_KEY_NoSymbol) ||
1100             (!needSymbol && si->interp.sym != XKB_KEY_NoSymbol))
1101             continue;
1102
1103         darray_append(info->keymap->sym_interpret, si->interp);
1104     }
1105 }
1106
1107 static void
1108 BindIndicators(CompatInfo *info, struct list *unbound_leds)
1109 {
1110     int i;
1111     LEDInfo *led, *next_led;
1112     struct xkb_indicator_map *map;
1113     struct xkb_keymap *keymap = info->keymap;
1114
1115     list_foreach(led, unbound_leds, entry) {
1116         if (led->indicator == _LED_NotBound) {
1117             for (i = 0; i < XkbNumIndicators; i++) {
1118                 if (keymap->indicator_names[i] &&
1119                     strcmp(keymap->indicator_names[i],
1120                            xkb_atom_text(keymap->ctx, led->name)) == 0) {
1121                     led->indicator = i + 1;
1122                     break;
1123                 }
1124             }
1125         }
1126     }
1127
1128     list_foreach(led, unbound_leds, entry) {
1129         if (led->indicator == _LED_NotBound) {
1130             for (i = 0; i < XkbNumIndicators; i++) {
1131                 if (keymap->indicator_names[i] == NULL) {
1132                     keymap->indicator_names[i] =
1133                         xkb_atom_strdup(keymap->ctx, led->name);
1134                     led->indicator = i + 1;
1135                     break;
1136                 }
1137             }
1138
1139             if (led->indicator == _LED_NotBound) {
1140                 log_err(info->keymap->ctx,
1141                         "No unnamed indicators found; "
1142                         "Virtual indicator map \"%s\" not bound\n",
1143                         xkb_atom_text(keymap->ctx, led->name));
1144                 continue;
1145             }
1146         }
1147     }
1148
1149     list_foreach_safe(led, next_led, unbound_leds, entry) {
1150         if (led->indicator == _LED_NotBound) {
1151             free(led);
1152             continue;
1153         }
1154
1155         if (strcmp(keymap->indicator_names[led->indicator - 1],
1156                    xkb_atom_text(keymap->ctx, led->name)) != 0) {
1157             const char *old = keymap->indicator_names[led->indicator - 1];
1158             log_err(info->keymap->ctx,
1159                     "Multiple names bound to indicator %d; "
1160                     "Using %s, ignoring %s\n",
1161                     led->indicator, old,
1162                     xkb_atom_text(keymap->ctx, led->name));
1163             free(led);
1164             continue;
1165         }
1166
1167         map = &keymap->indicators[led->indicator - 1];
1168         map->flags = led->flags;
1169         map->which_groups = led->which_groups;
1170         map->groups = led->groups;
1171         map->which_mods = led->which_mods;
1172         map->mods.mask = led->real_mods;
1173         map->mods.real_mods = led->real_mods;
1174         map->mods.vmods = led->vmods;
1175         map->ctrls = led->ctrls;
1176         free(led);
1177     }
1178
1179     list_init(unbound_leds);
1180 }
1181
1182 static bool
1183 CopyIndicatorMapDefs(CompatInfo *info)
1184 {
1185     LEDInfo *led, *next_led;
1186     struct list unbound_leds;
1187     struct xkb_indicator_map *im;
1188     struct xkb_keymap *keymap = info->keymap;
1189
1190     list_init(&unbound_leds);
1191
1192     list_foreach_safe(led, next_led, &info->leds, entry) {
1193         if (led->groups != 0 && led->which_groups == 0)
1194             led->which_groups = XkbIM_UseEffective;
1195
1196         if (led->which_mods == 0 && (led->real_mods || led->vmods))
1197             led->which_mods = XkbIM_UseEffective;
1198
1199         if (led->indicator == _LED_NotBound) {
1200             list_append(&led->entry, &unbound_leds);
1201             continue;
1202         }
1203
1204         im = &keymap->indicators[led->indicator - 1];
1205         im->flags = led->flags;
1206         im->which_groups = led->which_groups;
1207         im->groups = led->groups;
1208         im->which_mods = led->which_mods;
1209         im->mods.mask = led->real_mods;
1210         im->mods.real_mods = led->real_mods;
1211         im->mods.vmods = led->vmods;
1212         im->ctrls = led->ctrls;
1213         free(keymap->indicator_names[led->indicator - 1]);
1214         keymap->indicator_names[led->indicator - 1] =
1215             xkb_atom_strdup(keymap->ctx, led->name);
1216         free(led);
1217     }
1218     list_init(&info->leds);
1219
1220     BindIndicators(info, &unbound_leds);
1221
1222     return true;
1223 }
1224
1225 bool
1226 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
1227                  enum merge_mode merge)
1228 {
1229     xkb_group_index_t i;
1230     CompatInfo info;
1231     GroupCompatInfo *gcm;
1232
1233     InitCompatInfo(&info, keymap, file->id);
1234     info.dflt.merge = merge;
1235     info.ledDflt.merge = merge;
1236
1237     HandleCompatMapFile(&info, file, merge);
1238
1239     if (info.errorCount != 0)
1240         goto err_info;
1241
1242     darray_init(keymap->sym_interpret);
1243     darray_growalloc(keymap->sym_interpret, info.nInterps);
1244
1245     if (info.name)
1246         keymap->compat_section_name = strdup(info.name);
1247
1248     if (info.nInterps > 0) {
1249         CopyInterps(&info, true, XkbSI_Exactly);
1250         CopyInterps(&info, true, XkbSI_AllOf | XkbSI_NoneOf);
1251         CopyInterps(&info, true, XkbSI_AnyOf);
1252         CopyInterps(&info, true, XkbSI_AnyOfOrNone);
1253         CopyInterps(&info, false, XkbSI_Exactly);
1254         CopyInterps(&info, false, XkbSI_AllOf | XkbSI_NoneOf);
1255         CopyInterps(&info, false, XkbSI_AnyOf);
1256         CopyInterps(&info, false, XkbSI_AnyOfOrNone);
1257     }
1258
1259     for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
1260          i++, gcm++) {
1261         if (gcm->file_id != 0 || gcm->real_mods != 0 || gcm->vmods != 0) {
1262             keymap->groups[i].mask = gcm->real_mods;
1263             keymap->groups[i].real_mods = gcm->real_mods;
1264             keymap->groups[i].vmods = gcm->vmods;
1265         }
1266     }
1267
1268     if (!CopyIndicatorMapDefs(&info))
1269         info.errorCount++;
1270
1271     ClearCompatInfo(&info);
1272     return true;
1273
1274 err_info:
1275     ClearCompatInfo(&info);
1276     return false;
1277 }
1278
1279 uint32_t
1280 VModsToReal(struct xkb_keymap *keymap, uint32_t vmodmask)
1281 {
1282     uint32_t ret = 0;
1283     int i;
1284
1285     if (!vmodmask)
1286         return 0;
1287
1288     for (i = 0; i < XkbNumVirtualMods; i++) {
1289         if (!(vmodmask & (1 << i)))
1290             continue;
1291         ret |= keymap->vmods[i];
1292     }
1293
1294     return ret;
1295 }
1296
1297 static void
1298 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
1299                  uint32_t rmodmask)
1300 {
1301     switch (act->type) {
1302     case XkbSA_SetMods:
1303     case XkbSA_LatchMods:
1304     case XkbSA_LockMods:
1305         if (act->mods.flags & XkbSA_UseModMapMods)
1306             act->mods.real_mods = rmodmask;
1307         act->mods.mask = act->mods.real_mods;
1308         act->mods.mask |= VModsToReal(keymap, act->mods.vmods);
1309         break;
1310
1311     case XkbSA_ISOLock:
1312         if (act->iso.flags & XkbSA_UseModMapMods)
1313             act->iso.real_mods = rmodmask;
1314         act->iso.mask = act->iso.real_mods;
1315         act->iso.mask |= VModsToReal(keymap, act->iso.vmods);
1316         break;
1317
1318     default:
1319         break;
1320     }
1321 }
1322
1323 /**
1324  * Find an interpretation which applies to this particular level, either by
1325  * finding an exact match for the symbol and modifier combination, or a
1326  * generic XKB_KEY_NoSymbol match.
1327  */
1328 static struct xkb_sym_interpret *
1329 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
1330                  xkb_group_index_t group, uint32_t level)
1331 {
1332     struct xkb_sym_interpret *ret = NULL;
1333     struct xkb_sym_interpret *interp;
1334     const xkb_keysym_t *syms;
1335     int num_syms;
1336
1337     num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
1338     if (num_syms == 0)
1339         return NULL;
1340
1341     darray_foreach(interp, keymap->sym_interpret) {
1342         uint32_t mods;
1343         bool found;
1344
1345         if ((num_syms > 1 || interp->sym != syms[0]) &&
1346             interp->sym != XKB_KEY_NoSymbol)
1347             continue;
1348
1349         if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
1350             mods = key->modmap;
1351         else
1352             mods = 0;
1353
1354         switch (interp->match & XkbSI_OpMask) {
1355         case XkbSI_NoneOf:
1356             found = !(interp->mods & mods);
1357             break;
1358         case XkbSI_AnyOfOrNone:
1359             found = (!mods || (interp->mods & mods));
1360             break;
1361         case XkbSI_AnyOf:
1362             found = !!(interp->mods & mods);
1363             break;
1364         case XkbSI_AllOf:
1365             found = ((interp->mods & mods) == interp->mods);
1366             break;
1367         case XkbSI_Exactly:
1368             found = (interp->mods == mods);
1369             break;
1370         default:
1371             found = false;
1372             break;
1373         }
1374
1375         if (found && interp->sym != XKB_KEY_NoSymbol)
1376             return interp;
1377         else if (found && !ret)
1378             ret = interp;
1379     }
1380
1381     return ret;
1382 }
1383
1384 /**
1385  */
1386 static bool
1387 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
1388 {
1389 #define INTERP_SIZE (8 * 4)
1390     struct xkb_sym_interpret *interps[INTERP_SIZE];
1391     union xkb_action *acts;
1392     uint32_t vmodmask = 0;
1393     int num_acts = 0;
1394     xkb_group_index_t group;
1395     int level;
1396     int i;
1397
1398     /* If we've been told not to bind interps to this key, then don't. */
1399     if (key->explicit & XkbExplicitInterpretMask)
1400         return true;
1401
1402     for (i = 0; i < INTERP_SIZE; i++)
1403         interps[i] = NULL;
1404
1405     for (group = 0; group < key->num_groups; group++) {
1406         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1407              level++) {
1408             i = (group * key->width) + level;
1409             if (i >= INTERP_SIZE) /* XXX FIXME */
1410                 return false;
1411             interps[i] = FindInterpForKey(keymap, key, group, level);
1412             if (interps[i])
1413                 num_acts++;
1414         }
1415     }
1416
1417     if (num_acts)
1418         num_acts = key->num_groups * key->width;
1419     acts = XkbcResizeKeyActions(keymap, key, num_acts);
1420     if (num_acts && !acts)
1421         return false;
1422
1423     for (group = 0; group < key->num_groups; group++) {
1424         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1425              level++) {
1426             struct xkb_sym_interpret *interp;
1427
1428             i = (group * key->width) + level;
1429             interp = interps[i];
1430
1431             /* Infer default key behaviours from the base level. */
1432             if (group == 0 && level == 0) {
1433                 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
1434                     (!interp || (interp->flags & XkbSI_AutoRepeat)))
1435                     key->repeats = true;
1436                 if (!(key->explicit & XkbExplicitBehaviorMask) &&
1437                     interp && (interp->flags & XkbSI_LockingKey))
1438                     key->behavior.type = XkbKB_Lock;
1439             }
1440
1441             if (!interp)
1442                 continue;
1443
1444             if ((group == 0 && level == 0) ||
1445                 !(interp->match & XkbSI_LevelOneOnly)) {
1446                 if (interp->virtual_mod != XkbNoModifier)
1447                     vmodmask |= (1 << interp->virtual_mod);
1448             }
1449             acts[i] = interp->act;
1450         }
1451     }
1452
1453     if (!(key->explicit & XkbExplicitVModMapMask))
1454         key->vmodmap = vmodmask;
1455
1456     return true;
1457 #undef INTERP_SIZE
1458 }
1459
1460 /**
1461  * This collects a bunch of disparate functions which was done in the server
1462  * at various points that really should've been done within xkbcomp.  Turns out
1463  * your actions and types are a lot more useful when any of your modifiers
1464  * other than Shift actually do something ...
1465  */
1466 bool
1467 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
1468 {
1469     struct xkb_key *key;
1470     int i;
1471     struct xkb_key_type *type;
1472     struct xkb_kt_map_entry *entry;
1473
1474     /* Find all the interprets for the key and bind them to actions,
1475      * which will also update the vmodmap. */
1476     xkb_foreach_key(key, keymap)
1477         if (!ApplyInterpsToKey(keymap, key))
1478             return false;
1479
1480     /* Update keymap->vmods, the virtual -> real mod mapping. */
1481     for (i = 0; i < XkbNumVirtualMods; i++)
1482         keymap->vmods[i] = 0;
1483     xkb_foreach_key(key, keymap) {
1484         if (!key->vmodmap)
1485             continue;
1486
1487         for (i = 0; i < XkbNumVirtualMods; i++) {
1488             if (!(key->vmodmap & (1 << i)))
1489                 continue;
1490             keymap->vmods[i] |= key->modmap;
1491         }
1492     }
1493
1494     /* Now update the level masks for all the types to reflect the vmods. */
1495     darray_foreach(type, keymap->types) {
1496         uint32_t mask = 0;
1497         int j;
1498         type->mods.mask = type->mods.real_mods;
1499         type->mods.mask |= VModsToReal(keymap, type->mods.vmods);
1500         for (j = 0; j < XkbNumVirtualMods; j++) {
1501             if (!(type->mods.vmods & (1 << j)))
1502                 continue;
1503             mask |= keymap->vmods[j];
1504         }
1505
1506         darray_foreach(entry, type->map)
1507         entry->mods.mask = entry->mods.real_mods |
1508                            VModsToReal(keymap, entry->mods.vmods);
1509     }
1510
1511     /* Update action modifiers. */
1512     xkb_foreach_key(key, keymap) {
1513         union xkb_action *acts = XkbKeyActionsPtr(keymap, key);
1514         for (i = 0; i < XkbKeyNumActions(key); i++) {
1515             if (acts[i].any.type == XkbSA_NoAction)
1516                 continue;
1517             UpdateActionMods(keymap, &acts[i], key->modmap);
1518         }
1519     }
1520
1521     /* Update group modifiers. */
1522     for (i = 0; i < XkbNumKbdGroups; i++) {
1523         struct xkb_mods *group = &keymap->groups[i];
1524         group->mask = group->real_mods | VModsToReal(keymap, group->vmods);
1525     }
1526
1527     /* Update vmod -> indicator maps. */
1528     for (i = 0; i < XkbNumIndicators; i++) {
1529         struct xkb_mods *led = &keymap->indicators[i].mods;
1530         led->mask = led->real_mods | VModsToReal(keymap, led->vmods);
1531     }
1532
1533     return true;
1534 }