compat.c revision 690143cc
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
9f46a6179Smrg documentation, and that the name of Silicon Graphics not be
10f46a6179Smrg used in advertising or publicity pertaining to distribution
11f46a6179Smrg of the software without specific prior written permission.
12f46a6179Smrg 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.
15f46a6179Smrg
16f46a6179Smrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17f46a6179Smrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18f46a6179Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19f46a6179Smrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20f46a6179Smrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21f46a6179Smrg 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;
5334345a63Smrg    unsigned char real_mods;
5434345a63Smrg    unsigned short vmods;
55f46a6179Smrg} GroupCompatInfo;
56f46a6179Smrg
5734345a63Smrgtypedef struct _CompatInfo
5834345a63Smrg{
5934345a63Smrg    char *name;
6034345a63Smrg    unsigned fileID;
6134345a63Smrg    int errorCount;
6234345a63Smrg    int nInterps;
6334345a63Smrg    SymInterpInfo *interps;
6434345a63Smrg    SymInterpInfo dflt;
6534345a63Smrg    LEDInfo ledDflt;
6634345a63Smrg    GroupCompatInfo groupCompat[XkbNumKbdGroups];
6734345a63Smrg    LEDInfo *leds;
6834345a63Smrg    VModInfo vmods;
6934345a63Smrg    ActionInfo *act;
7034345a63Smrg    XkbDescPtr xkb;
71f46a6179Smrg} CompatInfo;
72f46a6179Smrg
73f46a6179Smrg/***====================================================================***/
74f46a6179Smrg
75f46a6179Smrg#define	ReportSINotArray(si,f,i) \
76f46a6179Smrg	ReportNotArray("symbol interpretation",(f),siText((si),(i)))
77f46a6179Smrg#define	ReportSIBadType(si,f,w,i) \
78f46a6179Smrg	ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
79f46a6179Smrg
80f46a6179Smrg/***====================================================================***/
81f46a6179Smrg
82f46a6179Smrgstatic char *
8334345a63SmrgsiText(SymInterpInfo * si, CompatInfo * info)
84f46a6179Smrg{
8534345a63Smrg    static char buf[128];
86f46a6179Smrg
8734345a63Smrg    if (si == &info->dflt)
8834345a63Smrg    {
8934345a63Smrg        snprintf(buf, sizeof(buf), "default");
90f46a6179Smrg    }
9134345a63Smrg    else
9234345a63Smrg    {
9334345a63Smrg        snprintf(buf, sizeof(buf), "%s+%s(%s)",
9434345a63Smrg		XkbKeysymText(si->interp.sym, XkbMessage),
9534345a63Smrg                XkbSIMatchText(si->interp.match, XkbMessage),
9634345a63Smrg                XkbModMaskText(si->interp.mods, XkbMessage));
97f46a6179Smrg    }
98f46a6179Smrg    return buf;
99f46a6179Smrg}
100f46a6179Smrg
101f46a6179Smrgstatic void
10234345a63SmrgInitCompatInfo(CompatInfo * info, XkbDescPtr xkb)
103f46a6179Smrg{
10434345a63Smrg    register int i;
10534345a63Smrg
10634345a63Smrg    info->xkb = xkb;
10734345a63Smrg    info->name = NULL;
10834345a63Smrg    info->fileID = 0;
10934345a63Smrg    info->errorCount = 0;
11034345a63Smrg    info->nInterps = 0;
11134345a63Smrg    info->interps = NULL;
11234345a63Smrg    info->act = NULL;
11334345a63Smrg    info->dflt.defs.fileID = info->fileID;
11434345a63Smrg    info->dflt.defs.defined = 0;
11534345a63Smrg    info->dflt.defs.merge = MergeOverride;
11634345a63Smrg    info->dflt.interp.flags = 0;
11734345a63Smrg    info->dflt.interp.virtual_mod = XkbNoModifier;
11834345a63Smrg    info->dflt.interp.act.type = XkbSA_NoAction;
11934345a63Smrg    for (i = 0; i < XkbAnyActionDataSize; i++)
12034345a63Smrg    {
12134345a63Smrg        info->dflt.interp.act.data[i] = 0;
12234345a63Smrg    }
12334345a63Smrg    ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
12434345a63Smrg    info->ledDflt.defs.fileID = info->fileID;
12534345a63Smrg    info->ledDflt.defs.defined = 0;
12634345a63Smrg    info->ledDflt.defs.merge = MergeOverride;
12734345a63Smrg    bzero((char *) &info->groupCompat[0],
12834345a63Smrg          XkbNumKbdGroups * sizeof(GroupCompatInfo));
12934345a63Smrg    info->leds = NULL;
13034345a63Smrg    InitVModInfo(&info->vmods, xkb);
131f46a6179Smrg    return;
132f46a6179Smrg}
133f46a6179Smrg
134f46a6179Smrgstatic void
13534345a63SmrgClearCompatInfo(CompatInfo * info, XkbDescPtr xkb)
136f46a6179Smrg{
13734345a63Smrg    register int i;
13834345a63Smrg
13934345a63Smrg    if (info->name != NULL)
14034345a63Smrg        uFree(info->name);
14134345a63Smrg    info->name = NULL;
14234345a63Smrg    info->dflt.defs.defined = 0;
14334345a63Smrg    info->dflt.defs.merge = MergeAugment;
14434345a63Smrg    info->dflt.interp.flags = 0;
14534345a63Smrg    info->dflt.interp.virtual_mod = XkbNoModifier;
14634345a63Smrg    info->dflt.interp.act.type = XkbSA_NoAction;
14734345a63Smrg    for (i = 0; i < XkbAnyActionDataSize; i++)
14834345a63Smrg    {
14934345a63Smrg        info->dflt.interp.act.data[i] = 0;
15034345a63Smrg    }
15134345a63Smrg    ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
15234345a63Smrg    info->nInterps = 0;
15334345a63Smrg    info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
15434345a63Smrg    bzero((char *) &info->groupCompat[0],
15534345a63Smrg          XkbNumKbdGroups * sizeof(GroupCompatInfo));
15634345a63Smrg    info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
157f46a6179Smrg    /* 3/30/94 (ef) -- XXX! Should free action info here */
15834345a63Smrg    ClearVModInfo(&info->vmods, xkb);
159f46a6179Smrg    return;
160f46a6179Smrg}
161f46a6179Smrg
162f46a6179Smrgstatic SymInterpInfo *
16334345a63SmrgNextInterp(CompatInfo * info)
164f46a6179Smrg{
16534345a63Smrg    SymInterpInfo *si;
166f46a6179Smrg
16734345a63Smrg    si = uTypedAlloc(SymInterpInfo);
16834345a63Smrg    if (si)
16934345a63Smrg    {
17034345a63Smrg        bzero((char *) si, sizeof(SymInterpInfo));
17134345a63Smrg        info->interps =
17234345a63Smrg            (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
17334345a63Smrg                                            (CommonInfo *) si);
17434345a63Smrg        info->nInterps++;
175f46a6179Smrg    }
176f46a6179Smrg    return si;
177f46a6179Smrg}
178f46a6179Smrg
179f46a6179Smrgstatic SymInterpInfo *
18034345a63SmrgFindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
181f46a6179Smrg{
18234345a63Smrg    SymInterpInfo *old;
18334345a63Smrg
18434345a63Smrg    for (old = info->interps; old != NULL;
18534345a63Smrg         old = (SymInterpInfo *) old->defs.next)
18634345a63Smrg    {
18734345a63Smrg        if ((old->interp.sym == new->interp.sym) &&
18834345a63Smrg            (old->interp.mods == new->interp.mods) &&
18934345a63Smrg            (old->interp.match == new->interp.match))
19034345a63Smrg        {
19134345a63Smrg            return old;
19234345a63Smrg        }
193f46a6179Smrg    }
194f46a6179Smrg    return NULL;
195f46a6179Smrg}
196f46a6179Smrg
197f46a6179Smrgstatic Bool
19834345a63SmrgAddInterp(CompatInfo * info, SymInterpInfo * new)
199f46a6179Smrg{
20034345a63Smrg    unsigned collide;
20134345a63Smrg    SymInterpInfo *old;
20234345a63Smrg
20334345a63Smrg    collide = 0;
20434345a63Smrg    old = FindMatchingInterp(info, new);
20534345a63Smrg    if (old != NULL)
20634345a63Smrg    {
20734345a63Smrg        if (new->defs.merge == MergeReplace)
20834345a63Smrg        {
20934345a63Smrg            SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
21034345a63Smrg            if (((old->defs.fileID == new->defs.fileID)
21134345a63Smrg                 && (warningLevel > 0)) || (warningLevel > 9))
21234345a63Smrg            {
21334345a63Smrg                WARN1("Multiple definitions for \"%s\"\n", siText(new, info));
21434345a63Smrg                ACTION("Earlier interpretation ignored\n");
21534345a63Smrg            }
21634345a63Smrg            *old = *new;
21734345a63Smrg            old->defs.next = &next->defs;
21834345a63Smrg            return True;
21934345a63Smrg        }
22034345a63Smrg        if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
22134345a63Smrg        {
22234345a63Smrg            old->interp.virtual_mod = new->interp.virtual_mod;
22334345a63Smrg            old->defs.defined |= _SI_VirtualMod;
22434345a63Smrg        }
22534345a63Smrg        if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
22634345a63Smrg        {
22734345a63Smrg            old->interp.act = new->interp.act;
22834345a63Smrg            old->defs.defined |= _SI_Action;
22934345a63Smrg        }
23034345a63Smrg        if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
23134345a63Smrg        {
23234345a63Smrg            old->interp.flags &= ~XkbSI_AutoRepeat;
23334345a63Smrg            old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
23434345a63Smrg            old->defs.defined |= _SI_AutoRepeat;
23534345a63Smrg        }
23634345a63Smrg        if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
23734345a63Smrg        {
23834345a63Smrg            old->interp.flags &= ~XkbSI_LockingKey;
23934345a63Smrg            old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
24034345a63Smrg            old->defs.defined |= _SI_LockingKey;
24134345a63Smrg        }
24234345a63Smrg        if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
24334345a63Smrg        {
24434345a63Smrg            old->interp.match &= ~XkbSI_LevelOneOnly;
24534345a63Smrg            old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
24634345a63Smrg            old->defs.defined |= _SI_LevelOneOnly;
24734345a63Smrg        }
24834345a63Smrg        if (collide)
24934345a63Smrg        {
25034345a63Smrg            WARN1("Multiple interpretations of \"%s\"\n", siText(new, info));
25134345a63Smrg            ACTION1("Using %s definition for duplicate fields\n",
25234345a63Smrg                    (new->defs.merge != MergeAugment ? "last" : "first"));
25334345a63Smrg        }
25434345a63Smrg        return True;
25534345a63Smrg    }
25634345a63Smrg    old = new;
25734345a63Smrg    if ((new = NextInterp(info)) == NULL)
25834345a63Smrg        return False;
25934345a63Smrg    *new = *old;
26034345a63Smrg    new->defs.next = NULL;
261f46a6179Smrg    return True;
262f46a6179Smrg}
263f46a6179Smrg
264f46a6179Smrgstatic Bool
26534345a63SmrgAddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
266f46a6179Smrg{
26734345a63Smrg    GroupCompatInfo *gc;
26834345a63Smrg    unsigned merge;
26934345a63Smrg
27034345a63Smrg    merge = newGC->merge;
27134345a63Smrg    gc = &info->groupCompat[group];
27234345a63Smrg    if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
27334345a63Smrg    {
27434345a63Smrg        return True;
27534345a63Smrg    }
27634345a63Smrg    if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
27734345a63Smrg        || (warningLevel > 9))
27834345a63Smrg    {
27934345a63Smrg        WARN1("Compat map for group %d redefined\n", group + 1);
28034345a63Smrg        ACTION1("Using %s definition\n",
28134345a63Smrg                (merge == MergeAugment ? "old" : "new"));
28234345a63Smrg    }
28334345a63Smrg    if (merge != MergeAugment)
28434345a63Smrg        *gc = *newGC;
285f46a6179Smrg    return True;
286f46a6179Smrg}
287f46a6179Smrg
288f46a6179Smrg/***====================================================================***/
289f46a6179Smrg
290f46a6179Smrgstatic Bool
29134345a63SmrgResolveStateAndPredicate(ExprDef * expr,
29234345a63Smrg                         unsigned *pred_rtrn,
29334345a63Smrg                         unsigned *mods_rtrn, CompatInfo * info)
294f46a6179Smrg{
29534345a63Smrg    ExprResult result;
29634345a63Smrg
29734345a63Smrg    if (expr == NULL)
29834345a63Smrg    {
29934345a63Smrg        *pred_rtrn = XkbSI_AnyOfOrNone;
30034345a63Smrg        *mods_rtrn = ~0;
30134345a63Smrg        return True;
30234345a63Smrg    }
30334345a63Smrg
30434345a63Smrg    *pred_rtrn = XkbSI_Exactly;
30534345a63Smrg    if (expr->op == ExprActionDecl)
30634345a63Smrg    {
30734345a63Smrg        char *pred_txt =
30834345a63Smrg            XkbAtomText(NULL, expr->value.action.name, XkbMessage);
30934345a63Smrg        if (uStrCaseCmp(pred_txt, "noneof") == 0)
31034345a63Smrg            *pred_rtrn = XkbSI_NoneOf;
31134345a63Smrg        else if (uStrCaseCmp(pred_txt, "anyofornone") == 0)
31234345a63Smrg            *pred_rtrn = XkbSI_AnyOfOrNone;
31334345a63Smrg        else if (uStrCaseCmp(pred_txt, "anyof") == 0)
31434345a63Smrg            *pred_rtrn = XkbSI_AnyOf;
31534345a63Smrg        else if (uStrCaseCmp(pred_txt, "allof") == 0)
31634345a63Smrg            *pred_rtrn = XkbSI_AllOf;
31734345a63Smrg        else if (uStrCaseCmp(pred_txt, "exactly") == 0)
31834345a63Smrg            *pred_rtrn = XkbSI_Exactly;
31934345a63Smrg        else
32034345a63Smrg        {
32134345a63Smrg            ERROR1("Illegal modifier predicate \"%s\"\n", pred_txt);
32234345a63Smrg            ACTION("Ignored\n");
32334345a63Smrg            return False;
32434345a63Smrg        }
32534345a63Smrg        expr = expr->value.action.args;
32634345a63Smrg    }
32734345a63Smrg    else if (expr->op == ExprIdent)
32834345a63Smrg    {
32934345a63Smrg        char *pred_txt = XkbAtomText(NULL, expr->value.str, XkbMessage);
33034345a63Smrg        if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0))
33134345a63Smrg        {
33234345a63Smrg            *pred_rtrn = XkbSI_AnyOf;
33334345a63Smrg            *mods_rtrn = 0xff;
33434345a63Smrg            return True;
33534345a63Smrg        }
33634345a63Smrg    }
33734345a63Smrg
33834345a63Smrg    if (ExprResolveModMask(expr, &result, NULL, NULL))
33934345a63Smrg    {
34034345a63Smrg        *mods_rtrn = result.uval;
34134345a63Smrg        return True;
342f46a6179Smrg    }
343f46a6179Smrg    return False;
344f46a6179Smrg}
345f46a6179Smrg
346f46a6179Smrg/***====================================================================***/
347f46a6179Smrg
348f46a6179Smrgstatic void
34934345a63SmrgMergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
350f46a6179Smrg{
35134345a63Smrg    SymInterpInfo *si;
35234345a63Smrg    LEDInfo *led, *rtrn, *next;
35334345a63Smrg    GroupCompatInfo *gcm;
35434345a63Smrg    register int i;
35534345a63Smrg
35634345a63Smrg    if (from->errorCount > 0)
35734345a63Smrg    {
35834345a63Smrg        into->errorCount += from->errorCount;
35934345a63Smrg        return;
36034345a63Smrg    }
36134345a63Smrg    if (into->name == NULL)
36234345a63Smrg    {
36334345a63Smrg        into->name = from->name;
36434345a63Smrg        from->name = NULL;
36534345a63Smrg    }
36634345a63Smrg    for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
36734345a63Smrg    {
36834345a63Smrg        if (merge != MergeDefault)
36934345a63Smrg            si->defs.merge = merge;
37034345a63Smrg        if (!AddInterp(into, si))
37134345a63Smrg            into->errorCount++;
37234345a63Smrg    }
37334345a63Smrg    for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
37434345a63Smrg    {
37534345a63Smrg        if (merge != MergeDefault)
37634345a63Smrg            gcm->merge = merge;
37734345a63Smrg        if (!AddGroupCompat(into, i, gcm))
37834345a63Smrg            into->errorCount++;
37934345a63Smrg    }
38034345a63Smrg    for (led = from->leds; led != NULL; led = next)
38134345a63Smrg    {
38234345a63Smrg        next = (LEDInfo *) led->defs.next;
38334345a63Smrg        if (merge != MergeDefault)
38434345a63Smrg            led->defs.merge = merge;
38534345a63Smrg        rtrn = AddIndicatorMap(into->leds, led);
38634345a63Smrg        if (rtrn != NULL)
38734345a63Smrg            into->leds = rtrn;
38834345a63Smrg        else
38934345a63Smrg            into->errorCount++;
390f46a6179Smrg    }
391f46a6179Smrg    return;
392f46a6179Smrg}
393f46a6179Smrg
39434345a63Smrgtypedef void (*FileHandler) (XkbFile * /* rtrn */ ,
39534345a63Smrg                             XkbDescPtr /* xkb */ ,
39634345a63Smrg                             unsigned /* merge */ ,
39734345a63Smrg                             CompatInfo *       /* info */
39834345a63Smrg    );
399f46a6179Smrg
400f46a6179Smrgstatic Bool
40134345a63SmrgHandleIncludeCompatMap(IncludeStmt * stmt,
40234345a63Smrg                       XkbDescPtr xkb, CompatInfo * info, FileHandler hndlr)
403f46a6179Smrg{
40434345a63Smrg    unsigned newMerge;
40534345a63Smrg    XkbFile *rtrn;
40634345a63Smrg    CompatInfo included;
40734345a63Smrg    Bool haveSelf;
40834345a63Smrg
40934345a63Smrg    haveSelf = False;
41034345a63Smrg    if ((stmt->file == NULL) && (stmt->map == NULL))
41134345a63Smrg    {
41234345a63Smrg        haveSelf = True;
41334345a63Smrg        included = *info;
41434345a63Smrg        bzero(info, sizeof(CompatInfo));
41534345a63Smrg    }
41634345a63Smrg    else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
41734345a63Smrg    {
41834345a63Smrg        InitCompatInfo(&included, xkb);
41934345a63Smrg        included.fileID = rtrn->id;
42034345a63Smrg        included.dflt = info->dflt;
42134345a63Smrg        included.dflt.defs.fileID = rtrn->id;
42234345a63Smrg        included.dflt.defs.merge = newMerge;
42334345a63Smrg        included.ledDflt.defs.fileID = rtrn->id;
42434345a63Smrg        included.ledDflt.defs.merge = newMerge;
42534345a63Smrg        included.act = info->act;
42634345a63Smrg        (*hndlr) (rtrn, xkb, MergeOverride, &included);
42734345a63Smrg        if (stmt->stmt != NULL)
42834345a63Smrg        {
42934345a63Smrg            if (included.name != NULL)
43034345a63Smrg                uFree(included.name);
43134345a63Smrg            included.name = stmt->stmt;
43234345a63Smrg            stmt->stmt = NULL;
43334345a63Smrg        }
43434345a63Smrg    }
43534345a63Smrg    else
43634345a63Smrg    {
43734345a63Smrg        info->errorCount += 10;
43834345a63Smrg        return False;
43934345a63Smrg    }
44034345a63Smrg    if ((stmt->next != NULL) && (included.errorCount < 1))
44134345a63Smrg    {
44234345a63Smrg        IncludeStmt *next;
44334345a63Smrg        unsigned op;
44434345a63Smrg        CompatInfo next_incl;
44534345a63Smrg
44634345a63Smrg        for (next = stmt->next; next != NULL; next = next->next)
44734345a63Smrg        {
44834345a63Smrg            if ((next->file == NULL) && (next->map == NULL))
44934345a63Smrg            {
45034345a63Smrg                haveSelf = True;
45134345a63Smrg                MergeIncludedCompatMaps(&included, info, next->merge);
45234345a63Smrg                ClearCompatInfo(info, xkb);
45334345a63Smrg            }
45434345a63Smrg            else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
45534345a63Smrg            {
45634345a63Smrg                InitCompatInfo(&next_incl, xkb);
45734345a63Smrg                next_incl.fileID = rtrn->id;
45834345a63Smrg                next_incl.dflt = info->dflt;
45934345a63Smrg                next_incl.dflt.defs.fileID = rtrn->id;
46034345a63Smrg                next_incl.dflt.defs.merge = op;
46134345a63Smrg                next_incl.ledDflt.defs.fileID = rtrn->id;
46234345a63Smrg                next_incl.ledDflt.defs.merge = op;
46334345a63Smrg                next_incl.act = info->act;
46434345a63Smrg                (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
46534345a63Smrg                MergeIncludedCompatMaps(&included, &next_incl, op);
46634345a63Smrg                ClearCompatInfo(&next_incl, xkb);
46734345a63Smrg            }
46834345a63Smrg            else
46934345a63Smrg            {
47034345a63Smrg                info->errorCount += 10;
47134345a63Smrg                return False;
47234345a63Smrg            }
47334345a63Smrg        }
474f46a6179Smrg    }
475f46a6179Smrg    if (haveSelf)
47634345a63Smrg        *info = included;
47734345a63Smrg    else
47834345a63Smrg    {
47934345a63Smrg        MergeIncludedCompatMaps(info, &included, newMerge);
48034345a63Smrg        ClearCompatInfo(&included, xkb);
481f46a6179Smrg    }
48234345a63Smrg    return (info->errorCount == 0);
483f46a6179Smrg}
484f46a6179Smrg
485f46a6179Smrgstatic LookupEntry useModMapValues[] = {
48634345a63Smrg    {"levelone", 1},
48734345a63Smrg    {"level1", 1},
48834345a63Smrg    {"anylevel", 0},
48934345a63Smrg    {"any", 0},
49034345a63Smrg    {NULL, 0}
491f46a6179Smrg};
492f46a6179Smrg
493f46a6179Smrgstatic int
49434345a63SmrgSetInterpField(SymInterpInfo * si,
49534345a63Smrg               XkbDescPtr xkb,
49634345a63Smrg               char *field,
49734345a63Smrg               ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
498f46a6179Smrg{
49934345a63Smrg    int ok = 1;
50034345a63Smrg    ExprResult tmp;
50134345a63Smrg
50234345a63Smrg    if (uStrCaseCmp(field, "action") == 0)
50334345a63Smrg    {
50434345a63Smrg        if (arrayNdx != NULL)
50534345a63Smrg            return ReportSINotArray(si, field, info);
50634345a63Smrg        ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
50734345a63Smrg                             info->act);
50834345a63Smrg        if (ok)
50934345a63Smrg            si->defs.defined |= _SI_Action;
51034345a63Smrg    }
51134345a63Smrg    else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
51234345a63Smrg             (uStrCaseCmp(field, "virtualmod") == 0))
51334345a63Smrg    {
51434345a63Smrg        if (arrayNdx != NULL)
51534345a63Smrg            return ReportSINotArray(si, field, info);
51634345a63Smrg        ok = ResolveVirtualModifier(value, &tmp, &info->vmods);
51734345a63Smrg        if (ok)
51834345a63Smrg        {
51934345a63Smrg            si->interp.virtual_mod = tmp.uval;
52034345a63Smrg            si->defs.defined |= _SI_VirtualMod;
52134345a63Smrg        }
52234345a63Smrg        else
52334345a63Smrg            return ReportSIBadType(si, field, "virtual modifier", info);
52434345a63Smrg    }
52534345a63Smrg    else if (uStrCaseCmp(field, "repeat") == 0)
52634345a63Smrg    {
52734345a63Smrg        if (arrayNdx != NULL)
52834345a63Smrg            return ReportSINotArray(si, field, info);
52934345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
53034345a63Smrg        if (ok)
53134345a63Smrg        {
53234345a63Smrg            if (tmp.uval)
53334345a63Smrg                si->interp.flags |= XkbSI_AutoRepeat;
53434345a63Smrg            else
53534345a63Smrg                si->interp.flags &= ~XkbSI_AutoRepeat;
53634345a63Smrg            si->defs.defined |= _SI_AutoRepeat;
53734345a63Smrg        }
53834345a63Smrg        else
53934345a63Smrg            return ReportSIBadType(si, field, "boolean", info);
54034345a63Smrg    }
54134345a63Smrg    else if (uStrCaseCmp(field, "locking") == 0)
54234345a63Smrg    {
54334345a63Smrg        if (arrayNdx != NULL)
54434345a63Smrg            return ReportSINotArray(si, field, info);
54534345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
54634345a63Smrg        if (ok)
54734345a63Smrg        {
54834345a63Smrg            if (tmp.uval)
54934345a63Smrg                si->interp.flags |= XkbSI_LockingKey;
55034345a63Smrg            else
55134345a63Smrg                si->interp.flags &= ~XkbSI_LockingKey;
55234345a63Smrg            si->defs.defined |= _SI_LockingKey;
55334345a63Smrg        }
55434345a63Smrg        else
55534345a63Smrg            return ReportSIBadType(si, field, "boolean", info);
55634345a63Smrg    }
55734345a63Smrg    else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
55834345a63Smrg             (uStrCaseCmp(field, "usemodmapmods") == 0))
55934345a63Smrg    {
56034345a63Smrg        if (arrayNdx != NULL)
56134345a63Smrg            return ReportSINotArray(si, field, info);
56234345a63Smrg        ok = ExprResolveEnum(value, &tmp, useModMapValues);
56334345a63Smrg        if (ok)
56434345a63Smrg        {
56534345a63Smrg            if (tmp.uval)
56634345a63Smrg                si->interp.match |= XkbSI_LevelOneOnly;
56734345a63Smrg            else
56834345a63Smrg                si->interp.match &= ~XkbSI_LevelOneOnly;
56934345a63Smrg            si->defs.defined |= _SI_LevelOneOnly;
57034345a63Smrg        }
57134345a63Smrg        else
57234345a63Smrg            return ReportSIBadType(si, field, "level specification", info);
57334345a63Smrg    }
57434345a63Smrg    else
57534345a63Smrg    {
57634345a63Smrg        ok = ReportBadField("symbol interpretation", field, siText(si, info));
577f46a6179Smrg    }
578f46a6179Smrg    return ok;
579f46a6179Smrg}
580f46a6179Smrg
58134345a63SmrgLookupEntry groupNames[] = {
58234345a63Smrg    {"group1", 0x01}
58334345a63Smrg    ,
58434345a63Smrg    {"group2", 0x02}
58534345a63Smrg    ,
58634345a63Smrg    {"group3", 0x04}
58734345a63Smrg    ,
58834345a63Smrg    {"group4", 0x08}
58934345a63Smrg    ,
59034345a63Smrg    {"group5", 0x10}
59134345a63Smrg    ,
59234345a63Smrg    {"group6", 0x20}
59334345a63Smrg    ,
59434345a63Smrg    {"group7", 0x40}
59534345a63Smrg    ,
59634345a63Smrg    {"group8", 0x80}
59734345a63Smrg    ,
59834345a63Smrg    {"none", 0x00}
59934345a63Smrg    ,
60034345a63Smrg    {"all", 0xff}
60134345a63Smrg    ,
60234345a63Smrg    {NULL, 0}
603f46a6179Smrg};
604f46a6179Smrg
605f46a6179Smrgstatic int
60634345a63SmrgHandleInterpVar(VarDef * stmt, XkbDescPtr xkb, CompatInfo * info)
607f46a6179Smrg{
60834345a63Smrg    ExprResult elem, field;
60934345a63Smrg    ExprDef *ndx;
61034345a63Smrg
61134345a63Smrg    if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
61234345a63Smrg        return 0;               /* internal error, already reported */
61334345a63Smrg    if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
61434345a63Smrg        return SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
61534345a63Smrg                              info);
61634345a63Smrg    if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
61734345a63Smrg    {
61834345a63Smrg        return SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
61934345a63Smrg                                    stmt->value);
62034345a63Smrg    }
62134345a63Smrg    return SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
62234345a63Smrg                          &info->act);
623f46a6179Smrg}
624f46a6179Smrg
625f46a6179Smrgstatic int
62634345a63SmrgHandleInterpBody(VarDef * def, XkbDescPtr xkb, SymInterpInfo * si,
62734345a63Smrg                 CompatInfo * info)
628f46a6179Smrg{
62934345a63Smrg    int ok = 1;
63034345a63Smrg    ExprResult tmp, field;
63134345a63Smrg    ExprDef *arrayNdx;
63234345a63Smrg
63334345a63Smrg    for (; def != NULL; def = (VarDef *) def->common.next)
63434345a63Smrg    {
63534345a63Smrg        if ((def->name) && (def->name->type == ExprFieldRef))
63634345a63Smrg        {
63734345a63Smrg            ok = HandleInterpVar(def, xkb, info);
63834345a63Smrg            continue;
63934345a63Smrg        }
64034345a63Smrg        ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
64134345a63Smrg        if (ok)
64234345a63Smrg            ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
64334345a63Smrg                                info);
644f46a6179Smrg    }
645f46a6179Smrg    return ok;
646f46a6179Smrg}
647f46a6179Smrg
648f46a6179Smrgstatic int
64934345a63SmrgHandleInterpDef(InterpDef * def, XkbDescPtr xkb, unsigned merge,
65034345a63Smrg                CompatInfo * info)
651f46a6179Smrg{
65234345a63Smrg    unsigned pred, mods;
65334345a63Smrg    SymInterpInfo si;
65434345a63Smrg
65534345a63Smrg    if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
65634345a63Smrg    {
65734345a63Smrg        ERROR("Couldn't determine matching modifiers\n");
65834345a63Smrg        ACTION("Symbol interpretation ignored\n");
659690143ccSmrg        return True;
66034345a63Smrg    }
661690143ccSmrg    if (def->ignore)
662690143ccSmrg    {
663690143ccSmrg        ERROR("Couldn't lookup keysym\n");
664690143ccSmrg        ACTION("Symbol interpretation ignored\n");
665690143ccSmrg        return True;
666690143ccSmrg    }
667690143ccSmrg
66834345a63Smrg    if (def->merge != MergeDefault)
66934345a63Smrg        merge = def->merge;
67034345a63Smrg
67134345a63Smrg    si = info->dflt;
67234345a63Smrg    si.defs.merge = merge;
67334345a63Smrg    si.interp.sym = def->sym;
67434345a63Smrg    si.interp.match = pred & XkbSI_OpMask;
67534345a63Smrg    si.interp.mods = mods;
67634345a63Smrg    if (!HandleInterpBody(def->def, xkb, &si, info))
67734345a63Smrg    {
67834345a63Smrg        info->errorCount++;
67934345a63Smrg        return False;
68034345a63Smrg    }
68134345a63Smrg
68234345a63Smrg    if (!AddInterp(info, &si))
68334345a63Smrg    {
68434345a63Smrg        info->errorCount++;
68534345a63Smrg        return False;
686f46a6179Smrg    }
687f46a6179Smrg    return True;
688f46a6179Smrg}
689f46a6179Smrg
690f46a6179Smrgstatic int
69134345a63SmrgHandleGroupCompatDef(GroupCompatDef * def,
69234345a63Smrg                     XkbDescPtr xkb, unsigned merge, CompatInfo * info)
693f46a6179Smrg{
69434345a63Smrg    ExprResult val;
69534345a63Smrg    GroupCompatInfo tmp;
69634345a63Smrg
69734345a63Smrg    if (def->merge != MergeDefault)
69834345a63Smrg        merge = def->merge;
69934345a63Smrg    if (!XkbIsLegalGroup(def->group - 1))
70034345a63Smrg    {
70134345a63Smrg        ERROR1("Keyboard group must be in the range 1..%d\n",
70234345a63Smrg               XkbNumKbdGroups + 1);
70334345a63Smrg        ACTION1("Compatibility map for illegal group %d ignored\n",
70434345a63Smrg                def->group);
70534345a63Smrg        return False;
70634345a63Smrg    }
70734345a63Smrg    tmp.fileID = info->fileID;
70834345a63Smrg    tmp.merge = merge;
70934345a63Smrg    if (!ExprResolveModMask(def->def, &val, LookupVModMask, (XPointer) xkb))
71034345a63Smrg    {
71134345a63Smrg        ERROR("Expected a modifier mask in group compatibility definition\n");
71234345a63Smrg        ACTION1("Ignoring illegal compatibility map for group %d\n",
71334345a63Smrg                def->group);
71434345a63Smrg        return False;
71534345a63Smrg    }
71634345a63Smrg    tmp.real_mods = val.uval & 0xff;
71734345a63Smrg    tmp.vmods = (val.uval >> 8) & 0xffff;
71834345a63Smrg    return AddGroupCompat(info, def->group - 1, &tmp);
719f46a6179Smrg}
720f46a6179Smrg
721f46a6179Smrgstatic void
72234345a63SmrgHandleCompatMapFile(XkbFile * file,
72334345a63Smrg                    XkbDescPtr xkb, unsigned merge, CompatInfo * info)
724f46a6179Smrg{
72534345a63Smrg    ParseCommon *stmt;
72634345a63Smrg
72734345a63Smrg    if (merge == MergeDefault)
72834345a63Smrg        merge = MergeAugment;
72934345a63Smrg    info->name = uStringDup(file->name);
73034345a63Smrg    stmt = file->defs;
73134345a63Smrg    while (stmt)
73234345a63Smrg    {
73334345a63Smrg        switch (stmt->stmtType)
73434345a63Smrg        {
73534345a63Smrg        case StmtInclude:
73634345a63Smrg            if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
73734345a63Smrg                                        HandleCompatMapFile))
73834345a63Smrg                info->errorCount++;
73934345a63Smrg            break;
74034345a63Smrg        case StmtInterpDef:
74134345a63Smrg            if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
74234345a63Smrg                info->errorCount++;
74334345a63Smrg            break;
74434345a63Smrg        case StmtGroupCompatDef:
74534345a63Smrg            if (!HandleGroupCompatDef
74634345a63Smrg                ((GroupCompatDef *) stmt, xkb, merge, info))
74734345a63Smrg                info->errorCount++;
74834345a63Smrg            break;
74934345a63Smrg        case StmtIndicatorMapDef:
75034345a63Smrg        {
75134345a63Smrg            LEDInfo *rtrn;
75234345a63Smrg            rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
75334345a63Smrg                                         &info->ledDflt, info->leds, merge);
75434345a63Smrg            if (rtrn != NULL)
75534345a63Smrg                info->leds = rtrn;
75634345a63Smrg            else
75734345a63Smrg                info->errorCount++;
75834345a63Smrg        }
75934345a63Smrg            break;
76034345a63Smrg        case StmtVarDef:
76134345a63Smrg            if (!HandleInterpVar((VarDef *) stmt, xkb, info))
76234345a63Smrg                info->errorCount++;
76334345a63Smrg            break;
76434345a63Smrg        case StmtVModDef:
76534345a63Smrg            if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
76634345a63Smrg                info->errorCount++;
76734345a63Smrg            break;
76834345a63Smrg        case StmtKeycodeDef:
76934345a63Smrg            ERROR("Interpretation files may not include other types\n");
77034345a63Smrg            ACTION("Ignoring definition of key name\n");
77134345a63Smrg            info->errorCount++;
77234345a63Smrg            break;
77334345a63Smrg        default:
77434345a63Smrg            WSGO1("Unexpected statement type %d in HandleCompatMapFile\n",
77534345a63Smrg                  stmt->stmtType);
77634345a63Smrg            break;
77734345a63Smrg        }
77834345a63Smrg        stmt = stmt->next;
77934345a63Smrg        if (info->errorCount > 10)
78034345a63Smrg        {
781f46a6179Smrg#ifdef NOISY
78234345a63Smrg            ERROR("Too many errors\n");
783f46a6179Smrg#endif
78434345a63Smrg            ACTION1("Abandoning compatibility map \"%s\"\n", file->topName);
78534345a63Smrg            break;
78634345a63Smrg        }
787f46a6179Smrg    }
788f46a6179Smrg    return;
789f46a6179Smrg}
790f46a6179Smrg
791f46a6179Smrgstatic void
79234345a63SmrgCopyInterps(CompatInfo * info,
79334345a63Smrg            XkbCompatMapPtr compat, Bool needSymbol, unsigned pred)
794f46a6179Smrg{
79534345a63Smrg    SymInterpInfo *si;
79634345a63Smrg
79734345a63Smrg    for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
79834345a63Smrg    {
79934345a63Smrg        if (((si->interp.match & XkbSI_OpMask) != pred) ||
80034345a63Smrg            (needSymbol && (si->interp.sym == NoSymbol)) ||
80134345a63Smrg            ((!needSymbol) && (si->interp.sym != NoSymbol)))
80234345a63Smrg            continue;
80334345a63Smrg        if (compat->num_si >= compat->size_si)
80434345a63Smrg        {
80534345a63Smrg            WSGO("No room to merge symbol interpretations\n");
80634345a63Smrg            ACTION("Symbol interpretations lost\n");
80734345a63Smrg            return;
80834345a63Smrg        }
80934345a63Smrg        compat->sym_interpret[compat->num_si++] = si->interp;
810f46a6179Smrg    }
811f46a6179Smrg    return;
812f46a6179Smrg}
813f46a6179Smrg
814f46a6179SmrgBool
81534345a63SmrgCompileCompatMap(XkbFile * file,
81634345a63Smrg                 XkbFileInfo * result, unsigned merge, LEDInfo ** unboundLEDs)
817f46a6179Smrg{
81834345a63Smrg    int i;
81934345a63Smrg    CompatInfo info;
82034345a63Smrg    XkbDescPtr xkb;
82134345a63Smrg    GroupCompatInfo *gcm;
82234345a63Smrg
82334345a63Smrg    xkb = result->xkb;
82434345a63Smrg    InitCompatInfo(&info, xkb);
82534345a63Smrg    info.dflt.defs.merge = merge;
82634345a63Smrg    info.ledDflt.defs.merge = merge;
82734345a63Smrg    HandleCompatMapFile(file, xkb, merge, &info);
82834345a63Smrg
82934345a63Smrg    if (info.errorCount == 0)
83034345a63Smrg    {
83134345a63Smrg        int size;
83234345a63Smrg        if (XkbAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
83334345a63Smrg            Success)
83434345a63Smrg        {
83534345a63Smrg            WSGO("Couldn't allocate compatibility map\n");
83634345a63Smrg            ACTION("Exiting\n");
83734345a63Smrg            return False;
83834345a63Smrg        }
83934345a63Smrg        if (info.name != NULL)
84034345a63Smrg        {
84134345a63Smrg            if (XkbAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
84234345a63Smrg                xkb->names->compat =
84334345a63Smrg                    XkbInternAtom(xkb->dpy, info.name, False);
84434345a63Smrg            else
84534345a63Smrg            {
84634345a63Smrg                WSGO("Couldn't allocate space for compat name\n");
84734345a63Smrg                ACTION2("Name \"%s\" (from %s) NOT assigned\n",
84834345a63Smrg                        scanFile, info.name);
84934345a63Smrg            }
85034345a63Smrg        }
85134345a63Smrg        size = info.nInterps * sizeof(XkbSymInterpretRec);
85234345a63Smrg        if (size > 0)
85334345a63Smrg        {
85434345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
85534345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
85634345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
85734345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
85834345a63Smrg            CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
85934345a63Smrg            CopyInterps(&info, xkb->compat, False,
86034345a63Smrg                        XkbSI_AllOf | XkbSI_NoneOf);
86134345a63Smrg            CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
86234345a63Smrg            CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
86334345a63Smrg        }
86434345a63Smrg        for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
86534345a63Smrg             i++, gcm++)
86634345a63Smrg        {
86734345a63Smrg            if ((gcm->fileID != 0) || (gcm->real_mods != 0)
86834345a63Smrg                || (gcm->vmods != 0))
86934345a63Smrg            {
87034345a63Smrg                xkb->compat->groups[i].mask = gcm->real_mods;
87134345a63Smrg                xkb->compat->groups[i].real_mods = gcm->real_mods;
87234345a63Smrg                xkb->compat->groups[i].vmods = gcm->vmods;
87334345a63Smrg            }
87434345a63Smrg        }
87534345a63Smrg        if (info.leds != NULL)
87634345a63Smrg        {
87734345a63Smrg            if (!CopyIndicatorMapDefs(result, info.leds, unboundLEDs))
87834345a63Smrg                info.errorCount++;
87934345a63Smrg            info.leds = NULL;
88034345a63Smrg        }
88134345a63Smrg        ClearCompatInfo(&info, xkb);
88234345a63Smrg        return True;
88334345a63Smrg    }
88434345a63Smrg    if (info.interps != NULL)
88534345a63Smrg        uFree(info.interps);
886f46a6179Smrg    return False;
887f46a6179Smrg}
888