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