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