symbols.c revision 1d8c7986
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 "xkbcomp.h"
28f46a6179Smrg#include "tokens.h"
29f46a6179Smrg#include "expr.h"
3083e5f723Smrg#include "parseutils.h"
31f46a6179Smrg
32f46a6179Smrg#include <X11/keysym.h>
33f46a6179Smrg#include <X11/Xutil.h>
34f46a6179Smrg#include <stdlib.h>
35f46a6179Smrg
36f46a6179Smrg#include "expr.h"
37f46a6179Smrg#include "vmod.h"
38f46a6179Smrg#include "action.h"
39f46a6179Smrg#include "keycodes.h"
40f46a6179Smrg#include "misc.h"
41f46a6179Smrg#include "alias.h"
42f46a6179Smrg
43f46a6179Smrg/***====================================================================***/
44f46a6179Smrg
45f46a6179Smrg#define	RepeatYes	1
46f46a6179Smrg#define	RepeatNo	0
47f46a6179Smrg#define	RepeatUndefined	~((unsigned)0)
48f46a6179Smrg
49f46a6179Smrg#define	_Key_Syms	(1<<0)
50f46a6179Smrg#define	_Key_Acts	(1<<1)
51f46a6179Smrg#define	_Key_Repeat	(1<<2)
52f46a6179Smrg#define	_Key_Behavior	(1<<3)
53f46a6179Smrg#define	_Key_Type_Dflt	(1<<4)
54f46a6179Smrg#define	_Key_Types	(1<<5)
55f46a6179Smrg#define	_Key_GroupInfo	(1<<6)
56f46a6179Smrg#define	_Key_VModMap	(1<<7)
57f46a6179Smrg
5834345a63Smrgtypedef struct _KeyInfo
5934345a63Smrg{
6034345a63Smrg    CommonInfo defs;
6134345a63Smrg    unsigned long name; /* the 4 chars of the key name, as long */
6234345a63Smrg    unsigned char groupInfo;
6334345a63Smrg    unsigned char typesDefined;
6434345a63Smrg    unsigned char symsDefined;
6534345a63Smrg    unsigned char actsDefined;
6634345a63Smrg    short numLevels[XkbNumKbdGroups];
6734345a63Smrg    KeySym *syms[XkbNumKbdGroups];
6834345a63Smrg    XkbAction *acts[XkbNumKbdGroups];
6934345a63Smrg    Atom types[XkbNumKbdGroups];
7034345a63Smrg    unsigned repeat;
7134345a63Smrg    XkbBehavior behavior;
7234345a63Smrg    unsigned short vmodmap;
7334345a63Smrg    unsigned long nameForOverlayKey;
7434345a63Smrg    unsigned long allowNone;
7534345a63Smrg    Atom dfltType;
76f46a6179Smrg} KeyInfo;
77f46a6179Smrg
7834345a63Smrg/**
7934345a63Smrg * Init the given key info to sane values.
8034345a63Smrg */
81f46a6179Smrgstatic void
8234345a63SmrgInitKeyInfo(KeyInfo * info)
83f46a6179Smrg{
8434345a63Smrg    register int i;
8534345a63Smrg    static char dflt[4] = "*";
8634345a63Smrg
8734345a63Smrg    info->defs.defined = 0;
8834345a63Smrg    info->defs.fileID = 0;
8934345a63Smrg    info->defs.merge = MergeOverride;
9034345a63Smrg    info->defs.next = NULL;
9134345a63Smrg    info->name = KeyNameToLong(dflt);
9234345a63Smrg    info->groupInfo = 0;
9334345a63Smrg    info->typesDefined = info->symsDefined = info->actsDefined = 0;
9434345a63Smrg    for (i = 0; i < XkbNumKbdGroups; i++)
9534345a63Smrg    {
9634345a63Smrg        info->numLevels[i] = 0;
9734345a63Smrg        info->types[i] = None;
9834345a63Smrg        info->syms[i] = NULL;
9934345a63Smrg        info->acts[i] = NULL;
10034345a63Smrg    }
10134345a63Smrg    info->dfltType = None;
10234345a63Smrg    info->behavior.type = XkbKB_Default;
10334345a63Smrg    info->behavior.data = 0;
10434345a63Smrg    info->vmodmap = 0;
10534345a63Smrg    info->nameForOverlayKey = 0;
10634345a63Smrg    info->repeat = RepeatUndefined;
10734345a63Smrg    info->allowNone = 0;
108f46a6179Smrg    return;
109f46a6179Smrg}
110f46a6179Smrg
11134345a63Smrg/**
11234345a63Smrg * Free memory associated with this key info and reset to sane values.
11334345a63Smrg */
114f46a6179Smrgstatic void
11534345a63SmrgFreeKeyInfo(KeyInfo * info)
116f46a6179Smrg{
11734345a63Smrg    register int i;
11834345a63Smrg
11934345a63Smrg    info->defs.defined = 0;
12034345a63Smrg    info->defs.fileID = 0;
12134345a63Smrg    info->defs.merge = MergeOverride;
12234345a63Smrg    info->defs.next = NULL;
12334345a63Smrg    info->groupInfo = 0;
12434345a63Smrg    info->typesDefined = info->symsDefined = info->actsDefined = 0;
12534345a63Smrg    for (i = 0; i < XkbNumKbdGroups; i++)
12634345a63Smrg    {
12734345a63Smrg        info->numLevels[i] = 0;
12834345a63Smrg        info->types[i] = None;
12934345a63Smrg        if (info->syms[i] != NULL)
13034345a63Smrg            uFree(info->syms[i]);
13134345a63Smrg        info->syms[i] = NULL;
13234345a63Smrg        if (info->acts[i] != NULL)
13334345a63Smrg            uFree(info->acts[i]);
13434345a63Smrg        info->acts[i] = NULL;
13534345a63Smrg    }
13634345a63Smrg    info->dfltType = None;
13734345a63Smrg    info->behavior.type = XkbKB_Default;
13834345a63Smrg    info->behavior.data = 0;
13934345a63Smrg    info->vmodmap = 0;
14034345a63Smrg    info->nameForOverlayKey = 0;
14134345a63Smrg    info->repeat = RepeatUndefined;
14234345a63Smrg    info->allowNone = 0;
143f46a6179Smrg    return;
144f46a6179Smrg}
145f46a6179Smrg
14634345a63Smrg/**
14734345a63Smrg * Copy old into new, optionally reset old to 0.
14834345a63Smrg * If old is reset, new simply re-uses old's memory. Otherwise, the memory is
14934345a63Smrg * newly allocated and new points to the new memory areas.
15034345a63Smrg */
151f46a6179Smrgstatic Bool
15234345a63SmrgCopyKeyInfo(KeyInfo * old, KeyInfo * new, Bool clearOld)
153f46a6179Smrg{
15434345a63Smrg    register int i;
15534345a63Smrg
15634345a63Smrg    *new = *old;
15734345a63Smrg    new->defs.next = NULL;
15834345a63Smrg    if (clearOld)
15934345a63Smrg    {
16034345a63Smrg        for (i = 0; i < XkbNumKbdGroups; i++)
16134345a63Smrg        {
16234345a63Smrg            old->numLevels[i] = 0;
16334345a63Smrg            old->syms[i] = NULL;
16434345a63Smrg            old->acts[i] = NULL;
16534345a63Smrg        }
16634345a63Smrg    }
16734345a63Smrg    else
16834345a63Smrg    {
16934345a63Smrg        int width;
17034345a63Smrg        for (i = 0; i < XkbNumKbdGroups; i++)
17134345a63Smrg        {
17234345a63Smrg            width = new->numLevels[i];
17334345a63Smrg            if (old->syms[i] != NULL)
17434345a63Smrg            {
17534345a63Smrg                new->syms[i] = uTypedCalloc(width, KeySym);
17634345a63Smrg                if (!new->syms[i])
17734345a63Smrg                {
17834345a63Smrg                    new->syms[i] = NULL;
17934345a63Smrg                    new->numLevels[i] = 0;
18034345a63Smrg                    return False;
18134345a63Smrg                }
18234345a63Smrg                memcpy((char *) new->syms[i], (char *) old->syms[i],
18334345a63Smrg                       width * sizeof(KeySym));
18434345a63Smrg            }
18534345a63Smrg            if (old->acts[i] != NULL)
18634345a63Smrg            {
18734345a63Smrg                new->acts[i] = uTypedCalloc(width, XkbAction);
18834345a63Smrg                if (!new->acts[i])
18934345a63Smrg                {
19034345a63Smrg                    new->acts[i] = NULL;
19134345a63Smrg                    return False;
19234345a63Smrg                }
19334345a63Smrg                memcpy((char *) new->acts[i], (char *) old->acts[i],
19434345a63Smrg                       width * sizeof(XkbAction));
19534345a63Smrg            }
19634345a63Smrg        }
197f46a6179Smrg    }
198f46a6179Smrg    return True;
199f46a6179Smrg}
200f46a6179Smrg
201f46a6179Smrg/***====================================================================***/
202f46a6179Smrg
20334345a63Smrgtypedef struct _ModMapEntry
20434345a63Smrg{
20534345a63Smrg    CommonInfo defs;
20634345a63Smrg    Bool haveSymbol;
20734345a63Smrg    int modifier;
20834345a63Smrg    union
20934345a63Smrg    {
21034345a63Smrg        unsigned long keyName;
21134345a63Smrg        KeySym keySym;
212f46a6179Smrg    } u;
213f46a6179Smrg} ModMapEntry;
214f46a6179Smrg
215f46a6179Smrg#define	SYMBOLS_INIT_SIZE	110
216f46a6179Smrg#define	SYMBOLS_CHUNK		20
21734345a63Smrgtypedef struct _SymbolsInfo
21834345a63Smrg{
21934345a63Smrg    char *name;         /* e.g. pc+us+inet(evdev) */
22034345a63Smrg    int errorCount;
22134345a63Smrg    unsigned fileID;
22234345a63Smrg    unsigned merge;
22334345a63Smrg    unsigned explicit_group;
22434345a63Smrg    unsigned groupInfo;
22534345a63Smrg    unsigned szKeys;
22634345a63Smrg    unsigned nKeys;
22734345a63Smrg    KeyInfo *keys;
22834345a63Smrg    KeyInfo dflt;
22934345a63Smrg    VModInfo vmods;
23034345a63Smrg    ActionInfo *action;
23134345a63Smrg    Atom groupNames[XkbNumKbdGroups];
23234345a63Smrg
23334345a63Smrg    ModMapEntry *modMap;
23434345a63Smrg    AliasInfo *aliases;
235f46a6179Smrg} SymbolsInfo;
236f46a6179Smrg
237f46a6179Smrgstatic void
23834345a63SmrgInitSymbolsInfo(SymbolsInfo * info, XkbDescPtr xkb)
239f46a6179Smrg{
24034345a63Smrg    register int i;
24134345a63Smrg
24234345a63Smrg    tok_ONE_LEVEL = XkbInternAtom(NULL, "ONE_LEVEL", False);
24334345a63Smrg    tok_TWO_LEVEL = XkbInternAtom(NULL, "TWO_LEVEL", False);
24434345a63Smrg    tok_KEYPAD = XkbInternAtom(NULL, "KEYPAD", False);
24534345a63Smrg    info->name = NULL;
24634345a63Smrg    info->explicit_group = 0;
24734345a63Smrg    info->errorCount = 0;
24834345a63Smrg    info->fileID = 0;
24934345a63Smrg    info->merge = MergeOverride;
25034345a63Smrg    info->groupInfo = 0;
25134345a63Smrg    info->szKeys = SYMBOLS_INIT_SIZE;
25234345a63Smrg    info->nKeys = 0;
25334345a63Smrg    info->keys = uTypedCalloc(SYMBOLS_INIT_SIZE, KeyInfo);
25434345a63Smrg    info->modMap = NULL;
25534345a63Smrg    for (i = 0; i < XkbNumKbdGroups; i++)
25634345a63Smrg        info->groupNames[i] = None;
257f46a6179Smrg    InitKeyInfo(&info->dflt);
25834345a63Smrg    InitVModInfo(&info->vmods, xkb);
25934345a63Smrg    info->action = NULL;
26034345a63Smrg    info->aliases = NULL;
261f46a6179Smrg    return;
262f46a6179Smrg}
263f46a6179Smrg
264f46a6179Smrgstatic void
26534345a63SmrgFreeSymbolsInfo(SymbolsInfo * info)
266f46a6179Smrg{
26734345a63Smrg    register int i;
268f46a6179Smrg
269f46a6179Smrg    if (info->name)
27034345a63Smrg        uFree(info->name);
27134345a63Smrg    info->name = NULL;
27234345a63Smrg    if (info->keys)
27334345a63Smrg    {
27434345a63Smrg        for (i = 0; i < info->nKeys; i++)
27534345a63Smrg        {
27634345a63Smrg            FreeKeyInfo(&info->keys[i]);
27734345a63Smrg        }
27834345a63Smrg        uFree(info->keys);
27934345a63Smrg        info->keys = NULL;
28034345a63Smrg    }
28134345a63Smrg    if (info->modMap)
28234345a63Smrg    {
28334345a63Smrg        ClearCommonInfo(&info->modMap->defs);
28434345a63Smrg        info->modMap = NULL;
28534345a63Smrg    }
28634345a63Smrg    if (info->aliases)
28734345a63Smrg    {
28834345a63Smrg        ClearAliases(&info->aliases);
28934345a63Smrg        info->aliases = NULL;
29034345a63Smrg    }
29134345a63Smrg    bzero((char *) info, sizeof(SymbolsInfo));
292f46a6179Smrg    return;
293f46a6179Smrg}
294f46a6179Smrg
295f46a6179Smrgstatic Bool
29634345a63SmrgResizeKeyGroup(KeyInfo * key,
29734345a63Smrg               unsigned group, unsigned atLeastSize, Bool forceActions)
298f46a6179Smrg{
29934345a63Smrg    Bool tooSmall;
30034345a63Smrg    unsigned newWidth;
30134345a63Smrg
30234345a63Smrg    tooSmall = (key->numLevels[group] < atLeastSize);
30334345a63Smrg    if (tooSmall)
30434345a63Smrg        newWidth = atLeastSize;
30534345a63Smrg    else
30634345a63Smrg        newWidth = key->numLevels[group];
30734345a63Smrg
30834345a63Smrg    if ((key->syms[group] == NULL) || tooSmall)
30934345a63Smrg    {
31034345a63Smrg        key->syms[group] = uTypedRecalloc(key->syms[group],
31134345a63Smrg                                          key->numLevels[group], newWidth,
31234345a63Smrg                                          KeySym);
31334345a63Smrg        if (!key->syms[group])
31434345a63Smrg            return False;
31534345a63Smrg    }
31634345a63Smrg    if (((forceActions) && (tooSmall || (key->acts[group] == NULL))) ||
31734345a63Smrg        (tooSmall && (key->acts[group] != NULL)))
31834345a63Smrg    {
31934345a63Smrg        key->acts[group] = uTypedRecalloc(key->acts[group],
32034345a63Smrg                                          key->numLevels[group], newWidth,
32134345a63Smrg                                          XkbAction);
32234345a63Smrg        if (!key->acts[group])
32334345a63Smrg            return False;
32434345a63Smrg    }
32534345a63Smrg    key->numLevels[group] = newWidth;
326f46a6179Smrg    return True;
327f46a6179Smrg}
328f46a6179Smrg
329f46a6179Smrgstatic Bool
33034345a63SmrgMergeKeyGroups(SymbolsInfo * info,
33134345a63Smrg               KeyInfo * into, KeyInfo * from, unsigned group)
332f46a6179Smrg{
33334345a63Smrg    KeySym *resultSyms;
33434345a63Smrg    XkbAction *resultActs;
33534345a63Smrg    int resultWidth;
33634345a63Smrg    register int i;
33734345a63Smrg    Bool report, clobber;
33834345a63Smrg
33934345a63Smrg    clobber = (from->defs.merge != MergeAugment);
34034345a63Smrg    report = (warningLevel > 9) ||
34134345a63Smrg        ((into->defs.fileID == from->defs.fileID) && (warningLevel > 0));
34234345a63Smrg    if (into->numLevels[group] >= from->numLevels[group])
34334345a63Smrg    {
34434345a63Smrg        resultSyms = into->syms[group];
34534345a63Smrg        resultActs = into->acts[group];
34634345a63Smrg        resultWidth = into->numLevels[group];
34734345a63Smrg    }
34834345a63Smrg    else
34934345a63Smrg    {
35034345a63Smrg        resultSyms = from->syms[group];
35134345a63Smrg        resultActs = from->acts[group];
35234345a63Smrg        resultWidth = from->numLevels[group];
35334345a63Smrg    }
35434345a63Smrg    if (resultSyms == NULL)
35534345a63Smrg    {
35634345a63Smrg        resultSyms = uTypedCalloc(resultWidth, KeySym);
35734345a63Smrg        if (!resultSyms)
35834345a63Smrg        {
35934345a63Smrg            WSGO("Could not allocate symbols for group merge\n");
36034345a63Smrg            ACTION2("Group %d of key %s not merged\n", group,
36134345a63Smrg                    longText(into->name, XkbMessage));
36234345a63Smrg            return False;
36334345a63Smrg        }
36434345a63Smrg    }
36534345a63Smrg    if ((resultActs == NULL) && (into->acts[group] || from->acts[group]))
36634345a63Smrg    {
36734345a63Smrg        resultActs = uTypedCalloc(resultWidth, XkbAction);
36834345a63Smrg        if (!resultActs)
36934345a63Smrg        {
37034345a63Smrg            WSGO("Could not allocate actions for group merge\n");
37134345a63Smrg            ACTION2("Group %d of key %s not merged\n", group,
37234345a63Smrg                    longText(into->name, XkbMessage));
37334345a63Smrg            return False;
37434345a63Smrg        }
37534345a63Smrg    }
37634345a63Smrg    for (i = 0; i < resultWidth; i++)
37734345a63Smrg    {
37834345a63Smrg        KeySym fromSym, toSym;
37934345a63Smrg        if (from->syms[group] && (i < from->numLevels[group]))
38034345a63Smrg            fromSym = from->syms[group][i];
38134345a63Smrg        else
38234345a63Smrg            fromSym = NoSymbol;
38334345a63Smrg        if (into->syms[group] && (i < into->numLevels[group]))
38434345a63Smrg            toSym = into->syms[group][i];
38534345a63Smrg        else
38634345a63Smrg            toSym = NoSymbol;
38734345a63Smrg        if ((fromSym == NoSymbol) || (fromSym == toSym))
38834345a63Smrg            resultSyms[i] = toSym;
38934345a63Smrg        else if (toSym == NoSymbol)
39034345a63Smrg            resultSyms[i] = fromSym;
39134345a63Smrg        else
39234345a63Smrg        {
39334345a63Smrg            KeySym use, ignore;
39434345a63Smrg            if (clobber)
39534345a63Smrg            {
39634345a63Smrg                use = fromSym;
39734345a63Smrg                ignore = toSym;
39834345a63Smrg            }
39934345a63Smrg            else
40034345a63Smrg            {
40134345a63Smrg                use = toSym;
40234345a63Smrg                ignore = fromSym;
40334345a63Smrg            }
40434345a63Smrg            if (report)
40534345a63Smrg            {
40634345a63Smrg                WARN3
40734345a63Smrg                    ("Multiple symbols for level %d/group %d on key %s\n",
40834345a63Smrg                     i + 1, group + 1, longText(into->name, XkbMessage));
40934345a63Smrg                ACTION2("Using %s, ignoring %s\n",
41034345a63Smrg                        XkbKeysymText(use, XkbMessage),
41134345a63Smrg                        XkbKeysymText(ignore, XkbMessage));
41234345a63Smrg            }
41334345a63Smrg            resultSyms[i] = use;
41434345a63Smrg        }
41534345a63Smrg        if (resultActs != NULL)
41634345a63Smrg        {
41734345a63Smrg            XkbAction *fromAct, *toAct;
41834345a63Smrg            fromAct = (from->acts[group] ? &from->acts[group][i] : NULL);
41934345a63Smrg            toAct = (into->acts[group] ? &into->acts[group][i] : NULL);
42034345a63Smrg            if (((fromAct == NULL) || (fromAct->type == XkbSA_NoAction))
42134345a63Smrg                && (toAct != NULL))
42234345a63Smrg            {
42334345a63Smrg                resultActs[i] = *toAct;
42434345a63Smrg            }
42534345a63Smrg            else if (((toAct == NULL) || (toAct->type == XkbSA_NoAction))
42634345a63Smrg                     && (fromAct != NULL))
42734345a63Smrg            {
42834345a63Smrg                resultActs[i] = *fromAct;
42934345a63Smrg            }
43034345a63Smrg            else
43134345a63Smrg            {
43234345a63Smrg                XkbAction *use, *ignore;
43334345a63Smrg                if (clobber)
43434345a63Smrg                {
43534345a63Smrg                    use = fromAct;
43634345a63Smrg                    ignore = toAct;
43734345a63Smrg                }
43834345a63Smrg                else
43934345a63Smrg                {
44034345a63Smrg                    use = toAct;
44134345a63Smrg                    ignore = fromAct;
44234345a63Smrg                }
44334345a63Smrg                if (report)
44434345a63Smrg                {
44534345a63Smrg                    WARN3
44634345a63Smrg                        ("Multiple actions for level %d/group %d on key %s\n",
44734345a63Smrg                         i + 1, group + 1, longText(into->name, XkbMessage));
44834345a63Smrg                    ACTION2("Using %s, ignoring %s\n",
44934345a63Smrg                            XkbActionTypeText(use->type, XkbMessage),
45034345a63Smrg                            XkbActionTypeText(ignore->type, XkbMessage));
45134345a63Smrg                }
45234345a63Smrg                resultActs[i] = *use;
45334345a63Smrg            }
45434345a63Smrg        }
45534345a63Smrg    }
45634345a63Smrg    if ((into->syms[group] != NULL) && (resultSyms != into->syms[group]))
45734345a63Smrg        uFree(into->syms[group]);
45834345a63Smrg    if ((from->syms[group] != NULL) && (resultSyms != from->syms[group]))
45934345a63Smrg        uFree(from->syms[group]);
46034345a63Smrg    if ((into->acts[group] != NULL) && (resultActs != into->acts[group]))
46134345a63Smrg        uFree(into->acts[group]);
46234345a63Smrg    if ((from->acts[group] != NULL) && (resultActs != from->acts[group]))
46334345a63Smrg        uFree(from->acts[group]);
46434345a63Smrg    into->numLevels[group] = resultWidth;
46534345a63Smrg    into->syms[group] = resultSyms;
46634345a63Smrg    from->syms[group] = NULL;
46734345a63Smrg    into->acts[group] = resultActs;
46834345a63Smrg    from->acts[group] = NULL;
46934345a63Smrg    into->symsDefined |= (1 << group);
47034345a63Smrg    from->symsDefined &= ~(1 << group);
47134345a63Smrg    into->actsDefined |= (1 << group);
47234345a63Smrg    from->actsDefined &= ~(1 << group);
473f46a6179Smrg    return True;
474f46a6179Smrg}
475f46a6179Smrg
476f46a6179Smrgstatic Bool
47734345a63SmrgMergeKeys(SymbolsInfo * info, KeyInfo * into, KeyInfo * from)
478f46a6179Smrg{
47934345a63Smrg    register int i;
48034345a63Smrg    unsigned collide = 0;
48134345a63Smrg    Bool report;
48234345a63Smrg
48334345a63Smrg    if (from->defs.merge == MergeReplace)
48434345a63Smrg    {
48534345a63Smrg        for (i = 0; i < XkbNumKbdGroups; i++)
48634345a63Smrg        {
48734345a63Smrg            if (into->numLevels[i] != 0)
48834345a63Smrg            {
48934345a63Smrg                if (into->syms[i])
49034345a63Smrg                    uFree(into->syms[i]);
49134345a63Smrg                if (into->acts[i])
49234345a63Smrg                    uFree(into->acts[i]);
49334345a63Smrg            }
49434345a63Smrg        }
49534345a63Smrg        *into = *from;
49634345a63Smrg        bzero(from, sizeof(KeyInfo));
49734345a63Smrg        return True;
49834345a63Smrg    }
49934345a63Smrg    report = ((warningLevel > 9) ||
50034345a63Smrg              ((into->defs.fileID == from->defs.fileID)
50134345a63Smrg               && (warningLevel > 0)));
50234345a63Smrg    for (i = 0; i < XkbNumKbdGroups; i++)
50334345a63Smrg    {
50434345a63Smrg        if (from->numLevels[i] > 0)
50534345a63Smrg        {
50634345a63Smrg            if (into->numLevels[i] == 0)
50734345a63Smrg            {
50834345a63Smrg                into->numLevels[i] = from->numLevels[i];
50934345a63Smrg                into->syms[i] = from->syms[i];
51034345a63Smrg                into->acts[i] = from->acts[i];
51134345a63Smrg                into->symsDefined |= (1 << i);
51234345a63Smrg                from->syms[i] = NULL;
51334345a63Smrg                from->acts[i] = NULL;
51434345a63Smrg                from->numLevels[i] = 0;
51534345a63Smrg                from->symsDefined &= ~(1 << i);
51634345a63Smrg                if (into->syms[i])
51734345a63Smrg                    into->defs.defined |= _Key_Syms;
51834345a63Smrg                if (into->acts[i])
51934345a63Smrg                    into->defs.defined |= _Key_Acts;
52034345a63Smrg            }
52134345a63Smrg            else
52234345a63Smrg            {
52334345a63Smrg                if (report)
52434345a63Smrg                {
52534345a63Smrg                    if (into->syms[i])
52634345a63Smrg                        collide |= _Key_Syms;
52734345a63Smrg                    if (into->acts[i])
52834345a63Smrg                        collide |= _Key_Acts;
52934345a63Smrg                }
53034345a63Smrg                MergeKeyGroups(info, into, from, (unsigned) i);
53134345a63Smrg            }
53234345a63Smrg        }
53334345a63Smrg        if (from->types[i] != None)
53434345a63Smrg        {
53534345a63Smrg            if ((into->types[i] != None) && (report) &&
53634345a63Smrg                (into->types[i] != from->types[i]))
53734345a63Smrg            {
53834345a63Smrg                Atom use, ignore;
53934345a63Smrg                collide |= _Key_Types;
54034345a63Smrg                if (from->defs.merge != MergeAugment)
54134345a63Smrg                {
54234345a63Smrg                    use = from->types[i];
54334345a63Smrg                    ignore = into->types[i];
54434345a63Smrg                }
54534345a63Smrg                else
54634345a63Smrg                {
54734345a63Smrg                    use = into->types[i];
54834345a63Smrg                    ignore = from->types[i];
54934345a63Smrg                }
55034345a63Smrg                WARN2
55134345a63Smrg                    ("Multiple definitions for group %d type of key %s\n",
55234345a63Smrg                     i, longText(into->name, XkbMessage));
55334345a63Smrg                ACTION2("Using %s, ignoring %s\n",
55434345a63Smrg                        XkbAtomText(NULL, use, XkbMessage),
55534345a63Smrg                        XkbAtomText(NULL, ignore, XkbMessage));
55634345a63Smrg            }
55734345a63Smrg            if ((from->defs.merge != MergeAugment)
55834345a63Smrg                || (into->types[i] == None))
55934345a63Smrg            {
56034345a63Smrg                into->types[i] = from->types[i];
56134345a63Smrg            }
56234345a63Smrg        }
56334345a63Smrg    }
56434345a63Smrg    if (UseNewField(_Key_Behavior, &into->defs, &from->defs, &collide))
56534345a63Smrg    {
56634345a63Smrg        into->behavior = from->behavior;
56734345a63Smrg        into->nameForOverlayKey = from->nameForOverlayKey;
56834345a63Smrg        into->defs.defined |= _Key_Behavior;
56934345a63Smrg    }
57034345a63Smrg    if (UseNewField(_Key_VModMap, &into->defs, &from->defs, &collide))
57134345a63Smrg    {
57234345a63Smrg        into->vmodmap = from->vmodmap;
57334345a63Smrg        into->defs.defined |= _Key_VModMap;
57434345a63Smrg    }
57534345a63Smrg    if (UseNewField(_Key_Repeat, &into->defs, &from->defs, &collide))
57634345a63Smrg    {
57734345a63Smrg        into->repeat = from->repeat;
57834345a63Smrg        into->defs.defined |= _Key_Repeat;
57934345a63Smrg    }
58034345a63Smrg    if (UseNewField(_Key_Type_Dflt, &into->defs, &from->defs, &collide))
58134345a63Smrg    {
58234345a63Smrg        into->dfltType = from->dfltType;
58334345a63Smrg        into->defs.defined |= _Key_Type_Dflt;
58434345a63Smrg    }
58534345a63Smrg    if (UseNewField(_Key_GroupInfo, &into->defs, &from->defs, &collide))
58634345a63Smrg    {
58734345a63Smrg        into->groupInfo = from->groupInfo;
58834345a63Smrg        into->defs.defined |= _Key_GroupInfo;
58934345a63Smrg    }
59034345a63Smrg    if (collide)
59134345a63Smrg    {
59234345a63Smrg        WARN1("Symbol map for key %s redefined\n",
59334345a63Smrg              longText(into->name, XkbMessage));
59434345a63Smrg        ACTION1("Using %s definition for conflicting fields\n",
59534345a63Smrg                (from->defs.merge == MergeAugment ? "first" : "last"));
596f46a6179Smrg    }
597f46a6179Smrg    return True;
598f46a6179Smrg}
599f46a6179Smrg
600f46a6179Smrgstatic Bool
60134345a63SmrgAddKeySymbols(SymbolsInfo * info, KeyInfo * key, XkbDescPtr xkb)
602f46a6179Smrg{
60334345a63Smrg    register int i;
60434345a63Smrg    unsigned long real_name;
60534345a63Smrg
60634345a63Smrg    for (i = 0; i < info->nKeys; i++)
60734345a63Smrg    {
60834345a63Smrg        if (info->keys[i].name == key->name)
60934345a63Smrg            return MergeKeys(info, &info->keys[i], key);
61034345a63Smrg    }
61134345a63Smrg    if (FindKeyNameForAlias(xkb, key->name, &real_name))
61234345a63Smrg    {
61334345a63Smrg        for (i = 0; i < info->nKeys; i++)
61434345a63Smrg        {
61534345a63Smrg            if (info->keys[i].name == real_name)
61634345a63Smrg                return MergeKeys(info, &info->keys[i], key);
617f46a6179Smrg        }
618f46a6179Smrg    }
61934345a63Smrg    if (info->nKeys >= info->szKeys)
62034345a63Smrg    {
62134345a63Smrg        info->szKeys += SYMBOLS_CHUNK;
62234345a63Smrg        info->keys =
62334345a63Smrg            uTypedRecalloc(info->keys, info->nKeys, info->szKeys, KeyInfo);
62434345a63Smrg        if (!info->keys)
62534345a63Smrg        {
62634345a63Smrg            WSGO("Could not allocate key symbols descriptions\n");
62734345a63Smrg            ACTION("Some key symbols definitions may be lost\n");
62834345a63Smrg            return False;
62934345a63Smrg        }
630f46a6179Smrg    }
63134345a63Smrg    return CopyKeyInfo(key, &info->keys[info->nKeys++], True);
632f46a6179Smrg}
633f46a6179Smrg
634f46a6179Smrgstatic Bool
63534345a63SmrgAddModMapEntry(SymbolsInfo * info, ModMapEntry * new)
636f46a6179Smrg{
63734345a63Smrg    ModMapEntry *mm;
63834345a63Smrg    Bool clobber;
63934345a63Smrg
64034345a63Smrg    clobber = (new->defs.merge != MergeAugment);
64134345a63Smrg    for (mm = info->modMap; mm != NULL; mm = (ModMapEntry *) mm->defs.next)
64234345a63Smrg    {
64334345a63Smrg        if (new->haveSymbol && mm->haveSymbol
64434345a63Smrg            && (new->u.keySym == mm->u.keySym))
64534345a63Smrg        {
64634345a63Smrg            unsigned use, ignore;
64734345a63Smrg            if (mm->modifier != new->modifier)
64834345a63Smrg            {
64934345a63Smrg                if (clobber)
65034345a63Smrg                {
65134345a63Smrg                    use = new->modifier;
65234345a63Smrg                    ignore = mm->modifier;
65334345a63Smrg                }
65434345a63Smrg                else
65534345a63Smrg                {
65634345a63Smrg                    use = mm->modifier;
65734345a63Smrg                    ignore = new->modifier;
65834345a63Smrg                }
65934345a63Smrg                ERROR1
66034345a63Smrg                    ("%s added to symbol map for multiple modifiers\n",
66134345a63Smrg                     XkbKeysymText(new->u.keySym, XkbMessage));
66234345a63Smrg                ACTION2("Using %s, ignoring %s.\n",
66334345a63Smrg                        XkbModIndexText(use, XkbMessage),
66434345a63Smrg                        XkbModIndexText(ignore, XkbMessage));
66534345a63Smrg                mm->modifier = use;
66634345a63Smrg            }
66734345a63Smrg            return True;
66834345a63Smrg        }
66934345a63Smrg        if ((!new->haveSymbol) && (!mm->haveSymbol) &&
67034345a63Smrg            (new->u.keyName == mm->u.keyName))
67134345a63Smrg        {
67234345a63Smrg            unsigned use, ignore;
67334345a63Smrg            if (mm->modifier != new->modifier)
67434345a63Smrg            {
67534345a63Smrg                if (clobber)
67634345a63Smrg                {
67734345a63Smrg                    use = new->modifier;
67834345a63Smrg                    ignore = mm->modifier;
67934345a63Smrg                }
68034345a63Smrg                else
68134345a63Smrg                {
68234345a63Smrg                    use = mm->modifier;
68334345a63Smrg                    ignore = new->modifier;
68434345a63Smrg                }
68534345a63Smrg                ERROR1("Key %s added to map for multiple modifiers\n",
68634345a63Smrg                       longText(new->u.keyName, XkbMessage));
68734345a63Smrg                ACTION2("Using %s, ignoring %s.\n",
68834345a63Smrg                        XkbModIndexText(use, XkbMessage),
68934345a63Smrg                        XkbModIndexText(ignore, XkbMessage));
69034345a63Smrg                mm->modifier = use;
69134345a63Smrg            }
69234345a63Smrg            return True;
69334345a63Smrg        }
69434345a63Smrg    }
69534345a63Smrg    mm = uTypedAlloc(ModMapEntry);
69634345a63Smrg    if (mm == NULL)
69734345a63Smrg    {
69834345a63Smrg        WSGO("Could not allocate modifier map entry\n");
69934345a63Smrg        ACTION1("Modifier map for %s will be incomplete\n",
70034345a63Smrg                XkbModIndexText(new->modifier, XkbMessage));
70134345a63Smrg        return False;
70234345a63Smrg    }
70334345a63Smrg    *mm = *new;
70434345a63Smrg    mm->defs.next = &info->modMap->defs;
70534345a63Smrg    info->modMap = mm;
706f46a6179Smrg    return True;
707f46a6179Smrg}
708f46a6179Smrg
709f46a6179Smrg/***====================================================================***/
710f46a6179Smrg
711f46a6179Smrgstatic void
71234345a63SmrgMergeIncludedSymbols(SymbolsInfo * into, SymbolsInfo * from,
71334345a63Smrg                     unsigned merge, XkbDescPtr xkb)
714f46a6179Smrg{
71534345a63Smrg    register int i;
71634345a63Smrg    KeyInfo *key;
71734345a63Smrg
71834345a63Smrg    if (from->errorCount > 0)
71934345a63Smrg    {
72034345a63Smrg        into->errorCount += from->errorCount;
72134345a63Smrg        return;
72234345a63Smrg    }
72334345a63Smrg    if (into->name == NULL)
72434345a63Smrg    {
72534345a63Smrg        into->name = from->name;
72634345a63Smrg        from->name = NULL;
72734345a63Smrg    }
72834345a63Smrg    for (i = 0; i < XkbNumKbdGroups; i++)
72934345a63Smrg    {
73034345a63Smrg        if (from->groupNames[i] != None)
73134345a63Smrg        {
73234345a63Smrg            if ((merge != MergeAugment) || (into->groupNames[i] == None))
73334345a63Smrg                into->groupNames[i] = from->groupNames[i];
73434345a63Smrg        }
73534345a63Smrg    }
73634345a63Smrg    for (i = 0, key = from->keys; i < from->nKeys; i++, key++)
73734345a63Smrg    {
73834345a63Smrg        if (merge != MergeDefault)
73934345a63Smrg            key->defs.merge = merge;
74034345a63Smrg        if (!AddKeySymbols(into, key, xkb))
74134345a63Smrg            into->errorCount++;
74234345a63Smrg    }
74334345a63Smrg    if (from->modMap != NULL)
74434345a63Smrg    {
74534345a63Smrg        ModMapEntry *mm, *next;
74634345a63Smrg        for (mm = from->modMap; mm != NULL; mm = next)
74734345a63Smrg        {
74834345a63Smrg            if (merge != MergeDefault)
74934345a63Smrg                mm->defs.merge = merge;
75034345a63Smrg            if (!AddModMapEntry(into, mm))
75134345a63Smrg                into->errorCount++;
75234345a63Smrg            next = (ModMapEntry *) mm->defs.next;
75334345a63Smrg            uFree(mm);
75434345a63Smrg        }
75534345a63Smrg        from->modMap = NULL;
75634345a63Smrg    }
75734345a63Smrg    if (!MergeAliases(&into->aliases, &from->aliases, merge))
75834345a63Smrg        into->errorCount++;
759f46a6179Smrg    return;
760f46a6179Smrg}
761f46a6179Smrg
76234345a63Smrgtypedef void (*FileHandler) (XkbFile * /* rtrn */ ,
76334345a63Smrg                             XkbDescPtr /* xkb */ ,
76434345a63Smrg                             unsigned /* merge */ ,
76534345a63Smrg                             SymbolsInfo *      /* included */
76634345a63Smrg    );
767f46a6179Smrg
768f46a6179Smrgstatic Bool
76934345a63SmrgHandleIncludeSymbols(IncludeStmt * stmt,
77034345a63Smrg                     XkbDescPtr xkb, SymbolsInfo * info, FileHandler hndlr)
771f46a6179Smrg{
77234345a63Smrg    unsigned newMerge;
77334345a63Smrg    XkbFile *rtrn;
77434345a63Smrg    SymbolsInfo included;
77534345a63Smrg    Bool haveSelf;
77634345a63Smrg
77734345a63Smrg    haveSelf = False;
77834345a63Smrg    if ((stmt->file == NULL) && (stmt->map == NULL))
77934345a63Smrg    {
78034345a63Smrg        haveSelf = True;
78134345a63Smrg        included = *info;
78234345a63Smrg        bzero(info, sizeof(SymbolsInfo));
78334345a63Smrg    }
78434345a63Smrg    else if (ProcessIncludeFile(stmt, XkmSymbolsIndex, &rtrn, &newMerge))
78534345a63Smrg    {
78634345a63Smrg        InitSymbolsInfo(&included, xkb);
78734345a63Smrg        included.fileID = included.dflt.defs.fileID = rtrn->id;
78834345a63Smrg        included.merge = included.dflt.defs.merge = MergeOverride;
78934345a63Smrg        if (stmt->modifier)
79034345a63Smrg        {
79134345a63Smrg            included.explicit_group = atoi(stmt->modifier) - 1;
79234345a63Smrg        }
79334345a63Smrg        else
79434345a63Smrg        {
79534345a63Smrg            included.explicit_group = info->explicit_group;
79634345a63Smrg        }
79734345a63Smrg        (*hndlr) (rtrn, xkb, MergeOverride, &included);
79834345a63Smrg        if (stmt->stmt != NULL)
79934345a63Smrg        {
80034345a63Smrg            if (included.name != NULL)
80134345a63Smrg                uFree(included.name);
80234345a63Smrg            included.name = stmt->stmt;
80334345a63Smrg            stmt->stmt = NULL;
80434345a63Smrg        }
80534345a63Smrg    }
80634345a63Smrg    else
80734345a63Smrg    {
80834345a63Smrg        info->errorCount += 10;
80934345a63Smrg        return False;
81034345a63Smrg    }
81134345a63Smrg    if ((stmt->next != NULL) && (included.errorCount < 1))
81234345a63Smrg    {
81334345a63Smrg        IncludeStmt *next;
81434345a63Smrg        unsigned op;
81534345a63Smrg        SymbolsInfo next_incl;
81634345a63Smrg
81734345a63Smrg        for (next = stmt->next; next != NULL; next = next->next)
81834345a63Smrg        {
81934345a63Smrg            if ((next->file == NULL) && (next->map == NULL))
82034345a63Smrg            {
82134345a63Smrg                haveSelf = True;
82234345a63Smrg                MergeIncludedSymbols(&included, info, next->merge, xkb);
82334345a63Smrg                FreeSymbolsInfo(info);
82434345a63Smrg            }
82534345a63Smrg            else if (ProcessIncludeFile(next, XkmSymbolsIndex, &rtrn, &op))
82634345a63Smrg            {
82734345a63Smrg                InitSymbolsInfo(&next_incl, xkb);
82834345a63Smrg                next_incl.fileID = next_incl.dflt.defs.fileID = rtrn->id;
82934345a63Smrg                next_incl.merge = next_incl.dflt.defs.merge = MergeOverride;
83034345a63Smrg                if (next->modifier)
83134345a63Smrg                {
83234345a63Smrg                    next_incl.explicit_group = atoi(next->modifier) - 1;
83334345a63Smrg                }
83434345a63Smrg                else
83534345a63Smrg                {
83634345a63Smrg                    next_incl.explicit_group = info->explicit_group;
837f46a6179Smrg                }
83834345a63Smrg                (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
83934345a63Smrg                MergeIncludedSymbols(&included, &next_incl, op, xkb);
84034345a63Smrg                FreeSymbolsInfo(&next_incl);
84134345a63Smrg            }
84234345a63Smrg            else
84334345a63Smrg            {
84434345a63Smrg                info->errorCount += 10;
84534345a63Smrg                return False;
84634345a63Smrg            }
84734345a63Smrg        }
848f46a6179Smrg    }
849f46a6179Smrg    if (haveSelf)
85034345a63Smrg        *info = included;
85134345a63Smrg    else
85234345a63Smrg    {
85334345a63Smrg        MergeIncludedSymbols(info, &included, newMerge, xkb);
85434345a63Smrg        FreeSymbolsInfo(&included);
855f46a6179Smrg    }
85634345a63Smrg    return (info->errorCount == 0);
857f46a6179Smrg}
858f46a6179Smrg
85934345a63Smrgstatic LookupEntry groupNames[] = {
86034345a63Smrg    {"group1", 1},
86134345a63Smrg    {"group2", 2},
86234345a63Smrg    {"group3", 3},
86334345a63Smrg    {"group4", 4},
86434345a63Smrg    {"group5", 5},
86534345a63Smrg    {"group6", 6},
86634345a63Smrg    {"group7", 7},
86734345a63Smrg    {"group8", 8},
86834345a63Smrg    {NULL, 0}
869f46a6179Smrg};
870f46a6179Smrg
871f46a6179Smrg
872f46a6179Smrg#define	SYMBOLS 1
873f46a6179Smrg#define	ACTIONS	2
874f46a6179Smrg
875f46a6179Smrgstatic Bool
87634345a63SmrgGetGroupIndex(KeyInfo * key,
87734345a63Smrg              ExprDef * arrayNdx, unsigned what, unsigned *ndx_rtrn)
878f46a6179Smrg{
87934345a63Smrg    const char *name;
88034345a63Smrg    ExprResult tmp;
88134345a63Smrg
88234345a63Smrg    if (what == SYMBOLS)
88334345a63Smrg        name = "symbols";
88434345a63Smrg    else
88534345a63Smrg        name = "actions";
88634345a63Smrg
88734345a63Smrg    if (arrayNdx == NULL)
88834345a63Smrg    {
88934345a63Smrg        register int i;
89034345a63Smrg        unsigned defined;
89134345a63Smrg        if (what == SYMBOLS)
89234345a63Smrg            defined = key->symsDefined;
89334345a63Smrg        else
89434345a63Smrg            defined = key->actsDefined;
89534345a63Smrg
89634345a63Smrg        for (i = 0; i < XkbNumKbdGroups; i++)
89734345a63Smrg        {
89834345a63Smrg            if ((defined & (1 << i)) == 0)
89934345a63Smrg            {
90034345a63Smrg                *ndx_rtrn = i;
90134345a63Smrg                return True;
90234345a63Smrg            }
90334345a63Smrg        }
90434345a63Smrg        ERROR3("Too many groups of %s for key %s (max %d)\n", name,
90534345a63Smrg               longText(key->name, XkbMessage), XkbNumKbdGroups + 1);
90634345a63Smrg        ACTION1("Ignoring %s defined for extra groups\n", name);
90734345a63Smrg        return False;
90834345a63Smrg    }
90934345a63Smrg    if (!ExprResolveInteger
91034345a63Smrg        (arrayNdx, &tmp, SimpleLookup, (XPointer) groupNames))
91134345a63Smrg    {
91234345a63Smrg        ERROR2("Illegal group index for %s of key %s\n", name,
91334345a63Smrg               longText(key->name, XkbMessage));
91434345a63Smrg        ACTION("Definition with non-integer array index ignored\n");
91534345a63Smrg        return False;
91634345a63Smrg    }
91734345a63Smrg    if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
91834345a63Smrg    {
91934345a63Smrg        ERROR3("Group index for %s of key %s is out of range (1..%d)\n",
92034345a63Smrg               name, longText(key->name, XkbMessage), XkbNumKbdGroups + 1);
92134345a63Smrg        ACTION2("Ignoring %s for group %d\n", name, tmp.uval);
92234345a63Smrg        return False;
92334345a63Smrg    }
92434345a63Smrg    *ndx_rtrn = tmp.uval - 1;
925f46a6179Smrg    return True;
926f46a6179Smrg}
927f46a6179Smrg
928f46a6179Smrgstatic Bool
92934345a63SmrgAddSymbolsToKey(KeyInfo * key,
93034345a63Smrg                XkbDescPtr xkb,
93134345a63Smrg                char *field,
93234345a63Smrg                ExprDef * arrayNdx, ExprDef * value, SymbolsInfo * info)
933f46a6179Smrg{
93434345a63Smrg    unsigned ndx, nSyms;
93534345a63Smrg    int i;
93634345a63Smrg
93734345a63Smrg    if (!GetGroupIndex(key, arrayNdx, SYMBOLS, &ndx))
93834345a63Smrg        return False;
93934345a63Smrg    if (value == NULL)
94034345a63Smrg    {
94134345a63Smrg        key->symsDefined |= (1 << ndx);
94234345a63Smrg        return True;
94334345a63Smrg    }
94434345a63Smrg    if (value->op != ExprKeysymList)
94534345a63Smrg    {
94634345a63Smrg        ERROR1("Expected a list of symbols, found %s\n",
94734345a63Smrg               exprOpText(value->op));
94834345a63Smrg        ACTION2("Ignoring symbols for group %d of %s\n", ndx,
94934345a63Smrg                longText(key->name, XkbMessage));
95034345a63Smrg        return False;
95134345a63Smrg    }
95234345a63Smrg    if (key->syms[ndx] != NULL)
95334345a63Smrg    {
95434345a63Smrg        WSGO2("Symbols for key %s, group %d already defined\n",
95534345a63Smrg              longText(key->name, XkbMessage), ndx);
95634345a63Smrg        return False;
95734345a63Smrg    }
95834345a63Smrg    nSyms = value->value.list.nSyms;
95934345a63Smrg    if (((key->numLevels[ndx] < nSyms) || (key->syms[ndx] == NULL)) &&
96034345a63Smrg        (!ResizeKeyGroup(key, ndx, nSyms, False)))
96134345a63Smrg    {
96234345a63Smrg        WSGO2("Could not resize group %d of key %s\n", ndx,
96334345a63Smrg              longText(key->name, XkbMessage));
96434345a63Smrg        ACTION("Symbols lost\n");
96534345a63Smrg        return False;
96634345a63Smrg    }
96734345a63Smrg    key->symsDefined |= (1 << ndx);
96883e5f723Smrg    for (i = 0; i < nSyms; i++) {
96983e5f723Smrg        if (!LookupKeysym(value->value.list.syms[i], &key->syms[ndx][i])) {
97083e5f723Smrg            WSGO1("Could not resolve keysym %s\n", value->value.list.syms[i]);
97183e5f723Smrg            key->syms[ndx][i] = NoSymbol;
97283e5f723Smrg        }
97383e5f723Smrg    }
97434345a63Smrg    for (i = key->numLevels[ndx] - 1;
97534345a63Smrg         (i >= 0) && (key->syms[ndx][i] == NoSymbol); i--)
97634345a63Smrg    {
97734345a63Smrg        key->numLevels[ndx]--;
978f46a6179Smrg    }
979f46a6179Smrg    return True;
980f46a6179Smrg}
981f46a6179Smrg
982f46a6179Smrgstatic Bool
98334345a63SmrgAddActionsToKey(KeyInfo * key,
98434345a63Smrg                XkbDescPtr xkb,
98534345a63Smrg                char *field,
98634345a63Smrg                ExprDef * arrayNdx, ExprDef * value, SymbolsInfo * info)
987f46a6179Smrg{
98834345a63Smrg    register int i;
98934345a63Smrg    unsigned ndx, nActs;
99034345a63Smrg    ExprDef *act;
99134345a63Smrg    XkbAnyAction *toAct;
99234345a63Smrg
99334345a63Smrg    if (!GetGroupIndex(key, arrayNdx, ACTIONS, &ndx))
99434345a63Smrg        return False;
99534345a63Smrg
99634345a63Smrg    if (value == NULL)
99734345a63Smrg    {
99834345a63Smrg        key->actsDefined |= (1 << ndx);
99934345a63Smrg        return True;
100034345a63Smrg    }
100134345a63Smrg    if (value->op != ExprActionList)
100234345a63Smrg    {
100334345a63Smrg        WSGO1("Bad expression type (%d) for action list value\n", value->op);
100434345a63Smrg        ACTION2("Ignoring actions for group %d of %s\n", ndx,
100534345a63Smrg                longText(key->name, XkbMessage));
100634345a63Smrg        return False;
100734345a63Smrg    }
100834345a63Smrg    if (key->acts[ndx] != NULL)
100934345a63Smrg    {
101034345a63Smrg        WSGO2("Actions for key %s, group %d already defined\n",
101134345a63Smrg              longText(key->name, XkbMessage), ndx);
101234345a63Smrg        return False;
101334345a63Smrg    }
101434345a63Smrg    for (nActs = 0, act = value->value.child; act != NULL; nActs++)
101534345a63Smrg    {
101634345a63Smrg        act = (ExprDef *) act->common.next;
101734345a63Smrg    }
101834345a63Smrg    if (nActs < 1)
101934345a63Smrg    {
102034345a63Smrg        WSGO("Action list but not actions in AddActionsToKey\n");
102134345a63Smrg        return False;
102234345a63Smrg    }
102334345a63Smrg    if (((key->numLevels[ndx] < nActs) || (key->acts[ndx] == NULL)) &&
102434345a63Smrg        (!ResizeKeyGroup(key, ndx, nActs, True)))
102534345a63Smrg    {
102634345a63Smrg        WSGO2("Could not resize group %d of key %s\n", ndx,
102734345a63Smrg              longText(key->name, XkbMessage));
102834345a63Smrg        ACTION("Actions lost\n");
102934345a63Smrg        return False;
103034345a63Smrg    }
103134345a63Smrg    key->actsDefined |= (1 << ndx);
103234345a63Smrg
103334345a63Smrg    toAct = (XkbAnyAction *) key->acts[ndx];
103434345a63Smrg    act = value->value.child;
103534345a63Smrg    for (i = 0; i < nActs; i++, toAct++)
103634345a63Smrg    {
103734345a63Smrg        if (!HandleActionDef(act, xkb, toAct, MergeOverride, info->action))
103834345a63Smrg        {
103934345a63Smrg            ERROR1("Illegal action definition for %s\n",
104034345a63Smrg                   longText(key->name, XkbMessage));
104134345a63Smrg            ACTION2("Action for group %d/level %d ignored\n", ndx + 1, i + 1);
104234345a63Smrg        }
104334345a63Smrg        act = (ExprDef *) act->common.next;
1044f46a6179Smrg    }
1045f46a6179Smrg    return True;
1046f46a6179Smrg}
1047f46a6179Smrg
1048f46a6179Smrgstatic int
104934345a63SmrgSetAllowNone(KeyInfo * key, ExprDef * arrayNdx, ExprDef * value)
1050f46a6179Smrg{
105134345a63Smrg    ExprResult tmp;
105234345a63Smrg    unsigned radio_groups = 0;
105334345a63Smrg
105434345a63Smrg    if (arrayNdx == NULL)
105534345a63Smrg    {
105634345a63Smrg        radio_groups = XkbAllRadioGroupsMask;
105734345a63Smrg    }
105834345a63Smrg    else
105934345a63Smrg    {
106034345a63Smrg        if (!ExprResolveInteger(arrayNdx, &tmp, RadioLookup, NULL))
106134345a63Smrg        {
106234345a63Smrg            ERROR("Illegal index in group name definition\n");
106334345a63Smrg            ACTION("Definition with non-integer array index ignored\n");
106434345a63Smrg            return False;
106534345a63Smrg        }
106634345a63Smrg        if ((tmp.uval < 1) || (tmp.uval > XkbMaxRadioGroups))
106734345a63Smrg        {
106834345a63Smrg            ERROR1("Illegal radio group specified (must be 1..%d)\n",
106934345a63Smrg                   XkbMaxRadioGroups + 1);
107034345a63Smrg            ACTION1("Value of \"allow none\" for group %d ignored\n",
107134345a63Smrg                    tmp.uval);
107234345a63Smrg            return False;
107334345a63Smrg        }
107434345a63Smrg        radio_groups |= (1 << (tmp.uval - 1));
107534345a63Smrg    }
107634345a63Smrg    if (!ExprResolveBoolean(value, &tmp, NULL, NULL))
107734345a63Smrg    {
107834345a63Smrg        ERROR1("Illegal \"allow none\" value for %s\n",
107934345a63Smrg               longText(key->name, XkbMessage));
108034345a63Smrg        ACTION("Non-boolean value ignored\n");
108134345a63Smrg        return False;
108234345a63Smrg    }
108334345a63Smrg    if (tmp.uval)
108434345a63Smrg        key->allowNone |= radio_groups;
108534345a63Smrg    else
108634345a63Smrg        key->allowNone &= ~radio_groups;
1087f46a6179Smrg    return True;
1088f46a6179Smrg}
1089f46a6179Smrg
1090f46a6179Smrg
109134345a63Smrgstatic LookupEntry lockingEntries[] = {
109234345a63Smrg    {"true", XkbKB_Lock},
109334345a63Smrg    {"yes", XkbKB_Lock},
109434345a63Smrg    {"on", XkbKB_Lock},
109534345a63Smrg    {"false", XkbKB_Default},
109634345a63Smrg    {"no", XkbKB_Default},
109734345a63Smrg    {"off", XkbKB_Default},
109834345a63Smrg    {"permanent", XkbKB_Lock | XkbKB_Permanent},
109934345a63Smrg    {NULL, 0}
1100f46a6179Smrg};
1101f46a6179Smrg
110234345a63Smrgstatic LookupEntry repeatEntries[] = {
110334345a63Smrg    {"true", RepeatYes},
110434345a63Smrg    {"yes", RepeatYes},
110534345a63Smrg    {"on", RepeatYes},
110634345a63Smrg    {"false", RepeatNo},
110734345a63Smrg    {"no", RepeatNo},
110834345a63Smrg    {"off", RepeatNo},
110934345a63Smrg    {"default", RepeatUndefined},
111034345a63Smrg    {NULL, 0}
1111f46a6179Smrg};
1112f46a6179Smrg
111334345a63Smrgstatic LookupEntry rgEntries[] = {
111434345a63Smrg    {"none", 0},
111534345a63Smrg    {NULL, 0}
1116f46a6179Smrg};
1117f46a6179Smrg
1118f46a6179Smrgstatic Bool
111934345a63SmrgSetSymbolsField(KeyInfo * key,
112034345a63Smrg                XkbDescPtr xkb,
112134345a63Smrg                char *field,
112234345a63Smrg                ExprDef * arrayNdx, ExprDef * value, SymbolsInfo * info)
1123f46a6179Smrg{
112434345a63Smrg    Bool ok = True;
112534345a63Smrg    ExprResult tmp;
112634345a63Smrg
112734345a63Smrg    if (uStrCaseCmp(field, "type") == 0)
112834345a63Smrg    {
112934345a63Smrg        ExprResult ndx;
113034345a63Smrg        if ((!ExprResolveString(value, &tmp, NULL, NULL))
113134345a63Smrg            && (warningLevel > 0))
113234345a63Smrg        {
113334345a63Smrg            WARN("The type field of a key symbol map must be a string\n");
113434345a63Smrg            ACTION("Ignoring illegal type definition\n");
113534345a63Smrg        }
113634345a63Smrg        if (arrayNdx == NULL)
113734345a63Smrg        {
113834345a63Smrg            key->dfltType = XkbInternAtom(NULL, tmp.str, False);
113934345a63Smrg            key->defs.defined |= _Key_Type_Dflt;
114034345a63Smrg        }
114134345a63Smrg        else if (!ExprResolveInteger(arrayNdx, &ndx, SimpleLookup,
114234345a63Smrg                                     (XPointer) groupNames))
114334345a63Smrg        {
114434345a63Smrg            ERROR1("Illegal group index for type of key %s\n",
114534345a63Smrg                   longText(key->name, XkbMessage));
114634345a63Smrg            ACTION("Definition with non-integer array index ignored\n");
114734345a63Smrg            return False;
114834345a63Smrg        }
114934345a63Smrg        else if ((ndx.uval < 1) || (ndx.uval > XkbNumKbdGroups))
115034345a63Smrg        {
115134345a63Smrg            ERROR2
115234345a63Smrg                ("Group index for type of key %s is out of range (1..%d)\n",
115334345a63Smrg                 longText(key->name, XkbMessage), XkbNumKbdGroups + 1);
115434345a63Smrg            ACTION1("Ignoring type for group %d\n", ndx.uval);
115534345a63Smrg            return False;
115634345a63Smrg        }
115734345a63Smrg        else
115834345a63Smrg        {
115934345a63Smrg            key->types[ndx.uval - 1] = XkbInternAtom(NULL, tmp.str, False);
116034345a63Smrg            key->typesDefined |= (1 << (ndx.uval - 1));
116134345a63Smrg        }
116234345a63Smrg    }
116334345a63Smrg    else if (uStrCaseCmp(field, "symbols") == 0)
116434345a63Smrg        return AddSymbolsToKey(key, xkb, field, arrayNdx, value, info);
116534345a63Smrg    else if (uStrCaseCmp(field, "actions") == 0)
116634345a63Smrg        return AddActionsToKey(key, xkb, field, arrayNdx, value, info);
116734345a63Smrg    else if ((uStrCaseCmp(field, "vmods") == 0) ||
116834345a63Smrg             (uStrCaseCmp(field, "virtualmods") == 0) ||
116934345a63Smrg             (uStrCaseCmp(field, "virtualmodifiers") == 0))
117034345a63Smrg    {
117134345a63Smrg        ok = ExprResolveModMask(value, &tmp, LookupVModMask, (XPointer) xkb);
117234345a63Smrg        if (ok)
117334345a63Smrg        {
117434345a63Smrg            key->vmodmap = (tmp.uval >> 8);
117534345a63Smrg            key->defs.defined |= _Key_VModMap;
117634345a63Smrg        }
117734345a63Smrg        else
117834345a63Smrg        {
117934345a63Smrg            ERROR1("Expected a virtual modifier mask, found %s\n",
118034345a63Smrg                   exprOpText(value->op));
118134345a63Smrg            ACTION1("Ignoring virtual modifiers definition for key %s\n",
118234345a63Smrg                    longText(key->name, XkbMessage));
118334345a63Smrg        }
118434345a63Smrg    }
118534345a63Smrg    else if ((uStrCaseCmp(field, "locking") == 0)
118634345a63Smrg             || (uStrCaseCmp(field, "lock") == 0)
118734345a63Smrg             || (uStrCaseCmp(field, "locks") == 0))
118834345a63Smrg    {
118934345a63Smrg        ok = ExprResolveEnum(value, &tmp, lockingEntries);
119034345a63Smrg        if (ok)
119134345a63Smrg            key->behavior.type = tmp.uval;
119234345a63Smrg        key->defs.defined |= _Key_Behavior;
119334345a63Smrg    }
119434345a63Smrg    else if ((uStrCaseCmp(field, "radiogroup") == 0) ||
119534345a63Smrg             (uStrCaseCmp(field, "permanentradiogroup") == 0))
119634345a63Smrg    {
119734345a63Smrg        Bool permanent = False;
119834345a63Smrg        if (uStrCaseCmp(field, "permanentradiogroup") == 0)
119934345a63Smrg            permanent = True;
120034345a63Smrg        ok = ExprResolveInteger(value, &tmp, SimpleLookup,
120134345a63Smrg                                (XPointer) rgEntries);
120234345a63Smrg        if (!ok)
120334345a63Smrg        {
120434345a63Smrg            ERROR1("Illegal radio group specification for %s\n",
120534345a63Smrg                   longText(key->name, XkbMessage));
120634345a63Smrg            ACTION("Non-integer radio group ignored\n");
120734345a63Smrg            return False;
120834345a63Smrg        }
120934345a63Smrg        if (tmp.uval == 0)
121034345a63Smrg        {
121134345a63Smrg            key->behavior.type = XkbKB_Default;
121234345a63Smrg            key->behavior.data = 0;
121334345a63Smrg            return ok;
121434345a63Smrg        }
121534345a63Smrg        if ((tmp.uval < 1) || (tmp.uval > XkbMaxRadioGroups))
121634345a63Smrg        {
121734345a63Smrg            ERROR1
121834345a63Smrg                ("Radio group specification for %s out of range (1..32)\n",
121934345a63Smrg                 longText(key->name, XkbMessage));
122034345a63Smrg            ACTION1("Illegal radio group %d ignored\n", tmp.uval);
122134345a63Smrg            return False;
122234345a63Smrg        }
122334345a63Smrg        key->behavior.type =
122434345a63Smrg            XkbKB_RadioGroup | (permanent ? XkbKB_Permanent : 0);
122534345a63Smrg        key->behavior.data = tmp.uval - 1;
122634345a63Smrg        if (key->allowNone & (1 << (tmp.uval - 1)))
122734345a63Smrg            key->behavior.data |= XkbKB_RGAllowNone;
122834345a63Smrg        key->defs.defined |= _Key_Behavior;
122934345a63Smrg    }
123034345a63Smrg    else if (uStrCaseEqual(field, "allownone"))
123134345a63Smrg    {
123234345a63Smrg        ok = SetAllowNone(key, arrayNdx, value);
123334345a63Smrg    }
123434345a63Smrg    else if (uStrCasePrefix("overlay", field) ||
123534345a63Smrg             uStrCasePrefix("permanentoverlay", field))
123634345a63Smrg    {
123734345a63Smrg        Bool permanent = False;
123834345a63Smrg        char *which;
123934345a63Smrg        int overlayNdx;
124034345a63Smrg        if (uStrCasePrefix("permanent", field))
124134345a63Smrg        {
124234345a63Smrg            permanent = True;
124334345a63Smrg            which = &field[sizeof("permanentoverlay") - 1];
124434345a63Smrg        }
124534345a63Smrg        else
124634345a63Smrg        {
124734345a63Smrg            which = &field[sizeof("overlay") - 1];
124834345a63Smrg        }
124934345a63Smrg        if (sscanf(which, "%d", &overlayNdx) == 1)
125034345a63Smrg        {
125134345a63Smrg            if (((overlayNdx < 1) || (overlayNdx > 2)) && (warningLevel > 0))
125234345a63Smrg            {
125334345a63Smrg                ERROR2("Illegal overlay %d specified for %s\n",
125434345a63Smrg                       overlayNdx, longText(key->name, XkbMessage));
125534345a63Smrg                ACTION("Ignored\n");
125634345a63Smrg                return False;
125734345a63Smrg            }
125834345a63Smrg        }
125934345a63Smrg        else if (*which == '\0')
126034345a63Smrg            overlayNdx = 1;
126134345a63Smrg        else if (warningLevel > 0)
126234345a63Smrg        {
126334345a63Smrg            ERROR2("Illegal overlay \"%s\" specified for %s\n",
126434345a63Smrg                   which, longText(key->name, XkbMessage));
126534345a63Smrg            ACTION("Ignored\n");
126634345a63Smrg            return False;
126734345a63Smrg        }
126834345a63Smrg        ok = ExprResolveKeyName(value, &tmp, NULL, NULL);
126934345a63Smrg        if (!ok)
127034345a63Smrg        {
127134345a63Smrg            ERROR1("Illegal overlay key specification for %s\n",
127234345a63Smrg                   longText(key->name, XkbMessage));
127334345a63Smrg            ACTION("Overlay key must be specified by name\n");
127434345a63Smrg            return False;
127534345a63Smrg        }
127634345a63Smrg        if (overlayNdx == 1)
127734345a63Smrg            key->behavior.type = XkbKB_Overlay1;
127834345a63Smrg        else
127934345a63Smrg            key->behavior.type = XkbKB_Overlay2;
128034345a63Smrg        if (permanent)
128134345a63Smrg            key->behavior.type |= XkbKB_Permanent;
128234345a63Smrg
128334345a63Smrg        key->behavior.data = 0;
128434345a63Smrg        key->nameForOverlayKey = KeyNameToLong(tmp.keyName.name);
128534345a63Smrg        key->defs.defined |= _Key_Behavior;
128634345a63Smrg    }
128734345a63Smrg    else if ((uStrCaseCmp(field, "repeating") == 0) ||
128834345a63Smrg             (uStrCaseCmp(field, "repeats") == 0) ||
128934345a63Smrg             (uStrCaseCmp(field, "repeat") == 0))
129034345a63Smrg    {
129134345a63Smrg        ok = ExprResolveEnum(value, &tmp, repeatEntries);
129234345a63Smrg        if (!ok)
129334345a63Smrg        {
129434345a63Smrg            ERROR1("Illegal repeat setting for %s\n",
129534345a63Smrg                   longText(key->name, XkbMessage));
129634345a63Smrg            ACTION("Non-boolean repeat setting ignored\n");
129734345a63Smrg            return False;
129834345a63Smrg        }
129934345a63Smrg        key->repeat = tmp.uval;
130034345a63Smrg        key->defs.defined |= _Key_Repeat;
130134345a63Smrg    }
130234345a63Smrg    else if ((uStrCaseCmp(field, "groupswrap") == 0) ||
130334345a63Smrg             (uStrCaseCmp(field, "wrapgroups") == 0))
130434345a63Smrg    {
130534345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
130634345a63Smrg        if (!ok)
130734345a63Smrg        {
130834345a63Smrg            ERROR1("Illegal groupsWrap setting for %s\n",
130934345a63Smrg                   longText(key->name, XkbMessage));
131034345a63Smrg            ACTION("Non-boolean value ignored\n");
131134345a63Smrg            return False;
131234345a63Smrg        }
131334345a63Smrg        if (tmp.uval)
131434345a63Smrg            key->groupInfo = XkbWrapIntoRange;
131534345a63Smrg        else
131634345a63Smrg            key->groupInfo = XkbClampIntoRange;
131734345a63Smrg        key->defs.defined |= _Key_GroupInfo;
131834345a63Smrg    }
131934345a63Smrg    else if ((uStrCaseCmp(field, "groupsclamp") == 0) ||
132034345a63Smrg             (uStrCaseCmp(field, "clampgroups") == 0))
132134345a63Smrg    {
132234345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
132334345a63Smrg        if (!ok)
132434345a63Smrg        {
132534345a63Smrg            ERROR1("Illegal groupsClamp setting for %s\n",
132634345a63Smrg                   longText(key->name, XkbMessage));
132734345a63Smrg            ACTION("Non-boolean value ignored\n");
132834345a63Smrg            return False;
132934345a63Smrg        }
133034345a63Smrg        if (tmp.uval)
133134345a63Smrg            key->groupInfo = XkbClampIntoRange;
133234345a63Smrg        else
133334345a63Smrg            key->groupInfo = XkbWrapIntoRange;
133434345a63Smrg        key->defs.defined |= _Key_GroupInfo;
133534345a63Smrg    }
133634345a63Smrg    else if ((uStrCaseCmp(field, "groupsredirect") == 0) ||
133734345a63Smrg             (uStrCaseCmp(field, "redirectgroups") == 0))
133834345a63Smrg    {
133934345a63Smrg        if (!ExprResolveInteger
134034345a63Smrg            (value, &tmp, SimpleLookup, (XPointer) groupNames))
134134345a63Smrg        {
134234345a63Smrg            ERROR1("Illegal group index for redirect of key %s\n",
134334345a63Smrg                   longText(key->name, XkbMessage));
134434345a63Smrg            ACTION("Definition with non-integer group ignored\n");
134534345a63Smrg            return False;
134634345a63Smrg        }
134734345a63Smrg        if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
134834345a63Smrg        {
134934345a63Smrg            ERROR2("Out-of-range (1..%d) group for redirect of key %s\n",
135034345a63Smrg                   XkbNumKbdGroups, longText(key->name, XkbMessage));
135134345a63Smrg            ERROR1("Ignoring illegal group %d\n", tmp.uval);
135234345a63Smrg            return False;
135334345a63Smrg        }
135434345a63Smrg        key->groupInfo =
135534345a63Smrg            XkbSetGroupInfo(0, XkbRedirectIntoRange, tmp.uval - 1);
135634345a63Smrg        key->defs.defined |= _Key_GroupInfo;
135734345a63Smrg    }
135834345a63Smrg    else
135934345a63Smrg    {
136034345a63Smrg        ERROR1("Unknown field %s in a symbol interpretation\n", field);
136134345a63Smrg        ACTION("Definition ignored\n");
136234345a63Smrg        ok = False;
1363f46a6179Smrg    }
1364f46a6179Smrg    return ok;
1365f46a6179Smrg}
1366f46a6179Smrg
1367f46a6179Smrgstatic int
136834345a63SmrgSetGroupName(SymbolsInfo * info, ExprDef * arrayNdx, ExprDef * value)
1369f46a6179Smrg{
137034345a63Smrg    ExprResult tmp, name;
137134345a63Smrg
137234345a63Smrg    if ((arrayNdx == NULL) && (warningLevel > 0))
137334345a63Smrg    {
137434345a63Smrg        WARN("You must specify an index when specifying a group name\n");
137534345a63Smrg        ACTION("Group name definition without array subscript ignored\n");
137634345a63Smrg        return False;
137734345a63Smrg    }
137834345a63Smrg    if (!ExprResolveInteger
137934345a63Smrg        (arrayNdx, &tmp, SimpleLookup, (XPointer) groupNames))
138034345a63Smrg    {
138134345a63Smrg        ERROR("Illegal index in group name definition\n");
138234345a63Smrg        ACTION("Definition with non-integer array index ignored\n");
138334345a63Smrg        return False;
138434345a63Smrg    }
138534345a63Smrg    if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
138634345a63Smrg    {
138734345a63Smrg        ERROR1
138834345a63Smrg            ("Attempt to specify name for illegal group (must be 1..%d)\n",
138934345a63Smrg             XkbNumKbdGroups + 1);
139034345a63Smrg        ACTION1("Name for group %d ignored\n", tmp.uval);
139134345a63Smrg        return False;
139234345a63Smrg    }
139334345a63Smrg    if (!ExprResolveString(value, &name, NULL, NULL))
139434345a63Smrg    {
139534345a63Smrg        ERROR("Group name must be a string\n");
139634345a63Smrg        ACTION1("Illegal name for group %d ignored\n", tmp.uval);
139734345a63Smrg        return False;
139834345a63Smrg    }
139934345a63Smrg    info->groupNames[tmp.uval - 1 + info->explicit_group] =
140034345a63Smrg        XkbInternAtom(NULL, name.str, False);
140134345a63Smrg
1402f46a6179Smrg    return True;
1403f46a6179Smrg}
1404f46a6179Smrg
1405f46a6179Smrgstatic int
140634345a63SmrgHandleSymbolsVar(VarDef * stmt, XkbDescPtr xkb, SymbolsInfo * info)
1407f46a6179Smrg{
140834345a63Smrg    ExprResult elem, field, tmp;
140934345a63Smrg    ExprDef *arrayNdx;
141034345a63Smrg
141134345a63Smrg    if (ExprResolveLhs(stmt->name, &elem, &field, &arrayNdx) == 0)
141234345a63Smrg        return 0;               /* internal error, already reported */
141334345a63Smrg    if (elem.str && (uStrCaseCmp(elem.str, "key") == 0))
141434345a63Smrg    {
141534345a63Smrg        return SetSymbolsField(&info->dflt, xkb, field.str, arrayNdx,
141634345a63Smrg                               stmt->value, info);
141734345a63Smrg    }
141834345a63Smrg    else if ((elem.str == NULL) && ((uStrCaseCmp(field.str, "name") == 0) ||
141934345a63Smrg                                    (uStrCaseCmp(field.str, "groupname") ==
142034345a63Smrg                                     0)))
142134345a63Smrg    {
142234345a63Smrg        return SetGroupName(info, arrayNdx, stmt->value);
142334345a63Smrg    }
142434345a63Smrg    else if ((elem.str == NULL)
142534345a63Smrg             && ((uStrCaseCmp(field.str, "groupswrap") == 0)
142634345a63Smrg                 || (uStrCaseCmp(field.str, "wrapgroups") == 0)))
142734345a63Smrg    {
142834345a63Smrg        if (!ExprResolveBoolean(stmt->value, &tmp, NULL, NULL))
142934345a63Smrg        {
143034345a63Smrg            ERROR("Illegal setting for global groupsWrap\n");
143134345a63Smrg            ACTION("Non-boolean value ignored\n");
143234345a63Smrg            return False;
143334345a63Smrg        }
143434345a63Smrg        if (tmp.uval)
143534345a63Smrg            info->groupInfo = XkbWrapIntoRange;
143634345a63Smrg        else
143734345a63Smrg            info->groupInfo = XkbClampIntoRange;
143834345a63Smrg        return True;
143934345a63Smrg    }
144034345a63Smrg    else if ((elem.str == NULL)
144134345a63Smrg             && ((uStrCaseCmp(field.str, "groupsclamp") == 0)
144234345a63Smrg                 || (uStrCaseCmp(field.str, "clampgroups") == 0)))
144334345a63Smrg    {
144434345a63Smrg        if (!ExprResolveBoolean(stmt->value, &tmp, NULL, NULL))
144534345a63Smrg        {
144634345a63Smrg            ERROR("Illegal setting for global groupsClamp\n");
144734345a63Smrg            ACTION("Non-boolean value ignored\n");
144834345a63Smrg            return False;
144934345a63Smrg        }
145034345a63Smrg        if (tmp.uval)
145134345a63Smrg            info->groupInfo = XkbClampIntoRange;
145234345a63Smrg        else
145334345a63Smrg            info->groupInfo = XkbWrapIntoRange;
145434345a63Smrg        return True;
145534345a63Smrg    }
145634345a63Smrg    else if ((elem.str == NULL)
145734345a63Smrg             && ((uStrCaseCmp(field.str, "groupsredirect") == 0)
145834345a63Smrg                 || (uStrCaseCmp(field.str, "redirectgroups") == 0)))
145934345a63Smrg    {
146034345a63Smrg        if (!ExprResolveInteger(stmt->value, &tmp,
146134345a63Smrg                                SimpleLookup, (XPointer) groupNames))
146234345a63Smrg        {
146334345a63Smrg            ERROR("Illegal group index for global groupsRedirect\n");
146434345a63Smrg            ACTION("Definition with non-integer group ignored\n");
146534345a63Smrg            return False;
146634345a63Smrg        }
146734345a63Smrg        if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
146834345a63Smrg        {
146934345a63Smrg            ERROR1
147034345a63Smrg                ("Out-of-range (1..%d) group for global groupsRedirect\n",
147134345a63Smrg                 XkbNumKbdGroups);
147234345a63Smrg            ACTION1("Ignoring illegal group %d\n", tmp.uval);
147334345a63Smrg            return False;
147434345a63Smrg        }
147534345a63Smrg        info->groupInfo = XkbSetGroupInfo(0, XkbRedirectIntoRange, tmp.uval);
147634345a63Smrg        return True;
147734345a63Smrg    }
147834345a63Smrg    else if ((elem.str == NULL) && (uStrCaseCmp(field.str, "allownone") == 0))
147934345a63Smrg    {
148034345a63Smrg        return SetAllowNone(&info->dflt, arrayNdx, stmt->value);
148134345a63Smrg    }
148234345a63Smrg    return SetActionField(xkb, elem.str, field.str, arrayNdx, stmt->value,
148334345a63Smrg                          &info->action);
1484f46a6179Smrg}
1485f46a6179Smrg
1486f46a6179Smrgstatic Bool
148734345a63SmrgHandleSymbolsBody(VarDef * def,
148834345a63Smrg                  XkbDescPtr xkb, KeyInfo * key, SymbolsInfo * info)
1489f46a6179Smrg{
149034345a63Smrg    Bool ok = True;
149134345a63Smrg    ExprResult tmp, field;
149234345a63Smrg    ExprDef *arrayNdx;
149334345a63Smrg
149434345a63Smrg    for (; def != NULL; def = (VarDef *) def->common.next)
149534345a63Smrg    {
149634345a63Smrg        if ((def->name) && (def->name->type == ExprFieldRef))
149734345a63Smrg        {
149834345a63Smrg            ok = HandleSymbolsVar(def, xkb, info);
149934345a63Smrg            continue;
150034345a63Smrg        }
150134345a63Smrg        else
150234345a63Smrg        {
150334345a63Smrg            if (def->name == NULL)
150434345a63Smrg            {
150534345a63Smrg                if ((def->value == NULL)
150634345a63Smrg                    || (def->value->op == ExprKeysymList))
150734345a63Smrg                    field.str = "symbols";
150834345a63Smrg                else
150934345a63Smrg                    field.str = "actions";
151034345a63Smrg                arrayNdx = NULL;
151134345a63Smrg            }
151234345a63Smrg            else
151334345a63Smrg            {
151434345a63Smrg                ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
151534345a63Smrg            }
151634345a63Smrg            if (ok)
151734345a63Smrg                ok = SetSymbolsField(key, xkb, field.str, arrayNdx,
151834345a63Smrg                                     def->value, info);
151934345a63Smrg        }
1520f46a6179Smrg    }
1521f46a6179Smrg    return ok;
1522f46a6179Smrg}
1523f46a6179Smrg
1524f46a6179Smrgstatic Bool
152534345a63SmrgSetExplicitGroup(SymbolsInfo * info, KeyInfo * key)
1526f46a6179Smrg{
1527f46a6179Smrg    unsigned group = info->explicit_group;
1528f46a6179Smrg
1529f46a6179Smrg    if (group == 0)
153034345a63Smrg        return True;
153134345a63Smrg
153234345a63Smrg    if ((key->typesDefined | key->symsDefined | key->actsDefined) & ~1)
153334345a63Smrg    {
153434345a63Smrg        int i;
153534345a63Smrg        WARN1("For the map %s an explicit group specified\n", info->name);
153634345a63Smrg        WARN1("but key %s has more than one group defined\n",
153734345a63Smrg              longText(key->name, XkbMessage));
153834345a63Smrg        ACTION("All groups except first one will be ignored\n");
153934345a63Smrg        for (i = 1; i < XkbNumKbdGroups; i++)
154034345a63Smrg        {
154134345a63Smrg            key->numLevels[i] = 0;
154234345a63Smrg            if (key->syms[i] != NULL)
154334345a63Smrg                uFree(key->syms[i]);
154434345a63Smrg            key->syms[i] = (KeySym *) NULL;
154534345a63Smrg            if (key->acts[i] != NULL)
154634345a63Smrg                uFree(key->acts[i]);
154734345a63Smrg            key->acts[i] = (XkbAction *) NULL;
154834345a63Smrg            key->types[i] = (Atom) 0;
154934345a63Smrg        }
155034345a63Smrg    }
155134345a63Smrg    key->typesDefined = key->symsDefined = key->actsDefined = 1 << group;
155234345a63Smrg
155334345a63Smrg    key->numLevels[group] = key->numLevels[0];
155434345a63Smrg    key->numLevels[0] = 0;
155534345a63Smrg    key->syms[group] = key->syms[0];
155634345a63Smrg    key->syms[0] = (KeySym *) NULL;
155734345a63Smrg    key->acts[group] = key->acts[0];
155834345a63Smrg    key->acts[0] = (XkbAction *) NULL;
155934345a63Smrg    key->types[group] = key->types[0];
156034345a63Smrg    key->types[0] = (Atom) 0;
156134345a63Smrg    return True;
1562f46a6179Smrg}
1563f46a6179Smrg
1564f46a6179Smrgstatic int
156534345a63SmrgHandleSymbolsDef(SymbolsDef * stmt,
156634345a63Smrg                 XkbDescPtr xkb, unsigned merge, SymbolsInfo * info)
1567f46a6179Smrg{
156834345a63Smrg    KeyInfo key;
156934345a63Smrg
1570f46a6179Smrg    InitKeyInfo(&key);
157134345a63Smrg    CopyKeyInfo(&info->dflt, &key, False);
157234345a63Smrg    key.defs.merge = stmt->merge;
157334345a63Smrg    key.name = KeyNameToLong(stmt->keyName);
157434345a63Smrg    if (!HandleSymbolsBody((VarDef *) stmt->symbols, xkb, &key, info))
157534345a63Smrg    {
157634345a63Smrg        info->errorCount++;
157734345a63Smrg        return False;
1578f46a6179Smrg    }
1579f46a6179Smrg
158034345a63Smrg    if (!SetExplicitGroup(info, &key))
158134345a63Smrg    {
1582f46a6179Smrg        info->errorCount++;
1583f46a6179Smrg        return False;
1584f46a6179Smrg    }
1585f46a6179Smrg
158634345a63Smrg    if (!AddKeySymbols(info, &key, xkb))
158734345a63Smrg    {
158834345a63Smrg        info->errorCount++;
158934345a63Smrg        return False;
1590f46a6179Smrg    }
1591f46a6179Smrg    return True;
1592f46a6179Smrg}
1593f46a6179Smrg
1594f46a6179Smrgstatic Bool
159534345a63SmrgHandleModMapDef(ModMapDef * def,
159634345a63Smrg                XkbDescPtr xkb, unsigned merge, SymbolsInfo * info)
1597f46a6179Smrg{
159834345a63Smrg    ExprDef *key;
159934345a63Smrg    ModMapEntry tmp;
160034345a63Smrg    ExprResult rtrn;
160134345a63Smrg    Bool ok;
160234345a63Smrg
160334345a63Smrg    if (!LookupModIndex(NULL, None, def->modifier, TypeInt, &rtrn))
160434345a63Smrg    {
160534345a63Smrg        ERROR("Illegal modifier map definition\n");
160634345a63Smrg        ACTION1("Ignoring map for non-modifier \"%s\"\n",
160734345a63Smrg                XkbAtomText(NULL, def->modifier, XkbMessage));
160834345a63Smrg        return False;
160934345a63Smrg    }
161034345a63Smrg    ok = True;
161134345a63Smrg    tmp.modifier = rtrn.uval;
161234345a63Smrg    for (key = def->keys; key != NULL; key = (ExprDef *) key->common.next)
161334345a63Smrg    {
161434345a63Smrg        if ((key->op == ExprValue) && (key->type == TypeKeyName))
161534345a63Smrg        {
161634345a63Smrg            tmp.haveSymbol = False;
161734345a63Smrg            tmp.u.keyName = KeyNameToLong(key->value.keyName);
161834345a63Smrg        }
161934345a63Smrg        else if (ExprResolveKeySym(key, &rtrn, NULL, NULL))
162034345a63Smrg        {
162134345a63Smrg            tmp.haveSymbol = True;
162234345a63Smrg            tmp.u.keySym = rtrn.uval;
162334345a63Smrg        }
162434345a63Smrg        else
162534345a63Smrg        {
162634345a63Smrg            ERROR("Modmap entries may contain only key names or keysyms\n");
162734345a63Smrg            ACTION1("Illegal definition for %s modifier ignored\n",
162834345a63Smrg                    XkbModIndexText(tmp.modifier, XkbMessage));
162934345a63Smrg            continue;
163034345a63Smrg        }
163134345a63Smrg
163234345a63Smrg        ok = AddModMapEntry(info, &tmp) && ok;
1633f46a6179Smrg    }
1634f46a6179Smrg    return ok;
1635f46a6179Smrg}
1636f46a6179Smrg
1637f46a6179Smrgstatic void
163834345a63SmrgHandleSymbolsFile(XkbFile * file,
163934345a63Smrg                  XkbDescPtr xkb, unsigned merge, SymbolsInfo * info)
1640f46a6179Smrg{
164134345a63Smrg    ParseCommon *stmt;
164234345a63Smrg
164334345a63Smrg    info->name = uStringDup(file->name);
164434345a63Smrg    stmt = file->defs;
164534345a63Smrg    while (stmt)
164634345a63Smrg    {
164734345a63Smrg        switch (stmt->stmtType)
164834345a63Smrg        {
164934345a63Smrg        case StmtInclude:
165034345a63Smrg            if (!HandleIncludeSymbols((IncludeStmt *) stmt, xkb, info,
165134345a63Smrg                                      HandleSymbolsFile))
165234345a63Smrg                info->errorCount++;
165334345a63Smrg            break;
165434345a63Smrg        case StmtSymbolsDef:
165534345a63Smrg            if (!HandleSymbolsDef((SymbolsDef *) stmt, xkb, merge, info))
165634345a63Smrg                info->errorCount++;
165734345a63Smrg            break;
165834345a63Smrg        case StmtVarDef:
165934345a63Smrg            if (!HandleSymbolsVar((VarDef *) stmt, xkb, info))
166034345a63Smrg                info->errorCount++;
166134345a63Smrg            break;
166234345a63Smrg        case StmtVModDef:
166334345a63Smrg            if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
166434345a63Smrg                info->errorCount++;
166534345a63Smrg            break;
166634345a63Smrg        case StmtInterpDef:
166734345a63Smrg            ERROR("Interpretation files may not include other types\n");
166834345a63Smrg            ACTION("Ignoring definition of symbol interpretation\n");
166934345a63Smrg            info->errorCount++;
167034345a63Smrg            break;
167134345a63Smrg        case StmtKeycodeDef:
167234345a63Smrg            ERROR("Interpretation files may not include other types\n");
167334345a63Smrg            ACTION("Ignoring definition of key name\n");
167434345a63Smrg            info->errorCount++;
167534345a63Smrg            break;
167634345a63Smrg        case StmtModMapDef:
167734345a63Smrg            if (!HandleModMapDef((ModMapDef *) stmt, xkb, merge, info))
167834345a63Smrg                info->errorCount++;
167934345a63Smrg            break;
168034345a63Smrg        default:
168134345a63Smrg            WSGO1("Unexpected statement type %d in HandleSymbolsFile\n",
168234345a63Smrg                  stmt->stmtType);
168334345a63Smrg            break;
168434345a63Smrg        }
168534345a63Smrg        stmt = stmt->next;
168634345a63Smrg        if (info->errorCount > 10)
168734345a63Smrg        {
1688f46a6179Smrg#ifdef NOISY
168934345a63Smrg            ERROR("Too many errors\n");
1690f46a6179Smrg#endif
169134345a63Smrg            ACTION1("Abandoning symbols file \"%s\"\n", file->topName);
169234345a63Smrg            break;
169334345a63Smrg        }
1694f46a6179Smrg    }
1695f46a6179Smrg    return;
1696f46a6179Smrg}
1697f46a6179Smrg
1698f46a6179Smrgstatic Bool
169934345a63SmrgFindKeyForSymbol(XkbDescPtr xkb, KeySym sym, unsigned int *kc_rtrn)
1700f46a6179Smrg{
170134345a63Smrg    register int i, j;
170234345a63Smrg    register Bool gotOne;
170334345a63Smrg
170434345a63Smrg    j = 0;
170534345a63Smrg    do
170634345a63Smrg    {
170734345a63Smrg        gotOne = False;
170834345a63Smrg        for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++)
170934345a63Smrg        {
171034345a63Smrg            if (j < (int) XkbKeyNumSyms(xkb, i))
171134345a63Smrg            {
1712f46a6179Smrg                gotOne = True;
17131d8c7986Smrg                if (XkbKeySym(xkb, i, j) == sym)
171434345a63Smrg                {
171534345a63Smrg                    *kc_rtrn = i;
1716f46a6179Smrg                    return True;
171734345a63Smrg                }
1718f46a6179Smrg            }
1719f46a6179Smrg        }
1720f46a6179Smrg        j++;
172134345a63Smrg    }
172234345a63Smrg    while (gotOne);
1723f46a6179Smrg    return False;
1724f46a6179Smrg}
1725f46a6179Smrg
172634345a63Smrg/**
172734345a63Smrg * Find the given name in the xkb->map->types and return its index.
172834345a63Smrg *
172934345a63Smrg * @param name The atom to search for.
173034345a63Smrg * @param type_rtrn Set to the index of the name if found.
173134345a63Smrg *
173234345a63Smrg * @return True if found, False otherwise.
173334345a63Smrg */
1734f46a6179Smrgstatic Bool
173534345a63SmrgFindNamedType(XkbDescPtr xkb, Atom name, unsigned *type_rtrn)
1736f46a6179Smrg{
173734345a63Smrg    register unsigned n;
173834345a63Smrg
173934345a63Smrg    if (xkb && xkb->map && xkb->map->types)
174034345a63Smrg    {
174134345a63Smrg        for (n = 0; n < xkb->map->num_types; n++)
174234345a63Smrg        {
174334345a63Smrg            if (xkb->map->types[n].name == (Atom) name)
174434345a63Smrg            {
174534345a63Smrg                *type_rtrn = n;
174634345a63Smrg                return True;
174734345a63Smrg            }
174834345a63Smrg        }
1749f46a6179Smrg    }
1750f46a6179Smrg    return False;
1751f46a6179Smrg}
1752f46a6179Smrg
1753f46a6179Smrgstatic Bool
175434345a63SmrgKSIsLower(KeySym ks)
1755f46a6179Smrg{
1756f46a6179Smrg    KeySym lower, upper;
1757f46a6179Smrg    XConvertCase(ks, &lower, &upper);
1758f46a6179Smrg
1759f46a6179Smrg    if (lower == upper)
1760f46a6179Smrg        return False;
1761f46a6179Smrg    return (ks == lower ? True : False);
1762f46a6179Smrg}
1763f46a6179Smrg
1764f46a6179Smrgstatic Bool
176534345a63SmrgKSIsUpper(KeySym ks)
1766f46a6179Smrg{
1767f46a6179Smrg    KeySym lower, upper;
1768f46a6179Smrg    XConvertCase(ks, &lower, &upper);
1769f46a6179Smrg
1770f46a6179Smrg    if (lower == upper)
1771f46a6179Smrg        return False;
1772f46a6179Smrg    return (ks == upper ? True : False);
1773f46a6179Smrg}
1774f46a6179Smrg
177534345a63Smrg/**
177634345a63Smrg * Assign a type to the given sym and return the Atom for the type assigned.
177734345a63Smrg *
177834345a63Smrg * Simple recipe:
177934345a63Smrg * - ONE_LEVEL for width 0/1
178034345a63Smrg * - ALPHABETIC for 2 shift levels, with lower/upercase
178134345a63Smrg * - KEYPAD for keypad keys.
178234345a63Smrg * - TWO_LEVEL for other 2 shift level keys.
178334345a63Smrg * and the same for four level keys.
178434345a63Smrg *
178534345a63Smrg * @param width Number of sysms in syms.
178634345a63Smrg * @param syms The keysyms for the given key (must be size width).
178734345a63Smrg * @param typeNameRtrn Set to the Atom of the type name.
178834345a63Smrg *
178934345a63Smrg * @returns True if a type could be found, False otherwise.
179034345a63Smrg */
1791f46a6179Smrgstatic Bool
179234345a63SmrgFindAutomaticType(int width, KeySym * syms, Atom * typeNameRtrn,
179334345a63Smrg                  Bool * autoType)
1794f46a6179Smrg{
1795f46a6179Smrg    *autoType = False;
179634345a63Smrg    if ((width == 1) || (width == 0))
179734345a63Smrg    {
179834345a63Smrg        *typeNameRtrn = XkbInternAtom(NULL, "ONE_LEVEL", False);
179934345a63Smrg        *autoType = True;
180034345a63Smrg    }
180134345a63Smrg    else if (width == 2)
180234345a63Smrg    {
180334345a63Smrg        if (syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]))
180434345a63Smrg        {
180534345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "ALPHABETIC", False);
180634345a63Smrg        }
180734345a63Smrg        else if (syms && (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])))
180834345a63Smrg        {
180934345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "KEYPAD", False);
181034345a63Smrg            *autoType = True;
181134345a63Smrg        }
181234345a63Smrg        else
181334345a63Smrg        {
181434345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "TWO_LEVEL", False);
181534345a63Smrg            *autoType = True;
181634345a63Smrg        }
181734345a63Smrg    }
181834345a63Smrg    else if (width <= 4)
181934345a63Smrg    {
182034345a63Smrg        if (syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]))
182134345a63Smrg            if (KSIsLower(syms[2]) && KSIsUpper(syms[3]))
182234345a63Smrg                *typeNameRtrn =
182334345a63Smrg                    XkbInternAtom(NULL, "FOUR_LEVEL_ALPHABETIC", False);
182434345a63Smrg            else
182534345a63Smrg                *typeNameRtrn = XkbInternAtom(NULL,
182634345a63Smrg                                              "FOUR_LEVEL_SEMIALPHABETIC",
182734345a63Smrg                                              False);
182834345a63Smrg
182934345a63Smrg        else if (syms && (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])))
183034345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "FOUR_LEVEL_KEYPAD", False);
183134345a63Smrg        else
183234345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "FOUR_LEVEL", False);
183334345a63Smrg        /* XXX: why not set autoType here? */
183434345a63Smrg    }
183534345a63Smrg    return ((width >= 0) && (width <= 4));
1836f46a6179Smrg}
1837f46a6179Smrg
183834345a63Smrg/**
183934345a63Smrg * Ensure the given KeyInfo is in a coherent state, i.e. no gaps between the
184034345a63Smrg * groups, and reduce to one group if all groups are identical anyway.
184134345a63Smrg */
1842f46a6179Smrgstatic void
184334345a63SmrgPrepareKeyDef(KeyInfo * key)
1844f46a6179Smrg{
1845f46a6179Smrg    int i, j, width, defined, lastGroup;
1846f46a6179Smrg    Bool identical;
184734345a63Smrg
1848f46a6179Smrg    defined = key->symsDefined | key->actsDefined | key->typesDefined;
184934345a63Smrg    /* get highest group number */
185034345a63Smrg    for (i = XkbNumKbdGroups - 1; i >= 0; i--)
185134345a63Smrg    {
185234345a63Smrg        if (defined & (1 << i))
185334345a63Smrg            break;
1854f46a6179Smrg    }
1855f46a6179Smrg    lastGroup = i;
1856f46a6179Smrg
1857f46a6179Smrg    if (lastGroup == 0)
185834345a63Smrg        return;
1859f46a6179Smrg
1860f46a6179Smrg    /* If there are empty groups between non-empty ones fill them with data */
1861f46a6179Smrg    /* from the first group. */
1862f46a6179Smrg    /* We can make a wrong assumption here. But leaving gaps is worse. */
186334345a63Smrg    for (i = lastGroup; i > 0; i--)
186434345a63Smrg    {
186534345a63Smrg        if (defined & (1 << i))
1866f46a6179Smrg            continue;
1867f46a6179Smrg        width = key->numLevels[0];
186834345a63Smrg        if (key->typesDefined & 1)
186934345a63Smrg        {
187034345a63Smrg            for (j = 0; j < width; j++)
187134345a63Smrg            {
1872f46a6179Smrg                key->types[i] = key->types[0];
1873f46a6179Smrg            }
1874f46a6179Smrg            key->typesDefined |= 1 << i;
1875f46a6179Smrg        }
187634345a63Smrg        if ((key->actsDefined & 1) && key->acts[0])
187734345a63Smrg        {
187834345a63Smrg            key->acts[i] = uTypedCalloc(width, XkbAction);
1879f46a6179Smrg            if (key->acts[i] == NULL)
1880f46a6179Smrg                continue;
1881f46a6179Smrg            memcpy((void *) key->acts[i], (void *) key->acts[0],
1882f46a6179Smrg                   width * sizeof(XkbAction));
1883f46a6179Smrg            key->actsDefined |= 1 << i;
1884f46a6179Smrg        }
188534345a63Smrg        if ((key->symsDefined & 1) && key->syms[0])
188634345a63Smrg        {
188734345a63Smrg            key->syms[i] = uTypedCalloc(width, KeySym);
1888f46a6179Smrg            if (key->syms[i] == NULL)
1889f46a6179Smrg                continue;
1890f46a6179Smrg            memcpy((void *) key->syms[i], (void *) key->syms[0],
1891f46a6179Smrg                   width * sizeof(KeySym));
1892f46a6179Smrg            key->symsDefined |= 1 << i;
1893f46a6179Smrg        }
189434345a63Smrg        if (defined & 1)
189534345a63Smrg        {
1896f46a6179Smrg            key->numLevels[i] = key->numLevels[0];
1897f46a6179Smrg        }
1898f46a6179Smrg    }
1899f46a6179Smrg    /* If all groups are completely identical remove them all */
1900f46a6179Smrg    /* exept the first one. */
1901f46a6179Smrg    identical = True;
190234345a63Smrg    for (i = lastGroup; i > 0; i--)
190334345a63Smrg    {
1904f46a6179Smrg        if ((key->numLevels[i] != key->numLevels[0]) ||
190534345a63Smrg            (key->types[i] != key->types[0]))
190634345a63Smrg        {
1907f46a6179Smrg            identical = False;
1908f46a6179Smrg            break;
1909f46a6179Smrg        }
1910f46a6179Smrg        if ((key->syms[i] != key->syms[0]) &&
191134345a63Smrg            (key->syms[i] == NULL || key->syms[0] == NULL ||
191234345a63Smrg             memcmp((void *) key->syms[i], (void *) key->syms[0],
191334345a63Smrg                    sizeof(KeySym) * key->numLevels[0])))
191434345a63Smrg        {
191534345a63Smrg            identical = False;
191634345a63Smrg            break;
191734345a63Smrg        }
1918f46a6179Smrg        if ((key->acts[i] != key->acts[0]) &&
191934345a63Smrg            (key->acts[i] == NULL || key->acts[0] == NULL ||
192034345a63Smrg             memcmp((void *) key->acts[i], (void *) key->acts[0],
192134345a63Smrg                    sizeof(XkbAction) * key->numLevels[0])))
192234345a63Smrg        {
1923f46a6179Smrg            identical = False;
1924f46a6179Smrg            break;
192534345a63Smrg        }
192634345a63Smrg    }
192734345a63Smrg    if (identical)
192834345a63Smrg    {
192934345a63Smrg        for (i = lastGroup; i > 0; i--)
193034345a63Smrg        {
193134345a63Smrg            key->numLevels[i] = 0;
193234345a63Smrg            if (key->syms[i] != NULL)
193334345a63Smrg                uFree(key->syms[i]);
193434345a63Smrg            key->syms[i] = (KeySym *) NULL;
193534345a63Smrg            if (key->acts[i] != NULL)
193634345a63Smrg                uFree(key->acts[i]);
193734345a63Smrg            key->acts[i] = (XkbAction *) NULL;
193834345a63Smrg            key->types[i] = (Atom) 0;
193934345a63Smrg        }
194034345a63Smrg        key->symsDefined &= 1;
194134345a63Smrg        key->actsDefined &= 1;
194234345a63Smrg        key->typesDefined &= 1;
1943f46a6179Smrg    }
1944f46a6179Smrg    return;
1945f46a6179Smrg}
1946f46a6179Smrg
194734345a63Smrg/**
194834345a63Smrg * Copy the KeyInfo into result.
194934345a63Smrg *
195034345a63Smrg * This function recurses.
195134345a63Smrg */
1952f46a6179Smrgstatic Bool
195334345a63SmrgCopySymbolsDef(XkbFileInfo * result, KeyInfo * key, int start_from)
1954f46a6179Smrg{
195534345a63Smrg    register int i;
195634345a63Smrg    unsigned okc, kc, width, tmp, nGroups;
195734345a63Smrg    XkbKeyTypePtr type;
195834345a63Smrg    Bool haveActions, autoType, useAlias;
195934345a63Smrg    KeySym *outSyms;
196034345a63Smrg    XkbAction *outActs;
196134345a63Smrg    XkbDescPtr xkb;
196234345a63Smrg    unsigned types[XkbNumKbdGroups];
196334345a63Smrg
196434345a63Smrg    xkb = result->xkb;
196534345a63Smrg    useAlias = (start_from == 0);
196634345a63Smrg
196734345a63Smrg    /* get the keycode for the key. */
196834345a63Smrg    if (!FindNamedKey(xkb, key->name, &kc, useAlias, CreateKeyNames(xkb),
196934345a63Smrg                      start_from))
197034345a63Smrg    {
197134345a63Smrg        if ((start_from == 0) && (warningLevel >= 5))
197234345a63Smrg        {
197334345a63Smrg            WARN2("Key %s not found in %s keycodes\n",
197434345a63Smrg                  longText(key->name, XkbMessage),
197534345a63Smrg                  XkbAtomText(NULL, xkb->names->keycodes, XkbMessage));
197634345a63Smrg            ACTION("Symbols ignored\n");
197734345a63Smrg        }
197834345a63Smrg        return False;
197934345a63Smrg    }
198034345a63Smrg
198134345a63Smrg    haveActions = False;
198234345a63Smrg    for (i = width = nGroups = 0; i < XkbNumKbdGroups; i++)
198334345a63Smrg    {
198434345a63Smrg        if (((i + 1) > nGroups)
198534345a63Smrg            && (((key->symsDefined | key->actsDefined) & (1 << i))
198634345a63Smrg                || (key->typesDefined) & (1 << i)))
198734345a63Smrg            nGroups = i + 1;
198834345a63Smrg        if (key->acts[i])
198934345a63Smrg            haveActions = True;
199034345a63Smrg        autoType = False;
199134345a63Smrg        /* Assign the type to the key, if it is missing. */
199234345a63Smrg        if (key->types[i] == None)
199334345a63Smrg        {
199434345a63Smrg            if (key->dfltType != None)
199534345a63Smrg                key->types[i] = key->dfltType;
199634345a63Smrg            else if (FindAutomaticType(key->numLevels[i], key->syms[i],
199734345a63Smrg                                       &key->types[i], &autoType))
199834345a63Smrg            {
199934345a63Smrg            }
200034345a63Smrg            else
200134345a63Smrg            {
200234345a63Smrg                if (warningLevel >= 5)
200334345a63Smrg                {
200434345a63Smrg                    WARN1("No automatic type for %d symbols\n",
200534345a63Smrg                          (unsigned int) key->numLevels[i]);
200634345a63Smrg                    ACTION3("Using %s for the %s key (keycode %d)\n",
200734345a63Smrg                            XkbAtomText(NULL, key->types[i],
200834345a63Smrg                                        XkbMessage),
200934345a63Smrg                            longText(key->name, XkbMessage), kc);
201034345a63Smrg                }
201134345a63Smrg            }
201234345a63Smrg        }
201334345a63Smrg        if (FindNamedType(xkb, key->types[i], &types[i]))
201434345a63Smrg        {
201534345a63Smrg            if (!autoType || key->numLevels[i] > 2)
201634345a63Smrg                xkb->server->explicit[kc] |= (1 << i);
201734345a63Smrg        }
201834345a63Smrg        else
201934345a63Smrg        {
202034345a63Smrg            if (warningLevel >= 3)
202134345a63Smrg            {
202234345a63Smrg                WARN1("Type \"%s\" is not defined\n",
202334345a63Smrg                      XkbAtomText(NULL, key->types[i], XkbMessage));
202434345a63Smrg                ACTION2("Using TWO_LEVEL for the %s key (keycode %d)\n",
202534345a63Smrg                        longText(key->name, XkbMessage), kc);
202634345a63Smrg            }
202734345a63Smrg            types[i] = XkbTwoLevelIndex;
202834345a63Smrg        }
202934345a63Smrg        /* if the type specifies less syms than the key has, shrink the key */
203034345a63Smrg        type = &xkb->map->types[types[i]];
203134345a63Smrg        if (type->num_levels < key->numLevels[i])
203234345a63Smrg        {
203334345a63Smrg            if (warningLevel > 0)
203434345a63Smrg            {
203534345a63Smrg                WARN4
203634345a63Smrg                    ("Type \"%s\" has %d levels, but %s has %d symbols\n",
203734345a63Smrg                     XkbAtomText(NULL, type->name, XkbMessage),
203834345a63Smrg                     (unsigned int) type->num_levels,
203934345a63Smrg                     longText(key->name, XkbMessage),
204034345a63Smrg                     (unsigned int) key->numLevels[i]);
204134345a63Smrg                ACTION("Ignoring extra symbols\n");
204234345a63Smrg            }
204334345a63Smrg            key->numLevels[i] = type->num_levels;
204434345a63Smrg        }
204534345a63Smrg        if (key->numLevels[i] > width)
204634345a63Smrg            width = key->numLevels[i];
204734345a63Smrg        if (type->num_levels > width)
204834345a63Smrg            width = type->num_levels;
204934345a63Smrg    }
205034345a63Smrg
205134345a63Smrg    /* width is now the largest width found */
205234345a63Smrg
205334345a63Smrg    i = width * nGroups;
205434345a63Smrg    outSyms = XkbResizeKeySyms(xkb, kc, i);
205534345a63Smrg    if (outSyms == NULL)
205634345a63Smrg    {
205734345a63Smrg        WSGO2("Could not enlarge symbols for %s (keycode %d)\n",
205834345a63Smrg              longText(key->name, XkbMessage), kc);
205934345a63Smrg        return False;
206034345a63Smrg    }
206134345a63Smrg    if (haveActions)
206234345a63Smrg    {
206334345a63Smrg        outActs = XkbResizeKeyActions(xkb, kc, i);
206434345a63Smrg        if (outActs == NULL)
206534345a63Smrg        {
206634345a63Smrg            WSGO2("Could not enlarge actions for %s (key %d)\n",
206734345a63Smrg                  longText(key->name, XkbMessage), kc);
206834345a63Smrg            return False;
206934345a63Smrg        }
207034345a63Smrg        xkb->server->explicit[kc] |= XkbExplicitInterpretMask;
207134345a63Smrg    }
207234345a63Smrg    else
207334345a63Smrg        outActs = NULL;
207434345a63Smrg    if (key->defs.defined & _Key_GroupInfo)
207534345a63Smrg        i = key->groupInfo;
207634345a63Smrg    else
207734345a63Smrg        i = xkb->map->key_sym_map[kc].group_info;
207834345a63Smrg
207934345a63Smrg    xkb->map->key_sym_map[kc].group_info = XkbSetNumGroups(i, nGroups);
208034345a63Smrg    xkb->map->key_sym_map[kc].width = width;
208134345a63Smrg    for (i = 0; i < nGroups; i++)
208234345a63Smrg    {
208334345a63Smrg        /* assign kt_index[i] to the index of the type in map->types.
208434345a63Smrg         * kt_index[i] may have been set by a previous run (if we have two
208534345a63Smrg         * layouts specified). Let's not overwrite it with the ONE_LEVEL
208634345a63Smrg         * default group if we dont even have keys for this group anyway.
208734345a63Smrg         *
208834345a63Smrg         * FIXME: There should be a better fix for this.
208934345a63Smrg         */
209034345a63Smrg        if (key->numLevels[i])
209134345a63Smrg            xkb->map->key_sym_map[kc].kt_index[i] = types[i];
209234345a63Smrg        if (key->syms[i] != NULL)
209334345a63Smrg        {
209434345a63Smrg            /* fill key to "width" symbols*/
209534345a63Smrg            for (tmp = 0; tmp < width; tmp++)
209634345a63Smrg            {
209734345a63Smrg                if (tmp < key->numLevels[i])
209834345a63Smrg                    outSyms[tmp] = key->syms[i][tmp];
209934345a63Smrg                else
210034345a63Smrg                    outSyms[tmp] = NoSymbol;
210134345a63Smrg                if ((outActs != NULL) && (key->acts[i] != NULL))
210234345a63Smrg                {
210334345a63Smrg                    if (tmp < key->numLevels[i])
210434345a63Smrg                        outActs[tmp] = key->acts[i][tmp];
210534345a63Smrg                    else
210634345a63Smrg                        outActs[tmp].type = XkbSA_NoAction;
210734345a63Smrg                }
210834345a63Smrg            }
210934345a63Smrg        }
211034345a63Smrg        outSyms += width;
211134345a63Smrg        if (outActs)
211234345a63Smrg            outActs += width;
211334345a63Smrg    }
211434345a63Smrg    switch (key->behavior.type & XkbKB_OpMask)
211534345a63Smrg    {
211634345a63Smrg    case XkbKB_Default:
211734345a63Smrg        break;
211834345a63Smrg    case XkbKB_Overlay1:
211934345a63Smrg    case XkbKB_Overlay2:
212034345a63Smrg        /* find key by name! */
212134345a63Smrg        if (!FindNamedKey(xkb, key->nameForOverlayKey, &okc, True,
212234345a63Smrg                          CreateKeyNames(xkb), 0))
212334345a63Smrg        {
212434345a63Smrg            if (warningLevel >= 1)
212534345a63Smrg            {
212634345a63Smrg                WARN2("Key %s not found in %s keycodes\n",
212734345a63Smrg                      longText(key->nameForOverlayKey, XkbMessage),
212834345a63Smrg                      XkbAtomText(NULL, xkb->names->keycodes, XkbMessage));
212934345a63Smrg                ACTION1("Not treating %s as an overlay key \n",
213034345a63Smrg                        longText(key->name, XkbMessage));
213134345a63Smrg            }
213234345a63Smrg            break;
213334345a63Smrg        }
213434345a63Smrg        key->behavior.data = okc;
213534345a63Smrg    default:
213634345a63Smrg        xkb->server->behaviors[kc] = key->behavior;
213734345a63Smrg        xkb->server->explicit[kc] |= XkbExplicitBehaviorMask;
213834345a63Smrg        break;
213934345a63Smrg    }
214034345a63Smrg    if (key->defs.defined & _Key_VModMap)
214134345a63Smrg    {
214234345a63Smrg        xkb->server->vmodmap[kc] = key->vmodmap;
214334345a63Smrg        xkb->server->explicit[kc] |= XkbExplicitVModMapMask;
214434345a63Smrg    }
214534345a63Smrg    if (key->repeat != RepeatUndefined)
214634345a63Smrg    {
214734345a63Smrg        if (key->repeat == RepeatYes)
214834345a63Smrg            xkb->ctrls->per_key_repeat[kc / 8] |= (1 << (kc % 8));
214934345a63Smrg        else
215034345a63Smrg            xkb->ctrls->per_key_repeat[kc / 8] &= ~(1 << (kc % 8));
215134345a63Smrg        xkb->server->explicit[kc] |= XkbExplicitAutoRepeatMask;
215234345a63Smrg    }
215334345a63Smrg
215434345a63Smrg    /* do the same thing for the next key */
215534345a63Smrg    CopySymbolsDef(result, key, kc + 1);
2156f46a6179Smrg    return True;
2157f46a6179Smrg}
2158f46a6179Smrg
2159f46a6179Smrgstatic Bool
216034345a63SmrgCopyModMapDef(XkbFileInfo * result, ModMapEntry * entry)
2161f46a6179Smrg{
216234345a63Smrg    unsigned kc;
216334345a63Smrg    XkbDescPtr xkb;
216434345a63Smrg
216534345a63Smrg    xkb = result->xkb;
216634345a63Smrg    if ((!entry->haveSymbol)
216734345a63Smrg        &&
216834345a63Smrg        (!FindNamedKey
216934345a63Smrg         (xkb, entry->u.keyName, &kc, True, CreateKeyNames(xkb), 0)))
217034345a63Smrg    {
217134345a63Smrg        if (warningLevel >= 5)
217234345a63Smrg        {
217334345a63Smrg            WARN2("Key %s not found in %s keycodes\n",
217434345a63Smrg                  longText(entry->u.keyName, XkbMessage),
217534345a63Smrg                  XkbAtomText(NULL, xkb->names->keycodes, XkbMessage));
217634345a63Smrg            ACTION1("Modifier map entry for %s not updated\n",
217734345a63Smrg                    XkbModIndexText(entry->modifier, XkbMessage));
217834345a63Smrg        }
217934345a63Smrg        return False;
218034345a63Smrg    }
218134345a63Smrg    else if (entry->haveSymbol
218234345a63Smrg             && (!FindKeyForSymbol(xkb, entry->u.keySym, &kc)))
218334345a63Smrg    {
218434345a63Smrg        if (warningLevel > 5)
218534345a63Smrg        {
218634345a63Smrg            WARN2("Key \"%s\" not found in %s symbol map\n",
218734345a63Smrg                  XkbKeysymText(entry->u.keySym, XkbMessage),
218834345a63Smrg                  XkbAtomText(NULL, xkb->names->symbols, XkbMessage));
218934345a63Smrg            ACTION1("Modifier map entry for %s not updated\n",
219034345a63Smrg                    XkbModIndexText(entry->modifier, XkbMessage));
219134345a63Smrg        }
219234345a63Smrg        return False;
219334345a63Smrg    }
219434345a63Smrg    xkb->map->modmap[kc] |= (1 << entry->modifier);
2195f46a6179Smrg    return True;
2196f46a6179Smrg}
2197f46a6179Smrg
219834345a63Smrg/**
219934345a63Smrg * Handle the xkb_symbols section of an xkb file.
220034345a63Smrg *
220134345a63Smrg * @param file The parsed xkb_symbols section of the xkb file.
220234345a63Smrg * @param result Handle to the data to store the result in.
220334345a63Smrg * @param merge Merge strategy (e.g. MergeOverride).
220434345a63Smrg */
2205f46a6179SmrgBool
220634345a63SmrgCompileSymbols(XkbFile * file, XkbFileInfo * result, unsigned merge)
2207f46a6179Smrg{
220834345a63Smrg    register int i;
220934345a63Smrg    SymbolsInfo info;
221034345a63Smrg    XkbDescPtr xkb;
2211f46a6179Smrg
221234345a63Smrg    xkb = result->xkb;
221334345a63Smrg    InitSymbolsInfo(&info, xkb);
221434345a63Smrg    info.dflt.defs.fileID = file->id;
221534345a63Smrg    info.dflt.defs.merge = merge;
221634345a63Smrg    HandleSymbolsFile(file, xkb, merge, &info);
2217f46a6179Smrg
2218f46a6179Smrg    if (info.nKeys == 0)
2219f46a6179Smrg        return True;
222034345a63Smrg    if (info.errorCount == 0)
222134345a63Smrg    {
222234345a63Smrg        KeyInfo *key;
222334345a63Smrg
222434345a63Smrg        /* alloc memory in the xkb struct */
222534345a63Smrg        if (XkbAllocNames(xkb, XkbSymbolsNameMask | XkbGroupNamesMask, 0, 0)
222634345a63Smrg            != Success)
222734345a63Smrg        {
222834345a63Smrg            WSGO("Can not allocate names in CompileSymbols\n");
222934345a63Smrg            ACTION("Symbols not added\n");
223034345a63Smrg            return False;
223134345a63Smrg        }
223234345a63Smrg        if (XkbAllocClientMap(xkb, XkbKeySymsMask | XkbModifierMapMask, 0)
223334345a63Smrg            != Success)
223434345a63Smrg        {
223534345a63Smrg            WSGO("Could not allocate client map in CompileSymbols\n");
223634345a63Smrg            ACTION("Symbols not added\n");
223734345a63Smrg            return False;
223834345a63Smrg        }
223934345a63Smrg        if (XkbAllocServerMap(xkb, XkbAllServerInfoMask, 32) != Success)
224034345a63Smrg        {
224134345a63Smrg            WSGO("Could not allocate server map in CompileSymbols\n");
224234345a63Smrg            ACTION("Symbols not added\n");
224334345a63Smrg            return False;
224434345a63Smrg        }
224534345a63Smrg        if (XkbAllocControls(xkb, XkbPerKeyRepeatMask) != Success)
224634345a63Smrg        {
224734345a63Smrg            WSGO("Could not allocate controls in CompileSymbols\n");
224834345a63Smrg            ACTION("Symbols not added\n");
224934345a63Smrg            return False;
225034345a63Smrg        }
225134345a63Smrg
225234345a63Smrg        /* now copy info into xkb. */
225334345a63Smrg        xkb->names->symbols = XkbInternAtom(xkb->dpy, info.name, False);
225434345a63Smrg        if (info.aliases)
225534345a63Smrg            ApplyAliases(xkb, False, &info.aliases);
225634345a63Smrg        for (i = 0; i < XkbNumKbdGroups; i++)
225734345a63Smrg        {
225834345a63Smrg            if (info.groupNames[i] != None)
225934345a63Smrg                xkb->names->groups[i] = info.groupNames[i];
226034345a63Smrg        }
226134345a63Smrg        /* sanitize keys */
226234345a63Smrg        for (key = info.keys, i = 0; i < info.nKeys; i++, key++)
226334345a63Smrg        {
226434345a63Smrg            PrepareKeyDef(key);
226534345a63Smrg        }
226634345a63Smrg        /* copy! */
226734345a63Smrg        for (key = info.keys, i = 0; i < info.nKeys; i++, key++)
226834345a63Smrg        {
226934345a63Smrg            if (!CopySymbolsDef(result, key, 0))
227034345a63Smrg                info.errorCount++;
227134345a63Smrg        }
227234345a63Smrg        if (warningLevel > 3)
227334345a63Smrg        {
227434345a63Smrg            for (i = xkb->min_key_code; i <= xkb->max_key_code; i++)
227534345a63Smrg            {
227634345a63Smrg                if (xkb->names->keys[i].name[0] == '\0')
227734345a63Smrg                    continue;
227834345a63Smrg                if (XkbKeyNumGroups(xkb, i) < 1)
227934345a63Smrg                {
228034345a63Smrg                    char buf[5];
228134345a63Smrg                    memcpy(buf, xkb->names->keys[i].name, 4);
228234345a63Smrg                    buf[4] = '\0';
228334345a63Smrg                    WARN2
228434345a63Smrg                        ("No symbols defined for <%s> (keycode %d)\n",
228534345a63Smrg                         buf, i);
228634345a63Smrg                }
228734345a63Smrg            }
228834345a63Smrg        }
228934345a63Smrg        if (info.modMap)
229034345a63Smrg        {
229134345a63Smrg            ModMapEntry *mm, *next;
229234345a63Smrg            for (mm = info.modMap; mm != NULL; mm = next)
229334345a63Smrg            {
229434345a63Smrg                if (!CopyModMapDef(result, mm))
229534345a63Smrg                    info.errorCount++;
229634345a63Smrg                next = (ModMapEntry *) mm->defs.next;
229734345a63Smrg            }
229834345a63Smrg        }
229934345a63Smrg        return True;
2300f46a6179Smrg    }
2301f46a6179Smrg    return False;
2302f46a6179Smrg}
2303