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