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