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