compat.c revision a57d84fe
1f46a6179Smrg/************************************************************
2f46a6179Smrg Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3f46a6179Smrg
4f46a6179Smrg Permission to use, copy, modify, and distribute this
5f46a6179Smrg software and its documentation for any purpose and without
6f46a6179Smrg fee is hereby granted, provided that the above copyright
7f46a6179Smrg notice appear in all copies and that both that copyright
8f46a6179Smrg notice and this permission notice appear in supporting
9bfe6082cSmrg documentation, and that the name of Silicon Graphics not be
10bfe6082cSmrg used in advertising or publicity pertaining to distribution
11f46a6179Smrg of the software without specific prior written permission.
12bfe6082cSmrg Silicon Graphics makes no representation about the suitability
13f46a6179Smrg of this software for any purpose. It is provided "as is"
14f46a6179Smrg without any express or implied warranty.
15bfe6082cSmrg
16bfe6082cSmrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17bfe6082cSmrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18f46a6179Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19bfe6082cSmrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20bfe6082cSmrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21bfe6082cSmrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22f46a6179Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23f46a6179Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
24f46a6179Smrg
25f46a6179Smrg ********************************************************/
26f46a6179Smrg
27f46a6179Smrg#include <X11/Xos.h>
28f46a6179Smrg#include "xkbcomp.h"
29f46a6179Smrg#include "tokens.h"
30f46a6179Smrg#include "expr.h"
31f46a6179Smrg#include "vmod.h"
32f46a6179Smrg#include "misc.h"
33f46a6179Smrg#include "indicators.h"
34f46a6179Smrg#include "action.h"
3534345a63Smrg#include "compat.h"
36f46a6179Smrg
3734345a63Smrgtypedef struct _SymInterpInfo
3834345a63Smrg{
3934345a63Smrg    CommonInfo defs;
4034345a63Smrg    XkbSymInterpretRec interp;
41f46a6179Smrg} SymInterpInfo;
42f46a6179Smrg
43f46a6179Smrg#define	_SI_VirtualMod		(1<<0)
44f46a6179Smrg#define	_SI_Action		(1<<1)
45f46a6179Smrg#define	_SI_AutoRepeat		(1<<2)
46f46a6179Smrg#define	_SI_LockingKey		(1<<3)
47f46a6179Smrg#define	_SI_LevelOneOnly	(1<<4)
48f46a6179Smrg
4934345a63Smrgtypedef struct _GroupCompatInfo
5034345a63Smrg{
5134345a63Smrg    unsigned char fileID;
5234345a63Smrg    unsigned char merge;
531d8c7986Smrg    Bool defined;
5434345a63Smrg    unsigned char real_mods;
5534345a63Smrg    unsigned short vmods;
56f46a6179Smrg} GroupCompatInfo;
57f46a6179Smrg
5834345a63Smrgtypedef struct _CompatInfo
5934345a63Smrg{
6034345a63Smrg    char *name;
6134345a63Smrg    unsigned fileID;
6234345a63Smrg    int errorCount;
6334345a63Smrg    int nInterps;
6434345a63Smrg    SymInterpInfo *interps;
6534345a63Smrg    SymInterpInfo dflt;
6634345a63Smrg    LEDInfo ledDflt;
6734345a63Smrg    GroupCompatInfo groupCompat[XkbNumKbdGroups];
6834345a63Smrg    LEDInfo *leds;
6934345a63Smrg    VModInfo vmods;
7034345a63Smrg    ActionInfo *act;
7134345a63Smrg    XkbDescPtr xkb;
72f46a6179Smrg} CompatInfo;
73f46a6179Smrg
74f46a6179Smrg/***====================================================================***/
75f46a6179Smrg
76f46a6179Smrg#define	ReportSINotArray(si,f,i) \
77f46a6179Smrg	ReportNotArray("symbol interpretation",(f),siText((si),(i)))
78f46a6179Smrg#define	ReportSIBadType(si,f,w,i) \
79f46a6179Smrg	ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
80f46a6179Smrg
81f46a6179Smrg/***====================================================================***/
82f46a6179Smrg
83f46a6179Smrgstatic char *
8434345a63SmrgsiText(SymInterpInfo * si, CompatInfo * info)
85f46a6179Smrg{
8634345a63Smrg    static char buf[128];
87f46a6179Smrg
8834345a63Smrg    if (si == &info->dflt)
8934345a63Smrg    {
9034345a63Smrg        snprintf(buf, sizeof(buf), "default");
91f46a6179Smrg    }
9234345a63Smrg    else
9334345a63Smrg    {
94bfe6082cSmrg        snprintf(buf, sizeof(buf), "%s+%s(%s)",
9534345a63Smrg		XkbKeysymText(si->interp.sym, XkbMessage),
9634345a63Smrg                XkbSIMatchText(si->interp.match, XkbMessage),
9734345a63Smrg                XkbModMaskText(si->interp.mods, XkbMessage));
98f46a6179Smrg    }
99f46a6179Smrg    return buf;
100f46a6179Smrg}
101f46a6179Smrg
102f46a6179Smrgstatic void
10334345a63SmrgInitCompatInfo(CompatInfo * info, XkbDescPtr xkb)
104f46a6179Smrg{
10534345a63Smrg    register int i;
10634345a63Smrg
10734345a63Smrg    info->xkb = xkb;
10834345a63Smrg    info->name = NULL;
10934345a63Smrg    info->fileID = 0;
11034345a63Smrg    info->errorCount = 0;
11134345a63Smrg    info->nInterps = 0;
11234345a63Smrg    info->interps = NULL;
11334345a63Smrg    info->act = NULL;
11434345a63Smrg    info->dflt.defs.fileID = info->fileID;
11534345a63Smrg    info->dflt.defs.defined = 0;
11634345a63Smrg    info->dflt.defs.merge = MergeOverride;
11734345a63Smrg    info->dflt.interp.flags = 0;
11834345a63Smrg    info->dflt.interp.virtual_mod = XkbNoModifier;
11934345a63Smrg    info->dflt.interp.act.type = XkbSA_NoAction;
12034345a63Smrg    for (i = 0; i < XkbAnyActionDataSize; i++)
12134345a63Smrg    {
12234345a63Smrg        info->dflt.interp.act.data[i] = 0;
12334345a63Smrg    }
12434345a63Smrg    ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
12534345a63Smrg    info->ledDflt.defs.fileID = info->fileID;
12634345a63Smrg    info->ledDflt.defs.defined = 0;
12734345a63Smrg    info->ledDflt.defs.merge = MergeOverride;
12834345a63Smrg    bzero((char *) &info->groupCompat[0],
12934345a63Smrg          XkbNumKbdGroups * sizeof(GroupCompatInfo));
13034345a63Smrg    info->leds = NULL;
13134345a63Smrg    InitVModInfo(&info->vmods, xkb);
132f46a6179Smrg    return;
133f46a6179Smrg}
134f46a6179Smrg
135f46a6179Smrgstatic void
13634345a63SmrgClearCompatInfo(CompatInfo * info, XkbDescPtr xkb)
137f46a6179Smrg{
13834345a63Smrg    register int i;
13934345a63Smrg
14034345a63Smrg    if (info->name != NULL)
14134345a63Smrg        uFree(info->name);
14234345a63Smrg    info->name = NULL;
14334345a63Smrg    info->dflt.defs.defined = 0;
14434345a63Smrg    info->dflt.defs.merge = MergeAugment;
14534345a63Smrg    info->dflt.interp.flags = 0;
14634345a63Smrg    info->dflt.interp.virtual_mod = XkbNoModifier;
14734345a63Smrg    info->dflt.interp.act.type = XkbSA_NoAction;
14834345a63Smrg    for (i = 0; i < XkbAnyActionDataSize; i++)
14934345a63Smrg    {
15034345a63Smrg        info->dflt.interp.act.data[i] = 0;
15134345a63Smrg    }
15234345a63Smrg    ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
15334345a63Smrg    info->nInterps = 0;
15434345a63Smrg    info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
15534345a63Smrg    bzero((char *) &info->groupCompat[0],
15634345a63Smrg          XkbNumKbdGroups * sizeof(GroupCompatInfo));
15734345a63Smrg    info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
158f46a6179Smrg    /* 3/30/94 (ef) -- XXX! Should free action info here */
15934345a63Smrg    ClearVModInfo(&info->vmods, xkb);
160f46a6179Smrg    return;
161f46a6179Smrg}
162f46a6179Smrg
163f46a6179Smrgstatic SymInterpInfo *
16434345a63SmrgNextInterp(CompatInfo * info)
165f46a6179Smrg{
16634345a63Smrg    SymInterpInfo *si;
167f46a6179Smrg
16834345a63Smrg    si = uTypedAlloc(SymInterpInfo);
16934345a63Smrg    if (si)
17034345a63Smrg    {
17134345a63Smrg        bzero((char *) si, sizeof(SymInterpInfo));
17234345a63Smrg        info->interps =
17334345a63Smrg            (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
17434345a63Smrg                                            (CommonInfo *) si);
17534345a63Smrg        info->nInterps++;
176f46a6179Smrg    }
177f46a6179Smrg    return si;
178f46a6179Smrg}
179f46a6179Smrg
180f46a6179Smrgstatic SymInterpInfo *
18134345a63SmrgFindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
182f46a6179Smrg{
18334345a63Smrg    SymInterpInfo *old;
18434345a63Smrg
18534345a63Smrg    for (old = info->interps; old != NULL;
18634345a63Smrg         old = (SymInterpInfo *) old->defs.next)
18734345a63Smrg    {
18834345a63Smrg        if ((old->interp.sym == new->interp.sym) &&
18934345a63Smrg            (old->interp.mods == new->interp.mods) &&
19034345a63Smrg            (old->interp.match == new->interp.match))
19134345a63Smrg        {
19234345a63Smrg            return old;
19334345a63Smrg        }
194f46a6179Smrg    }
195f46a6179Smrg    return NULL;
196f46a6179Smrg}
197f46a6179Smrg
198f46a6179Smrgstatic Bool
19934345a63SmrgAddInterp(CompatInfo * info, SymInterpInfo * new)
200f46a6179Smrg{
20134345a63Smrg    unsigned collide;
20234345a63Smrg    SymInterpInfo *old;
20334345a63Smrg
20434345a63Smrg    collide = 0;
20534345a63Smrg    old = FindMatchingInterp(info, new);
20634345a63Smrg    if (old != NULL)
20734345a63Smrg    {
20834345a63Smrg        if (new->defs.merge == MergeReplace)
20934345a63Smrg        {
21034345a63Smrg            SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
21134345a63Smrg            if (((old->defs.fileID == new->defs.fileID)
21234345a63Smrg                 && (warningLevel > 0)) || (warningLevel > 9))
21334345a63Smrg            {
214bfe6082cSmrg                WARN("Multiple definitions for \"%s\"\n", siText(new, info));
21534345a63Smrg                ACTION("Earlier interpretation ignored\n");
21634345a63Smrg            }
21734345a63Smrg            *old = *new;
21834345a63Smrg            old->defs.next = &next->defs;
21934345a63Smrg            return True;
22034345a63Smrg        }
22134345a63Smrg        if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
22234345a63Smrg        {
22334345a63Smrg            old->interp.virtual_mod = new->interp.virtual_mod;
22434345a63Smrg            old->defs.defined |= _SI_VirtualMod;
22534345a63Smrg        }
22634345a63Smrg        if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
22734345a63Smrg        {
22834345a63Smrg            old->interp.act = new->interp.act;
22934345a63Smrg            old->defs.defined |= _SI_Action;
23034345a63Smrg        }
23134345a63Smrg        if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
23234345a63Smrg        {
23334345a63Smrg            old->interp.flags &= ~XkbSI_AutoRepeat;
23434345a63Smrg            old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
23534345a63Smrg            old->defs.defined |= _SI_AutoRepeat;
23634345a63Smrg        }
23734345a63Smrg        if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
23834345a63Smrg        {
23934345a63Smrg            old->interp.flags &= ~XkbSI_LockingKey;
24034345a63Smrg            old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
24134345a63Smrg            old->defs.defined |= _SI_LockingKey;
24234345a63Smrg        }
24334345a63Smrg        if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
24434345a63Smrg        {
24534345a63Smrg            old->interp.match &= ~XkbSI_LevelOneOnly;
24634345a63Smrg            old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
24734345a63Smrg            old->defs.defined |= _SI_LevelOneOnly;
24834345a63Smrg        }
249a57d84feSmrg        if (collide && (warningLevel > 0))
25034345a63Smrg        {
251bfe6082cSmrg            WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
252bfe6082cSmrg            ACTION("Using %s definition for duplicate fields\n",
25334345a63Smrg                    (new->defs.merge != MergeAugment ? "last" : "first"));
25434345a63Smrg        }
25534345a63Smrg        return True;
25634345a63Smrg    }
25734345a63Smrg    old = new;
25834345a63Smrg    if ((new = NextInterp(info)) == NULL)
25934345a63Smrg        return False;
26034345a63Smrg    *new = *old;
26134345a63Smrg    new->defs.next = NULL;
262f46a6179Smrg    return True;
263f46a6179Smrg}
264f46a6179Smrg
265f46a6179Smrgstatic Bool
26634345a63SmrgAddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
267f46a6179Smrg{
26834345a63Smrg    GroupCompatInfo *gc;
26934345a63Smrg    unsigned merge;
27034345a63Smrg
27134345a63Smrg    merge = newGC->merge;
27234345a63Smrg    gc = &info->groupCompat[group];
27334345a63Smrg    if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
27434345a63Smrg    {
27534345a63Smrg        return True;
27634345a63Smrg    }
277c82dfdfbSmrg    if (((gc->defined && gc->fileID == newGC->fileID) && (warningLevel > 0))
27834345a63Smrg        || (warningLevel > 9))
27934345a63Smrg    {
280bfe6082cSmrg        WARN("Compat map for group %d redefined\n", group + 1);
281bfe6082cSmrg        ACTION("Using %s definition\n",
28234345a63Smrg                (merge == MergeAugment ? "old" : "new"));
28334345a63Smrg    }
2841d8c7986Smrg    if(newGC->defined && (merge != MergeAugment || !gc->defined))
2851d8c7986Smrg	*gc = *newGC;
286f46a6179Smrg    return True;
287f46a6179Smrg}
288f46a6179Smrg
289f46a6179Smrg/***====================================================================***/
290f46a6179Smrg
291f46a6179Smrgstatic Bool
29234345a63SmrgResolveStateAndPredicate(ExprDef * expr,
29334345a63Smrg                         unsigned *pred_rtrn,
29434345a63Smrg                         unsigned *mods_rtrn, CompatInfo * info)
295f46a6179Smrg{
29634345a63Smrg    ExprResult result;
29734345a63Smrg
29834345a63Smrg    if (expr == NULL)
29934345a63Smrg    {
30034345a63Smrg        *pred_rtrn = XkbSI_AnyOfOrNone;
30134345a63Smrg        *mods_rtrn = ~0;
30234345a63Smrg        return True;
30334345a63Smrg    }
30434345a63Smrg
30534345a63Smrg    *pred_rtrn = XkbSI_Exactly;
30634345a63Smrg    if (expr->op == ExprActionDecl)
30734345a63Smrg    {
30834345a63Smrg        char *pred_txt =
30934345a63Smrg            XkbAtomText(NULL, expr->value.action.name, XkbMessage);
31034345a63Smrg        if (uStrCaseCmp(pred_txt, "noneof") == 0)
31134345a63Smrg            *pred_rtrn = XkbSI_NoneOf;
31234345a63Smrg        else if (uStrCaseCmp(pred_txt, "anyofornone") == 0)
31334345a63Smrg            *pred_rtrn = XkbSI_AnyOfOrNone;
31434345a63Smrg        else if (uStrCaseCmp(pred_txt, "anyof") == 0)
31534345a63Smrg            *pred_rtrn = XkbSI_AnyOf;
31634345a63Smrg        else if (uStrCaseCmp(pred_txt, "allof") == 0)
31734345a63Smrg            *pred_rtrn = XkbSI_AllOf;
31834345a63Smrg        else if (uStrCaseCmp(pred_txt, "exactly") == 0)
31934345a63Smrg            *pred_rtrn = XkbSI_Exactly;
32034345a63Smrg        else
32134345a63Smrg        {
322bfe6082cSmrg            ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
32334345a63Smrg            ACTION("Ignored\n");
32434345a63Smrg            return False;
32534345a63Smrg        }
32634345a63Smrg        expr = expr->value.action.args;
32734345a63Smrg    }
32834345a63Smrg    else if (expr->op == ExprIdent)
32934345a63Smrg    {
33034345a63Smrg        char *pred_txt = XkbAtomText(NULL, expr->value.str, XkbMessage);
33134345a63Smrg        if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0))
33234345a63Smrg        {
33334345a63Smrg            *pred_rtrn = XkbSI_AnyOf;
33434345a63Smrg            *mods_rtrn = 0xff;
33534345a63Smrg            return True;
33634345a63Smrg        }
33734345a63Smrg    }
33834345a63Smrg
33934345a63Smrg    if (ExprResolveModMask(expr, &result, NULL, NULL))
34034345a63Smrg    {
34134345a63Smrg        *mods_rtrn = result.uval;
34234345a63Smrg        return True;
343f46a6179Smrg    }
344f46a6179Smrg    return False;
345f46a6179Smrg}
346f46a6179Smrg
347f46a6179Smrg/***====================================================================***/
348f46a6179Smrg
349f46a6179Smrgstatic void
35034345a63SmrgMergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
351f46a6179Smrg{
35234345a63Smrg    SymInterpInfo *si;
35334345a63Smrg    LEDInfo *led, *rtrn, *next;
35434345a63Smrg    GroupCompatInfo *gcm;
35534345a63Smrg    register int i;
35634345a63Smrg
35734345a63Smrg    if (from->errorCount > 0)
35834345a63Smrg    {
35934345a63Smrg        into->errorCount += from->errorCount;
36034345a63Smrg        return;
36134345a63Smrg    }
36234345a63Smrg    if (into->name == NULL)
36334345a63Smrg    {
36434345a63Smrg        into->name = from->name;
36534345a63Smrg        from->name = NULL;
36634345a63Smrg    }
36734345a63Smrg    for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
36834345a63Smrg    {
36934345a63Smrg        if (merge != MergeDefault)
37034345a63Smrg            si->defs.merge = merge;
37134345a63Smrg        if (!AddInterp(into, si))
37234345a63Smrg            into->errorCount++;
37334345a63Smrg    }
37434345a63Smrg    for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
37534345a63Smrg    {
37634345a63Smrg        if (merge != MergeDefault)
37734345a63Smrg            gcm->merge = merge;
37834345a63Smrg        if (!AddGroupCompat(into, i, gcm))
37934345a63Smrg            into->errorCount++;
38034345a63Smrg    }
38134345a63Smrg    for (led = from->leds; led != NULL; led = next)
38234345a63Smrg    {
38334345a63Smrg        next = (LEDInfo *) led->defs.next;
38434345a63Smrg        if (merge != MergeDefault)
38534345a63Smrg            led->defs.merge = merge;
38634345a63Smrg        rtrn = AddIndicatorMap(into->leds, led);
38734345a63Smrg        if (rtrn != NULL)
38834345a63Smrg            into->leds = rtrn;
38934345a63Smrg        else
39034345a63Smrg            into->errorCount++;
391f46a6179Smrg    }
392f46a6179Smrg    return;
393f46a6179Smrg}
394f46a6179Smrg
39534345a63Smrgtypedef void (*FileHandler) (XkbFile * /* rtrn */ ,
39634345a63Smrg                             XkbDescPtr /* xkb */ ,
39734345a63Smrg                             unsigned /* merge */ ,
39834345a63Smrg                             CompatInfo *       /* info */
39934345a63Smrg    );
400f46a6179Smrg
401f46a6179Smrgstatic Bool
40234345a63SmrgHandleIncludeCompatMap(IncludeStmt * stmt,
40334345a63Smrg                       XkbDescPtr xkb, CompatInfo * info, FileHandler hndlr)
404f46a6179Smrg{
40534345a63Smrg    unsigned newMerge;
40634345a63Smrg    XkbFile *rtrn;
40734345a63Smrg    CompatInfo included;
40834345a63Smrg    Bool haveSelf;
40934345a63Smrg
41034345a63Smrg    haveSelf = False;
41134345a63Smrg    if ((stmt->file == NULL) && (stmt->map == NULL))
41234345a63Smrg    {
41334345a63Smrg        haveSelf = True;
41434345a63Smrg        included = *info;
41534345a63Smrg        bzero(info, sizeof(CompatInfo));
41634345a63Smrg    }
41734345a63Smrg    else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
41834345a63Smrg    {
41934345a63Smrg        InitCompatInfo(&included, xkb);
42034345a63Smrg        included.fileID = rtrn->id;
42134345a63Smrg        included.dflt = info->dflt;
42234345a63Smrg        included.dflt.defs.fileID = rtrn->id;
42334345a63Smrg        included.dflt.defs.merge = newMerge;
42434345a63Smrg        included.ledDflt.defs.fileID = rtrn->id;
42534345a63Smrg        included.ledDflt.defs.merge = newMerge;
42634345a63Smrg        included.act = info->act;
42734345a63Smrg        (*hndlr) (rtrn, xkb, MergeOverride, &included);
42834345a63Smrg        if (stmt->stmt != NULL)
42934345a63Smrg        {
43034345a63Smrg            if (included.name != NULL)
43134345a63Smrg                uFree(included.name);
43234345a63Smrg            included.name = stmt->stmt;
43334345a63Smrg            stmt->stmt = NULL;
43434345a63Smrg        }
43534345a63Smrg    }
43634345a63Smrg    else
43734345a63Smrg    {
43834345a63Smrg        info->errorCount += 10;
43934345a63Smrg        return False;
44034345a63Smrg    }
44134345a63Smrg    if ((stmt->next != NULL) && (included.errorCount < 1))
44234345a63Smrg    {
44334345a63Smrg        IncludeStmt *next;
44434345a63Smrg        unsigned op;
44534345a63Smrg        CompatInfo next_incl;
44634345a63Smrg
44734345a63Smrg        for (next = stmt->next; next != NULL; next = next->next)
44834345a63Smrg        {
44934345a63Smrg            if ((next->file == NULL) && (next->map == NULL))
45034345a63Smrg            {
45134345a63Smrg                haveSelf = True;
45234345a63Smrg                MergeIncludedCompatMaps(&included, info, next->merge);
45334345a63Smrg                ClearCompatInfo(info, xkb);
45434345a63Smrg            }
45534345a63Smrg            else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
45634345a63Smrg            {
45734345a63Smrg                InitCompatInfo(&next_incl, xkb);
45834345a63Smrg                next_incl.fileID = rtrn->id;
45934345a63Smrg                next_incl.dflt = info->dflt;
46034345a63Smrg                next_incl.dflt.defs.fileID = rtrn->id;
46134345a63Smrg                next_incl.dflt.defs.merge = op;
46234345a63Smrg                next_incl.ledDflt.defs.fileID = rtrn->id;
46334345a63Smrg                next_incl.ledDflt.defs.merge = op;
46434345a63Smrg                next_incl.act = info->act;
46534345a63Smrg                (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
46634345a63Smrg                MergeIncludedCompatMaps(&included, &next_incl, op);
46734345a63Smrg                ClearCompatInfo(&next_incl, xkb);
46834345a63Smrg            }
46934345a63Smrg            else
47034345a63Smrg            {
47134345a63Smrg                info->errorCount += 10;
47234345a63Smrg                return False;
47334345a63Smrg            }
47434345a63Smrg        }
475f46a6179Smrg    }
476f46a6179Smrg    if (haveSelf)
47734345a63Smrg        *info = included;
47834345a63Smrg    else
47934345a63Smrg    {
48034345a63Smrg        MergeIncludedCompatMaps(info, &included, newMerge);
48134345a63Smrg        ClearCompatInfo(&included, xkb);
482f46a6179Smrg    }
48334345a63Smrg    return (info->errorCount == 0);
484f46a6179Smrg}
485f46a6179Smrg
486f46a6179Smrgstatic LookupEntry useModMapValues[] = {
48734345a63Smrg    {"levelone", 1},
48834345a63Smrg    {"level1", 1},
48934345a63Smrg    {"anylevel", 0},
49034345a63Smrg    {"any", 0},
49134345a63Smrg    {NULL, 0}
492f46a6179Smrg};
493f46a6179Smrg
494f46a6179Smrgstatic int
49534345a63SmrgSetInterpField(SymInterpInfo * si,
49634345a63Smrg               XkbDescPtr xkb,
497c82dfdfbSmrg               const char *field,
49834345a63Smrg               ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
499f46a6179Smrg{
50034345a63Smrg    int ok = 1;
50134345a63Smrg    ExprResult tmp;
50234345a63Smrg
50334345a63Smrg    if (uStrCaseCmp(field, "action") == 0)
50434345a63Smrg    {
50534345a63Smrg        if (arrayNdx != NULL)
50634345a63Smrg            return ReportSINotArray(si, field, info);
50734345a63Smrg        ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
50834345a63Smrg                             info->act);
50934345a63Smrg        if (ok)
51034345a63Smrg            si->defs.defined |= _SI_Action;
51134345a63Smrg    }
51234345a63Smrg    else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
51334345a63Smrg             (uStrCaseCmp(field, "virtualmod") == 0))
51434345a63Smrg    {
51534345a63Smrg        if (arrayNdx != NULL)
51634345a63Smrg            return ReportSINotArray(si, field, info);
51734345a63Smrg        ok = ResolveVirtualModifier(value, &tmp, &info->vmods);
51834345a63Smrg        if (ok)
51934345a63Smrg        {
52034345a63Smrg            si->interp.virtual_mod = tmp.uval;
52134345a63Smrg            si->defs.defined |= _SI_VirtualMod;
52234345a63Smrg        }
52334345a63Smrg        else
52434345a63Smrg            return ReportSIBadType(si, field, "virtual modifier", info);
52534345a63Smrg    }
52634345a63Smrg    else if (uStrCaseCmp(field, "repeat") == 0)
52734345a63Smrg    {
52834345a63Smrg        if (arrayNdx != NULL)
52934345a63Smrg            return ReportSINotArray(si, field, info);
53034345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
53134345a63Smrg        if (ok)
53234345a63Smrg        {
53334345a63Smrg            if (tmp.uval)
53434345a63Smrg                si->interp.flags |= XkbSI_AutoRepeat;
53534345a63Smrg            else
53634345a63Smrg                si->interp.flags &= ~XkbSI_AutoRepeat;
53734345a63Smrg            si->defs.defined |= _SI_AutoRepeat;
53834345a63Smrg        }
53934345a63Smrg        else
54034345a63Smrg            return ReportSIBadType(si, field, "boolean", info);
54134345a63Smrg    }
54234345a63Smrg    else if (uStrCaseCmp(field, "locking") == 0)
54334345a63Smrg    {
54434345a63Smrg        if (arrayNdx != NULL)
54534345a63Smrg            return ReportSINotArray(si, field, info);
54634345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
54734345a63Smrg        if (ok)
54834345a63Smrg        {
54934345a63Smrg            if (tmp.uval)
55034345a63Smrg                si->interp.flags |= XkbSI_LockingKey;
55134345a63Smrg            else
55234345a63Smrg                si->interp.flags &= ~XkbSI_LockingKey;
55334345a63Smrg            si->defs.defined |= _SI_LockingKey;
55434345a63Smrg        }
55534345a63Smrg        else
55634345a63Smrg            return ReportSIBadType(si, field, "boolean", info);
55734345a63Smrg    }
55834345a63Smrg    else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
55934345a63Smrg             (uStrCaseCmp(field, "usemodmapmods") == 0))
56034345a63Smrg    {
56134345a63Smrg        if (arrayNdx != NULL)
56234345a63Smrg            return ReportSINotArray(si, field, info);
56334345a63Smrg        ok = ExprResolveEnum(value, &tmp, useModMapValues);
56434345a63Smrg        if (ok)
56534345a63Smrg        {
56634345a63Smrg            if (tmp.uval)
56734345a63Smrg                si->interp.match |= XkbSI_LevelOneOnly;
56834345a63Smrg            else
56934345a63Smrg                si->interp.match &= ~XkbSI_LevelOneOnly;
57034345a63Smrg            si->defs.defined |= _SI_LevelOneOnly;
57134345a63Smrg        }
57234345a63Smrg        else
57334345a63Smrg            return ReportSIBadType(si, field, "level specification", info);
57434345a63Smrg    }
57534345a63Smrg    else
57634345a63Smrg    {
57734345a63Smrg        ok = ReportBadField("symbol interpretation", field, siText(si, info));
578f46a6179Smrg    }
579f46a6179Smrg    return ok;
580f46a6179Smrg}
581f46a6179Smrg
58234345a63SmrgLookupEntry groupNames[] = {
58334345a63Smrg    {"group1", 0x01}
58434345a63Smrg    ,
58534345a63Smrg    {"group2", 0x02}
58634345a63Smrg    ,
58734345a63Smrg    {"group3", 0x04}
58834345a63Smrg    ,
58934345a63Smrg    {"group4", 0x08}
59034345a63Smrg    ,
59134345a63Smrg    {"group5", 0x10}
59234345a63Smrg    ,
59334345a63Smrg    {"group6", 0x20}
59434345a63Smrg    ,
59534345a63Smrg    {"group7", 0x40}
59634345a63Smrg    ,
59734345a63Smrg    {"group8", 0x80}
59834345a63Smrg    ,
59934345a63Smrg    {"none", 0x00}
60034345a63Smrg    ,
60134345a63Smrg    {"all", 0xff}
60234345a63Smrg    ,
60334345a63Smrg    {NULL, 0}
604f46a6179Smrg};
605f46a6179Smrg
606f46a6179Smrgstatic int
60734345a63SmrgHandleInterpVar(VarDef * stmt, XkbDescPtr xkb, CompatInfo * info)
608f46a6179Smrg{
60934345a63Smrg    ExprResult elem, field;
61034345a63Smrg    ExprDef *ndx;
61134345a63Smrg
61234345a63Smrg    if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
61334345a63Smrg        return 0;               /* internal error, already reported */
61434345a63Smrg    if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
61534345a63Smrg        return SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
61634345a63Smrg                              info);
61734345a63Smrg    if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
61834345a63Smrg    {
61934345a63Smrg        return SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
62034345a63Smrg                                    stmt->value);
62134345a63Smrg    }
62234345a63Smrg    return SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
62334345a63Smrg                          &info->act);
624f46a6179Smrg}
625f46a6179Smrg
626f46a6179Smrgstatic int
62734345a63SmrgHandleInterpBody(VarDef * def, XkbDescPtr xkb, SymInterpInfo * si,
62834345a63Smrg                 CompatInfo * info)
629f46a6179Smrg{
63034345a63Smrg    int ok = 1;
63134345a63Smrg    ExprResult tmp, field;
63234345a63Smrg    ExprDef *arrayNdx;
63334345a63Smrg
63434345a63Smrg    for (; def != NULL; def = (VarDef *) def->common.next)
63534345a63Smrg    {
63634345a63Smrg        if ((def->name) && (def->name->type == ExprFieldRef))
63734345a63Smrg        {
63834345a63Smrg            ok = HandleInterpVar(def, xkb, info);
63934345a63Smrg            continue;
64034345a63Smrg        }
64134345a63Smrg        ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
64234345a63Smrg        if (ok)
64334345a63Smrg            ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
64434345a63Smrg                                info);
645f46a6179Smrg    }
646f46a6179Smrg    return ok;
647f46a6179Smrg}
648f46a6179Smrg
649f46a6179Smrgstatic int
65034345a63SmrgHandleInterpDef(InterpDef * def, XkbDescPtr xkb, unsigned merge,
65134345a63Smrg                CompatInfo * info)
652f46a6179Smrg{
65334345a63Smrg    unsigned pred, mods;
65434345a63Smrg    SymInterpInfo si;
65534345a63Smrg
65634345a63Smrg    if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
65734345a63Smrg    {
65834345a63Smrg        ERROR("Couldn't determine matching modifiers\n");
65934345a63Smrg        ACTION("Symbol interpretation ignored\n");
660690143ccSmrg        return True;
66134345a63Smrg    }
662690143ccSmrg    if (def->ignore)
663690143ccSmrg    {
664690143ccSmrg        ERROR("Couldn't lookup keysym\n");
665690143ccSmrg        ACTION("Symbol interpretation ignored\n");
666690143ccSmrg        return True;
667690143ccSmrg    }
668690143ccSmrg
66934345a63Smrg    if (def->merge != MergeDefault)
67034345a63Smrg        merge = def->merge;
67134345a63Smrg
67234345a63Smrg    si = info->dflt;
67334345a63Smrg    si.defs.merge = merge;
67434345a63Smrg    si.interp.sym = def->sym;
67534345a63Smrg    si.interp.match = pred & XkbSI_OpMask;
67634345a63Smrg    si.interp.mods = mods;
67734345a63Smrg    if (!HandleInterpBody(def->def, xkb, &si, info))
67834345a63Smrg    {
67934345a63Smrg        info->errorCount++;
68034345a63Smrg        return False;
68134345a63Smrg    }
68234345a63Smrg
68334345a63Smrg    if (!AddInterp(info, &si))
68434345a63Smrg    {
68534345a63Smrg        info->errorCount++;
68634345a63Smrg        return False;
687f46a6179Smrg    }
688f46a6179Smrg    return True;
689f46a6179Smrg}
690f46a6179Smrg
691f46a6179Smrgstatic int
69234345a63SmrgHandleGroupCompatDef(GroupCompatDef * def,
69334345a63Smrg                     XkbDescPtr xkb, unsigned merge, CompatInfo * info)
694f46a6179Smrg{
69534345a63Smrg    ExprResult val;
69634345a63Smrg    GroupCompatInfo tmp;
69734345a63Smrg
69834345a63Smrg    if (def->merge != MergeDefault)
69934345a63Smrg        merge = def->merge;
70034345a63Smrg    if (!XkbIsLegalGroup(def->group - 1))
70134345a63Smrg    {
702bfe6082cSmrg        ERROR("Keyboard group must be in the range 1..%d\n",
70334345a63Smrg               XkbNumKbdGroups + 1);
704bfe6082cSmrg        ACTION("Compatibility map for illegal group %d ignored\n",
70534345a63Smrg                def->group);
70634345a63Smrg        return False;
70734345a63Smrg    }
70834345a63Smrg    tmp.fileID = info->fileID;
70934345a63Smrg    tmp.merge = merge;
71034345a63Smrg    if (!ExprResolveModMask(def->def, &val, LookupVModMask, (XPointer) xkb))
71134345a63Smrg    {
71234345a63Smrg        ERROR("Expected a modifier mask in group compatibility definition\n");
713bfe6082cSmrg        ACTION("Ignoring illegal compatibility map for group %d\n",
71434345a63Smrg                def->group);
71534345a63Smrg        return False;
71634345a63Smrg    }
71734345a63Smrg    tmp.real_mods = val.uval & 0xff;
71834345a63Smrg    tmp.vmods = (val.uval >> 8) & 0xffff;
7191d8c7986Smrg    tmp.defined = True;
72034345a63Smrg    return AddGroupCompat(info, def->group - 1, &tmp);
721f46a6179Smrg}
722f46a6179Smrg
723f46a6179Smrgstatic void
72434345a63SmrgHandleCompatMapFile(XkbFile * file,
72534345a63Smrg                    XkbDescPtr xkb, unsigned merge, CompatInfo * info)
726f46a6179Smrg{
72734345a63Smrg    ParseCommon *stmt;
72834345a63Smrg
72934345a63Smrg    if (merge == MergeDefault)
73034345a63Smrg        merge = MergeAugment;
73134345a63Smrg    info->name = uStringDup(file->name);
73234345a63Smrg    stmt = file->defs;
73334345a63Smrg    while (stmt)
73434345a63Smrg    {
73534345a63Smrg        switch (stmt->stmtType)
73634345a63Smrg        {
73734345a63Smrg        case StmtInclude:
73834345a63Smrg            if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
73934345a63Smrg                                        HandleCompatMapFile))
74034345a63Smrg                info->errorCount++;
74134345a63Smrg            break;
74234345a63Smrg        case StmtInterpDef:
74334345a63Smrg            if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
74434345a63Smrg                info->errorCount++;
74534345a63Smrg            break;
74634345a63Smrg        case StmtGroupCompatDef:
74734345a63Smrg            if (!HandleGroupCompatDef
74834345a63Smrg                ((GroupCompatDef *) stmt, xkb, merge, info))
74934345a63Smrg                info->errorCount++;
75034345a63Smrg            break;
75134345a63Smrg        case StmtIndicatorMapDef:
75234345a63Smrg        {
75334345a63Smrg            LEDInfo *rtrn;
75434345a63Smrg            rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
75534345a63Smrg                                         &info->ledDflt, info->leds, merge);
75634345a63Smrg            if (rtrn != NULL)
75734345a63Smrg                info->leds = rtrn;
75834345a63Smrg            else
75934345a63Smrg                info->errorCount++;
76034345a63Smrg        }
76134345a63Smrg            break;
76234345a63Smrg        case StmtVarDef:
76334345a63Smrg            if (!HandleInterpVar((VarDef *) stmt, xkb, info))
76434345a63Smrg                info->errorCount++;
76534345a63Smrg            break;
76634345a63Smrg        case StmtVModDef:
76734345a63Smrg            if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
76834345a63Smrg                info->errorCount++;
76934345a63Smrg            break;
77034345a63Smrg        case StmtKeycodeDef:
77134345a63Smrg            ERROR("Interpretation files may not include other types\n");
77234345a63Smrg            ACTION("Ignoring definition of key name\n");
77334345a63Smrg            info->errorCount++;
77434345a63Smrg            break;
77534345a63Smrg        default:
776bfe6082cSmrg            WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
77734345a63Smrg                  stmt->stmtType);
77834345a63Smrg            break;
77934345a63Smrg        }
78034345a63Smrg        stmt = stmt->next;
78134345a63Smrg        if (info->errorCount > 10)
78234345a63Smrg        {
783f46a6179Smrg#ifdef NOISY
78434345a63Smrg            ERROR("Too many errors\n");
785f46a6179Smrg#endif
786bfe6082cSmrg            ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
78734345a63Smrg            break;
78834345a63Smrg        }
789f46a6179Smrg    }
790f46a6179Smrg    return;
791f46a6179Smrg}
792f46a6179Smrg
793f46a6179Smrgstatic void
79434345a63SmrgCopyInterps(CompatInfo * info,
79534345a63Smrg            XkbCompatMapPtr compat, Bool needSymbol, unsigned pred)
796f46a6179Smrg{
79734345a63Smrg    SymInterpInfo *si;
79834345a63Smrg
79934345a63Smrg    for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
80034345a63Smrg    {
80134345a63Smrg        if (((si->interp.match & XkbSI_OpMask) != pred) ||
80234345a63Smrg            (needSymbol && (si->interp.sym == NoSymbol)) ||
80334345a63Smrg            ((!needSymbol) && (si->interp.sym != NoSymbol)))
80434345a63Smrg            continue;
80534345a63Smrg        if (compat->num_si >= compat->size_si)
80634345a63Smrg        {
80734345a63Smrg            WSGO("No room to merge symbol interpretations\n");
80834345a63Smrg            ACTION("Symbol interpretations lost\n");
80934345a63Smrg            return;
81034345a63Smrg        }
81134345a63Smrg        compat->sym_interpret[compat->num_si++] = si->interp;
812f46a6179Smrg    }
813f46a6179Smrg    return;
814f46a6179Smrg}
815f46a6179Smrg
816f46a6179SmrgBool
81734345a63SmrgCompileCompatMap(XkbFile * file,
81834345a63Smrg                 XkbFileInfo * result, unsigned merge, LEDInfo ** unboundLEDs)
819f46a6179Smrg{
82034345a63Smrg    int i;
82134345a63Smrg    CompatInfo info;
82234345a63Smrg    XkbDescPtr xkb;
82334345a63Smrg    GroupCompatInfo *gcm;
82434345a63Smrg
82534345a63Smrg    xkb = result->xkb;
82634345a63Smrg    InitCompatInfo(&info, xkb);
82734345a63Smrg    info.dflt.defs.merge = merge;
82834345a63Smrg    info.ledDflt.defs.merge = merge;
82934345a63Smrg    HandleCompatMapFile(file, xkb, merge, &info);
83034345a63Smrg
83134345a63Smrg    if (info.errorCount == 0)
83234345a63Smrg    {
83334345a63Smrg        int size;
83434345a63Smrg        if (XkbAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
83534345a63Smrg            Success)
83634345a63Smrg        {
83734345a63Smrg            WSGO("Couldn't allocate compatibility map\n");
83834345a63Smrg            ACTION("Exiting\n");
83934345a63Smrg            return False;
84034345a63Smrg        }
84134345a63Smrg        if (info.name != NULL)
84234345a63Smrg        {
84334345a63Smrg            if (XkbAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
84434345a63Smrg                xkb->names->compat =
84534345a63Smrg                    XkbInternAtom(xkb->dpy, info.name, False);
84634345a63Smrg            else
84734345a63Smrg            {
84834345a63Smrg                WSGO("Couldn't allocate space for compat name\n");
849bfe6082cSmrg                ACTION("Name \"%s\" (from %s) NOT assigned\n",
85034345a63Smrg                        scanFile, info.name);
85134345a63Smrg            }
85234345a63Smrg        }
85334345a63Smrg        size = info.nInterps * sizeof(XkbSymInterpretRec);
85434345a63Smrg        if (size > 0)
85534345a63Smrg        {
85634345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
85734345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
85834345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
85934345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
86034345a63Smrg            CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
86134345a63Smrg            CopyInterps(&info, xkb->compat, False,
86234345a63Smrg                        XkbSI_AllOf | XkbSI_NoneOf);
86334345a63Smrg            CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
86434345a63Smrg            CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
86534345a63Smrg        }
86634345a63Smrg        for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
86734345a63Smrg             i++, gcm++)
86834345a63Smrg        {
86934345a63Smrg            if ((gcm->fileID != 0) || (gcm->real_mods != 0)
87034345a63Smrg                || (gcm->vmods != 0))
87134345a63Smrg            {
87234345a63Smrg                xkb->compat->groups[i].mask = gcm->real_mods;
87334345a63Smrg                xkb->compat->groups[i].real_mods = gcm->real_mods;
87434345a63Smrg                xkb->compat->groups[i].vmods = gcm->vmods;
87534345a63Smrg            }
87634345a63Smrg        }
87734345a63Smrg        if (info.leds != NULL)
87834345a63Smrg        {
87934345a63Smrg            if (!CopyIndicatorMapDefs(result, info.leds, unboundLEDs))
88034345a63Smrg                info.errorCount++;
88134345a63Smrg            info.leds = NULL;
88234345a63Smrg        }
88334345a63Smrg        ClearCompatInfo(&info, xkb);
88434345a63Smrg        return True;
88534345a63Smrg    }
88634345a63Smrg    if (info.interps != NULL)
88734345a63Smrg        uFree(info.interps);
888f46a6179Smrg    return False;
889f46a6179Smrg}
890