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 *
846930ead5SmrgsiText(const SymInterpInfo *si, const 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    info->xkb = xkb;
10634345a63Smrg    info->name = NULL;
10734345a63Smrg    info->fileID = 0;
10834345a63Smrg    info->errorCount = 0;
10934345a63Smrg    info->nInterps = 0;
11034345a63Smrg    info->interps = NULL;
11134345a63Smrg    info->act = NULL;
11234345a63Smrg    info->dflt.defs.fileID = info->fileID;
11334345a63Smrg    info->dflt.defs.defined = 0;
11434345a63Smrg    info->dflt.defs.merge = MergeOverride;
11534345a63Smrg    info->dflt.interp.flags = 0;
11634345a63Smrg    info->dflt.interp.virtual_mod = XkbNoModifier;
11734345a63Smrg    info->dflt.interp.act.type = XkbSA_NoAction;
1186930ead5Smrg    for (int i = 0; i < XkbAnyActionDataSize; i++)
11934345a63Smrg    {
12034345a63Smrg        info->dflt.interp.act.data[i] = 0;
12134345a63Smrg    }
12234345a63Smrg    ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
12334345a63Smrg    info->ledDflt.defs.fileID = info->fileID;
12434345a63Smrg    info->ledDflt.defs.defined = 0;
12534345a63Smrg    info->ledDflt.defs.merge = MergeOverride;
1266930ead5Smrg    bzero(&info->groupCompat[0], XkbNumKbdGroups * sizeof(GroupCompatInfo));
12734345a63Smrg    info->leds = NULL;
12834345a63Smrg    InitVModInfo(&info->vmods, xkb);
129f46a6179Smrg    return;
130f46a6179Smrg}
131f46a6179Smrg
132f46a6179Smrgstatic void
13334345a63SmrgClearCompatInfo(CompatInfo * info, XkbDescPtr xkb)
134f46a6179Smrg{
1356930ead5Smrg    free(info->name);
13634345a63Smrg    info->name = NULL;
13734345a63Smrg    info->dflt.defs.defined = 0;
13834345a63Smrg    info->dflt.defs.merge = MergeAugment;
13934345a63Smrg    info->dflt.interp.flags = 0;
14034345a63Smrg    info->dflt.interp.virtual_mod = XkbNoModifier;
14134345a63Smrg    info->dflt.interp.act.type = XkbSA_NoAction;
1426930ead5Smrg    for (int i = 0; i < XkbAnyActionDataSize; i++)
14334345a63Smrg    {
14434345a63Smrg        info->dflt.interp.act.data[i] = 0;
14534345a63Smrg    }
14634345a63Smrg    ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
14734345a63Smrg    info->nInterps = 0;
14834345a63Smrg    info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
1496930ead5Smrg    bzero(&info->groupCompat[0], XkbNumKbdGroups * sizeof(GroupCompatInfo));
15034345a63Smrg    info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
151f46a6179Smrg    /* 3/30/94 (ef) -- XXX! Should free action info here */
15234345a63Smrg    ClearVModInfo(&info->vmods, xkb);
153f46a6179Smrg    return;
154f46a6179Smrg}
155f46a6179Smrg
156f46a6179Smrgstatic SymInterpInfo *
15734345a63SmrgNextInterp(CompatInfo * info)
158f46a6179Smrg{
15934345a63Smrg    SymInterpInfo *si;
160f46a6179Smrg
1616930ead5Smrg    si = calloc(1, sizeof(SymInterpInfo));
16234345a63Smrg    if (si)
16334345a63Smrg    {
16434345a63Smrg        info->interps =
16534345a63Smrg            (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
16634345a63Smrg                                            (CommonInfo *) si);
16734345a63Smrg        info->nInterps++;
168f46a6179Smrg    }
169f46a6179Smrg    return si;
170f46a6179Smrg}
171f46a6179Smrg
172f46a6179Smrgstatic SymInterpInfo *
1736930ead5SmrgFindMatchingInterp(CompatInfo *info, const SymInterpInfo *new)
174f46a6179Smrg{
17534345a63Smrg    SymInterpInfo *old;
17634345a63Smrg
17734345a63Smrg    for (old = info->interps; old != NULL;
17834345a63Smrg         old = (SymInterpInfo *) old->defs.next)
17934345a63Smrg    {
18034345a63Smrg        if ((old->interp.sym == new->interp.sym) &&
18134345a63Smrg            (old->interp.mods == new->interp.mods) &&
18234345a63Smrg            (old->interp.match == new->interp.match))
18334345a63Smrg        {
18434345a63Smrg            return old;
18534345a63Smrg        }
186f46a6179Smrg    }
187f46a6179Smrg    return NULL;
188f46a6179Smrg}
189f46a6179Smrg
190f46a6179Smrgstatic Bool
19134345a63SmrgAddInterp(CompatInfo * info, SymInterpInfo * new)
192f46a6179Smrg{
19334345a63Smrg    SymInterpInfo *old;
19434345a63Smrg
19534345a63Smrg    old = FindMatchingInterp(info, new);
19634345a63Smrg    if (old != NULL)
19734345a63Smrg    {
1986930ead5Smrg        unsigned collide = 0;
1996930ead5Smrg
20034345a63Smrg        if (new->defs.merge == MergeReplace)
20134345a63Smrg        {
20234345a63Smrg            SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
20334345a63Smrg            if (((old->defs.fileID == new->defs.fileID)
20434345a63Smrg                 && (warningLevel > 0)) || (warningLevel > 9))
20534345a63Smrg            {
206bfe6082cSmrg                WARN("Multiple definitions for \"%s\"\n", siText(new, info));
20734345a63Smrg                ACTION("Earlier interpretation ignored\n");
20834345a63Smrg            }
20934345a63Smrg            *old = *new;
21034345a63Smrg            old->defs.next = &next->defs;
21134345a63Smrg            return True;
21234345a63Smrg        }
21334345a63Smrg        if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
21434345a63Smrg        {
21534345a63Smrg            old->interp.virtual_mod = new->interp.virtual_mod;
21634345a63Smrg            old->defs.defined |= _SI_VirtualMod;
21734345a63Smrg        }
21834345a63Smrg        if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
21934345a63Smrg        {
22034345a63Smrg            old->interp.act = new->interp.act;
22134345a63Smrg            old->defs.defined |= _SI_Action;
22234345a63Smrg        }
22334345a63Smrg        if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
22434345a63Smrg        {
22534345a63Smrg            old->interp.flags &= ~XkbSI_AutoRepeat;
22634345a63Smrg            old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
22734345a63Smrg            old->defs.defined |= _SI_AutoRepeat;
22834345a63Smrg        }
22934345a63Smrg        if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
23034345a63Smrg        {
23134345a63Smrg            old->interp.flags &= ~XkbSI_LockingKey;
23234345a63Smrg            old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
23334345a63Smrg            old->defs.defined |= _SI_LockingKey;
23434345a63Smrg        }
23534345a63Smrg        if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
23634345a63Smrg        {
23734345a63Smrg            old->interp.match &= ~XkbSI_LevelOneOnly;
23834345a63Smrg            old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
23934345a63Smrg            old->defs.defined |= _SI_LevelOneOnly;
24034345a63Smrg        }
241a57d84feSmrg        if (collide && (warningLevel > 0))
24234345a63Smrg        {
243bfe6082cSmrg            WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
244bfe6082cSmrg            ACTION("Using %s definition for duplicate fields\n",
24534345a63Smrg                    (new->defs.merge != MergeAugment ? "last" : "first"));
24634345a63Smrg        }
24734345a63Smrg        return True;
24834345a63Smrg    }
24934345a63Smrg    old = new;
25034345a63Smrg    if ((new = NextInterp(info)) == NULL)
25134345a63Smrg        return False;
25234345a63Smrg    *new = *old;
25334345a63Smrg    new->defs.next = NULL;
254f46a6179Smrg    return True;
255f46a6179Smrg}
256f46a6179Smrg
257f46a6179Smrgstatic Bool
2586930ead5SmrgAddGroupCompat(CompatInfo *info, unsigned group, const GroupCompatInfo *newGC)
259f46a6179Smrg{
26034345a63Smrg    GroupCompatInfo *gc;
26134345a63Smrg    unsigned merge;
26234345a63Smrg
26334345a63Smrg    merge = newGC->merge;
26434345a63Smrg    gc = &info->groupCompat[group];
26534345a63Smrg    if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
26634345a63Smrg    {
26734345a63Smrg        return True;
26834345a63Smrg    }
269c82dfdfbSmrg    if (((gc->defined && gc->fileID == newGC->fileID) && (warningLevel > 0))
27034345a63Smrg        || (warningLevel > 9))
27134345a63Smrg    {
272bfe6082cSmrg        WARN("Compat map for group %d redefined\n", group + 1);
273bfe6082cSmrg        ACTION("Using %s definition\n",
27434345a63Smrg                (merge == MergeAugment ? "old" : "new"));
27534345a63Smrg    }
2761d8c7986Smrg    if(newGC->defined && (merge != MergeAugment || !gc->defined))
2771d8c7986Smrg	*gc = *newGC;
278f46a6179Smrg    return True;
279f46a6179Smrg}
280f46a6179Smrg
281f46a6179Smrg/***====================================================================***/
282f46a6179Smrg
283f46a6179Smrgstatic Bool
2846930ead5SmrgResolveStateAndPredicate(const ExprDef *expr,
2856930ead5Smrg                         unsigned *pred_rtrn, unsigned *mods_rtrn,
2866930ead5Smrg                         const CompatInfo *info)
287f46a6179Smrg{
28834345a63Smrg    ExprResult result;
28934345a63Smrg
29034345a63Smrg    if (expr == NULL)
29134345a63Smrg    {
29234345a63Smrg        *pred_rtrn = XkbSI_AnyOfOrNone;
29334345a63Smrg        *mods_rtrn = ~0;
29434345a63Smrg        return True;
29534345a63Smrg    }
29634345a63Smrg
29734345a63Smrg    *pred_rtrn = XkbSI_Exactly;
29834345a63Smrg    if (expr->op == ExprActionDecl)
29934345a63Smrg    {
30034345a63Smrg        char *pred_txt =
30134345a63Smrg            XkbAtomText(NULL, expr->value.action.name, XkbMessage);
30234345a63Smrg        if (uStrCaseCmp(pred_txt, "noneof") == 0)
30334345a63Smrg            *pred_rtrn = XkbSI_NoneOf;
30434345a63Smrg        else if (uStrCaseCmp(pred_txt, "anyofornone") == 0)
30534345a63Smrg            *pred_rtrn = XkbSI_AnyOfOrNone;
30634345a63Smrg        else if (uStrCaseCmp(pred_txt, "anyof") == 0)
30734345a63Smrg            *pred_rtrn = XkbSI_AnyOf;
30834345a63Smrg        else if (uStrCaseCmp(pred_txt, "allof") == 0)
30934345a63Smrg            *pred_rtrn = XkbSI_AllOf;
31034345a63Smrg        else if (uStrCaseCmp(pred_txt, "exactly") == 0)
31134345a63Smrg            *pred_rtrn = XkbSI_Exactly;
31234345a63Smrg        else
31334345a63Smrg        {
314bfe6082cSmrg            ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
31534345a63Smrg            ACTION("Ignored\n");
31634345a63Smrg            return False;
31734345a63Smrg        }
31834345a63Smrg        expr = expr->value.action.args;
31934345a63Smrg    }
32034345a63Smrg    else if (expr->op == ExprIdent)
32134345a63Smrg    {
32234345a63Smrg        char *pred_txt = XkbAtomText(NULL, expr->value.str, XkbMessage);
32334345a63Smrg        if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0))
32434345a63Smrg        {
32534345a63Smrg            *pred_rtrn = XkbSI_AnyOf;
32634345a63Smrg            *mods_rtrn = 0xff;
32734345a63Smrg            return True;
32834345a63Smrg        }
32934345a63Smrg    }
33034345a63Smrg
33134345a63Smrg    if (ExprResolveModMask(expr, &result, NULL, NULL))
33234345a63Smrg    {
33334345a63Smrg        *mods_rtrn = result.uval;
33434345a63Smrg        return True;
335f46a6179Smrg    }
336f46a6179Smrg    return False;
337f46a6179Smrg}
338f46a6179Smrg
339f46a6179Smrg/***====================================================================***/
340f46a6179Smrg
341f46a6179Smrgstatic void
34234345a63SmrgMergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
343f46a6179Smrg{
3446930ead5Smrg    LEDInfo *next;
34534345a63Smrg    GroupCompatInfo *gcm;
3466930ead5Smrg    int i;
34734345a63Smrg
34834345a63Smrg    if (from->errorCount > 0)
34934345a63Smrg    {
35034345a63Smrg        into->errorCount += from->errorCount;
35134345a63Smrg        return;
35234345a63Smrg    }
35334345a63Smrg    if (into->name == NULL)
35434345a63Smrg    {
35534345a63Smrg        into->name = from->name;
35634345a63Smrg        from->name = NULL;
35734345a63Smrg    }
3586930ead5Smrg    for (SymInterpInfo *si = from->interps; si;
3596930ead5Smrg         si = (SymInterpInfo *) si->defs.next)
36034345a63Smrg    {
36134345a63Smrg        if (merge != MergeDefault)
36234345a63Smrg            si->defs.merge = merge;
36334345a63Smrg        if (!AddInterp(into, si))
36434345a63Smrg            into->errorCount++;
36534345a63Smrg    }
36634345a63Smrg    for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
36734345a63Smrg    {
36834345a63Smrg        if (merge != MergeDefault)
36934345a63Smrg            gcm->merge = merge;
37034345a63Smrg        if (!AddGroupCompat(into, i, gcm))
37134345a63Smrg            into->errorCount++;
37234345a63Smrg    }
3736930ead5Smrg    for (LEDInfo *led = from->leds; led != NULL; led = next)
37434345a63Smrg    {
3756930ead5Smrg        LEDInfo *rtrn;
3766930ead5Smrg
37734345a63Smrg        next = (LEDInfo *) led->defs.next;
37834345a63Smrg        if (merge != MergeDefault)
37934345a63Smrg            led->defs.merge = merge;
38034345a63Smrg        rtrn = AddIndicatorMap(into->leds, led);
38134345a63Smrg        if (rtrn != NULL)
38234345a63Smrg            into->leds = rtrn;
38334345a63Smrg        else
38434345a63Smrg            into->errorCount++;
385f46a6179Smrg    }
386f46a6179Smrg    return;
387f46a6179Smrg}
388f46a6179Smrg
3896930ead5Smrgtypedef void (*FileHandler) (const XkbFile * /* rtrn */ ,
39034345a63Smrg                             XkbDescPtr /* xkb */ ,
39134345a63Smrg                             unsigned /* merge */ ,
39234345a63Smrg                             CompatInfo *       /* info */
39334345a63Smrg    );
394f46a6179Smrg
395f46a6179Smrgstatic Bool
3966930ead5SmrgHandleIncludeCompatMap(IncludeStmt *stmt,
39734345a63Smrg                       XkbDescPtr xkb, CompatInfo * info, FileHandler hndlr)
398f46a6179Smrg{
39934345a63Smrg    unsigned newMerge;
40034345a63Smrg    XkbFile *rtrn;
40134345a63Smrg    CompatInfo included;
40234345a63Smrg    Bool haveSelf;
40334345a63Smrg
40434345a63Smrg    haveSelf = False;
40534345a63Smrg    if ((stmt->file == NULL) && (stmt->map == NULL))
40634345a63Smrg    {
40734345a63Smrg        haveSelf = True;
40834345a63Smrg        included = *info;
40934345a63Smrg        bzero(info, sizeof(CompatInfo));
41034345a63Smrg    }
41134345a63Smrg    else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
41234345a63Smrg    {
41334345a63Smrg        InitCompatInfo(&included, xkb);
41434345a63Smrg        included.fileID = rtrn->id;
41534345a63Smrg        included.dflt = info->dflt;
41634345a63Smrg        included.dflt.defs.fileID = rtrn->id;
41734345a63Smrg        included.dflt.defs.merge = newMerge;
41834345a63Smrg        included.ledDflt.defs.fileID = rtrn->id;
41934345a63Smrg        included.ledDflt.defs.merge = newMerge;
42034345a63Smrg        included.act = info->act;
42134345a63Smrg        (*hndlr) (rtrn, xkb, MergeOverride, &included);
42234345a63Smrg        if (stmt->stmt != NULL)
42334345a63Smrg        {
4246930ead5Smrg            free(included.name);
42534345a63Smrg            included.name = stmt->stmt;
42634345a63Smrg            stmt->stmt = NULL;
42734345a63Smrg        }
42834345a63Smrg    }
42934345a63Smrg    else
43034345a63Smrg    {
43134345a63Smrg        info->errorCount += 10;
43234345a63Smrg        return False;
43334345a63Smrg    }
43434345a63Smrg    if ((stmt->next != NULL) && (included.errorCount < 1))
43534345a63Smrg    {
43634345a63Smrg        IncludeStmt *next;
43734345a63Smrg        unsigned op;
43834345a63Smrg        CompatInfo next_incl;
43934345a63Smrg
44034345a63Smrg        for (next = stmt->next; next != NULL; next = next->next)
44134345a63Smrg        {
44234345a63Smrg            if ((next->file == NULL) && (next->map == NULL))
44334345a63Smrg            {
44434345a63Smrg                haveSelf = True;
44534345a63Smrg                MergeIncludedCompatMaps(&included, info, next->merge);
44634345a63Smrg                ClearCompatInfo(info, xkb);
44734345a63Smrg            }
44834345a63Smrg            else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
44934345a63Smrg            {
45034345a63Smrg                InitCompatInfo(&next_incl, xkb);
45134345a63Smrg                next_incl.fileID = rtrn->id;
45234345a63Smrg                next_incl.dflt = info->dflt;
45334345a63Smrg                next_incl.dflt.defs.fileID = rtrn->id;
45434345a63Smrg                next_incl.dflt.defs.merge = op;
45534345a63Smrg                next_incl.ledDflt.defs.fileID = rtrn->id;
45634345a63Smrg                next_incl.ledDflt.defs.merge = op;
45734345a63Smrg                next_incl.act = info->act;
45834345a63Smrg                (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
45934345a63Smrg                MergeIncludedCompatMaps(&included, &next_incl, op);
46034345a63Smrg                ClearCompatInfo(&next_incl, xkb);
46134345a63Smrg            }
46234345a63Smrg            else
46334345a63Smrg            {
46434345a63Smrg                info->errorCount += 10;
46534345a63Smrg                return False;
46634345a63Smrg            }
46734345a63Smrg        }
468f46a6179Smrg    }
469f46a6179Smrg    if (haveSelf)
47034345a63Smrg        *info = included;
47134345a63Smrg    else
47234345a63Smrg    {
47334345a63Smrg        MergeIncludedCompatMaps(info, &included, newMerge);
47434345a63Smrg        ClearCompatInfo(&included, xkb);
475f46a6179Smrg    }
47634345a63Smrg    return (info->errorCount == 0);
477f46a6179Smrg}
478f46a6179Smrg
479f46a6179Smrgstatic LookupEntry useModMapValues[] = {
48034345a63Smrg    {"levelone", 1},
48134345a63Smrg    {"level1", 1},
48234345a63Smrg    {"anylevel", 0},
48334345a63Smrg    {"any", 0},
48434345a63Smrg    {NULL, 0}
485f46a6179Smrg};
486f46a6179Smrg
487f46a6179Smrgstatic int
4886930ead5SmrgSetInterpField(SymInterpInfo *si, XkbDescPtr xkb, const char *field,
4896930ead5Smrg               const ExprDef *arrayNdx, const ExprDef *value,
4906930ead5Smrg               const CompatInfo *info)
491f46a6179Smrg{
49234345a63Smrg    int ok = 1;
49334345a63Smrg    ExprResult tmp;
49434345a63Smrg
49534345a63Smrg    if (uStrCaseCmp(field, "action") == 0)
49634345a63Smrg    {
49734345a63Smrg        if (arrayNdx != NULL)
49834345a63Smrg            return ReportSINotArray(si, field, info);
49934345a63Smrg        ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
50034345a63Smrg                             info->act);
50134345a63Smrg        if (ok)
50234345a63Smrg            si->defs.defined |= _SI_Action;
50334345a63Smrg    }
50434345a63Smrg    else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
50534345a63Smrg             (uStrCaseCmp(field, "virtualmod") == 0))
50634345a63Smrg    {
50734345a63Smrg        if (arrayNdx != NULL)
50834345a63Smrg            return ReportSINotArray(si, field, info);
50934345a63Smrg        ok = ResolveVirtualModifier(value, &tmp, &info->vmods);
51034345a63Smrg        if (ok)
51134345a63Smrg        {
51234345a63Smrg            si->interp.virtual_mod = tmp.uval;
51334345a63Smrg            si->defs.defined |= _SI_VirtualMod;
51434345a63Smrg        }
51534345a63Smrg        else
51634345a63Smrg            return ReportSIBadType(si, field, "virtual modifier", info);
51734345a63Smrg    }
51834345a63Smrg    else if (uStrCaseCmp(field, "repeat") == 0)
51934345a63Smrg    {
52034345a63Smrg        if (arrayNdx != NULL)
52134345a63Smrg            return ReportSINotArray(si, field, info);
52234345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
52334345a63Smrg        if (ok)
52434345a63Smrg        {
52534345a63Smrg            if (tmp.uval)
52634345a63Smrg                si->interp.flags |= XkbSI_AutoRepeat;
52734345a63Smrg            else
52834345a63Smrg                si->interp.flags &= ~XkbSI_AutoRepeat;
52934345a63Smrg            si->defs.defined |= _SI_AutoRepeat;
53034345a63Smrg        }
53134345a63Smrg        else
53234345a63Smrg            return ReportSIBadType(si, field, "boolean", info);
53334345a63Smrg    }
53434345a63Smrg    else if (uStrCaseCmp(field, "locking") == 0)
53534345a63Smrg    {
53634345a63Smrg        if (arrayNdx != NULL)
53734345a63Smrg            return ReportSINotArray(si, field, info);
53834345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
53934345a63Smrg        if (ok)
54034345a63Smrg        {
54134345a63Smrg            if (tmp.uval)
54234345a63Smrg                si->interp.flags |= XkbSI_LockingKey;
54334345a63Smrg            else
54434345a63Smrg                si->interp.flags &= ~XkbSI_LockingKey;
54534345a63Smrg            si->defs.defined |= _SI_LockingKey;
54634345a63Smrg        }
54734345a63Smrg        else
54834345a63Smrg            return ReportSIBadType(si, field, "boolean", info);
54934345a63Smrg    }
55034345a63Smrg    else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
55134345a63Smrg             (uStrCaseCmp(field, "usemodmapmods") == 0))
55234345a63Smrg    {
55334345a63Smrg        if (arrayNdx != NULL)
55434345a63Smrg            return ReportSINotArray(si, field, info);
55534345a63Smrg        ok = ExprResolveEnum(value, &tmp, useModMapValues);
55634345a63Smrg        if (ok)
55734345a63Smrg        {
55834345a63Smrg            if (tmp.uval)
55934345a63Smrg                si->interp.match |= XkbSI_LevelOneOnly;
56034345a63Smrg            else
56134345a63Smrg                si->interp.match &= ~XkbSI_LevelOneOnly;
56234345a63Smrg            si->defs.defined |= _SI_LevelOneOnly;
56334345a63Smrg        }
56434345a63Smrg        else
56534345a63Smrg            return ReportSIBadType(si, field, "level specification", info);
56634345a63Smrg    }
56734345a63Smrg    else
56834345a63Smrg    {
56934345a63Smrg        ok = ReportBadField("symbol interpretation", field, siText(si, info));
570f46a6179Smrg    }
571f46a6179Smrg    return ok;
572f46a6179Smrg}
573f46a6179Smrg
57434345a63SmrgLookupEntry groupNames[] = {
57534345a63Smrg    {"group1", 0x01}
57634345a63Smrg    ,
57734345a63Smrg    {"group2", 0x02}
57834345a63Smrg    ,
57934345a63Smrg    {"group3", 0x04}
58034345a63Smrg    ,
58134345a63Smrg    {"group4", 0x08}
58234345a63Smrg    ,
58334345a63Smrg    {"group5", 0x10}
58434345a63Smrg    ,
58534345a63Smrg    {"group6", 0x20}
58634345a63Smrg    ,
58734345a63Smrg    {"group7", 0x40}
58834345a63Smrg    ,
58934345a63Smrg    {"group8", 0x80}
59034345a63Smrg    ,
59134345a63Smrg    {"none", 0x00}
59234345a63Smrg    ,
59334345a63Smrg    {"all", 0xff}
59434345a63Smrg    ,
59534345a63Smrg    {NULL, 0}
596f46a6179Smrg};
597f46a6179Smrg
598f46a6179Smrgstatic int
5996930ead5SmrgHandleInterpVar(const VarDef *stmt, XkbDescPtr xkb, CompatInfo *info)
600f46a6179Smrg{
60134345a63Smrg    ExprResult elem, field;
60234345a63Smrg    ExprDef *ndx;
60334345a63Smrg
60434345a63Smrg    if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
60534345a63Smrg        return 0;               /* internal error, already reported */
60634345a63Smrg    if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
60734345a63Smrg        return SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
60834345a63Smrg                              info);
60934345a63Smrg    if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
61034345a63Smrg    {
61134345a63Smrg        return SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
61234345a63Smrg                                    stmt->value);
61334345a63Smrg    }
61434345a63Smrg    return SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
61534345a63Smrg                          &info->act);
616f46a6179Smrg}
617f46a6179Smrg
618f46a6179Smrgstatic int
6196930ead5SmrgHandleInterpBody(const VarDef *def, XkbDescPtr xkb, SymInterpInfo *si,
6206930ead5Smrg                 CompatInfo *info)
621f46a6179Smrg{
62234345a63Smrg    int ok = 1;
62334345a63Smrg    ExprResult tmp, field;
62434345a63Smrg    ExprDef *arrayNdx;
62534345a63Smrg
62634345a63Smrg    for (; def != NULL; def = (VarDef *) def->common.next)
62734345a63Smrg    {
62834345a63Smrg        if ((def->name) && (def->name->type == ExprFieldRef))
62934345a63Smrg        {
63034345a63Smrg            ok = HandleInterpVar(def, xkb, info);
63134345a63Smrg            continue;
63234345a63Smrg        }
63334345a63Smrg        ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
63434345a63Smrg        if (ok)
63534345a63Smrg            ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
63634345a63Smrg                                info);
637f46a6179Smrg    }
638f46a6179Smrg    return ok;
639f46a6179Smrg}
640f46a6179Smrg
641f46a6179Smrgstatic int
6426930ead5SmrgHandleInterpDef(const InterpDef *def, XkbDescPtr xkb, unsigned merge,
6436930ead5Smrg                CompatInfo *info)
644f46a6179Smrg{
64534345a63Smrg    unsigned pred, mods;
64634345a63Smrg    SymInterpInfo si;
64734345a63Smrg
64834345a63Smrg    if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
64934345a63Smrg    {
65034345a63Smrg        ERROR("Couldn't determine matching modifiers\n");
65134345a63Smrg        ACTION("Symbol interpretation ignored\n");
652690143ccSmrg        return True;
65334345a63Smrg    }
654690143ccSmrg    if (def->ignore)
655690143ccSmrg    {
656690143ccSmrg        ERROR("Couldn't lookup keysym\n");
657690143ccSmrg        ACTION("Symbol interpretation ignored\n");
658690143ccSmrg        return True;
659690143ccSmrg    }
660690143ccSmrg
66134345a63Smrg    if (def->merge != MergeDefault)
66234345a63Smrg        merge = def->merge;
66334345a63Smrg
66434345a63Smrg    si = info->dflt;
66534345a63Smrg    si.defs.merge = merge;
66634345a63Smrg    si.interp.sym = def->sym;
66734345a63Smrg    si.interp.match = pred & XkbSI_OpMask;
66834345a63Smrg    si.interp.mods = mods;
66934345a63Smrg    if (!HandleInterpBody(def->def, xkb, &si, info))
67034345a63Smrg    {
67134345a63Smrg        info->errorCount++;
67234345a63Smrg        return False;
67334345a63Smrg    }
67434345a63Smrg
67534345a63Smrg    if (!AddInterp(info, &si))
67634345a63Smrg    {
67734345a63Smrg        info->errorCount++;
67834345a63Smrg        return False;
679f46a6179Smrg    }
680f46a6179Smrg    return True;
681f46a6179Smrg}
682f46a6179Smrg
683f46a6179Smrgstatic int
6846930ead5SmrgHandleGroupCompatDef(const GroupCompatDef *def,
6856930ead5Smrg                     XkbDescPtr xkb, unsigned merge, CompatInfo *info)
686f46a6179Smrg{
68734345a63Smrg    ExprResult val;
68834345a63Smrg    GroupCompatInfo tmp;
68934345a63Smrg
69034345a63Smrg    if (def->merge != MergeDefault)
69134345a63Smrg        merge = def->merge;
69234345a63Smrg    if (!XkbIsLegalGroup(def->group - 1))
69334345a63Smrg    {
694bfe6082cSmrg        ERROR("Keyboard group must be in the range 1..%d\n",
69534345a63Smrg               XkbNumKbdGroups + 1);
696bfe6082cSmrg        ACTION("Compatibility map for illegal group %d ignored\n",
69734345a63Smrg                def->group);
69834345a63Smrg        return False;
69934345a63Smrg    }
70034345a63Smrg    tmp.fileID = info->fileID;
70134345a63Smrg    tmp.merge = merge;
70234345a63Smrg    if (!ExprResolveModMask(def->def, &val, LookupVModMask, (XPointer) xkb))
70334345a63Smrg    {
70434345a63Smrg        ERROR("Expected a modifier mask in group compatibility definition\n");
705bfe6082cSmrg        ACTION("Ignoring illegal compatibility map for group %d\n",
70634345a63Smrg                def->group);
70734345a63Smrg        return False;
70834345a63Smrg    }
70934345a63Smrg    tmp.real_mods = val.uval & 0xff;
71034345a63Smrg    tmp.vmods = (val.uval >> 8) & 0xffff;
7111d8c7986Smrg    tmp.defined = True;
71234345a63Smrg    return AddGroupCompat(info, def->group - 1, &tmp);
713f46a6179Smrg}
714f46a6179Smrg
715f46a6179Smrgstatic void
7166930ead5SmrgHandleCompatMapFile(const XkbFile *file,
7176930ead5Smrg                    XkbDescPtr xkb, unsigned merge, CompatInfo *info)
718f46a6179Smrg{
71934345a63Smrg    ParseCommon *stmt;
72034345a63Smrg
72134345a63Smrg    if (merge == MergeDefault)
72234345a63Smrg        merge = MergeAugment;
72334345a63Smrg    info->name = uStringDup(file->name);
72434345a63Smrg    stmt = file->defs;
72534345a63Smrg    while (stmt)
72634345a63Smrg    {
72734345a63Smrg        switch (stmt->stmtType)
72834345a63Smrg        {
72934345a63Smrg        case StmtInclude:
73034345a63Smrg            if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
73134345a63Smrg                                        HandleCompatMapFile))
73234345a63Smrg                info->errorCount++;
73334345a63Smrg            break;
73434345a63Smrg        case StmtInterpDef:
73534345a63Smrg            if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
73634345a63Smrg                info->errorCount++;
73734345a63Smrg            break;
73834345a63Smrg        case StmtGroupCompatDef:
73934345a63Smrg            if (!HandleGroupCompatDef
74034345a63Smrg                ((GroupCompatDef *) stmt, xkb, merge, info))
74134345a63Smrg                info->errorCount++;
74234345a63Smrg            break;
74334345a63Smrg        case StmtIndicatorMapDef:
74434345a63Smrg        {
74534345a63Smrg            LEDInfo *rtrn;
74634345a63Smrg            rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
74734345a63Smrg                                         &info->ledDflt, info->leds, merge);
74834345a63Smrg            if (rtrn != NULL)
74934345a63Smrg                info->leds = rtrn;
75034345a63Smrg            else
75134345a63Smrg                info->errorCount++;
75234345a63Smrg        }
75334345a63Smrg            break;
75434345a63Smrg        case StmtVarDef:
75534345a63Smrg            if (!HandleInterpVar((VarDef *) stmt, xkb, info))
75634345a63Smrg                info->errorCount++;
75734345a63Smrg            break;
75834345a63Smrg        case StmtVModDef:
75934345a63Smrg            if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
76034345a63Smrg                info->errorCount++;
76134345a63Smrg            break;
76234345a63Smrg        case StmtKeycodeDef:
76334345a63Smrg            ERROR("Interpretation files may not include other types\n");
76434345a63Smrg            ACTION("Ignoring definition of key name\n");
76534345a63Smrg            info->errorCount++;
76634345a63Smrg            break;
76734345a63Smrg        default:
768bfe6082cSmrg            WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
76934345a63Smrg                  stmt->stmtType);
77034345a63Smrg            break;
77134345a63Smrg        }
77234345a63Smrg        stmt = stmt->next;
77334345a63Smrg        if (info->errorCount > 10)
77434345a63Smrg        {
775f46a6179Smrg#ifdef NOISY
77634345a63Smrg            ERROR("Too many errors\n");
777f46a6179Smrg#endif
778bfe6082cSmrg            ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
77934345a63Smrg            break;
78034345a63Smrg        }
781f46a6179Smrg    }
782f46a6179Smrg    return;
783f46a6179Smrg}
784f46a6179Smrg
785f46a6179Smrgstatic void
7866930ead5SmrgCopyInterps(const CompatInfo *info,
78734345a63Smrg            XkbCompatMapPtr compat, Bool needSymbol, unsigned pred)
788f46a6179Smrg{
7896930ead5Smrg    for (SymInterpInfo *si = info->interps; si;
7906930ead5Smrg         si = (SymInterpInfo *) si->defs.next)
79134345a63Smrg    {
79234345a63Smrg        if (((si->interp.match & XkbSI_OpMask) != pred) ||
79334345a63Smrg            (needSymbol && (si->interp.sym == NoSymbol)) ||
79434345a63Smrg            ((!needSymbol) && (si->interp.sym != NoSymbol)))
79534345a63Smrg            continue;
79634345a63Smrg        if (compat->num_si >= compat->size_si)
79734345a63Smrg        {
79834345a63Smrg            WSGO("No room to merge symbol interpretations\n");
79934345a63Smrg            ACTION("Symbol interpretations lost\n");
80034345a63Smrg            return;
80134345a63Smrg        }
80234345a63Smrg        compat->sym_interpret[compat->num_si++] = si->interp;
803f46a6179Smrg    }
804f46a6179Smrg    return;
805f46a6179Smrg}
806f46a6179Smrg
807f46a6179SmrgBool
8086930ead5SmrgCompileCompatMap(const XkbFile *file,
8096930ead5Smrg                 XkbFileInfo *result, unsigned merge, LEDInfo **unboundLEDs)
810f46a6179Smrg{
81134345a63Smrg    CompatInfo info;
81234345a63Smrg    XkbDescPtr xkb;
81334345a63Smrg
81434345a63Smrg    xkb = result->xkb;
81534345a63Smrg    InitCompatInfo(&info, xkb);
81634345a63Smrg    info.dflt.defs.merge = merge;
81734345a63Smrg    info.ledDflt.defs.merge = merge;
81834345a63Smrg    HandleCompatMapFile(file, xkb, merge, &info);
81934345a63Smrg
82034345a63Smrg    if (info.errorCount == 0)
82134345a63Smrg    {
8226930ead5Smrg        int size, i;
8236930ead5Smrg        GroupCompatInfo *gcm;
8246930ead5Smrg
82534345a63Smrg        if (XkbAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
82634345a63Smrg            Success)
82734345a63Smrg        {
82834345a63Smrg            WSGO("Couldn't allocate compatibility map\n");
82934345a63Smrg            ACTION("Exiting\n");
83034345a63Smrg            return False;
83134345a63Smrg        }
83234345a63Smrg        if (info.name != NULL)
83334345a63Smrg        {
83434345a63Smrg            if (XkbAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
83534345a63Smrg                xkb->names->compat =
83634345a63Smrg                    XkbInternAtom(xkb->dpy, info.name, False);
83734345a63Smrg            else
83834345a63Smrg            {
83934345a63Smrg                WSGO("Couldn't allocate space for compat name\n");
840bfe6082cSmrg                ACTION("Name \"%s\" (from %s) NOT assigned\n",
84134345a63Smrg                        scanFile, info.name);
84234345a63Smrg            }
84334345a63Smrg        }
84434345a63Smrg        size = info.nInterps * sizeof(XkbSymInterpretRec);
84534345a63Smrg        if (size > 0)
84634345a63Smrg        {
84734345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
84834345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
84934345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
85034345a63Smrg            CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
85134345a63Smrg            CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
85234345a63Smrg            CopyInterps(&info, xkb->compat, False,
85334345a63Smrg                        XkbSI_AllOf | XkbSI_NoneOf);
85434345a63Smrg            CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
85534345a63Smrg            CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
85634345a63Smrg        }
85734345a63Smrg        for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
85834345a63Smrg             i++, gcm++)
85934345a63Smrg        {
86034345a63Smrg            if ((gcm->fileID != 0) || (gcm->real_mods != 0)
86134345a63Smrg                || (gcm->vmods != 0))
86234345a63Smrg            {
86334345a63Smrg                xkb->compat->groups[i].mask = gcm->real_mods;
86434345a63Smrg                xkb->compat->groups[i].real_mods = gcm->real_mods;
86534345a63Smrg                xkb->compat->groups[i].vmods = gcm->vmods;
86634345a63Smrg            }
86734345a63Smrg        }
86834345a63Smrg        if (info.leds != NULL)
86934345a63Smrg        {
87034345a63Smrg            if (!CopyIndicatorMapDefs(result, info.leds, unboundLEDs))
87134345a63Smrg                info.errorCount++;
87234345a63Smrg            info.leds = NULL;
87334345a63Smrg        }
87434345a63Smrg        ClearCompatInfo(&info, xkb);
87534345a63Smrg        return True;
87634345a63Smrg    }
8776930ead5Smrg    free(info.interps);
878f46a6179Smrg    return False;
879f46a6179Smrg}
880