Convert macros to inline functions
[platform/upstream/libxkbcommon.git] / src / xkbcomp / compat.c
1 /************************************************************
2  * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3  *
4  * Permission to use, copy, modify, and distribute this
5  * software and its documentation for any purpose and without
6  * fee is hereby granted, provided that the above copyright
7  * notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting
9  * documentation, and that the name of Silicon Graphics not be
10  * used in advertising or publicity pertaining to distribution
11  * of the software without specific prior written permission.
12  * Silicon Graphics makes no representation about the suitability
13  * of this software for any purpose. It is provided "as is"
14  * without any express or implied warranty.
15  *
16  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  ********************************************************/
26
27 #include "xkbcomp-priv.h"
28 #include "parseutils.h"
29 #include "action.h"
30 #include "indicators.h"
31 #include "vmod.h"
32
33 typedef struct _SymInterpInfo {
34     CommonInfo defs;
35     struct xkb_sym_interpret interp;
36 } SymInterpInfo;
37
38 #define _SI_VirtualMod   (1 << 0)
39 #define _SI_Action       (1 << 1)
40 #define _SI_AutoRepeat   (1 << 2)
41 #define _SI_LockingKey   (1 << 3)
42 #define _SI_LevelOneOnly (1 << 4)
43
44 typedef struct _GroupCompatInfo {
45     unsigned file_id;
46     enum merge_mode merge;
47     bool defined;
48     unsigned char real_mods;
49     xkb_atom_t vmods;
50 } GroupCompatInfo;
51
52 typedef struct _CompatInfo {
53     char *name;
54     unsigned file_id;
55     int errorCount;
56     int nInterps;
57     SymInterpInfo *interps;
58     SymInterpInfo dflt;
59     LEDInfo ledDflt;
60     GroupCompatInfo groupCompat[XkbNumKbdGroups];
61     LEDInfo *leds;
62     VModInfo vmods;
63     ActionInfo *act;
64     struct xkb_keymap *keymap;
65 } CompatInfo;
66
67 static const char *
68 siText(SymInterpInfo * si, CompatInfo * info)
69 {
70     static char buf[128];
71
72     if (si == &info->dflt) {
73         snprintf(buf, sizeof(buf), "default");
74     }
75     else {
76         snprintf(buf, sizeof(buf), "%s+%s(%s)",
77                  XkbcKeysymText(si->interp.sym),
78                  XkbcSIMatchText(si->interp.match),
79                  XkbcModMaskText(si->interp.mods, false));
80     }
81     return buf;
82 }
83
84 static inline bool
85 ReportSINotArray(SymInterpInfo *si, const char *field, CompatInfo *info)
86 {
87     return ReportNotArray("symbol interpretation", field, siText(si, info));
88 }
89
90 static inline bool
91 ReportSIBadType(SymInterpInfo *si, const char *field, const char *wanted,
92                 CompatInfo *info)
93 {
94     return ReportBadType("symbol interpretation", field, siText(si, info),
95                          wanted);
96 }
97
98 static void
99 InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id)
100 {
101     unsigned int i;
102
103     info->keymap = keymap;
104     info->name = NULL;
105     info->file_id = file_id;
106     info->errorCount = 0;
107     info->nInterps = 0;
108     info->interps = NULL;
109     info->act = NULL;
110     info->dflt.defs.file_id = file_id;
111     info->dflt.defs.defined = 0;
112     info->dflt.defs.merge = MERGE_OVERRIDE;
113     info->dflt.interp.flags = 0;
114     info->dflt.interp.virtual_mod = XkbNoModifier;
115     info->dflt.interp.act.type = XkbSA_NoAction;
116     for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
117         info->dflt.interp.act.any.data[i] = 0;
118     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
119     info->ledDflt.defs.file_id = file_id;
120     info->ledDflt.defs.defined = 0;
121     info->ledDflt.defs.merge = MERGE_OVERRIDE;
122     memset(&info->groupCompat[0], 0,
123            XkbNumKbdGroups * sizeof(GroupCompatInfo));
124     info->leds = NULL;
125     InitVModInfo(&info->vmods, keymap);
126 }
127
128 static void
129 ClearCompatInfo(CompatInfo *info, struct xkb_keymap *keymap)
130 {
131     unsigned int i;
132     ActionInfo *next;
133
134     free(info->name);
135     info->name = NULL;
136     info->dflt.defs.defined = 0;
137     info->dflt.defs.merge = MERGE_AUGMENT;
138     info->dflt.interp.flags = 0;
139     info->dflt.interp.virtual_mod = XkbNoModifier;
140     info->dflt.interp.act.type = XkbSA_NoAction;
141     for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
142         info->dflt.interp.act.any.data[i] = 0;
143     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
144     info->nInterps = 0;
145     info->interps = ClearCommonInfo(&info->interps->defs);
146     memset(&info->groupCompat[0], 0,
147            XkbNumKbdGroups * sizeof(GroupCompatInfo));
148     info->leds = ClearCommonInfo(&info->leds->defs);
149     while (info->act) {
150         next = info->act->next;
151         free(info->act);
152         info->act = next;
153     }
154     ClearVModInfo(&info->vmods, keymap);
155 }
156
157 static SymInterpInfo *
158 NextInterp(CompatInfo * info)
159 {
160     SymInterpInfo *si;
161
162     si = uTypedAlloc(SymInterpInfo);
163     if (si) {
164         memset(si, 0, sizeof(SymInterpInfo));
165         info->interps = AddCommonInfo(&info->interps->defs, &si->defs);
166         info->nInterps++;
167     }
168     return si;
169 }
170
171 static SymInterpInfo *
172 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
173 {
174     SymInterpInfo *old;
175
176     for (old = info->interps; old != NULL;
177          old = (SymInterpInfo *) old->defs.next) {
178         if ((old->interp.sym == new->interp.sym) &&
179             (old->interp.mods == new->interp.mods) &&
180             (old->interp.match == new->interp.match)) {
181             return old;
182         }
183     }
184     return NULL;
185 }
186
187 static bool
188 AddInterp(CompatInfo * info, SymInterpInfo * new)
189 {
190     unsigned collide;
191     SymInterpInfo *old;
192
193     collide = 0;
194     old = FindMatchingInterp(info, new);
195     if (old != NULL) {
196         if (new->defs.merge == MERGE_REPLACE) {
197             SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
198             if (((old->defs.file_id == new->defs.file_id)
199                  && (warningLevel > 0)) || (warningLevel > 9)) {
200                 WARN("Multiple definitions for \"%s\"\n", siText(new, info));
201                 ACTION("Earlier interpretation ignored\n");
202             }
203             *old = *new;
204             old->defs.next = &next->defs;
205             return true;
206         }
207         if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide)) {
208             old->interp.virtual_mod = new->interp.virtual_mod;
209             old->defs.defined |= _SI_VirtualMod;
210         }
211         if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide)) {
212             old->interp.act = new->interp.act;
213             old->defs.defined |= _SI_Action;
214         }
215         if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide)) {
216             old->interp.flags &= ~XkbSI_AutoRepeat;
217             old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
218             old->defs.defined |= _SI_AutoRepeat;
219         }
220         if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide)) {
221             old->interp.flags &= ~XkbSI_LockingKey;
222             old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
223             old->defs.defined |= _SI_LockingKey;
224         }
225         if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs,
226                         &collide)) {
227             old->interp.match &= ~XkbSI_LevelOneOnly;
228             old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
229             old->defs.defined |= _SI_LevelOneOnly;
230         }
231         if (collide) {
232             WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
233             ACTION("Using %s definition for duplicate fields\n",
234                    (new->defs.merge != MERGE_AUGMENT ? "last" : "first"));
235         }
236         return true;
237     }
238     old = new;
239     if ((new = NextInterp(info)) == NULL)
240         return false;
241     *new = *old;
242     new->defs.next = NULL;
243     return true;
244 }
245
246 static bool
247 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
248 {
249     GroupCompatInfo *gc;
250     enum merge_mode merge;
251
252     merge = newGC->merge;
253     gc = &info->groupCompat[group];
254     if (((gc->real_mods == newGC->real_mods) &&
255          (gc->vmods == newGC->vmods))) {
256         return true;
257     }
258     if (((gc->file_id == newGC->file_id) && (warningLevel > 0))
259         || (warningLevel > 9)) {
260         WARN("Compat map for group %d redefined\n", group + 1);
261         ACTION("Using %s definition\n",
262                (merge == MERGE_AUGMENT ? "old" : "new"));
263     }
264     if (newGC->defined && (merge != MERGE_AUGMENT || !gc->defined))
265         *gc = *newGC;
266     return true;
267 }
268
269 /***====================================================================***/
270
271 static bool
272 ResolveStateAndPredicate(ExprDef * expr,
273                          unsigned *pred_rtrn,
274                          unsigned *mods_rtrn, CompatInfo * info)
275 {
276     ExprResult result;
277
278     if (expr == NULL) {
279         *pred_rtrn = XkbSI_AnyOfOrNone;
280         *mods_rtrn = ~0;
281         return true;
282     }
283
284     *pred_rtrn = XkbSI_Exactly;
285     if (expr->op == ExprActionDecl) {
286         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
287                                              expr->value.action.name);
288         if (strcasecmp(pred_txt, "noneof") == 0)
289             *pred_rtrn = XkbSI_NoneOf;
290         else if (strcasecmp(pred_txt, "anyofornone") == 0)
291             *pred_rtrn = XkbSI_AnyOfOrNone;
292         else if (strcasecmp(pred_txt, "anyof") == 0)
293             *pred_rtrn = XkbSI_AnyOf;
294         else if (strcasecmp(pred_txt, "allof") == 0)
295             *pred_rtrn = XkbSI_AllOf;
296         else if (strcasecmp(pred_txt, "exactly") == 0)
297             *pred_rtrn = XkbSI_Exactly;
298         else {
299             ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
300             ACTION("Ignored\n");
301             return false;
302         }
303         expr = expr->value.action.args;
304     }
305     else if (expr->op == ExprIdent) {
306         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
307                                              expr->value.str);
308         if ((pred_txt) && (strcasecmp(pred_txt, "any") == 0)) {
309             *pred_rtrn = XkbSI_AnyOf;
310             *mods_rtrn = 0xff;
311             return true;
312         }
313     }
314
315     if (ExprResolveModMask(info->keymap->ctx, expr, &result)) {
316         *mods_rtrn = result.uval;
317         return true;
318     }
319     return false;
320 }
321
322 /***====================================================================***/
323
324 static void
325 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from,
326                         enum merge_mode merge)
327 {
328     SymInterpInfo *si;
329     LEDInfo *led, *rtrn, *next;
330     GroupCompatInfo *gcm;
331     int i;
332
333     if (from->errorCount > 0) {
334         into->errorCount += from->errorCount;
335         return;
336     }
337     if (into->name == NULL) {
338         into->name = from->name;
339         from->name = NULL;
340     }
341     for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next) {
342         if (merge != MERGE_DEFAULT)
343             si->defs.merge = merge;
344         if (!AddInterp(into, si))
345             into->errorCount++;
346     }
347     for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++,
348          gcm++) {
349         if (merge != MERGE_DEFAULT)
350             gcm->merge = merge;
351         if (!AddGroupCompat(into, i, gcm))
352             into->errorCount++;
353     }
354     for (led = from->leds; led != NULL; led = next) {
355         next = (LEDInfo *) led->defs.next;
356         if (merge != MERGE_DEFAULT)
357             led->defs.merge = merge;
358         rtrn = AddIndicatorMap(from->keymap, into->leds, led);
359         if (rtrn != NULL)
360             into->leds = rtrn;
361         else
362             into->errorCount++;
363     }
364 }
365
366 static void
367 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap,
368                     enum merge_mode merge,
369                     CompatInfo *info);
370
371 static bool
372 HandleIncludeCompatMap(IncludeStmt *stmt, struct xkb_keymap *keymap,
373                        CompatInfo *info)
374 {
375     enum merge_mode newMerge;
376     XkbFile *rtrn;
377     CompatInfo included;
378     bool haveSelf;
379
380     haveSelf = false;
381     if ((stmt->file == NULL) && (stmt->map == NULL)) {
382         haveSelf = true;
383         included = *info;
384         memset(info, 0, sizeof(CompatInfo));
385     }
386     else if (ProcessIncludeFile(keymap->ctx, stmt, FILE_TYPE_COMPAT, &rtrn,
387                                 &newMerge)) {
388         InitCompatInfo(&included, keymap, rtrn->id);
389         included.dflt = info->dflt;
390         included.dflt.defs.merge = newMerge;
391         included.ledDflt.defs.merge = newMerge;
392         included.act = info->act;
393         HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &included);
394         if (stmt->stmt != NULL) {
395             free(included.name);
396             included.name = stmt->stmt;
397             stmt->stmt = NULL;
398         }
399         if (info->act != NULL)
400             included.act = NULL;
401         FreeXKBFile(rtrn);
402     }
403     else {
404         info->errorCount += 10;
405         return false;
406     }
407     if ((stmt->next != NULL) && (included.errorCount < 1)) {
408         IncludeStmt *next;
409         unsigned op;
410         CompatInfo next_incl;
411
412         for (next = stmt->next; next != NULL; next = next->next) {
413             if ((next->file == NULL) && (next->map == NULL)) {
414                 haveSelf = true;
415                 MergeIncludedCompatMaps(&included, info, next->merge);
416                 ClearCompatInfo(info, keymap);
417             }
418             else if (ProcessIncludeFile(keymap->ctx, next, FILE_TYPE_COMPAT,
419                                         &rtrn, &op)) {
420                 InitCompatInfo(&next_incl, keymap, rtrn->id);
421                 next_incl.file_id = rtrn->id;
422                 next_incl.dflt = info->dflt;
423                 next_incl.dflt.defs.file_id = rtrn->id;
424                 next_incl.dflt.defs.merge = op;
425                 next_incl.ledDflt.defs.file_id = rtrn->id;
426                 next_incl.ledDflt.defs.merge = op;
427                 next_incl.act = info->act;
428                 HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &next_incl);
429                 MergeIncludedCompatMaps(&included, &next_incl, op);
430                 if (info->act != NULL)
431                     next_incl.act = NULL;
432                 ClearCompatInfo(&next_incl, keymap);
433                 FreeXKBFile(rtrn);
434             }
435             else {
436                 info->errorCount += 10;
437                 return false;
438             }
439         }
440     }
441     if (haveSelf)
442         *info = included;
443     else {
444         MergeIncludedCompatMaps(info, &included, newMerge);
445         ClearCompatInfo(&included, keymap);
446     }
447     return (info->errorCount == 0);
448 }
449
450 static const LookupEntry useModMapValues[] = {
451     { "levelone", 1 },
452     { "level1", 1 },
453     { "anylevel", 0 },
454     { "any", 0 },
455     { NULL, 0 }
456 };
457
458 static int
459 SetInterpField(SymInterpInfo *si, struct xkb_keymap *keymap, char *field,
460                ExprDef *arrayNdx, ExprDef *value, CompatInfo *info)
461 {
462     int ok = 1;
463     ExprResult tmp;
464
465     if (strcasecmp(field, "action") == 0) {
466         if (arrayNdx != NULL)
467             return ReportSINotArray(si, field, info);
468         ok = HandleActionDef(value, keymap, &si->interp.act.any, info->act);
469         if (ok)
470             si->defs.defined |= _SI_Action;
471     }
472     else if ((strcasecmp(field, "virtualmodifier") == 0) ||
473              (strcasecmp(field, "virtualmod") == 0)) {
474         if (arrayNdx != NULL)
475             return ReportSINotArray(si, field, info);
476         ok = ResolveVirtualModifier(value, keymap, &tmp, &info->vmods);
477         if (ok) {
478             si->interp.virtual_mod = tmp.uval;
479             si->defs.defined |= _SI_VirtualMod;
480         }
481         else
482             return ReportSIBadType(si, field, "virtual modifier", info);
483     }
484     else if (strcasecmp(field, "repeat") == 0) {
485         if (arrayNdx != NULL)
486             return ReportSINotArray(si, field, info);
487         ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
488         if (ok) {
489             if (tmp.uval)
490                 si->interp.flags |= XkbSI_AutoRepeat;
491             else
492                 si->interp.flags &= ~XkbSI_AutoRepeat;
493             si->defs.defined |= _SI_AutoRepeat;
494         }
495         else
496             return ReportSIBadType(si, field, "boolean", info);
497     }
498     else if (strcasecmp(field, "locking") == 0) {
499         if (arrayNdx != NULL)
500             return ReportSINotArray(si, field, info);
501         ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
502         if (ok) {
503             if (tmp.uval)
504                 si->interp.flags |= XkbSI_LockingKey;
505             else
506                 si->interp.flags &= ~XkbSI_LockingKey;
507             si->defs.defined |= _SI_LockingKey;
508         }
509         else
510             return ReportSIBadType(si, field, "boolean", info);
511     }
512     else if ((strcasecmp(field, "usemodmap") == 0) ||
513              (strcasecmp(field, "usemodmapmods") == 0)) {
514         if (arrayNdx != NULL)
515             return ReportSINotArray(si, field, info);
516         ok = ExprResolveEnum(keymap->ctx, value, &tmp, useModMapValues);
517         if (ok) {
518             if (tmp.uval)
519                 si->interp.match |= XkbSI_LevelOneOnly;
520             else
521                 si->interp.match &= ~XkbSI_LevelOneOnly;
522             si->defs.defined |= _SI_LevelOneOnly;
523         }
524         else
525             return ReportSIBadType(si, field, "level specification", info);
526     }
527     else {
528         ok = ReportBadField("symbol interpretation", field, siText(si, info));
529     }
530     return ok;
531 }
532
533 static int
534 HandleInterpVar(VarDef * stmt, struct xkb_keymap *keymap, CompatInfo * info)
535 {
536     ExprResult elem, field;
537     ExprDef *ndx;
538     int ret;
539
540     if (ExprResolveLhs(keymap, stmt->name, &elem, &field, &ndx) == 0)
541         ret = 0;               /* internal error, already reported */
542     else if (elem.str && (strcasecmp(elem.str, "interpret") == 0))
543         ret = SetInterpField(&info->dflt, keymap, field.str, ndx, stmt->value,
544                              info);
545     else if (elem.str && (strcasecmp(elem.str, "indicator") == 0))
546         ret = SetIndicatorMapField(&info->ledDflt, keymap, field.str, ndx,
547                                    stmt->value);
548     else
549         ret = SetActionField(keymap, elem.str, field.str, ndx, stmt->value,
550                              &info->act);
551     free(elem.str);
552     free(field.str);
553     return ret;
554 }
555
556 static int
557 HandleInterpBody(VarDef *def, struct xkb_keymap *keymap, SymInterpInfo *si,
558                  CompatInfo *info)
559 {
560     int ok = 1;
561     ExprResult tmp, field;
562     ExprDef *arrayNdx;
563
564     for (; def != NULL; def = (VarDef *) def->common.next) {
565         if ((def->name) && (def->name->type == ExprFieldRef)) {
566             ok = HandleInterpVar(def, keymap, info);
567             continue;
568         }
569         ok = ExprResolveLhs(keymap, def->name, &tmp, &field, &arrayNdx);
570         if (ok) {
571             ok = SetInterpField(si, keymap, field.str, arrayNdx, def->value,
572                                 info);
573             free(field.str);
574         }
575     }
576     return ok;
577 }
578
579 static int
580 HandleInterpDef(InterpDef *def, struct xkb_keymap *keymap,
581                 enum merge_mode merge,
582                 CompatInfo *info)
583 {
584     unsigned pred, mods;
585     SymInterpInfo si;
586
587     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
588         ERROR("Couldn't determine matching modifiers\n");
589         ACTION("Symbol interpretation ignored\n");
590         return false;
591     }
592     if (def->merge != MERGE_DEFAULT)
593         merge = def->merge;
594
595     si = info->dflt;
596     si.defs.merge = merge;
597     if (!LookupKeysym(def->sym, &si.interp.sym)) {
598         ERROR("Could not resolve keysym %s\n", def->sym);
599         ACTION("Symbol interpretation ignored\n");
600         return false;
601     }
602     si.interp.match = pred & XkbSI_OpMask;
603     si.interp.mods = mods;
604     if (!HandleInterpBody(def->def, keymap, &si, info)) {
605         info->errorCount++;
606         return false;
607     }
608
609     if (!AddInterp(info, &si)) {
610         info->errorCount++;
611         return false;
612     }
613     return true;
614 }
615
616 static int
617 HandleGroupCompatDef(GroupCompatDef *def, struct xkb_keymap *keymap,
618                      enum merge_mode merge, CompatInfo *info)
619 {
620     ExprResult val;
621     GroupCompatInfo tmp;
622
623     if (def->merge != MERGE_DEFAULT)
624         merge = def->merge;
625     if (!XkbIsLegalGroup(def->group - 1)) {
626         ERROR("Keyboard group must be in the range 1..%d\n",
627               XkbNumKbdGroups + 1);
628         ACTION("Compatibility map for illegal group %d ignored\n",
629                def->group);
630         return false;
631     }
632     tmp.file_id = info->file_id;
633     tmp.merge = merge;
634     if (!ExprResolveVModMask(def->def, &val, keymap)) {
635         ERROR("Expected a modifier mask in group compatibility definition\n");
636         ACTION("Ignoring illegal compatibility map for group %d\n",
637                def->group);
638         return false;
639     }
640     tmp.real_mods = val.uval & 0xff;
641     tmp.vmods = (val.uval >> 8) & 0xffff;
642     tmp.defined = true;
643     return AddGroupCompat(info, def->group - 1, &tmp);
644 }
645
646 static void
647 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap,
648                     enum merge_mode merge,
649                     CompatInfo *info)
650 {
651     ParseCommon *stmt;
652     LEDInfo *leds;
653
654     if (merge == MERGE_DEFAULT)
655         merge = MERGE_AUGMENT;
656     free(info->name);
657     info->name = uDupString(file->name);
658     stmt = file->defs;
659     while (stmt)
660     {
661         switch (stmt->stmtType) {
662         case StmtInclude:
663             if (!HandleIncludeCompatMap((IncludeStmt *) stmt, keymap, info))
664                 info->errorCount++;
665             break;
666         case StmtInterpDef:
667             if (!HandleInterpDef((InterpDef *) stmt, keymap, merge, info))
668                 info->errorCount++;
669             break;
670         case StmtGroupCompatDef:
671             if (!HandleGroupCompatDef
672                     ((GroupCompatDef *) stmt, keymap, merge, info))
673                 info->errorCount++;
674             break;
675         case StmtIndicatorMapDef:
676             leds = HandleIndicatorMapDef((IndicatorMapDef *) stmt, keymap,
677                                          &info->ledDflt, info->leds, merge);
678             if (leds != NULL)
679                 info->leds = leds;
680             else
681                 info->errorCount++;
682         break;
683         case StmtVarDef:
684             if (!HandleInterpVar((VarDef *) stmt, keymap, info))
685                 info->errorCount++;
686             break;
687         case StmtVModDef:
688             if (!HandleVModDef((VModDef *) stmt, keymap, merge, &info->vmods))
689                 info->errorCount++;
690             break;
691         case StmtKeycodeDef:
692             ERROR("Interpretation files may not include other types\n");
693             ACTION("Ignoring definition of key name\n");
694             info->errorCount++;
695             break;
696         default:
697             WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
698                  stmt->stmtType);
699             break;
700         }
701         stmt = stmt->next;
702         if (info->errorCount > 10) {
703 #ifdef NOISY
704             ERROR("Too many errors\n");
705 #endif
706             ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
707             break;
708         }
709     }
710 }
711
712 static void
713 CopyInterps(CompatInfo *info, struct xkb_keymap *keymap,
714             bool needSymbol, unsigned pred)
715 {
716     SymInterpInfo *si;
717
718     for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next) {
719         if (((si->interp.match & XkbSI_OpMask) != pred) ||
720             (needSymbol && (si->interp.sym == XKB_KEY_NoSymbol)) ||
721             ((!needSymbol) && (si->interp.sym != XKB_KEY_NoSymbol)))
722             continue;
723         darray_append(keymap->sym_interpret, si->interp);
724     }
725 }
726
727 bool
728 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
729                  enum merge_mode merge)
730 {
731     int i;
732     CompatInfo info;
733     GroupCompatInfo *gcm;
734
735     InitCompatInfo(&info, keymap, file->id);
736     info.dflt.defs.merge = merge;
737     info.ledDflt.defs.merge = merge;
738
739     HandleCompatMapFile(file, keymap, merge, &info);
740
741     if (info.errorCount != 0)
742         goto err_info;
743
744     darray_init(keymap->sym_interpret);
745     darray_growalloc(keymap->sym_interpret, info.nInterps);
746
747     if (info.name)
748         keymap->compat_section_name = strdup(info.name);
749
750     if (info.nInterps > 0) {
751         CopyInterps(&info, keymap, true, XkbSI_Exactly);
752         CopyInterps(&info, keymap, true, XkbSI_AllOf | XkbSI_NoneOf);
753         CopyInterps(&info, keymap, true, XkbSI_AnyOf);
754         CopyInterps(&info, keymap, true, XkbSI_AnyOfOrNone);
755         CopyInterps(&info, keymap, false, XkbSI_Exactly);
756         CopyInterps(&info, keymap, false, XkbSI_AllOf | XkbSI_NoneOf);
757         CopyInterps(&info, keymap, false, XkbSI_AnyOf);
758         CopyInterps(&info, keymap, false, XkbSI_AnyOfOrNone);
759     }
760
761     for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
762          i++, gcm++) {
763         if (gcm->file_id != 0 || gcm->real_mods != 0 || gcm->vmods != 0) {
764             keymap->groups[i].mask = gcm->real_mods;
765             keymap->groups[i].real_mods = gcm->real_mods;
766             keymap->groups[i].vmods = gcm->vmods;
767         }
768     }
769
770     if (info.leds != NULL) {
771         if (!CopyIndicatorMapDefs(keymap, info.leds))
772             info.errorCount++;
773         info.leds = NULL;
774     }
775
776     ClearCompatInfo(&info, keymap);
777     return true;
778
779 err_info:
780     ClearCompatInfo(&info, keymap);
781     return false;
782 }
783
784 uint32_t
785 VModsToReal(struct xkb_keymap *keymap, uint32_t vmodmask)
786 {
787     uint32_t ret = 0;
788     int i;
789
790     if (!vmodmask)
791         return 0;
792
793     for (i = 0; i < XkbNumVirtualMods; i++) {
794         if (!(vmodmask & (1 << i)))
795             continue;
796         ret |= keymap->vmods[i];
797     }
798
799     return ret;
800 }
801
802 static void
803 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
804                  uint32_t rmodmask)
805 {
806     switch (act->type) {
807     case XkbSA_SetMods:
808     case XkbSA_LatchMods:
809     case XkbSA_LockMods:
810         if (act->mods.flags & XkbSA_UseModMapMods)
811             act->mods.real_mods = rmodmask;
812         act->mods.mask = act->mods.real_mods;
813         act->mods.mask |= VModsToReal(keymap, act->mods.vmods);
814         break;
815
816     case XkbSA_ISOLock:
817         if (act->iso.flags & XkbSA_UseModMapMods)
818             act->iso.real_mods = rmodmask;
819         act->iso.mask = act->iso.real_mods;
820         act->iso.mask |= VModsToReal(keymap, act->iso.vmods);
821         break;
822
823     default:
824         break;
825     }
826 }
827
828 /**
829  * Find an interpretation which applies to this particular level, either by
830  * finding an exact match for the symbol and modifier combination, or a
831  * generic XKB_KEY_NoSymbol match.
832  */
833 static struct xkb_sym_interpret *
834 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
835                  uint32_t group, uint32_t level)
836 {
837     struct xkb_sym_interpret *ret = NULL;
838     struct xkb_sym_interpret *interp;
839     const xkb_keysym_t *syms;
840     int num_syms;
841
842     num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
843     if (num_syms == 0)
844         return NULL;
845
846     darray_foreach(interp, keymap->sym_interpret) {
847         uint32_t mods;
848         bool found;
849
850         if ((num_syms > 1 || interp->sym != syms[0]) &&
851             interp->sym != XKB_KEY_NoSymbol)
852             continue;
853
854         if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
855             mods = key->modmap;
856         else
857             mods = 0;
858
859         switch (interp->match & XkbSI_OpMask) {
860         case XkbSI_NoneOf:
861             found = !(interp->mods & mods);
862             break;
863         case XkbSI_AnyOfOrNone:
864             found = (!mods || (interp->mods & mods));
865             break;
866         case XkbSI_AnyOf:
867             found = !!(interp->mods & mods);
868             break;
869         case XkbSI_AllOf:
870             found = ((interp->mods & mods) == interp->mods);
871             break;
872         case XkbSI_Exactly:
873             found = (interp->mods == mods);
874             break;
875         default:
876             found = false;
877             break;
878         }
879
880         if (found && interp->sym != XKB_KEY_NoSymbol)
881             return interp;
882         else if (found && !ret)
883             ret = interp;
884     }
885
886     return ret;
887 }
888
889 /**
890  */
891 static bool
892 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
893 {
894 #define INTERP_SIZE (8 * 4)
895     struct xkb_sym_interpret *interps[INTERP_SIZE];
896     union xkb_action *acts;
897     uint32_t vmodmask = 0;
898     int num_acts = 0;
899     int group, level;
900     int i;
901
902     /* If we've been told not to bind interps to this key, then don't. */
903     if (key->explicit & XkbExplicitInterpretMask)
904         return true;
905
906     for (i = 0; i < INTERP_SIZE; i++)
907         interps[i] = NULL;
908
909     for (group = 0; group < key->num_groups; group++) {
910         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
911              level++) {
912             i = (group * key->width) + level;
913             if (i >= INTERP_SIZE) /* XXX FIXME */
914                 return false;
915             interps[i] = FindInterpForKey(keymap, key, group, level);
916             if (interps[i])
917                 num_acts++;
918         }
919     }
920
921     if (num_acts)
922         num_acts = key->num_groups * key->width;
923     acts = XkbcResizeKeyActions(keymap, key, num_acts);
924     if (num_acts && !acts)
925         return false;
926
927     for (group = 0; group < key->num_groups; group++) {
928         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
929              level++) {
930             struct xkb_sym_interpret *interp;
931
932             i = (group * key->width) + level;
933             interp = interps[i];
934
935             /* Infer default key behaviours from the base level. */
936             if (group == 0 && level == 0) {
937                 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
938                     (!interp || interp->flags & XkbSI_AutoRepeat))
939                     key->repeats = true;
940                 if (!(key->explicit & XkbExplicitBehaviorMask) &&
941                     interp && (interp->flags & XkbSI_LockingKey))
942                     key->behavior.type = XkbKB_Lock;
943             }
944
945             if (!interp)
946                 continue;
947
948             if ((group == 0 && level == 0) ||
949                 !(interp->match & XkbSI_LevelOneOnly)) {
950                 if (interp->virtual_mod != XkbNoModifier)
951                     vmodmask |= (1 << interp->virtual_mod);
952             }
953             acts[i] = interp->act;
954         }
955     }
956
957     if (!(key->explicit & XkbExplicitVModMapMask))
958         key->vmodmap = vmodmask;
959
960     return true;
961 #undef INTERP_SIZE
962 }
963
964 /**
965  * This collects a bunch of disparate functions which was done in the server
966  * at various points that really should've been done within xkbcomp.  Turns out
967  * your actions and types are a lot more useful when any of your modifiers
968  * other than Shift actually do something ...
969  */
970 bool
971 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
972 {
973     struct xkb_key *key;
974     int i;
975     struct xkb_key_type *type;
976     struct xkb_kt_map_entry *entry;
977
978     /* Find all the interprets for the key and bind them to actions,
979      * which will also update the vmodmap. */
980     xkb_foreach_key(key, keymap)
981         if (!ApplyInterpsToKey(keymap, key))
982             return false;
983
984     /* Update keymap->vmods, the virtual -> real mod mapping. */
985     for (i = 0; i < XkbNumVirtualMods; i++)
986         keymap->vmods[i] = 0;
987     xkb_foreach_key(key, keymap) {
988         if (!key->vmodmap)
989             continue;
990
991         for (i = 0; i < XkbNumVirtualMods; i++) {
992             if (!(key->vmodmap & (1 << i)))
993                 continue;
994             keymap->vmods[i] |= key->modmap;
995         }
996     }
997
998     /* Now update the level masks for all the types to reflect the vmods. */
999     darray_foreach(type, keymap->types) {
1000         uint32_t mask = 0;
1001         int j;
1002         type->mods.mask = type->mods.real_mods;
1003         type->mods.mask |= VModsToReal(keymap, type->mods.vmods);
1004         for (j = 0; j < XkbNumVirtualMods; j++) {
1005             if (!(type->mods.vmods & (1 << j)))
1006                 continue;
1007             mask |= keymap->vmods[j];
1008         }
1009
1010         darray_foreach(entry, type->map)
1011         entry->mods.mask = entry->mods.real_mods |
1012                            VModsToReal(keymap, entry->mods.vmods);
1013     }
1014
1015     /* Update action modifiers. */
1016     xkb_foreach_key(key, keymap) {
1017         union xkb_action *acts = XkbKeyActionsPtr(keymap, key);
1018         for (i = 0; i < XkbKeyNumActions(key); i++) {
1019             if (acts[i].any.type == XkbSA_NoAction)
1020                 continue;
1021             UpdateActionMods(keymap, &acts[i], key->modmap);
1022         }
1023     }
1024
1025     /* Update group modifiers. */
1026     for (i = 0; i < XkbNumKbdGroups; i++) {
1027         struct xkb_mods *group = &keymap->groups[i];
1028         group->mask = group->real_mods | VModsToReal(keymap, group->vmods);
1029     }
1030
1031     /* Update vmod -> indicator maps. */
1032     for (i = 0; i < XkbNumIndicators; i++) {
1033         struct xkb_mods *led = &keymap->indicators[i].mods;
1034         led->mask = led->real_mods | VModsToReal(keymap, led->vmods);
1035     }
1036
1037     return true;
1038 }