Remove priv arguments from ExprResolveModMask
[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 <X11/Xos.h>
28 #include "xkbcomp.h"
29 #include "xkballoc.h"
30 #include "xkbmisc.h"
31 #include "tokens.h"
32 #include "expr.h"
33 #include "vmod.h"
34 #include "misc.h"
35 #include "indicators.h"
36 #include "action.h"
37 #include "compat.h"
38 #include "parseutils.h"
39
40 typedef struct _SymInterpInfo
41 {
42     CommonInfo defs;
43     struct xkb_sym_interpret interp;
44 } SymInterpInfo;
45
46 #define _SI_VirtualMod          (1<<0)
47 #define _SI_Action              (1<<1)
48 #define _SI_AutoRepeat          (1<<2)
49 #define _SI_LockingKey          (1<<3)
50 #define _SI_LevelOneOnly        (1<<4)
51
52 typedef struct _GroupCompatInfo
53 {
54     unsigned char fileID;
55     unsigned char merge;
56     unsigned char real_mods;
57     uint32_t vmods;
58 } GroupCompatInfo;
59
60 typedef struct _CompatInfo
61 {
62     char *name;
63     unsigned fileID;
64     int errorCount;
65     int nInterps;
66     SymInterpInfo *interps;
67     SymInterpInfo dflt;
68     LEDInfo ledDflt;
69     GroupCompatInfo groupCompat[XkbNumKbdGroups];
70     LEDInfo *leds;
71     VModInfo vmods;
72     ActionInfo *act;
73     struct xkb_desc * xkb;
74 } CompatInfo;
75
76 /***====================================================================***/
77
78 #define ReportSINotArray(si,f,i) \
79         ReportNotArray("symbol interpretation",(f),siText((si),(i)))
80 #define ReportSIBadType(si,f,w,i) \
81         ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
82
83 /***====================================================================***/
84
85 static char *
86 siText(SymInterpInfo * si, CompatInfo * info)
87 {
88     static char buf[128];
89
90     if (si == &info->dflt)
91     {
92         snprintf(buf, sizeof(buf), "default");
93     }
94     else
95     {
96         snprintf(buf, sizeof(buf), "%s+%s(%s)",
97                 XkbcKeysymText(si->interp.sym),
98                 XkbcSIMatchText(si->interp.match),
99                 XkbcModMaskText(si->interp.mods, False));
100     }
101     return buf;
102 }
103
104 static void
105 InitCompatInfo(CompatInfo * info, struct xkb_desc * xkb)
106 {
107     register int i;
108
109     info->xkb = xkb;
110     info->name = NULL;
111     info->fileID = 0;
112     info->errorCount = 0;
113     info->nInterps = 0;
114     info->interps = NULL;
115     info->act = NULL;
116     info->dflt.defs.fileID = info->fileID;
117     info->dflt.defs.defined = 0;
118     info->dflt.defs.merge = MergeOverride;
119     info->dflt.interp.flags = 0;
120     info->dflt.interp.virtual_mod = XkbNoModifier;
121     info->dflt.interp.act.type = XkbSA_NoAction;
122     for (i = 0; i < sizeof info->dflt.interp.act.data; i++)
123     {
124         info->dflt.interp.act.data[i] = 0;
125     }
126     ClearIndicatorMapInfo(&info->ledDflt);
127     info->ledDflt.defs.fileID = info->fileID;
128     info->ledDflt.defs.defined = 0;
129     info->ledDflt.defs.merge = MergeOverride;
130     bzero((char *) &info->groupCompat[0],
131           XkbNumKbdGroups * sizeof(GroupCompatInfo));
132     info->leds = NULL;
133     InitVModInfo(&info->vmods, xkb);
134     return;
135 }
136
137 static void
138 ClearCompatInfo(CompatInfo * info, struct xkb_desc * xkb)
139 {
140     register int i;
141
142     if (info->name != NULL)
143         free(info->name);
144     info->name = NULL;
145     info->dflt.defs.defined = 0;
146     info->dflt.defs.merge = MergeAugment;
147     info->dflt.interp.flags = 0;
148     info->dflt.interp.virtual_mod = XkbNoModifier;
149     info->dflt.interp.act.type = XkbSA_NoAction;
150     for (i = 0; i < sizeof info->dflt.interp.act.data; i++)
151     {
152         info->dflt.interp.act.data[i] = 0;
153     }
154     ClearIndicatorMapInfo(&info->ledDflt);
155     info->nInterps = 0;
156     info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
157     bzero((char *) &info->groupCompat[0],
158           XkbNumKbdGroups * sizeof(GroupCompatInfo));
159     info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
160     /* 3/30/94 (ef) -- XXX! Should free action info here */
161     ClearVModInfo(&info->vmods, xkb);
162     return;
163 }
164
165 static SymInterpInfo *
166 NextInterp(CompatInfo * info)
167 {
168     SymInterpInfo *si;
169
170     si = uTypedAlloc(SymInterpInfo);
171     if (si)
172     {
173         bzero((char *) si, sizeof(SymInterpInfo));
174         info->interps =
175             (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
176                                             (CommonInfo *) si);
177         info->nInterps++;
178     }
179     return si;
180 }
181
182 static SymInterpInfo *
183 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
184 {
185     SymInterpInfo *old;
186
187     for (old = info->interps; old != NULL;
188          old = (SymInterpInfo *) old->defs.next)
189     {
190         if ((old->interp.sym == new->interp.sym) &&
191             (old->interp.mods == new->interp.mods) &&
192             (old->interp.match == new->interp.match))
193         {
194             return old;
195         }
196     }
197     return NULL;
198 }
199
200 static Bool
201 AddInterp(CompatInfo * info, SymInterpInfo * new)
202 {
203     unsigned collide;
204     SymInterpInfo *old;
205
206     collide = 0;
207     old = FindMatchingInterp(info, new);
208     if (old != NULL)
209     {
210         if (new->defs.merge == MergeReplace)
211         {
212             SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
213             if (((old->defs.fileID == new->defs.fileID)
214                  && (warningLevel > 0)) || (warningLevel > 9))
215             {
216                 WARN("Multiple definitions for \"%s\"\n", siText(new, info));
217                 ACTION("Earlier interpretation ignored\n");
218             }
219             *old = *new;
220             old->defs.next = &next->defs;
221             return True;
222         }
223         if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
224         {
225             old->interp.virtual_mod = new->interp.virtual_mod;
226             old->defs.defined |= _SI_VirtualMod;
227         }
228         if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
229         {
230             old->interp.act = new->interp.act;
231             old->defs.defined |= _SI_Action;
232         }
233         if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
234         {
235             old->interp.flags &= ~XkbSI_AutoRepeat;
236             old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
237             old->defs.defined |= _SI_AutoRepeat;
238         }
239         if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
240         {
241             old->interp.flags &= ~XkbSI_LockingKey;
242             old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
243             old->defs.defined |= _SI_LockingKey;
244         }
245         if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
246         {
247             old->interp.match &= ~XkbSI_LevelOneOnly;
248             old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
249             old->defs.defined |= _SI_LevelOneOnly;
250         }
251         if (collide)
252         {
253             WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
254             ACTION("Using %s definition for duplicate fields\n",
255                     (new->defs.merge != MergeAugment ? "last" : "first"));
256         }
257         return True;
258     }
259     old = new;
260     if ((new = NextInterp(info)) == NULL)
261         return False;
262     *new = *old;
263     new->defs.next = NULL;
264     return True;
265 }
266
267 static Bool
268 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
269 {
270     GroupCompatInfo *gc;
271     unsigned merge;
272
273     merge = newGC->merge;
274     gc = &info->groupCompat[group];
275     if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
276     {
277         return True;
278     }
279     if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
280         || (warningLevel > 9))
281     {
282         WARN("Compat map for group %d redefined\n", group + 1);
283         ACTION("Using %s definition\n",
284                 (merge == MergeAugment ? "old" : "new"));
285     }
286     if (merge != MergeAugment)
287         *gc = *newGC;
288     return True;
289 }
290
291 /***====================================================================***/
292
293 static Bool
294 ResolveStateAndPredicate(ExprDef * expr,
295                          unsigned *pred_rtrn,
296                          unsigned *mods_rtrn, CompatInfo * info)
297 {
298     ExprResult result;
299
300     if (expr == NULL)
301     {
302         *pred_rtrn = XkbSI_AnyOfOrNone;
303         *mods_rtrn = ~0;
304         return True;
305     }
306
307     *pred_rtrn = XkbSI_Exactly;
308     if (expr->op == ExprActionDecl)
309     {
310         const char *pred_txt = XkbcAtomText(expr->value.action.name);
311         if (uStrCaseCmp(pred_txt, "noneof") == 0)
312             *pred_rtrn = XkbSI_NoneOf;
313         else if (uStrCaseCmp(pred_txt, "anyofornone") == 0)
314             *pred_rtrn = XkbSI_AnyOfOrNone;
315         else if (uStrCaseCmp(pred_txt, "anyof") == 0)
316             *pred_rtrn = XkbSI_AnyOf;
317         else if (uStrCaseCmp(pred_txt, "allof") == 0)
318             *pred_rtrn = XkbSI_AllOf;
319         else if (uStrCaseCmp(pred_txt, "exactly") == 0)
320             *pred_rtrn = XkbSI_Exactly;
321         else
322         {
323             ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
324             ACTION("Ignored\n");
325             return False;
326         }
327         expr = expr->value.action.args;
328     }
329     else if (expr->op == ExprIdent)
330     {
331         const char *pred_txt = XkbcAtomText(expr->value.str);
332         if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0))
333         {
334             *pred_rtrn = XkbSI_AnyOf;
335             *mods_rtrn = 0xff;
336             return True;
337         }
338     }
339
340     if (ExprResolveModMask(expr, &result))
341     {
342         *mods_rtrn = result.uval;
343         return True;
344     }
345     return False;
346 }
347
348 /***====================================================================***/
349
350 static void
351 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
352 {
353     SymInterpInfo *si;
354     LEDInfo *led, *rtrn, *next;
355     GroupCompatInfo *gcm;
356     register int i;
357
358     if (from->errorCount > 0)
359     {
360         into->errorCount += from->errorCount;
361         return;
362     }
363     if (into->name == NULL)
364     {
365         into->name = from->name;
366         from->name = NULL;
367     }
368     for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
369     {
370         if (merge != MergeDefault)
371             si->defs.merge = merge;
372         if (!AddInterp(into, si))
373             into->errorCount++;
374     }
375     for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
376     {
377         if (merge != MergeDefault)
378             gcm->merge = merge;
379         if (!AddGroupCompat(into, i, gcm))
380             into->errorCount++;
381     }
382     for (led = from->leds; led != NULL; led = next)
383     {
384         next = (LEDInfo *) led->defs.next;
385         if (merge != MergeDefault)
386             led->defs.merge = merge;
387         rtrn = AddIndicatorMap(into->leds, led);
388         if (rtrn != NULL)
389             into->leds = rtrn;
390         else
391             into->errorCount++;
392     }
393     return;
394 }
395
396 typedef void (*FileHandler) (XkbFile * /* rtrn */ ,
397                              struct xkb_desc * /* xkb */ ,
398                              unsigned /* merge */ ,
399                              CompatInfo *       /* info */
400     );
401
402 static Bool
403 HandleIncludeCompatMap(IncludeStmt * stmt,
404                        struct xkb_desc * xkb, CompatInfo * info, FileHandler hndlr)
405 {
406     unsigned newMerge;
407     XkbFile *rtrn;
408     CompatInfo included;
409     Bool haveSelf;
410
411     haveSelf = False;
412     if ((stmt->file == NULL) && (stmt->map == NULL))
413     {
414         haveSelf = True;
415         included = *info;
416         bzero(info, sizeof(CompatInfo));
417     }
418     else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
419     {
420         InitCompatInfo(&included, xkb);
421         included.fileID = rtrn->id;
422         included.dflt = info->dflt;
423         included.dflt.defs.fileID = rtrn->id;
424         included.dflt.defs.merge = newMerge;
425         included.ledDflt.defs.fileID = rtrn->id;
426         included.ledDflt.defs.merge = newMerge;
427         included.act = info->act;
428         (*hndlr) (rtrn, xkb, MergeOverride, &included);
429         if (stmt->stmt != NULL)
430         {
431             if (included.name != NULL)
432                 free(included.name);
433             included.name = stmt->stmt;
434             stmt->stmt = NULL;
435         }
436     }
437     else
438     {
439         info->errorCount += 10;
440         return False;
441     }
442     if ((stmt->next != NULL) && (included.errorCount < 1))
443     {
444         IncludeStmt *next;
445         unsigned op;
446         CompatInfo next_incl;
447
448         for (next = stmt->next; next != NULL; next = next->next)
449         {
450             if ((next->file == NULL) && (next->map == NULL))
451             {
452                 haveSelf = True;
453                 MergeIncludedCompatMaps(&included, info, next->merge);
454                 ClearCompatInfo(info, xkb);
455             }
456             else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
457             {
458                 InitCompatInfo(&next_incl, xkb);
459                 next_incl.fileID = rtrn->id;
460                 next_incl.dflt = info->dflt;
461                 next_incl.dflt.defs.fileID = rtrn->id;
462                 next_incl.dflt.defs.merge = op;
463                 next_incl.ledDflt.defs.fileID = rtrn->id;
464                 next_incl.ledDflt.defs.merge = op;
465                 next_incl.act = info->act;
466                 (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
467                 MergeIncludedCompatMaps(&included, &next_incl, op);
468                 ClearCompatInfo(&next_incl, xkb);
469             }
470             else
471             {
472                 info->errorCount += 10;
473                 return False;
474             }
475         }
476     }
477     if (haveSelf)
478         *info = included;
479     else
480     {
481         MergeIncludedCompatMaps(info, &included, newMerge);
482         ClearCompatInfo(&included, xkb);
483     }
484     return (info->errorCount == 0);
485 }
486
487 static LookupEntry useModMapValues[] = {
488     {"levelone", 1},
489     {"level1", 1},
490     {"anylevel", 0},
491     {"any", 0},
492     {NULL, 0}
493 };
494
495 static int
496 SetInterpField(SymInterpInfo * si,
497                struct xkb_desc * xkb,
498                char *field,
499                ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
500 {
501     int ok = 1;
502     ExprResult tmp;
503
504     if (uStrCaseCmp(field, "action") == 0)
505     {
506         if (arrayNdx != NULL)
507             return ReportSINotArray(si, field, info);
508         ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
509                              info->act);
510         if (ok)
511             si->defs.defined |= _SI_Action;
512     }
513     else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
514              (uStrCaseCmp(field, "virtualmod") == 0))
515     {
516         if (arrayNdx != NULL)
517             return ReportSINotArray(si, field, info);
518         ok = ResolveVirtualModifier(value, xkb, &tmp, &info->vmods);
519         if (ok)
520         {
521             si->interp.virtual_mod = tmp.uval;
522             si->defs.defined |= _SI_VirtualMod;
523         }
524         else
525             return ReportSIBadType(si, field, "virtual modifier", info);
526     }
527     else if (uStrCaseCmp(field, "repeat") == 0)
528     {
529         if (arrayNdx != NULL)
530             return ReportSINotArray(si, field, info);
531         ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
532         if (ok)
533         {
534             if (tmp.uval)
535                 si->interp.flags |= XkbSI_AutoRepeat;
536             else
537                 si->interp.flags &= ~XkbSI_AutoRepeat;
538             si->defs.defined |= _SI_AutoRepeat;
539         }
540         else
541             return ReportSIBadType(si, field, "boolean", info);
542     }
543     else if (uStrCaseCmp(field, "locking") == 0)
544     {
545         if (arrayNdx != NULL)
546             return ReportSINotArray(si, field, info);
547         ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
548         if (ok)
549         {
550             if (tmp.uval)
551                 si->interp.flags |= XkbSI_LockingKey;
552             else
553                 si->interp.flags &= ~XkbSI_LockingKey;
554             si->defs.defined |= _SI_LockingKey;
555         }
556         else
557             return ReportSIBadType(si, field, "boolean", info);
558     }
559     else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
560              (uStrCaseCmp(field, "usemodmapmods") == 0))
561     {
562         if (arrayNdx != NULL)
563             return ReportSINotArray(si, field, info);
564         ok = ExprResolveEnum(value, &tmp, useModMapValues);
565         if (ok)
566         {
567             if (tmp.uval)
568                 si->interp.match |= XkbSI_LevelOneOnly;
569             else
570                 si->interp.match &= ~XkbSI_LevelOneOnly;
571             si->defs.defined |= _SI_LevelOneOnly;
572         }
573         else
574             return ReportSIBadType(si, field, "level specification", info);
575     }
576     else
577     {
578         ok = ReportBadField("symbol interpretation", field, siText(si, info));
579     }
580     return ok;
581 }
582
583 LookupEntry groupNames[] = {
584     {"group1", 0x01}
585     ,
586     {"group2", 0x02}
587     ,
588     {"group3", 0x04}
589     ,
590     {"group4", 0x08}
591     ,
592     {"group5", 0x10}
593     ,
594     {"group6", 0x20}
595     ,
596     {"group7", 0x40}
597     ,
598     {"group8", 0x80}
599     ,
600     {"none", 0x00}
601     ,
602     {"all", 0xff}
603     ,
604     {NULL, 0}
605 };
606
607 static int
608 HandleInterpVar(VarDef * stmt, struct xkb_desc * xkb, CompatInfo * info)
609 {
610     ExprResult elem, field;
611     ExprDef *ndx;
612     int ret;
613
614     if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
615         ret = 0;               /* internal error, already reported */
616     else if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
617         ret = SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
618                               info);
619     else if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
620         ret = SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
621                                   stmt->value);
622     else
623         ret = SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
624                             &info->act);
625     free(elem.str);
626     free(field.str);
627     return ret;
628 }
629
630 static int
631 HandleInterpBody(VarDef * def, struct xkb_desc * xkb, SymInterpInfo * si,
632                  CompatInfo * info)
633 {
634     int ok = 1;
635     ExprResult tmp, field;
636     ExprDef *arrayNdx;
637
638     for (; def != NULL; def = (VarDef *) def->common.next)
639     {
640         if ((def->name) && (def->name->type == ExprFieldRef))
641         {
642             ok = HandleInterpVar(def, xkb, info);
643             continue;
644         }
645         ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
646         if (ok) {
647             ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
648                                 info);
649             free(field.str);
650         }
651     }
652     return ok;
653 }
654
655 static int
656 HandleInterpDef(InterpDef * def, struct xkb_desc * xkb, unsigned merge,
657                 CompatInfo * info)
658 {
659     unsigned pred, mods;
660     SymInterpInfo si;
661
662     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
663     {
664         ERROR("Couldn't determine matching modifiers\n");
665         ACTION("Symbol interpretation ignored\n");
666         return False;
667     }
668     if (def->merge != MergeDefault)
669         merge = def->merge;
670
671     si = info->dflt;
672     si.defs.merge = merge;
673     if (!LookupKeysym(def->sym, &si.interp.sym))
674     {
675         WARN("Could not resolve keysym %s\n", def->sym);
676         info->errorCount++;
677         return False;
678     }
679     si.interp.match = pred & XkbSI_OpMask;
680     si.interp.mods = mods;
681     if (!HandleInterpBody(def->def, xkb, &si, info))
682     {
683         info->errorCount++;
684         return False;
685     }
686
687     if (!AddInterp(info, &si))
688     {
689         info->errorCount++;
690         return False;
691     }
692     return True;
693 }
694
695 static int
696 HandleGroupCompatDef(GroupCompatDef * def,
697                      struct xkb_desc * xkb, unsigned merge, CompatInfo * info)
698 {
699     ExprResult val;
700     GroupCompatInfo tmp;
701
702     if (def->merge != MergeDefault)
703         merge = def->merge;
704     if (!XkbIsLegalGroup(def->group - 1))
705     {
706         ERROR("Keyboard group must be in the range 1..%d\n",
707                XkbNumKbdGroups + 1);
708         ACTION("Compatibility map for illegal group %d ignored\n",
709                 def->group);
710         return False;
711     }
712     tmp.fileID = info->fileID;
713     tmp.merge = merge;
714     if (!ExprResolveVModMask(def->def, &val, xkb))
715     {
716         ERROR("Expected a modifier mask in group compatibility definition\n");
717         ACTION("Ignoring illegal compatibility map for group %d\n",
718                 def->group);
719         return False;
720     }
721     tmp.real_mods = val.uval & 0xff;
722     tmp.vmods = (val.uval >> 8) & 0xffff;
723     return AddGroupCompat(info, def->group - 1, &tmp);
724 }
725
726 static void
727 HandleCompatMapFile(XkbFile * file,
728                     struct xkb_desc * xkb, unsigned merge, CompatInfo * info)
729 {
730     ParseCommon *stmt;
731
732     if (merge == MergeDefault)
733         merge = MergeAugment;
734     info->name = _XkbDupString(file->name);
735     stmt = file->defs;
736     while (stmt)
737     {
738         switch (stmt->stmtType)
739         {
740         case StmtInclude:
741             if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
742                                         HandleCompatMapFile))
743                 info->errorCount++;
744             break;
745         case StmtInterpDef:
746             if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
747                 info->errorCount++;
748             break;
749         case StmtGroupCompatDef:
750             if (!HandleGroupCompatDef
751                 ((GroupCompatDef *) stmt, xkb, merge, info))
752                 info->errorCount++;
753             break;
754         case StmtIndicatorMapDef:
755         {
756             LEDInfo *rtrn;
757             rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
758                                          &info->ledDflt, info->leds, merge);
759             if (rtrn != NULL)
760                 info->leds = rtrn;
761             else
762                 info->errorCount++;
763         }
764             break;
765         case StmtVarDef:
766             if (!HandleInterpVar((VarDef *) stmt, xkb, info))
767                 info->errorCount++;
768             break;
769         case StmtVModDef:
770             if (!HandleVModDef((VModDef *) stmt, xkb, merge, &info->vmods))
771                 info->errorCount++;
772             break;
773         case StmtKeycodeDef:
774             ERROR("Interpretation files may not include other types\n");
775             ACTION("Ignoring definition of key name\n");
776             info->errorCount++;
777             break;
778         default:
779             WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
780                   stmt->stmtType);
781             break;
782         }
783         stmt = stmt->next;
784         if (info->errorCount > 10)
785         {
786 #ifdef NOISY
787             ERROR("Too many errors\n");
788 #endif
789             ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
790             break;
791         }
792     }
793     return;
794 }
795
796 static void
797 CopyInterps(CompatInfo * info,
798             struct xkb_compat_map * compat, Bool needSymbol, unsigned pred)
799 {
800     SymInterpInfo *si;
801
802     for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
803     {
804         if (((si->interp.match & XkbSI_OpMask) != pred) ||
805             (needSymbol && (si->interp.sym == NoSymbol)) ||
806             ((!needSymbol) && (si->interp.sym != NoSymbol)))
807             continue;
808         if (compat->num_si >= compat->size_si)
809         {
810             WSGO("No room to merge symbol interpretations\n");
811             ACTION("Symbol interpretations lost\n");
812             return;
813         }
814         compat->sym_interpret[compat->num_si++] = si->interp;
815     }
816     return;
817 }
818
819 Bool
820 CompileCompatMap(XkbFile *file, struct xkb_desc * xkb, unsigned merge,
821                  LEDInfoPtr *unboundLEDs)
822 {
823     int i;
824     CompatInfo info;
825     GroupCompatInfo *gcm;
826
827     InitCompatInfo(&info, xkb);
828     info.dflt.defs.merge = merge;
829     info.ledDflt.defs.merge = merge;
830     HandleCompatMapFile(file, xkb, merge, &info);
831
832     if (info.errorCount == 0)
833     {
834         int size;
835         if (XkbcAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
836             Success)
837         {
838             WSGO("Couldn't allocate compatibility map\n");
839             return False;
840         }
841         if (info.name != NULL)
842         {
843             if (XkbcAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
844                 xkb->names->compat =
845                     xkb_intern_atom(info.name);
846             else
847             {
848                 WSGO("Couldn't allocate space for compat name\n");
849                 ACTION("Name \"%s\" (from %s) NOT assigned\n",
850                         scanFile, info.name);
851             }
852         }
853         size = info.nInterps * sizeof(struct xkb_sym_interpret);
854         if (size > 0)
855         {
856             CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
857             CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
858             CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
859             CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
860             CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
861             CopyInterps(&info, xkb->compat, False,
862                         XkbSI_AllOf | XkbSI_NoneOf);
863             CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
864             CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
865         }
866         for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
867              i++, gcm++)
868         {
869             if ((gcm->fileID != 0) || (gcm->real_mods != 0)
870                 || (gcm->vmods != 0))
871             {
872                 xkb->compat->groups[i].mask = gcm->real_mods;
873                 xkb->compat->groups[i].real_mods = gcm->real_mods;
874                 xkb->compat->groups[i].vmods = gcm->vmods;
875             }
876         }
877         if (info.leds != NULL)
878         {
879             if (!CopyIndicatorMapDefs(xkb, info.leds, unboundLEDs))
880                 info.errorCount++;
881             info.leds = NULL;
882         }
883         ClearCompatInfo(&info, xkb);
884         return True;
885     }
886     if (info.interps != NULL)
887         free(info.interps);
888     return False;
889 }