symbols.c revision 6930ead5
1f46a6179Smrg/************************************************************
2f46a6179Smrg Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3f46a6179Smrg
4f46a6179Smrg Permission to use, copy, modify, and distribute this
5f46a6179Smrg software and its documentation for any purpose and without
6f46a6179Smrg fee is hereby granted, provided that the above copyright
7f46a6179Smrg notice appear in all copies and that both that copyright
8f46a6179Smrg notice and this permission notice appear in supporting
9bfe6082cSmrg documentation, and that the name of Silicon Graphics not be
10bfe6082cSmrg used in advertising or publicity pertaining to distribution
11f46a6179Smrg of the software without specific prior written permission.
12bfe6082cSmrg Silicon Graphics makes no representation about the suitability
13f46a6179Smrg of this software for any purpose. It is provided "as is"
14f46a6179Smrg without any express or implied warranty.
15bfe6082cSmrg
16bfe6082cSmrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17bfe6082cSmrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18f46a6179Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19bfe6082cSmrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20bfe6082cSmrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21bfe6082cSmrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22f46a6179Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23f46a6179Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
24f46a6179Smrg
25f46a6179Smrg ********************************************************/
26f46a6179Smrg
27f46a6179Smrg#include "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    static char dflt[4] = "*";
8534345a63Smrg
8634345a63Smrg    info->defs.defined = 0;
8734345a63Smrg    info->defs.fileID = 0;
8834345a63Smrg    info->defs.merge = MergeOverride;
8934345a63Smrg    info->defs.next = NULL;
9034345a63Smrg    info->name = KeyNameToLong(dflt);
9134345a63Smrg    info->groupInfo = 0;
9234345a63Smrg    info->typesDefined = info->symsDefined = info->actsDefined = 0;
936930ead5Smrg    for (int i = 0; i < XkbNumKbdGroups; i++)
9434345a63Smrg    {
9534345a63Smrg        info->numLevels[i] = 0;
9634345a63Smrg        info->types[i] = None;
9734345a63Smrg        info->syms[i] = NULL;
9834345a63Smrg        info->acts[i] = NULL;
9934345a63Smrg    }
10034345a63Smrg    info->dfltType = None;
10134345a63Smrg    info->behavior.type = XkbKB_Default;
10234345a63Smrg    info->behavior.data = 0;
10334345a63Smrg    info->vmodmap = 0;
10434345a63Smrg    info->nameForOverlayKey = 0;
10534345a63Smrg    info->repeat = RepeatUndefined;
10634345a63Smrg    info->allowNone = 0;
107f46a6179Smrg    return;
108f46a6179Smrg}
109f46a6179Smrg
11034345a63Smrg/**
11134345a63Smrg * Free memory associated with this key info and reset to sane values.
11234345a63Smrg */
113f46a6179Smrgstatic void
11434345a63SmrgFreeKeyInfo(KeyInfo * info)
115f46a6179Smrg{
11634345a63Smrg    info->defs.defined = 0;
11734345a63Smrg    info->defs.fileID = 0;
11834345a63Smrg    info->defs.merge = MergeOverride;
11934345a63Smrg    info->defs.next = NULL;
12034345a63Smrg    info->groupInfo = 0;
12134345a63Smrg    info->typesDefined = info->symsDefined = info->actsDefined = 0;
1226930ead5Smrg    for (int i = 0; i < XkbNumKbdGroups; i++)
12334345a63Smrg    {
12434345a63Smrg        info->numLevels[i] = 0;
12534345a63Smrg        info->types[i] = None;
1266930ead5Smrg        free(info->syms[i]);
12734345a63Smrg        info->syms[i] = NULL;
1286930ead5Smrg        free(info->acts[i]);
12934345a63Smrg        info->acts[i] = NULL;
13034345a63Smrg    }
13134345a63Smrg    info->dfltType = None;
13234345a63Smrg    info->behavior.type = XkbKB_Default;
13334345a63Smrg    info->behavior.data = 0;
13434345a63Smrg    info->vmodmap = 0;
13534345a63Smrg    info->nameForOverlayKey = 0;
13634345a63Smrg    info->repeat = RepeatUndefined;
13734345a63Smrg    info->allowNone = 0;
138f46a6179Smrg    return;
139f46a6179Smrg}
140f46a6179Smrg
14134345a63Smrg/**
14234345a63Smrg * Copy old into new, optionally reset old to 0.
14334345a63Smrg * If old is reset, new simply re-uses old's memory. Otherwise, the memory is
14434345a63Smrg * newly allocated and new points to the new memory areas.
14534345a63Smrg */
146f46a6179Smrgstatic Bool
14734345a63SmrgCopyKeyInfo(KeyInfo * old, KeyInfo * new, Bool clearOld)
148f46a6179Smrg{
14934345a63Smrg    *new = *old;
15034345a63Smrg    new->defs.next = NULL;
15134345a63Smrg    if (clearOld)
15234345a63Smrg    {
1536930ead5Smrg        for (int i = 0; i < XkbNumKbdGroups; i++)
15434345a63Smrg        {
15534345a63Smrg            old->numLevels[i] = 0;
15634345a63Smrg            old->syms[i] = NULL;
15734345a63Smrg            old->acts[i] = NULL;
15834345a63Smrg        }
15934345a63Smrg    }
16034345a63Smrg    else
16134345a63Smrg    {
1626930ead5Smrg        for (int i = 0; i < XkbNumKbdGroups; i++)
16334345a63Smrg        {
1646930ead5Smrg            int width = new->numLevels[i];
16534345a63Smrg            if (old->syms[i] != NULL)
16634345a63Smrg            {
1676930ead5Smrg                new->syms[i] = calloc(width, sizeof(KeySym));
16834345a63Smrg                if (!new->syms[i])
16934345a63Smrg                {
17034345a63Smrg                    new->syms[i] = NULL;
17134345a63Smrg                    new->numLevels[i] = 0;
17234345a63Smrg                    return False;
17334345a63Smrg                }
1746930ead5Smrg                memcpy(new->syms[i], old->syms[i], width * sizeof(KeySym));
17534345a63Smrg            }
17634345a63Smrg            if (old->acts[i] != NULL)
17734345a63Smrg            {
1786930ead5Smrg                new->acts[i] = calloc(width, sizeof(XkbAction));
17934345a63Smrg                if (!new->acts[i])
18034345a63Smrg                {
18134345a63Smrg                    new->acts[i] = NULL;
18234345a63Smrg                    return False;
18334345a63Smrg                }
1846930ead5Smrg                memcpy(new->acts[i], old->acts[i], width * sizeof(XkbAction));
18534345a63Smrg            }
18634345a63Smrg        }
187f46a6179Smrg    }
188f46a6179Smrg    return True;
189f46a6179Smrg}
190f46a6179Smrg
191f46a6179Smrg/***====================================================================***/
192f46a6179Smrg
19334345a63Smrgtypedef struct _ModMapEntry
19434345a63Smrg{
19534345a63Smrg    CommonInfo defs;
19634345a63Smrg    Bool haveSymbol;
19734345a63Smrg    int modifier;
19834345a63Smrg    union
19934345a63Smrg    {
20034345a63Smrg        unsigned long keyName;
20134345a63Smrg        KeySym keySym;
202f46a6179Smrg    } u;
203f46a6179Smrg} ModMapEntry;
204f46a6179Smrg
205f46a6179Smrg#define	SYMBOLS_INIT_SIZE	110
206f46a6179Smrg#define	SYMBOLS_CHUNK		20
20734345a63Smrgtypedef struct _SymbolsInfo
20834345a63Smrg{
20934345a63Smrg    char *name;         /* e.g. pc+us+inet(evdev) */
21034345a63Smrg    int errorCount;
21134345a63Smrg    unsigned fileID;
21234345a63Smrg    unsigned merge;
21334345a63Smrg    unsigned explicit_group;
21434345a63Smrg    unsigned groupInfo;
21534345a63Smrg    unsigned szKeys;
21634345a63Smrg    unsigned nKeys;
21734345a63Smrg    KeyInfo *keys;
21834345a63Smrg    KeyInfo dflt;
21934345a63Smrg    VModInfo vmods;
22034345a63Smrg    ActionInfo *action;
22134345a63Smrg    Atom groupNames[XkbNumKbdGroups];
22234345a63Smrg
22334345a63Smrg    ModMapEntry *modMap;
22434345a63Smrg    AliasInfo *aliases;
225f46a6179Smrg} SymbolsInfo;
226f46a6179Smrg
227f46a6179Smrgstatic void
22834345a63SmrgInitSymbolsInfo(SymbolsInfo * info, XkbDescPtr xkb)
229f46a6179Smrg{
23034345a63Smrg    tok_ONE_LEVEL = XkbInternAtom(NULL, "ONE_LEVEL", False);
23134345a63Smrg    tok_TWO_LEVEL = XkbInternAtom(NULL, "TWO_LEVEL", False);
23234345a63Smrg    tok_KEYPAD = XkbInternAtom(NULL, "KEYPAD", False);
23334345a63Smrg    info->name = NULL;
23434345a63Smrg    info->explicit_group = 0;
23534345a63Smrg    info->errorCount = 0;
23634345a63Smrg    info->fileID = 0;
23734345a63Smrg    info->merge = MergeOverride;
23834345a63Smrg    info->groupInfo = 0;
23934345a63Smrg    info->szKeys = SYMBOLS_INIT_SIZE;
24034345a63Smrg    info->nKeys = 0;
2416930ead5Smrg    info->keys = calloc(SYMBOLS_INIT_SIZE, sizeof(KeyInfo));
24234345a63Smrg    info->modMap = NULL;
2436930ead5Smrg    for (int i = 0; i < XkbNumKbdGroups; i++)
24434345a63Smrg        info->groupNames[i] = None;
245f46a6179Smrg    InitKeyInfo(&info->dflt);
24634345a63Smrg    InitVModInfo(&info->vmods, xkb);
24734345a63Smrg    info->action = NULL;
24834345a63Smrg    info->aliases = NULL;
249f46a6179Smrg    return;
250f46a6179Smrg}
251f46a6179Smrg
252f46a6179Smrgstatic void
25334345a63SmrgFreeSymbolsInfo(SymbolsInfo * info)
254f46a6179Smrg{
2556930ead5Smrg    free(info->name);
25634345a63Smrg    info->name = NULL;
25734345a63Smrg    if (info->keys)
25834345a63Smrg    {
2596930ead5Smrg        for (int i = 0; i < info->nKeys; i++)
26034345a63Smrg        {
26134345a63Smrg            FreeKeyInfo(&info->keys[i]);
26234345a63Smrg        }
2636930ead5Smrg        free(info->keys);
26434345a63Smrg        info->keys = NULL;
26534345a63Smrg    }
26634345a63Smrg    if (info->modMap)
26734345a63Smrg    {
26834345a63Smrg        ClearCommonInfo(&info->modMap->defs);
26934345a63Smrg        info->modMap = NULL;
27034345a63Smrg    }
27134345a63Smrg    if (info->aliases)
27234345a63Smrg    {
27334345a63Smrg        ClearAliases(&info->aliases);
27434345a63Smrg        info->aliases = NULL;
27534345a63Smrg    }
2766930ead5Smrg    bzero(info, sizeof(SymbolsInfo));
277f46a6179Smrg    return;
278f46a6179Smrg}
279f46a6179Smrg
280f46a6179Smrgstatic Bool
28134345a63SmrgResizeKeyGroup(KeyInfo * key,
28234345a63Smrg               unsigned group, unsigned atLeastSize, Bool forceActions)
283f46a6179Smrg{
28434345a63Smrg    Bool tooSmall;
28534345a63Smrg    unsigned newWidth;
28634345a63Smrg
28734345a63Smrg    tooSmall = (key->numLevels[group] < atLeastSize);
28834345a63Smrg    if (tooSmall)
28934345a63Smrg        newWidth = atLeastSize;
29034345a63Smrg    else
29134345a63Smrg        newWidth = key->numLevels[group];
29234345a63Smrg
29334345a63Smrg    if ((key->syms[group] == NULL) || tooSmall)
29434345a63Smrg    {
2956930ead5Smrg        key->syms[group] = recallocarray(key->syms[group],
2966930ead5Smrg                                         key->numLevels[group], newWidth,
2976930ead5Smrg                                         sizeof(KeySym));
29834345a63Smrg        if (!key->syms[group])
29934345a63Smrg            return False;
30034345a63Smrg    }
30134345a63Smrg    if (((forceActions) && (tooSmall || (key->acts[group] == NULL))) ||
30234345a63Smrg        (tooSmall && (key->acts[group] != NULL)))
30334345a63Smrg    {
3046930ead5Smrg        key->acts[group] = recallocarray(key->acts[group],
3056930ead5Smrg                                         key->numLevels[group], newWidth,
3066930ead5Smrg                                         sizeof(XkbAction));
30734345a63Smrg        if (!key->acts[group])
30834345a63Smrg            return False;
30934345a63Smrg    }
31034345a63Smrg    key->numLevels[group] = newWidth;
311f46a6179Smrg    return True;
312f46a6179Smrg}
313f46a6179Smrg
314f46a6179Smrgstatic Bool
31534345a63SmrgMergeKeyGroups(SymbolsInfo * info,
31634345a63Smrg               KeyInfo * into, KeyInfo * from, unsigned group)
317f46a6179Smrg{
31834345a63Smrg    KeySym *resultSyms;
31934345a63Smrg    XkbAction *resultActs;
32034345a63Smrg    int resultWidth;
32134345a63Smrg    Bool report, clobber;
32234345a63Smrg
32334345a63Smrg    clobber = (from->defs.merge != MergeAugment);
32434345a63Smrg    report = (warningLevel > 9) ||
32534345a63Smrg        ((into->defs.fileID == from->defs.fileID) && (warningLevel > 0));
326f757b1e9Smrg    if ((from->numLevels[group] > into->numLevels[group])
327f757b1e9Smrg        || (clobber && (from->types[group] != None)))
32834345a63Smrg    {
32934345a63Smrg        resultSyms = from->syms[group];
33034345a63Smrg        resultActs = from->acts[group];
33134345a63Smrg        resultWidth = from->numLevels[group];
33234345a63Smrg    }
333f757b1e9Smrg    else
334f757b1e9Smrg    {
335f757b1e9Smrg        resultSyms = into->syms[group];
336f757b1e9Smrg        resultActs = into->acts[group];
337f757b1e9Smrg        resultWidth = into->numLevels[group];
338f757b1e9Smrg    }
33934345a63Smrg    if (resultSyms == NULL)
34034345a63Smrg    {
3416930ead5Smrg        resultSyms = calloc(resultWidth, sizeof(KeySym));
34234345a63Smrg        if (!resultSyms)
34334345a63Smrg        {
34434345a63Smrg            WSGO("Could not allocate symbols for group merge\n");
345bfe6082cSmrg            ACTION("Group %d of key %s not merged\n", group,
34634345a63Smrg                    longText(into->name, XkbMessage));
34734345a63Smrg            return False;
34834345a63Smrg        }
34934345a63Smrg    }
35034345a63Smrg    if ((resultActs == NULL) && (into->acts[group] || from->acts[group]))
35134345a63Smrg    {
3526930ead5Smrg        resultActs = calloc(resultWidth, sizeof(XkbAction));
35334345a63Smrg        if (!resultActs)
35434345a63Smrg        {
35534345a63Smrg            WSGO("Could not allocate actions for group merge\n");
356bfe6082cSmrg            ACTION("Group %d of key %s not merged\n", group,
35734345a63Smrg                    longText(into->name, XkbMessage));
35834345a63Smrg            return False;
35934345a63Smrg        }
36034345a63Smrg    }
3616930ead5Smrg    for (int i = 0; i < resultWidth; i++)
36234345a63Smrg    {
36334345a63Smrg        KeySym fromSym, toSym;
36434345a63Smrg        if (from->syms[group] && (i < from->numLevels[group]))
36534345a63Smrg            fromSym = from->syms[group][i];
36634345a63Smrg        else
36734345a63Smrg            fromSym = NoSymbol;
36834345a63Smrg        if (into->syms[group] && (i < into->numLevels[group]))
36934345a63Smrg            toSym = into->syms[group][i];
37034345a63Smrg        else
37134345a63Smrg            toSym = NoSymbol;
37234345a63Smrg        if ((fromSym == NoSymbol) || (fromSym == toSym))
37334345a63Smrg            resultSyms[i] = toSym;
37434345a63Smrg        else if (toSym == NoSymbol)
37534345a63Smrg            resultSyms[i] = fromSym;
37634345a63Smrg        else
37734345a63Smrg        {
37834345a63Smrg            KeySym use, ignore;
37934345a63Smrg            if (clobber)
38034345a63Smrg            {
38134345a63Smrg                use = fromSym;
38234345a63Smrg                ignore = toSym;
38334345a63Smrg            }
38434345a63Smrg            else
38534345a63Smrg            {
38634345a63Smrg                use = toSym;
38734345a63Smrg                ignore = fromSym;
38834345a63Smrg            }
38934345a63Smrg            if (report)
39034345a63Smrg            {
391bfe6082cSmrg                WARN
39234345a63Smrg                    ("Multiple symbols for level %d/group %d on key %s\n",
39334345a63Smrg                     i + 1, group + 1, longText(into->name, XkbMessage));
394bfe6082cSmrg                ACTION("Using %s, ignoring %s\n",
39534345a63Smrg                        XkbKeysymText(use, XkbMessage),
39634345a63Smrg                        XkbKeysymText(ignore, XkbMessage));
39734345a63Smrg            }
39834345a63Smrg            resultSyms[i] = use;
39934345a63Smrg        }
40034345a63Smrg        if (resultActs != NULL)
40134345a63Smrg        {
40234345a63Smrg            XkbAction *fromAct, *toAct;
40334345a63Smrg            fromAct = (from->acts[group] ? &from->acts[group][i] : NULL);
40434345a63Smrg            toAct = (into->acts[group] ? &into->acts[group][i] : NULL);
40534345a63Smrg            if (((fromAct == NULL) || (fromAct->type == XkbSA_NoAction))
40634345a63Smrg                && (toAct != NULL))
40734345a63Smrg            {
40834345a63Smrg                resultActs[i] = *toAct;
40934345a63Smrg            }
41034345a63Smrg            else if (((toAct == NULL) || (toAct->type == XkbSA_NoAction))
41134345a63Smrg                     && (fromAct != NULL))
41234345a63Smrg            {
41334345a63Smrg                resultActs[i] = *fromAct;
41434345a63Smrg            }
41534345a63Smrg            else
41634345a63Smrg            {
41734345a63Smrg                XkbAction *use, *ignore;
41834345a63Smrg                if (clobber)
41934345a63Smrg                {
42034345a63Smrg                    use = fromAct;
42134345a63Smrg                    ignore = toAct;
42234345a63Smrg                }
42334345a63Smrg                else
42434345a63Smrg                {
42534345a63Smrg                    use = toAct;
42634345a63Smrg                    ignore = fromAct;
42734345a63Smrg                }
42834345a63Smrg                if (report)
42934345a63Smrg                {
430bfe6082cSmrg                    WARN
43134345a63Smrg                        ("Multiple actions for level %d/group %d on key %s\n",
43234345a63Smrg                         i + 1, group + 1, longText(into->name, XkbMessage));
433bfe6082cSmrg                    ACTION("Using %s, ignoring %s\n",
43434345a63Smrg                            XkbActionTypeText(use->type, XkbMessage),
43534345a63Smrg                            XkbActionTypeText(ignore->type, XkbMessage));
43634345a63Smrg                }
43734345a63Smrg                resultActs[i] = *use;
43834345a63Smrg            }
43934345a63Smrg        }
44034345a63Smrg    }
44134345a63Smrg    if ((into->syms[group] != NULL) && (resultSyms != into->syms[group]))
4426930ead5Smrg        free(into->syms[group]);
44334345a63Smrg    if ((from->syms[group] != NULL) && (resultSyms != from->syms[group]))
4446930ead5Smrg        free(from->syms[group]);
44534345a63Smrg    if ((into->acts[group] != NULL) && (resultActs != into->acts[group]))
4466930ead5Smrg        free(into->acts[group]);
44734345a63Smrg    if ((from->acts[group] != NULL) && (resultActs != from->acts[group]))
4486930ead5Smrg        free(from->acts[group]);
44934345a63Smrg    into->numLevels[group] = resultWidth;
45034345a63Smrg    into->syms[group] = resultSyms;
45134345a63Smrg    from->syms[group] = NULL;
45234345a63Smrg    into->acts[group] = resultActs;
45334345a63Smrg    from->acts[group] = NULL;
4546930ead5Smrg    into->symsDefined |= (1U << group);
4556930ead5Smrg    from->symsDefined &= ~(1U << group);
4566930ead5Smrg    into->actsDefined |= (1U << group);
4576930ead5Smrg    from->actsDefined &= ~(1U << group);
458f46a6179Smrg    return True;
459f46a6179Smrg}
460f46a6179Smrg
461f46a6179Smrgstatic Bool
46234345a63SmrgMergeKeys(SymbolsInfo * info, KeyInfo * into, KeyInfo * from)
463f46a6179Smrg{
46434345a63Smrg    unsigned collide = 0;
46534345a63Smrg    Bool report;
46634345a63Smrg
46734345a63Smrg    if (from->defs.merge == MergeReplace)
46834345a63Smrg    {
4696930ead5Smrg        for (int i = 0; i < XkbNumKbdGroups; i++)
47034345a63Smrg        {
47134345a63Smrg            if (into->numLevels[i] != 0)
47234345a63Smrg            {
4736930ead5Smrg                free(into->syms[i]);
4746930ead5Smrg                free(into->acts[i]);
47534345a63Smrg            }
47634345a63Smrg        }
47734345a63Smrg        *into = *from;
47834345a63Smrg        bzero(from, sizeof(KeyInfo));
47934345a63Smrg        return True;
48034345a63Smrg    }
48134345a63Smrg    report = ((warningLevel > 9) ||
48234345a63Smrg              ((into->defs.fileID == from->defs.fileID)
48334345a63Smrg               && (warningLevel > 0)));
4846930ead5Smrg    for (int i = 0; i < XkbNumKbdGroups; i++)
48534345a63Smrg    {
48634345a63Smrg        if (from->numLevels[i] > 0)
48734345a63Smrg        {
48834345a63Smrg            if (into->numLevels[i] == 0)
48934345a63Smrg            {
49034345a63Smrg                into->numLevels[i] = from->numLevels[i];
49134345a63Smrg                into->syms[i] = from->syms[i];
49234345a63Smrg                into->acts[i] = from->acts[i];
4936930ead5Smrg                into->symsDefined |= (1U << i);
49434345a63Smrg                from->syms[i] = NULL;
49534345a63Smrg                from->acts[i] = NULL;
49634345a63Smrg                from->numLevels[i] = 0;
4976930ead5Smrg                from->symsDefined &= ~(1U << i);
49834345a63Smrg                if (into->syms[i])
49934345a63Smrg                    into->defs.defined |= _Key_Syms;
50034345a63Smrg                if (into->acts[i])
50134345a63Smrg                    into->defs.defined |= _Key_Acts;
50234345a63Smrg            }
50334345a63Smrg            else
50434345a63Smrg            {
50534345a63Smrg                if (report)
50634345a63Smrg                {
50734345a63Smrg                    if (into->syms[i])
50834345a63Smrg                        collide |= _Key_Syms;
50934345a63Smrg                    if (into->acts[i])
51034345a63Smrg                        collide |= _Key_Acts;
51134345a63Smrg                }
51234345a63Smrg                MergeKeyGroups(info, into, from, (unsigned) i);
51334345a63Smrg            }
51434345a63Smrg        }
51534345a63Smrg        if (from->types[i] != None)
51634345a63Smrg        {
51734345a63Smrg            if ((into->types[i] != None) && (report) &&
51834345a63Smrg                (into->types[i] != from->types[i]))
51934345a63Smrg            {
52034345a63Smrg                Atom use, ignore;
52134345a63Smrg                collide |= _Key_Types;
52234345a63Smrg                if (from->defs.merge != MergeAugment)
52334345a63Smrg                {
52434345a63Smrg                    use = from->types[i];
52534345a63Smrg                    ignore = into->types[i];
52634345a63Smrg                }
52734345a63Smrg                else
52834345a63Smrg                {
52934345a63Smrg                    use = into->types[i];
53034345a63Smrg                    ignore = from->types[i];
53134345a63Smrg                }
532bfe6082cSmrg                WARN
53334345a63Smrg                    ("Multiple definitions for group %d type of key %s\n",
53434345a63Smrg                     i, longText(into->name, XkbMessage));
535bfe6082cSmrg                ACTION("Using %s, ignoring %s\n",
53634345a63Smrg                        XkbAtomText(NULL, use, XkbMessage),
53734345a63Smrg                        XkbAtomText(NULL, ignore, XkbMessage));
53834345a63Smrg            }
53934345a63Smrg            if ((from->defs.merge != MergeAugment)
54034345a63Smrg                || (into->types[i] == None))
54134345a63Smrg            {
54234345a63Smrg                into->types[i] = from->types[i];
54334345a63Smrg            }
54434345a63Smrg        }
54534345a63Smrg    }
54634345a63Smrg    if (UseNewField(_Key_Behavior, &into->defs, &from->defs, &collide))
54734345a63Smrg    {
54834345a63Smrg        into->behavior = from->behavior;
54934345a63Smrg        into->nameForOverlayKey = from->nameForOverlayKey;
55034345a63Smrg        into->defs.defined |= _Key_Behavior;
55134345a63Smrg    }
55234345a63Smrg    if (UseNewField(_Key_VModMap, &into->defs, &from->defs, &collide))
55334345a63Smrg    {
55434345a63Smrg        into->vmodmap = from->vmodmap;
55534345a63Smrg        into->defs.defined |= _Key_VModMap;
55634345a63Smrg    }
55734345a63Smrg    if (UseNewField(_Key_Repeat, &into->defs, &from->defs, &collide))
55834345a63Smrg    {
55934345a63Smrg        into->repeat = from->repeat;
56034345a63Smrg        into->defs.defined |= _Key_Repeat;
56134345a63Smrg    }
56234345a63Smrg    if (UseNewField(_Key_Type_Dflt, &into->defs, &from->defs, &collide))
56334345a63Smrg    {
56434345a63Smrg        into->dfltType = from->dfltType;
56534345a63Smrg        into->defs.defined |= _Key_Type_Dflt;
56634345a63Smrg    }
56734345a63Smrg    if (UseNewField(_Key_GroupInfo, &into->defs, &from->defs, &collide))
56834345a63Smrg    {
56934345a63Smrg        into->groupInfo = from->groupInfo;
57034345a63Smrg        into->defs.defined |= _Key_GroupInfo;
57134345a63Smrg    }
572a57d84feSmrg    if (collide && (warningLevel > 0))
57334345a63Smrg    {
574bfe6082cSmrg        WARN("Symbol map for key %s redefined\n",
57534345a63Smrg              longText(into->name, XkbMessage));
576bfe6082cSmrg        ACTION("Using %s definition for conflicting fields\n",
57734345a63Smrg                (from->defs.merge == MergeAugment ? "first" : "last"));
578f46a6179Smrg    }
579f46a6179Smrg    return True;
580f46a6179Smrg}
581f46a6179Smrg
582f46a6179Smrgstatic Bool
58334345a63SmrgAddKeySymbols(SymbolsInfo * info, KeyInfo * key, XkbDescPtr xkb)
584f46a6179Smrg{
58534345a63Smrg    unsigned long real_name;
58634345a63Smrg
5876930ead5Smrg    for (int i = 0; i < info->nKeys; i++)
58834345a63Smrg    {
58934345a63Smrg        if (info->keys[i].name == key->name)
59034345a63Smrg            return MergeKeys(info, &info->keys[i], key);
59134345a63Smrg    }
59234345a63Smrg    if (FindKeyNameForAlias(xkb, key->name, &real_name))
59334345a63Smrg    {
5946930ead5Smrg        for (int i = 0; i < info->nKeys; i++)
59534345a63Smrg        {
59634345a63Smrg            if (info->keys[i].name == real_name)
59734345a63Smrg                return MergeKeys(info, &info->keys[i], key);
598f46a6179Smrg        }
599f46a6179Smrg    }
60034345a63Smrg    if (info->nKeys >= info->szKeys)
60134345a63Smrg    {
60234345a63Smrg        info->szKeys += SYMBOLS_CHUNK;
6036930ead5Smrg        info->keys = recallocarray(info->keys, info->nKeys, info->szKeys,
6046930ead5Smrg                                   sizeof(KeyInfo));
60534345a63Smrg        if (!info->keys)
60634345a63Smrg        {
60734345a63Smrg            WSGO("Could not allocate key symbols descriptions\n");
60834345a63Smrg            ACTION("Some key symbols definitions may be lost\n");
60934345a63Smrg            return False;
61034345a63Smrg        }
611f46a6179Smrg    }
61234345a63Smrg    return CopyKeyInfo(key, &info->keys[info->nKeys++], True);
613f46a6179Smrg}
614f46a6179Smrg
615f46a6179Smrgstatic Bool
61634345a63SmrgAddModMapEntry(SymbolsInfo * info, ModMapEntry * new)
617f46a6179Smrg{
61834345a63Smrg    ModMapEntry *mm;
61934345a63Smrg    Bool clobber;
62034345a63Smrg
62134345a63Smrg    clobber = (new->defs.merge != MergeAugment);
62234345a63Smrg    for (mm = info->modMap; mm != NULL; mm = (ModMapEntry *) mm->defs.next)
62334345a63Smrg    {
62434345a63Smrg        if (new->haveSymbol && mm->haveSymbol
62534345a63Smrg            && (new->u.keySym == mm->u.keySym))
62634345a63Smrg        {
62734345a63Smrg            if (mm->modifier != new->modifier)
62834345a63Smrg            {
6296930ead5Smrg                unsigned use, ignore;
6306930ead5Smrg
63134345a63Smrg                if (clobber)
63234345a63Smrg                {
63334345a63Smrg                    use = new->modifier;
63434345a63Smrg                    ignore = mm->modifier;
63534345a63Smrg                }
63634345a63Smrg                else
63734345a63Smrg                {
63834345a63Smrg                    use = mm->modifier;
63934345a63Smrg                    ignore = new->modifier;
64034345a63Smrg                }
641bfe6082cSmrg                ERROR
64234345a63Smrg                    ("%s added to symbol map for multiple modifiers\n",
64334345a63Smrg                     XkbKeysymText(new->u.keySym, XkbMessage));
644bfe6082cSmrg                ACTION("Using %s, ignoring %s.\n",
64534345a63Smrg                        XkbModIndexText(use, XkbMessage),
64634345a63Smrg                        XkbModIndexText(ignore, XkbMessage));
64734345a63Smrg                mm->modifier = use;
64834345a63Smrg            }
64934345a63Smrg            return True;
65034345a63Smrg        }
65134345a63Smrg        if ((!new->haveSymbol) && (!mm->haveSymbol) &&
65234345a63Smrg            (new->u.keyName == mm->u.keyName))
65334345a63Smrg        {
65434345a63Smrg            if (mm->modifier != new->modifier)
65534345a63Smrg            {
6566930ead5Smrg                unsigned use, ignore;
6576930ead5Smrg
65834345a63Smrg                if (clobber)
65934345a63Smrg                {
66034345a63Smrg                    use = new->modifier;
66134345a63Smrg                    ignore = mm->modifier;
66234345a63Smrg                }
66334345a63Smrg                else
66434345a63Smrg                {
66534345a63Smrg                    use = mm->modifier;
66634345a63Smrg                    ignore = new->modifier;
66734345a63Smrg                }
668bfe6082cSmrg                ERROR("Key %s added to map for multiple modifiers\n",
66934345a63Smrg                       longText(new->u.keyName, XkbMessage));
670bfe6082cSmrg                ACTION("Using %s, ignoring %s.\n",
67134345a63Smrg                        XkbModIndexText(use, XkbMessage),
67234345a63Smrg                        XkbModIndexText(ignore, XkbMessage));
67334345a63Smrg                mm->modifier = use;
67434345a63Smrg            }
67534345a63Smrg            return True;
67634345a63Smrg        }
67734345a63Smrg    }
6786930ead5Smrg    mm = malloc(sizeof(ModMapEntry));
67934345a63Smrg    if (mm == NULL)
68034345a63Smrg    {
68134345a63Smrg        WSGO("Could not allocate modifier map entry\n");
682bfe6082cSmrg        ACTION("Modifier map for %s will be incomplete\n",
68334345a63Smrg                XkbModIndexText(new->modifier, XkbMessage));
68434345a63Smrg        return False;
68534345a63Smrg    }
68634345a63Smrg    *mm = *new;
68734345a63Smrg    mm->defs.next = &info->modMap->defs;
68834345a63Smrg    info->modMap = mm;
689f46a6179Smrg    return True;
690f46a6179Smrg}
691f46a6179Smrg
692f46a6179Smrg/***====================================================================***/
693f46a6179Smrg
694f46a6179Smrgstatic void
69534345a63SmrgMergeIncludedSymbols(SymbolsInfo * into, SymbolsInfo * from,
69634345a63Smrg                     unsigned merge, XkbDescPtr xkb)
697f46a6179Smrg{
6986930ead5Smrg    int i;
69934345a63Smrg    KeyInfo *key;
70034345a63Smrg
70134345a63Smrg    if (from->errorCount > 0)
70234345a63Smrg    {
70334345a63Smrg        into->errorCount += from->errorCount;
70434345a63Smrg        return;
70534345a63Smrg    }
70634345a63Smrg    if (into->name == NULL)
70734345a63Smrg    {
70834345a63Smrg        into->name = from->name;
70934345a63Smrg        from->name = NULL;
71034345a63Smrg    }
71134345a63Smrg    for (i = 0; i < XkbNumKbdGroups; i++)
71234345a63Smrg    {
71334345a63Smrg        if (from->groupNames[i] != None)
71434345a63Smrg        {
71534345a63Smrg            if ((merge != MergeAugment) || (into->groupNames[i] == None))
71634345a63Smrg                into->groupNames[i] = from->groupNames[i];
71734345a63Smrg        }
71834345a63Smrg    }
71934345a63Smrg    for (i = 0, key = from->keys; i < from->nKeys; i++, key++)
72034345a63Smrg    {
72134345a63Smrg        if (merge != MergeDefault)
72234345a63Smrg            key->defs.merge = merge;
72334345a63Smrg        if (!AddKeySymbols(into, key, xkb))
72434345a63Smrg            into->errorCount++;
72534345a63Smrg    }
72634345a63Smrg    if (from->modMap != NULL)
72734345a63Smrg    {
72834345a63Smrg        ModMapEntry *mm, *next;
72934345a63Smrg        for (mm = from->modMap; mm != NULL; mm = next)
73034345a63Smrg        {
73134345a63Smrg            if (merge != MergeDefault)
73234345a63Smrg                mm->defs.merge = merge;
73334345a63Smrg            if (!AddModMapEntry(into, mm))
73434345a63Smrg                into->errorCount++;
73534345a63Smrg            next = (ModMapEntry *) mm->defs.next;
7366930ead5Smrg            free(mm);
73734345a63Smrg        }
73834345a63Smrg        from->modMap = NULL;
73934345a63Smrg    }
74034345a63Smrg    if (!MergeAliases(&into->aliases, &from->aliases, merge))
74134345a63Smrg        into->errorCount++;
742f46a6179Smrg    return;
743f46a6179Smrg}
744f46a6179Smrg
74534345a63Smrgtypedef void (*FileHandler) (XkbFile * /* rtrn */ ,
74634345a63Smrg                             XkbDescPtr /* xkb */ ,
74734345a63Smrg                             unsigned /* merge */ ,
74834345a63Smrg                             SymbolsInfo *      /* included */
74934345a63Smrg    );
750f46a6179Smrg
751f46a6179Smrgstatic Bool
75234345a63SmrgHandleIncludeSymbols(IncludeStmt * stmt,
75334345a63Smrg                     XkbDescPtr xkb, SymbolsInfo * info, FileHandler hndlr)
754f46a6179Smrg{
75534345a63Smrg    unsigned newMerge;
75634345a63Smrg    XkbFile *rtrn;
75734345a63Smrg    SymbolsInfo included;
75834345a63Smrg    Bool haveSelf;
75934345a63Smrg
76034345a63Smrg    haveSelf = False;
76134345a63Smrg    if ((stmt->file == NULL) && (stmt->map == NULL))
76234345a63Smrg    {
76334345a63Smrg        haveSelf = True;
76434345a63Smrg        included = *info;
76534345a63Smrg        bzero(info, sizeof(SymbolsInfo));
76634345a63Smrg    }
76734345a63Smrg    else if (ProcessIncludeFile(stmt, XkmSymbolsIndex, &rtrn, &newMerge))
76834345a63Smrg    {
76934345a63Smrg        InitSymbolsInfo(&included, xkb);
77034345a63Smrg        included.fileID = included.dflt.defs.fileID = rtrn->id;
77134345a63Smrg        included.merge = included.dflt.defs.merge = MergeOverride;
77234345a63Smrg        if (stmt->modifier)
77334345a63Smrg        {
77434345a63Smrg            included.explicit_group = atoi(stmt->modifier) - 1;
77534345a63Smrg        }
77634345a63Smrg        else
77734345a63Smrg        {
77834345a63Smrg            included.explicit_group = info->explicit_group;
77934345a63Smrg        }
78034345a63Smrg        (*hndlr) (rtrn, xkb, MergeOverride, &included);
78134345a63Smrg        if (stmt->stmt != NULL)
78234345a63Smrg        {
7836930ead5Smrg            free(included.name);
78434345a63Smrg            included.name = stmt->stmt;
78534345a63Smrg            stmt->stmt = NULL;
78634345a63Smrg        }
78734345a63Smrg    }
78834345a63Smrg    else
78934345a63Smrg    {
79034345a63Smrg        info->errorCount += 10;
79134345a63Smrg        return False;
79234345a63Smrg    }
79334345a63Smrg    if ((stmt->next != NULL) && (included.errorCount < 1))
79434345a63Smrg    {
79534345a63Smrg        IncludeStmt *next;
79634345a63Smrg        unsigned op;
79734345a63Smrg        SymbolsInfo next_incl;
79834345a63Smrg
79934345a63Smrg        for (next = stmt->next; next != NULL; next = next->next)
80034345a63Smrg        {
80134345a63Smrg            if ((next->file == NULL) && (next->map == NULL))
80234345a63Smrg            {
80334345a63Smrg                haveSelf = True;
80434345a63Smrg                MergeIncludedSymbols(&included, info, next->merge, xkb);
80534345a63Smrg                FreeSymbolsInfo(info);
80634345a63Smrg            }
80734345a63Smrg            else if (ProcessIncludeFile(next, XkmSymbolsIndex, &rtrn, &op))
80834345a63Smrg            {
80934345a63Smrg                InitSymbolsInfo(&next_incl, xkb);
81034345a63Smrg                next_incl.fileID = next_incl.dflt.defs.fileID = rtrn->id;
81134345a63Smrg                next_incl.merge = next_incl.dflt.defs.merge = MergeOverride;
81234345a63Smrg                if (next->modifier)
81334345a63Smrg                {
81434345a63Smrg                    next_incl.explicit_group = atoi(next->modifier) - 1;
81534345a63Smrg                }
81634345a63Smrg                else
81734345a63Smrg                {
81834345a63Smrg                    next_incl.explicit_group = info->explicit_group;
819f46a6179Smrg                }
82034345a63Smrg                (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
82134345a63Smrg                MergeIncludedSymbols(&included, &next_incl, op, xkb);
82234345a63Smrg                FreeSymbolsInfo(&next_incl);
82334345a63Smrg            }
82434345a63Smrg            else
82534345a63Smrg            {
82634345a63Smrg                info->errorCount += 10;
82734345a63Smrg                return False;
82834345a63Smrg            }
82934345a63Smrg        }
830f46a6179Smrg    }
831f46a6179Smrg    if (haveSelf)
83234345a63Smrg        *info = included;
83334345a63Smrg    else
83434345a63Smrg    {
83534345a63Smrg        MergeIncludedSymbols(info, &included, newMerge, xkb);
83634345a63Smrg        FreeSymbolsInfo(&included);
837f46a6179Smrg    }
83834345a63Smrg    return (info->errorCount == 0);
839f46a6179Smrg}
840f46a6179Smrg
84134345a63Smrgstatic LookupEntry groupNames[] = {
84234345a63Smrg    {"group1", 1},
84334345a63Smrg    {"group2", 2},
84434345a63Smrg    {"group3", 3},
84534345a63Smrg    {"group4", 4},
84634345a63Smrg    {"group5", 5},
84734345a63Smrg    {"group6", 6},
84834345a63Smrg    {"group7", 7},
84934345a63Smrg    {"group8", 8},
85034345a63Smrg    {NULL, 0}
851f46a6179Smrg};
852f46a6179Smrg
853f46a6179Smrg
854f46a6179Smrg#define	SYMBOLS 1
855f46a6179Smrg#define	ACTIONS	2
856f46a6179Smrg
857f46a6179Smrgstatic Bool
8586930ead5SmrgGetGroupIndex(KeyInfo *key, const ExprDef *arrayNdx,
8596930ead5Smrg              unsigned what, unsigned *ndx_rtrn)
860f46a6179Smrg{
86134345a63Smrg    const char *name;
86234345a63Smrg    ExprResult tmp;
86334345a63Smrg
86434345a63Smrg    if (what == SYMBOLS)
86534345a63Smrg        name = "symbols";
86634345a63Smrg    else
86734345a63Smrg        name = "actions";
86834345a63Smrg
86934345a63Smrg    if (arrayNdx == NULL)
87034345a63Smrg    {
87134345a63Smrg        unsigned defined;
87234345a63Smrg        if (what == SYMBOLS)
87334345a63Smrg            defined = key->symsDefined;
87434345a63Smrg        else
87534345a63Smrg            defined = key->actsDefined;
87634345a63Smrg
8776930ead5Smrg        for (int i = 0; i < XkbNumKbdGroups; i++)
87834345a63Smrg        {
8796930ead5Smrg            if ((defined & (1U << i)) == 0)
88034345a63Smrg            {
88134345a63Smrg                *ndx_rtrn = i;
88234345a63Smrg                return True;
88334345a63Smrg            }
88434345a63Smrg        }
885bfe6082cSmrg        ERROR("Too many groups of %s for key %s (max %d)\n", name,
88634345a63Smrg               longText(key->name, XkbMessage), XkbNumKbdGroups + 1);
887bfe6082cSmrg        ACTION("Ignoring %s defined for extra groups\n", name);
88834345a63Smrg        return False;
88934345a63Smrg    }
89034345a63Smrg    if (!ExprResolveInteger
89134345a63Smrg        (arrayNdx, &tmp, SimpleLookup, (XPointer) groupNames))
89234345a63Smrg    {
893bfe6082cSmrg        ERROR("Illegal group index for %s of key %s\n", name,
89434345a63Smrg               longText(key->name, XkbMessage));
89534345a63Smrg        ACTION("Definition with non-integer array index ignored\n");
89634345a63Smrg        return False;
89734345a63Smrg    }
89834345a63Smrg    if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
89934345a63Smrg    {
900bfe6082cSmrg        ERROR("Group index for %s of key %s is out of range (1..%d)\n",
90134345a63Smrg               name, longText(key->name, XkbMessage), XkbNumKbdGroups + 1);
902bfe6082cSmrg        ACTION("Ignoring %s for group %d\n", name, tmp.uval);
90334345a63Smrg        return False;
90434345a63Smrg    }
90534345a63Smrg    *ndx_rtrn = tmp.uval - 1;
906f46a6179Smrg    return True;
907f46a6179Smrg}
908f46a6179Smrg
909f46a6179Smrgstatic Bool
9106930ead5SmrgAddSymbolsToKey(KeyInfo *key, XkbDescPtr xkb, const char *field,
9116930ead5Smrg                const ExprDef *arrayNdx, const ExprDef *value,
9126930ead5Smrg                SymbolsInfo *info)
913f46a6179Smrg{
91434345a63Smrg    unsigned ndx, nSyms;
91534345a63Smrg
91634345a63Smrg    if (!GetGroupIndex(key, arrayNdx, SYMBOLS, &ndx))
91734345a63Smrg        return False;
91834345a63Smrg    if (value == NULL)
91934345a63Smrg    {
9206930ead5Smrg        key->symsDefined |= (1U << ndx);
92134345a63Smrg        return True;
92234345a63Smrg    }
92334345a63Smrg    if (value->op != ExprKeysymList)
92434345a63Smrg    {
925bfe6082cSmrg        ERROR("Expected a list of symbols, found %s\n",
92634345a63Smrg               exprOpText(value->op));
927bfe6082cSmrg        ACTION("Ignoring symbols for group %d of %s\n", ndx,
92834345a63Smrg                longText(key->name, XkbMessage));
92934345a63Smrg        return False;
93034345a63Smrg    }
93134345a63Smrg    if (key->syms[ndx] != NULL)
93234345a63Smrg    {
933bfe6082cSmrg        WSGO("Symbols for key %s, group %d already defined\n",
93434345a63Smrg              longText(key->name, XkbMessage), ndx);
93534345a63Smrg        return False;
93634345a63Smrg    }
93734345a63Smrg    nSyms = value->value.list.nSyms;
93834345a63Smrg    if (((key->numLevels[ndx] < nSyms) || (key->syms[ndx] == NULL)) &&
93934345a63Smrg        (!ResizeKeyGroup(key, ndx, nSyms, False)))
94034345a63Smrg    {
941bfe6082cSmrg        WSGO("Could not resize group %d of key %s\n", ndx,
94234345a63Smrg              longText(key->name, XkbMessage));
94334345a63Smrg        ACTION("Symbols lost\n");
94434345a63Smrg        return False;
94534345a63Smrg    }
9466930ead5Smrg    key->symsDefined |= (1U << ndx);
9476930ead5Smrg    for (int i = 0; i < nSyms; i++) {
94883e5f723Smrg        if (!LookupKeysym(value->value.list.syms[i], &key->syms[ndx][i])) {
949a57d84feSmrg            if (warningLevel > 0)
950a57d84feSmrg            {
951a57d84feSmrg                WARN("Could not resolve keysym %s\n",
952a57d84feSmrg                      value->value.list.syms[i]);
953a57d84feSmrg            }
95483e5f723Smrg            key->syms[ndx][i] = NoSymbol;
95583e5f723Smrg        }
95683e5f723Smrg    }
9576930ead5Smrg    for (int i = key->numLevels[ndx] - 1;
95834345a63Smrg         (i >= 0) && (key->syms[ndx][i] == NoSymbol); i--)
95934345a63Smrg    {
96034345a63Smrg        key->numLevels[ndx]--;
961f46a6179Smrg    }
962f46a6179Smrg    return True;
963f46a6179Smrg}
964f46a6179Smrg
965f46a6179Smrgstatic Bool
9666930ead5SmrgAddActionsToKey(KeyInfo *key, XkbDescPtr xkb, const char *field,
9676930ead5Smrg                const ExprDef *arrayNdx, const ExprDef *value,
9686930ead5Smrg                SymbolsInfo *info)
969f46a6179Smrg{
97034345a63Smrg    unsigned ndx, nActs;
97134345a63Smrg    ExprDef *act;
97234345a63Smrg    XkbAnyAction *toAct;
97334345a63Smrg
97434345a63Smrg    if (!GetGroupIndex(key, arrayNdx, ACTIONS, &ndx))
97534345a63Smrg        return False;
97634345a63Smrg
97734345a63Smrg    if (value == NULL)
97834345a63Smrg    {
9796930ead5Smrg        key->actsDefined |= (1U << ndx);
98034345a63Smrg        return True;
98134345a63Smrg    }
98234345a63Smrg    if (value->op != ExprActionList)
98334345a63Smrg    {
984bfe6082cSmrg        WSGO("Bad expression type (%d) for action list value\n", value->op);
985bfe6082cSmrg        ACTION("Ignoring actions for group %d of %s\n", ndx,
98634345a63Smrg                longText(key->name, XkbMessage));
98734345a63Smrg        return False;
98834345a63Smrg    }
98934345a63Smrg    if (key->acts[ndx] != NULL)
99034345a63Smrg    {
991bfe6082cSmrg        WSGO("Actions for key %s, group %d already defined\n",
99234345a63Smrg              longText(key->name, XkbMessage), ndx);
99334345a63Smrg        return False;
99434345a63Smrg    }
99534345a63Smrg    for (nActs = 0, act = value->value.child; act != NULL; nActs++)
99634345a63Smrg    {
99734345a63Smrg        act = (ExprDef *) act->common.next;
99834345a63Smrg    }
99934345a63Smrg    if (nActs < 1)
100034345a63Smrg    {
100134345a63Smrg        WSGO("Action list but not actions in AddActionsToKey\n");
100234345a63Smrg        return False;
100334345a63Smrg    }
100434345a63Smrg    if (((key->numLevels[ndx] < nActs) || (key->acts[ndx] == NULL)) &&
100534345a63Smrg        (!ResizeKeyGroup(key, ndx, nActs, True)))
100634345a63Smrg    {
1007bfe6082cSmrg        WSGO("Could not resize group %d of key %s\n", ndx,
100834345a63Smrg              longText(key->name, XkbMessage));
100934345a63Smrg        ACTION("Actions lost\n");
101034345a63Smrg        return False;
101134345a63Smrg    }
10126930ead5Smrg    key->actsDefined |= (1U << ndx);
101334345a63Smrg
101434345a63Smrg    toAct = (XkbAnyAction *) key->acts[ndx];
101534345a63Smrg    act = value->value.child;
10166930ead5Smrg    for (int i = 0; i < nActs; i++, toAct++)
101734345a63Smrg    {
101834345a63Smrg        if (!HandleActionDef(act, xkb, toAct, MergeOverride, info->action))
101934345a63Smrg        {
1020bfe6082cSmrg            ERROR("Illegal action definition for %s\n",
102134345a63Smrg                   longText(key->name, XkbMessage));
1022bfe6082cSmrg            ACTION("Action for group %d/level %d ignored\n", ndx + 1, i + 1);
102334345a63Smrg        }
102434345a63Smrg        act = (ExprDef *) act->common.next;
1025f46a6179Smrg    }
1026f46a6179Smrg    return True;
1027f46a6179Smrg}
1028f46a6179Smrg
1029f46a6179Smrgstatic int
10306930ead5SmrgSetAllowNone(KeyInfo *key, const ExprDef *arrayNdx, const ExprDef *value)
1031f46a6179Smrg{
103234345a63Smrg    ExprResult tmp;
103334345a63Smrg    unsigned radio_groups = 0;
103434345a63Smrg
103534345a63Smrg    if (arrayNdx == NULL)
103634345a63Smrg    {
103734345a63Smrg        radio_groups = XkbAllRadioGroupsMask;
103834345a63Smrg    }
103934345a63Smrg    else
104034345a63Smrg    {
104134345a63Smrg        if (!ExprResolveInteger(arrayNdx, &tmp, RadioLookup, NULL))
104234345a63Smrg        {
104334345a63Smrg            ERROR("Illegal index in group name definition\n");
104434345a63Smrg            ACTION("Definition with non-integer array index ignored\n");
104534345a63Smrg            return False;
104634345a63Smrg        }
104734345a63Smrg        if ((tmp.uval < 1) || (tmp.uval > XkbMaxRadioGroups))
104834345a63Smrg        {
1049bfe6082cSmrg            ERROR("Illegal radio group specified (must be 1..%d)\n",
105034345a63Smrg                   XkbMaxRadioGroups + 1);
1051bfe6082cSmrg            ACTION("Value of \"allow none\" for group %d ignored\n",
105234345a63Smrg                    tmp.uval);
105334345a63Smrg            return False;
105434345a63Smrg        }
10556930ead5Smrg        radio_groups |= (1U << (tmp.uval - 1));
105634345a63Smrg    }
105734345a63Smrg    if (!ExprResolveBoolean(value, &tmp, NULL, NULL))
105834345a63Smrg    {
1059bfe6082cSmrg        ERROR("Illegal \"allow none\" value for %s\n",
106034345a63Smrg               longText(key->name, XkbMessage));
106134345a63Smrg        ACTION("Non-boolean value ignored\n");
106234345a63Smrg        return False;
106334345a63Smrg    }
106434345a63Smrg    if (tmp.uval)
106534345a63Smrg        key->allowNone |= radio_groups;
106634345a63Smrg    else
106734345a63Smrg        key->allowNone &= ~radio_groups;
1068f46a6179Smrg    return True;
1069f46a6179Smrg}
1070f46a6179Smrg
1071f46a6179Smrg
107234345a63Smrgstatic LookupEntry lockingEntries[] = {
107334345a63Smrg    {"true", XkbKB_Lock},
107434345a63Smrg    {"yes", XkbKB_Lock},
107534345a63Smrg    {"on", XkbKB_Lock},
107634345a63Smrg    {"false", XkbKB_Default},
107734345a63Smrg    {"no", XkbKB_Default},
107834345a63Smrg    {"off", XkbKB_Default},
107934345a63Smrg    {"permanent", XkbKB_Lock | XkbKB_Permanent},
108034345a63Smrg    {NULL, 0}
1081f46a6179Smrg};
1082f46a6179Smrg
108334345a63Smrgstatic LookupEntry repeatEntries[] = {
108434345a63Smrg    {"true", RepeatYes},
108534345a63Smrg    {"yes", RepeatYes},
108634345a63Smrg    {"on", RepeatYes},
108734345a63Smrg    {"false", RepeatNo},
108834345a63Smrg    {"no", RepeatNo},
108934345a63Smrg    {"off", RepeatNo},
109034345a63Smrg    {"default", RepeatUndefined},
109134345a63Smrg    {NULL, 0}
1092f46a6179Smrg};
1093f46a6179Smrg
109434345a63Smrgstatic LookupEntry rgEntries[] = {
109534345a63Smrg    {"none", 0},
109634345a63Smrg    {NULL, 0}
1097f46a6179Smrg};
1098f46a6179Smrg
1099f46a6179Smrgstatic Bool
11006930ead5SmrgSetSymbolsField(KeyInfo *key, XkbDescPtr xkb, const char *field,
11016930ead5Smrg                const ExprDef *arrayNdx, const ExprDef *value,
11026930ead5Smrg                SymbolsInfo *info)
1103f46a6179Smrg{
110434345a63Smrg    Bool ok = True;
110534345a63Smrg    ExprResult tmp;
110634345a63Smrg
110734345a63Smrg    if (uStrCaseCmp(field, "type") == 0)
110834345a63Smrg    {
110934345a63Smrg        ExprResult ndx;
111034345a63Smrg        if ((!ExprResolveString(value, &tmp, NULL, NULL))
111134345a63Smrg            && (warningLevel > 0))
111234345a63Smrg        {
111334345a63Smrg            WARN("The type field of a key symbol map must be a string\n");
111434345a63Smrg            ACTION("Ignoring illegal type definition\n");
111534345a63Smrg        }
111634345a63Smrg        if (arrayNdx == NULL)
111734345a63Smrg        {
111834345a63Smrg            key->dfltType = XkbInternAtom(NULL, tmp.str, False);
111934345a63Smrg            key->defs.defined |= _Key_Type_Dflt;
112034345a63Smrg        }
112134345a63Smrg        else if (!ExprResolveInteger(arrayNdx, &ndx, SimpleLookup,
112234345a63Smrg                                     (XPointer) groupNames))
112334345a63Smrg        {
1124bfe6082cSmrg            ERROR("Illegal group index for type of key %s\n",
112534345a63Smrg                   longText(key->name, XkbMessage));
112634345a63Smrg            ACTION("Definition with non-integer array index ignored\n");
112734345a63Smrg            return False;
112834345a63Smrg        }
112934345a63Smrg        else if ((ndx.uval < 1) || (ndx.uval > XkbNumKbdGroups))
113034345a63Smrg        {
1131bfe6082cSmrg            ERROR
113234345a63Smrg                ("Group index for type of key %s is out of range (1..%d)\n",
113334345a63Smrg                 longText(key->name, XkbMessage), XkbNumKbdGroups + 1);
1134bfe6082cSmrg            ACTION("Ignoring type for group %d\n", ndx.uval);
113534345a63Smrg            return False;
113634345a63Smrg        }
113734345a63Smrg        else
113834345a63Smrg        {
113934345a63Smrg            key->types[ndx.uval - 1] = XkbInternAtom(NULL, tmp.str, False);
11406930ead5Smrg            key->typesDefined |= (1U << (ndx.uval - 1));
114134345a63Smrg        }
114234345a63Smrg    }
114334345a63Smrg    else if (uStrCaseCmp(field, "symbols") == 0)
114434345a63Smrg        return AddSymbolsToKey(key, xkb, field, arrayNdx, value, info);
114534345a63Smrg    else if (uStrCaseCmp(field, "actions") == 0)
114634345a63Smrg        return AddActionsToKey(key, xkb, field, arrayNdx, value, info);
114734345a63Smrg    else if ((uStrCaseCmp(field, "vmods") == 0) ||
114834345a63Smrg             (uStrCaseCmp(field, "virtualmods") == 0) ||
114934345a63Smrg             (uStrCaseCmp(field, "virtualmodifiers") == 0))
115034345a63Smrg    {
115134345a63Smrg        ok = ExprResolveModMask(value, &tmp, LookupVModMask, (XPointer) xkb);
115234345a63Smrg        if (ok)
115334345a63Smrg        {
115434345a63Smrg            key->vmodmap = (tmp.uval >> 8);
115534345a63Smrg            key->defs.defined |= _Key_VModMap;
115634345a63Smrg        }
115734345a63Smrg        else
115834345a63Smrg        {
1159bfe6082cSmrg            ERROR("Expected a virtual modifier mask, found %s\n",
116034345a63Smrg                   exprOpText(value->op));
1161bfe6082cSmrg            ACTION("Ignoring virtual modifiers definition for key %s\n",
116234345a63Smrg                    longText(key->name, XkbMessage));
116334345a63Smrg        }
116434345a63Smrg    }
116534345a63Smrg    else if ((uStrCaseCmp(field, "locking") == 0)
116634345a63Smrg             || (uStrCaseCmp(field, "lock") == 0)
116734345a63Smrg             || (uStrCaseCmp(field, "locks") == 0))
116834345a63Smrg    {
116934345a63Smrg        ok = ExprResolveEnum(value, &tmp, lockingEntries);
117034345a63Smrg        if (ok)
117134345a63Smrg            key->behavior.type = tmp.uval;
117234345a63Smrg        key->defs.defined |= _Key_Behavior;
117334345a63Smrg    }
117434345a63Smrg    else if ((uStrCaseCmp(field, "radiogroup") == 0) ||
117534345a63Smrg             (uStrCaseCmp(field, "permanentradiogroup") == 0))
117634345a63Smrg    {
117734345a63Smrg        Bool permanent = False;
117834345a63Smrg        if (uStrCaseCmp(field, "permanentradiogroup") == 0)
117934345a63Smrg            permanent = True;
118034345a63Smrg        ok = ExprResolveInteger(value, &tmp, SimpleLookup,
118134345a63Smrg                                (XPointer) rgEntries);
118234345a63Smrg        if (!ok)
118334345a63Smrg        {
1184bfe6082cSmrg            ERROR("Illegal radio group specification for %s\n",
118534345a63Smrg                   longText(key->name, XkbMessage));
118634345a63Smrg            ACTION("Non-integer radio group ignored\n");
118734345a63Smrg            return False;
118834345a63Smrg        }
118934345a63Smrg        if (tmp.uval == 0)
119034345a63Smrg        {
119134345a63Smrg            key->behavior.type = XkbKB_Default;
119234345a63Smrg            key->behavior.data = 0;
119334345a63Smrg            return ok;
119434345a63Smrg        }
119534345a63Smrg        if ((tmp.uval < 1) || (tmp.uval > XkbMaxRadioGroups))
119634345a63Smrg        {
1197bfe6082cSmrg            ERROR
119834345a63Smrg                ("Radio group specification for %s out of range (1..32)\n",
119934345a63Smrg                 longText(key->name, XkbMessage));
1200bfe6082cSmrg            ACTION("Illegal radio group %d ignored\n", tmp.uval);
120134345a63Smrg            return False;
120234345a63Smrg        }
120334345a63Smrg        key->behavior.type =
120434345a63Smrg            XkbKB_RadioGroup | (permanent ? XkbKB_Permanent : 0);
120534345a63Smrg        key->behavior.data = tmp.uval - 1;
12066930ead5Smrg        if (key->allowNone & (1U << (tmp.uval - 1)))
120734345a63Smrg            key->behavior.data |= XkbKB_RGAllowNone;
120834345a63Smrg        key->defs.defined |= _Key_Behavior;
120934345a63Smrg    }
121034345a63Smrg    else if (uStrCaseEqual(field, "allownone"))
121134345a63Smrg    {
121234345a63Smrg        ok = SetAllowNone(key, arrayNdx, value);
121334345a63Smrg    }
121434345a63Smrg    else if (uStrCasePrefix("overlay", field) ||
121534345a63Smrg             uStrCasePrefix("permanentoverlay", field))
121634345a63Smrg    {
121734345a63Smrg        Bool permanent = False;
1218c82dfdfbSmrg        const char *which;
121934345a63Smrg        int overlayNdx;
122034345a63Smrg        if (uStrCasePrefix("permanent", field))
122134345a63Smrg        {
122234345a63Smrg            permanent = True;
122334345a63Smrg            which = &field[sizeof("permanentoverlay") - 1];
122434345a63Smrg        }
122534345a63Smrg        else
122634345a63Smrg        {
122734345a63Smrg            which = &field[sizeof("overlay") - 1];
122834345a63Smrg        }
122934345a63Smrg        if (sscanf(which, "%d", &overlayNdx) == 1)
123034345a63Smrg        {
123134345a63Smrg            if (((overlayNdx < 1) || (overlayNdx > 2)) && (warningLevel > 0))
123234345a63Smrg            {
1233bfe6082cSmrg                ERROR("Illegal overlay %d specified for %s\n",
123434345a63Smrg                       overlayNdx, longText(key->name, XkbMessage));
123534345a63Smrg                ACTION("Ignored\n");
123634345a63Smrg                return False;
123734345a63Smrg            }
123834345a63Smrg        }
123934345a63Smrg        else if (*which == '\0')
124034345a63Smrg            overlayNdx = 1;
124134345a63Smrg        else if (warningLevel > 0)
124234345a63Smrg        {
1243bfe6082cSmrg            ERROR("Illegal overlay \"%s\" specified for %s\n",
124434345a63Smrg                   which, longText(key->name, XkbMessage));
124534345a63Smrg            ACTION("Ignored\n");
124634345a63Smrg            return False;
124734345a63Smrg        }
124834345a63Smrg        ok = ExprResolveKeyName(value, &tmp, NULL, NULL);
124934345a63Smrg        if (!ok)
125034345a63Smrg        {
1251bfe6082cSmrg            ERROR("Illegal overlay key specification for %s\n",
125234345a63Smrg                   longText(key->name, XkbMessage));
125334345a63Smrg            ACTION("Overlay key must be specified by name\n");
125434345a63Smrg            return False;
125534345a63Smrg        }
125634345a63Smrg        if (overlayNdx == 1)
125734345a63Smrg            key->behavior.type = XkbKB_Overlay1;
125834345a63Smrg        else
125934345a63Smrg            key->behavior.type = XkbKB_Overlay2;
126034345a63Smrg        if (permanent)
126134345a63Smrg            key->behavior.type |= XkbKB_Permanent;
126234345a63Smrg
126334345a63Smrg        key->behavior.data = 0;
126434345a63Smrg        key->nameForOverlayKey = KeyNameToLong(tmp.keyName.name);
126534345a63Smrg        key->defs.defined |= _Key_Behavior;
126634345a63Smrg    }
126734345a63Smrg    else if ((uStrCaseCmp(field, "repeating") == 0) ||
126834345a63Smrg             (uStrCaseCmp(field, "repeats") == 0) ||
126934345a63Smrg             (uStrCaseCmp(field, "repeat") == 0))
127034345a63Smrg    {
127134345a63Smrg        ok = ExprResolveEnum(value, &tmp, repeatEntries);
127234345a63Smrg        if (!ok)
127334345a63Smrg        {
1274bfe6082cSmrg            ERROR("Illegal repeat setting for %s\n",
127534345a63Smrg                   longText(key->name, XkbMessage));
127634345a63Smrg            ACTION("Non-boolean repeat setting ignored\n");
127734345a63Smrg            return False;
127834345a63Smrg        }
127934345a63Smrg        key->repeat = tmp.uval;
128034345a63Smrg        key->defs.defined |= _Key_Repeat;
128134345a63Smrg    }
128234345a63Smrg    else if ((uStrCaseCmp(field, "groupswrap") == 0) ||
128334345a63Smrg             (uStrCaseCmp(field, "wrapgroups") == 0))
128434345a63Smrg    {
128534345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
128634345a63Smrg        if (!ok)
128734345a63Smrg        {
1288bfe6082cSmrg            ERROR("Illegal groupsWrap setting for %s\n",
128934345a63Smrg                   longText(key->name, XkbMessage));
129034345a63Smrg            ACTION("Non-boolean value ignored\n");
129134345a63Smrg            return False;
129234345a63Smrg        }
129334345a63Smrg        if (tmp.uval)
129434345a63Smrg            key->groupInfo = XkbWrapIntoRange;
129534345a63Smrg        else
129634345a63Smrg            key->groupInfo = XkbClampIntoRange;
129734345a63Smrg        key->defs.defined |= _Key_GroupInfo;
129834345a63Smrg    }
129934345a63Smrg    else if ((uStrCaseCmp(field, "groupsclamp") == 0) ||
130034345a63Smrg             (uStrCaseCmp(field, "clampgroups") == 0))
130134345a63Smrg    {
130234345a63Smrg        ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
130334345a63Smrg        if (!ok)
130434345a63Smrg        {
1305bfe6082cSmrg            ERROR("Illegal groupsClamp setting for %s\n",
130634345a63Smrg                   longText(key->name, XkbMessage));
130734345a63Smrg            ACTION("Non-boolean value ignored\n");
130834345a63Smrg            return False;
130934345a63Smrg        }
131034345a63Smrg        if (tmp.uval)
131134345a63Smrg            key->groupInfo = XkbClampIntoRange;
131234345a63Smrg        else
131334345a63Smrg            key->groupInfo = XkbWrapIntoRange;
131434345a63Smrg        key->defs.defined |= _Key_GroupInfo;
131534345a63Smrg    }
131634345a63Smrg    else if ((uStrCaseCmp(field, "groupsredirect") == 0) ||
131734345a63Smrg             (uStrCaseCmp(field, "redirectgroups") == 0))
131834345a63Smrg    {
131934345a63Smrg        if (!ExprResolveInteger
132034345a63Smrg            (value, &tmp, SimpleLookup, (XPointer) groupNames))
132134345a63Smrg        {
1322bfe6082cSmrg            ERROR("Illegal group index for redirect of key %s\n",
132334345a63Smrg                   longText(key->name, XkbMessage));
132434345a63Smrg            ACTION("Definition with non-integer group ignored\n");
132534345a63Smrg            return False;
132634345a63Smrg        }
132734345a63Smrg        if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
132834345a63Smrg        {
1329bfe6082cSmrg            ERROR("Out-of-range (1..%d) group for redirect of key %s\n",
133034345a63Smrg                   XkbNumKbdGroups, longText(key->name, XkbMessage));
1331bfe6082cSmrg            ERROR("Ignoring illegal group %d\n", tmp.uval);
133234345a63Smrg            return False;
133334345a63Smrg        }
133434345a63Smrg        key->groupInfo =
133534345a63Smrg            XkbSetGroupInfo(0, XkbRedirectIntoRange, tmp.uval - 1);
133634345a63Smrg        key->defs.defined |= _Key_GroupInfo;
133734345a63Smrg    }
133834345a63Smrg    else
133934345a63Smrg    {
1340bfe6082cSmrg        ERROR("Unknown field %s in a symbol interpretation\n", field);
134134345a63Smrg        ACTION("Definition ignored\n");
134234345a63Smrg        ok = False;
1343f46a6179Smrg    }
1344f46a6179Smrg    return ok;
1345f46a6179Smrg}
1346f46a6179Smrg
1347f46a6179Smrgstatic int
13486930ead5SmrgSetGroupName(SymbolsInfo *info, const ExprDef *arrayNdx,const  ExprDef *value)
1349f46a6179Smrg{
135034345a63Smrg    ExprResult tmp, name;
135134345a63Smrg
135234345a63Smrg    if ((arrayNdx == NULL) && (warningLevel > 0))
135334345a63Smrg    {
135434345a63Smrg        WARN("You must specify an index when specifying a group name\n");
135534345a63Smrg        ACTION("Group name definition without array subscript ignored\n");
135634345a63Smrg        return False;
135734345a63Smrg    }
135834345a63Smrg    if (!ExprResolveInteger
135934345a63Smrg        (arrayNdx, &tmp, SimpleLookup, (XPointer) groupNames))
136034345a63Smrg    {
136134345a63Smrg        ERROR("Illegal index in group name definition\n");
136234345a63Smrg        ACTION("Definition with non-integer array index ignored\n");
136334345a63Smrg        return False;
136434345a63Smrg    }
136534345a63Smrg    if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
136634345a63Smrg    {
1367bfe6082cSmrg        ERROR
136834345a63Smrg            ("Attempt to specify name for illegal group (must be 1..%d)\n",
136934345a63Smrg             XkbNumKbdGroups + 1);
1370bfe6082cSmrg        ACTION("Name for group %d ignored\n", tmp.uval);
137134345a63Smrg        return False;
137234345a63Smrg    }
137334345a63Smrg    if (!ExprResolveString(value, &name, NULL, NULL))
137434345a63Smrg    {
137534345a63Smrg        ERROR("Group name must be a string\n");
1376bfe6082cSmrg        ACTION("Illegal name for group %d ignored\n", tmp.uval);
137734345a63Smrg        return False;
137834345a63Smrg    }
137934345a63Smrg    info->groupNames[tmp.uval - 1 + info->explicit_group] =
138034345a63Smrg        XkbInternAtom(NULL, name.str, False);
138134345a63Smrg
1382f46a6179Smrg    return True;
1383f46a6179Smrg}
1384f46a6179Smrg
1385f46a6179Smrgstatic int
138634345a63SmrgHandleSymbolsVar(VarDef * stmt, XkbDescPtr xkb, SymbolsInfo * info)
1387f46a6179Smrg{
138834345a63Smrg    ExprResult elem, field, tmp;
138934345a63Smrg    ExprDef *arrayNdx;
139034345a63Smrg
139134345a63Smrg    if (ExprResolveLhs(stmt->name, &elem, &field, &arrayNdx) == 0)
139234345a63Smrg        return 0;               /* internal error, already reported */
139334345a63Smrg    if (elem.str && (uStrCaseCmp(elem.str, "key") == 0))
139434345a63Smrg    {
139534345a63Smrg        return SetSymbolsField(&info->dflt, xkb, field.str, arrayNdx,
139634345a63Smrg                               stmt->value, info);
139734345a63Smrg    }
139834345a63Smrg    else if ((elem.str == NULL) && ((uStrCaseCmp(field.str, "name") == 0) ||
139934345a63Smrg                                    (uStrCaseCmp(field.str, "groupname") ==
140034345a63Smrg                                     0)))
140134345a63Smrg    {
140234345a63Smrg        return SetGroupName(info, arrayNdx, stmt->value);
140334345a63Smrg    }
140434345a63Smrg    else if ((elem.str == NULL)
140534345a63Smrg             && ((uStrCaseCmp(field.str, "groupswrap") == 0)
140634345a63Smrg                 || (uStrCaseCmp(field.str, "wrapgroups") == 0)))
140734345a63Smrg    {
140834345a63Smrg        if (!ExprResolveBoolean(stmt->value, &tmp, NULL, NULL))
140934345a63Smrg        {
141034345a63Smrg            ERROR("Illegal setting for global groupsWrap\n");
141134345a63Smrg            ACTION("Non-boolean value ignored\n");
141234345a63Smrg            return False;
141334345a63Smrg        }
141434345a63Smrg        if (tmp.uval)
141534345a63Smrg            info->groupInfo = XkbWrapIntoRange;
141634345a63Smrg        else
141734345a63Smrg            info->groupInfo = XkbClampIntoRange;
141834345a63Smrg        return True;
141934345a63Smrg    }
142034345a63Smrg    else if ((elem.str == NULL)
142134345a63Smrg             && ((uStrCaseCmp(field.str, "groupsclamp") == 0)
142234345a63Smrg                 || (uStrCaseCmp(field.str, "clampgroups") == 0)))
142334345a63Smrg    {
142434345a63Smrg        if (!ExprResolveBoolean(stmt->value, &tmp, NULL, NULL))
142534345a63Smrg        {
142634345a63Smrg            ERROR("Illegal setting for global groupsClamp\n");
142734345a63Smrg            ACTION("Non-boolean value ignored\n");
142834345a63Smrg            return False;
142934345a63Smrg        }
143034345a63Smrg        if (tmp.uval)
143134345a63Smrg            info->groupInfo = XkbClampIntoRange;
143234345a63Smrg        else
143334345a63Smrg            info->groupInfo = XkbWrapIntoRange;
143434345a63Smrg        return True;
143534345a63Smrg    }
143634345a63Smrg    else if ((elem.str == NULL)
143734345a63Smrg             && ((uStrCaseCmp(field.str, "groupsredirect") == 0)
143834345a63Smrg                 || (uStrCaseCmp(field.str, "redirectgroups") == 0)))
143934345a63Smrg    {
144034345a63Smrg        if (!ExprResolveInteger(stmt->value, &tmp,
144134345a63Smrg                                SimpleLookup, (XPointer) groupNames))
144234345a63Smrg        {
144334345a63Smrg            ERROR("Illegal group index for global groupsRedirect\n");
144434345a63Smrg            ACTION("Definition with non-integer group ignored\n");
144534345a63Smrg            return False;
144634345a63Smrg        }
144734345a63Smrg        if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
144834345a63Smrg        {
1449bfe6082cSmrg            ERROR
145034345a63Smrg                ("Out-of-range (1..%d) group for global groupsRedirect\n",
145134345a63Smrg                 XkbNumKbdGroups);
1452bfe6082cSmrg            ACTION("Ignoring illegal group %d\n", tmp.uval);
145334345a63Smrg            return False;
145434345a63Smrg        }
145534345a63Smrg        info->groupInfo = XkbSetGroupInfo(0, XkbRedirectIntoRange, tmp.uval);
145634345a63Smrg        return True;
145734345a63Smrg    }
145834345a63Smrg    else if ((elem.str == NULL) && (uStrCaseCmp(field.str, "allownone") == 0))
145934345a63Smrg    {
146034345a63Smrg        return SetAllowNone(&info->dflt, arrayNdx, stmt->value);
146134345a63Smrg    }
146234345a63Smrg    return SetActionField(xkb, elem.str, field.str, arrayNdx, stmt->value,
146334345a63Smrg                          &info->action);
1464f46a6179Smrg}
1465f46a6179Smrg
1466f46a6179Smrgstatic Bool
146734345a63SmrgHandleSymbolsBody(VarDef * def,
146834345a63Smrg                  XkbDescPtr xkb, KeyInfo * key, SymbolsInfo * info)
1469f46a6179Smrg{
147034345a63Smrg    Bool ok = True;
147134345a63Smrg
147234345a63Smrg    for (; def != NULL; def = (VarDef *) def->common.next)
147334345a63Smrg    {
147434345a63Smrg        if ((def->name) && (def->name->type == ExprFieldRef))
147534345a63Smrg        {
147634345a63Smrg            ok = HandleSymbolsVar(def, xkb, info);
147734345a63Smrg            continue;
147834345a63Smrg        }
147934345a63Smrg        else
148034345a63Smrg        {
14816930ead5Smrg            ExprResult tmp, field;
14826930ead5Smrg            ExprDef *arrayNdx;
14836930ead5Smrg
148434345a63Smrg            if (def->name == NULL)
148534345a63Smrg            {
148634345a63Smrg                if ((def->value == NULL)
148734345a63Smrg                    || (def->value->op == ExprKeysymList))
148834345a63Smrg                    field.str = "symbols";
148934345a63Smrg                else
149034345a63Smrg                    field.str = "actions";
149134345a63Smrg                arrayNdx = NULL;
149234345a63Smrg            }
149334345a63Smrg            else
149434345a63Smrg            {
149534345a63Smrg                ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
149634345a63Smrg            }
149734345a63Smrg            if (ok)
149834345a63Smrg                ok = SetSymbolsField(key, xkb, field.str, arrayNdx,
149934345a63Smrg                                     def->value, info);
150034345a63Smrg        }
1501f46a6179Smrg    }
1502f46a6179Smrg    return ok;
1503f46a6179Smrg}
1504f46a6179Smrg
1505f46a6179Smrgstatic Bool
150634345a63SmrgSetExplicitGroup(SymbolsInfo * info, KeyInfo * key)
1507f46a6179Smrg{
1508f46a6179Smrg    unsigned group = info->explicit_group;
1509f46a6179Smrg
1510f46a6179Smrg    if (group == 0)
151134345a63Smrg        return True;
151234345a63Smrg
151334345a63Smrg    if ((key->typesDefined | key->symsDefined | key->actsDefined) & ~1)
151434345a63Smrg    {
1515a57d84feSmrg        if (warningLevel > 0)
1516a57d84feSmrg        {
1517a57d84feSmrg            WARN("For map %s an explicit group is specified\n", info->name);
1518a57d84feSmrg            WARN("but key %s has more than one group defined\n",
1519a57d84feSmrg                  longText(key->name, XkbMessage));
1520a57d84feSmrg            ACTION("All groups except first one will be ignored\n");
1521a57d84feSmrg        }
15226930ead5Smrg        for (int i = 1; i < XkbNumKbdGroups; i++)
152334345a63Smrg        {
152434345a63Smrg            key->numLevels[i] = 0;
15256930ead5Smrg            free(key->syms[i]);
152634345a63Smrg            key->syms[i] = (KeySym *) NULL;
15276930ead5Smrg            free(key->acts[i]);
152834345a63Smrg            key->acts[i] = (XkbAction *) NULL;
152934345a63Smrg            key->types[i] = (Atom) 0;
153034345a63Smrg        }
153134345a63Smrg    }
15326930ead5Smrg    key->typesDefined = key->symsDefined = key->actsDefined = 1U << group;
153334345a63Smrg
153434345a63Smrg    key->numLevels[group] = key->numLevels[0];
153534345a63Smrg    key->numLevels[0] = 0;
153634345a63Smrg    key->syms[group] = key->syms[0];
153734345a63Smrg    key->syms[0] = (KeySym *) NULL;
153834345a63Smrg    key->acts[group] = key->acts[0];
153934345a63Smrg    key->acts[0] = (XkbAction *) NULL;
154034345a63Smrg    key->types[group] = key->types[0];
154134345a63Smrg    key->types[0] = (Atom) 0;
154234345a63Smrg    return True;
1543f46a6179Smrg}
1544f46a6179Smrg
1545f46a6179Smrgstatic int
154634345a63SmrgHandleSymbolsDef(SymbolsDef * stmt,
154734345a63Smrg                 XkbDescPtr xkb, unsigned merge, SymbolsInfo * info)
1548f46a6179Smrg{
154934345a63Smrg    KeyInfo key;
155034345a63Smrg
1551f46a6179Smrg    InitKeyInfo(&key);
155234345a63Smrg    CopyKeyInfo(&info->dflt, &key, False);
155334345a63Smrg    key.defs.merge = stmt->merge;
155434345a63Smrg    key.name = KeyNameToLong(stmt->keyName);
155534345a63Smrg    if (!HandleSymbolsBody((VarDef *) stmt->symbols, xkb, &key, info))
155634345a63Smrg    {
155734345a63Smrg        info->errorCount++;
155834345a63Smrg        return False;
1559f46a6179Smrg    }
1560f46a6179Smrg
156134345a63Smrg    if (!SetExplicitGroup(info, &key))
156234345a63Smrg    {
1563f46a6179Smrg        info->errorCount++;
1564f46a6179Smrg        return False;
1565f46a6179Smrg    }
1566f46a6179Smrg
156734345a63Smrg    if (!AddKeySymbols(info, &key, xkb))
156834345a63Smrg    {
156934345a63Smrg        info->errorCount++;
157034345a63Smrg        return False;
1571f46a6179Smrg    }
1572f46a6179Smrg    return True;
1573f46a6179Smrg}
1574f46a6179Smrg
1575f46a6179Smrgstatic Bool
157634345a63SmrgHandleModMapDef(ModMapDef * def,
157734345a63Smrg                XkbDescPtr xkb, unsigned merge, SymbolsInfo * info)
1578f46a6179Smrg{
157934345a63Smrg    ModMapEntry tmp;
158034345a63Smrg    ExprResult rtrn;
158134345a63Smrg    Bool ok;
158234345a63Smrg
158334345a63Smrg    if (!LookupModIndex(NULL, None, def->modifier, TypeInt, &rtrn))
158434345a63Smrg    {
158534345a63Smrg        ERROR("Illegal modifier map definition\n");
1586bfe6082cSmrg        ACTION("Ignoring map for non-modifier \"%s\"\n",
158734345a63Smrg                XkbAtomText(NULL, def->modifier, XkbMessage));
158834345a63Smrg        return False;
158934345a63Smrg    }
159034345a63Smrg    ok = True;
159134345a63Smrg    tmp.modifier = rtrn.uval;
15926930ead5Smrg    for (ExprDef *key = def->keys; key != NULL;
15936930ead5Smrg         key = (ExprDef *) key->common.next)
159434345a63Smrg    {
159534345a63Smrg        if ((key->op == ExprValue) && (key->type == TypeKeyName))
159634345a63Smrg        {
159734345a63Smrg            tmp.haveSymbol = False;
159834345a63Smrg            tmp.u.keyName = KeyNameToLong(key->value.keyName);
159934345a63Smrg        }
160034345a63Smrg        else if (ExprResolveKeySym(key, &rtrn, NULL, NULL))
160134345a63Smrg        {
160234345a63Smrg            tmp.haveSymbol = True;
160334345a63Smrg            tmp.u.keySym = rtrn.uval;
160434345a63Smrg        }
160534345a63Smrg        else
160634345a63Smrg        {
160734345a63Smrg            ERROR("Modmap entries may contain only key names or keysyms\n");
1608bfe6082cSmrg            ACTION("Illegal definition for %s modifier ignored\n",
160934345a63Smrg                    XkbModIndexText(tmp.modifier, XkbMessage));
161034345a63Smrg            continue;
161134345a63Smrg        }
161234345a63Smrg
161334345a63Smrg        ok = AddModMapEntry(info, &tmp) && ok;
1614f46a6179Smrg    }
1615f46a6179Smrg    return ok;
1616f46a6179Smrg}
1617f46a6179Smrg
1618f46a6179Smrgstatic void
161934345a63SmrgHandleSymbolsFile(XkbFile * file,
162034345a63Smrg                  XkbDescPtr xkb, unsigned merge, SymbolsInfo * info)
1621f46a6179Smrg{
162234345a63Smrg    ParseCommon *stmt;
162334345a63Smrg
162434345a63Smrg    info->name = uStringDup(file->name);
162534345a63Smrg    stmt = file->defs;
162634345a63Smrg    while (stmt)
162734345a63Smrg    {
162834345a63Smrg        switch (stmt->stmtType)
162934345a63Smrg        {
163034345a63Smrg        case StmtInclude:
163134345a63Smrg            if (!HandleIncludeSymbols((IncludeStmt *) stmt, xkb, info,
163234345a63Smrg                                      HandleSymbolsFile))
163334345a63Smrg                info->errorCount++;
163434345a63Smrg            break;
163534345a63Smrg        case StmtSymbolsDef:
163634345a63Smrg            if (!HandleSymbolsDef((SymbolsDef *) stmt, xkb, merge, info))
163734345a63Smrg                info->errorCount++;
163834345a63Smrg            break;
163934345a63Smrg        case StmtVarDef:
164034345a63Smrg            if (!HandleSymbolsVar((VarDef *) stmt, xkb, info))
164134345a63Smrg                info->errorCount++;
164234345a63Smrg            break;
164334345a63Smrg        case StmtVModDef:
164434345a63Smrg            if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
164534345a63Smrg                info->errorCount++;
164634345a63Smrg            break;
164734345a63Smrg        case StmtInterpDef:
164834345a63Smrg            ERROR("Interpretation files may not include other types\n");
164934345a63Smrg            ACTION("Ignoring definition of symbol interpretation\n");
165034345a63Smrg            info->errorCount++;
165134345a63Smrg            break;
165234345a63Smrg        case StmtKeycodeDef:
165334345a63Smrg            ERROR("Interpretation files may not include other types\n");
165434345a63Smrg            ACTION("Ignoring definition of key name\n");
165534345a63Smrg            info->errorCount++;
165634345a63Smrg            break;
165734345a63Smrg        case StmtModMapDef:
165834345a63Smrg            if (!HandleModMapDef((ModMapDef *) stmt, xkb, merge, info))
165934345a63Smrg                info->errorCount++;
166034345a63Smrg            break;
166134345a63Smrg        default:
1662bfe6082cSmrg            WSGO("Unexpected statement type %d in HandleSymbolsFile\n",
166334345a63Smrg                  stmt->stmtType);
166434345a63Smrg            break;
166534345a63Smrg        }
166634345a63Smrg        stmt = stmt->next;
166734345a63Smrg        if (info->errorCount > 10)
166834345a63Smrg        {
1669f46a6179Smrg#ifdef NOISY
167034345a63Smrg            ERROR("Too many errors\n");
1671f46a6179Smrg#endif
1672bfe6082cSmrg            ACTION("Abandoning symbols file \"%s\"\n", file->topName);
167334345a63Smrg            break;
167434345a63Smrg        }
1675f46a6179Smrg    }
1676f46a6179Smrg    return;
1677f46a6179Smrg}
1678f46a6179Smrg
1679f46a6179Smrgstatic Bool
168034345a63SmrgFindKeyForSymbol(XkbDescPtr xkb, KeySym sym, unsigned int *kc_rtrn)
1681f46a6179Smrg{
16826930ead5Smrg    int j;
16836930ead5Smrg    Bool gotOne;
168434345a63Smrg
168534345a63Smrg    j = 0;
168634345a63Smrg    do
168734345a63Smrg    {
168834345a63Smrg        gotOne = False;
16896930ead5Smrg        for (int i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++)
169034345a63Smrg        {
169134345a63Smrg            if (j < (int) XkbKeyNumSyms(xkb, i))
169234345a63Smrg            {
1693f46a6179Smrg                gotOne = True;
16941d8c7986Smrg                if (XkbKeySym(xkb, i, j) == sym)
169534345a63Smrg                {
169634345a63Smrg                    *kc_rtrn = i;
1697f46a6179Smrg                    return True;
169834345a63Smrg                }
1699f46a6179Smrg            }
1700f46a6179Smrg        }
1701f46a6179Smrg        j++;
170234345a63Smrg    }
170334345a63Smrg    while (gotOne);
1704f46a6179Smrg    return False;
1705f46a6179Smrg}
1706f46a6179Smrg
170734345a63Smrg/**
170834345a63Smrg * Find the given name in the xkb->map->types and return its index.
170934345a63Smrg *
171034345a63Smrg * @param name The atom to search for.
171134345a63Smrg * @param type_rtrn Set to the index of the name if found.
171234345a63Smrg *
171334345a63Smrg * @return True if found, False otherwise.
171434345a63Smrg */
1715f46a6179Smrgstatic Bool
17166930ead5SmrgFindNamedType(const XkbDescPtr xkb, Atom name, unsigned *type_rtrn)
1717f46a6179Smrg{
171834345a63Smrg    if (xkb && xkb->map && xkb->map->types)
171934345a63Smrg    {
17206930ead5Smrg        for (unsigned n = 0; n < xkb->map->num_types; n++)
172134345a63Smrg        {
172234345a63Smrg            if (xkb->map->types[n].name == (Atom) name)
172334345a63Smrg            {
172434345a63Smrg                *type_rtrn = n;
172534345a63Smrg                return True;
172634345a63Smrg            }
172734345a63Smrg        }
1728f46a6179Smrg    }
1729f46a6179Smrg    return False;
1730f46a6179Smrg}
1731f46a6179Smrg
1732f46a6179Smrgstatic Bool
173334345a63SmrgKSIsLower(KeySym ks)
1734f46a6179Smrg{
1735f46a6179Smrg    KeySym lower, upper;
1736f46a6179Smrg    XConvertCase(ks, &lower, &upper);
1737f46a6179Smrg
1738f46a6179Smrg    if (lower == upper)
1739f46a6179Smrg        return False;
1740f46a6179Smrg    return (ks == lower ? True : False);
1741f46a6179Smrg}
1742f46a6179Smrg
1743f46a6179Smrgstatic Bool
174434345a63SmrgKSIsUpper(KeySym ks)
1745f46a6179Smrg{
1746f46a6179Smrg    KeySym lower, upper;
1747f46a6179Smrg    XConvertCase(ks, &lower, &upper);
1748f46a6179Smrg
1749f46a6179Smrg    if (lower == upper)
1750f46a6179Smrg        return False;
1751f46a6179Smrg    return (ks == upper ? True : False);
1752f46a6179Smrg}
1753f46a6179Smrg
175434345a63Smrg/**
175534345a63Smrg * Assign a type to the given sym and return the Atom for the type assigned.
175634345a63Smrg *
175734345a63Smrg * Simple recipe:
175834345a63Smrg * - ONE_LEVEL for width 0/1
1759a57d84feSmrg * - ALPHABETIC for 2 shift levels, with lower/uppercase
176034345a63Smrg * - KEYPAD for keypad keys.
176134345a63Smrg * - TWO_LEVEL for other 2 shift level keys.
176234345a63Smrg * and the same for four level keys.
176334345a63Smrg *
17646930ead5Smrg * @param width Number of syms in syms.
176534345a63Smrg * @param syms The keysyms for the given key (must be size width).
176634345a63Smrg * @param typeNameRtrn Set to the Atom of the type name.
176734345a63Smrg *
176834345a63Smrg * @returns True if a type could be found, False otherwise.
176934345a63Smrg */
1770f46a6179Smrgstatic Bool
17716930ead5SmrgFindAutomaticType(int width, const KeySym *syms,
17726930ead5Smrg                  Atom *typeNameRtrn, Bool *autoType)
1773f46a6179Smrg{
1774f46a6179Smrg    *autoType = False;
177534345a63Smrg    if ((width == 1) || (width == 0))
177634345a63Smrg    {
177734345a63Smrg        *typeNameRtrn = XkbInternAtom(NULL, "ONE_LEVEL", False);
177834345a63Smrg        *autoType = True;
177934345a63Smrg    }
178034345a63Smrg    else if (width == 2)
178134345a63Smrg    {
178234345a63Smrg        if (syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]))
178334345a63Smrg        {
178434345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "ALPHABETIC", False);
178534345a63Smrg        }
178634345a63Smrg        else if (syms && (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])))
178734345a63Smrg        {
178834345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "KEYPAD", False);
178934345a63Smrg            *autoType = True;
179034345a63Smrg        }
179134345a63Smrg        else
179234345a63Smrg        {
179334345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "TWO_LEVEL", False);
179434345a63Smrg            *autoType = True;
179534345a63Smrg        }
179634345a63Smrg    }
179734345a63Smrg    else if (width <= 4)
179834345a63Smrg    {
179934345a63Smrg        if (syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]))
180034345a63Smrg            if (KSIsLower(syms[2]) && KSIsUpper(syms[3]))
180134345a63Smrg                *typeNameRtrn =
180234345a63Smrg                    XkbInternAtom(NULL, "FOUR_LEVEL_ALPHABETIC", False);
180334345a63Smrg            else
180434345a63Smrg                *typeNameRtrn = XkbInternAtom(NULL,
180534345a63Smrg                                              "FOUR_LEVEL_SEMIALPHABETIC",
180634345a63Smrg                                              False);
180734345a63Smrg
180834345a63Smrg        else if (syms && (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])))
180934345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "FOUR_LEVEL_KEYPAD", False);
181034345a63Smrg        else
181134345a63Smrg            *typeNameRtrn = XkbInternAtom(NULL, "FOUR_LEVEL", False);
181234345a63Smrg        /* XXX: why not set autoType here? */
181334345a63Smrg    }
181434345a63Smrg    return ((width >= 0) && (width <= 4));
1815f46a6179Smrg}
1816f46a6179Smrg
181734345a63Smrg/**
181834345a63Smrg * Ensure the given KeyInfo is in a coherent state, i.e. no gaps between the
181934345a63Smrg * groups, and reduce to one group if all groups are identical anyway.
182034345a63Smrg */
1821f46a6179Smrgstatic void
182234345a63SmrgPrepareKeyDef(KeyInfo * key)
1823f46a6179Smrg{
18246930ead5Smrg    int i, defined, lastGroup;
1825f46a6179Smrg    Bool identical;
182634345a63Smrg
1827f46a6179Smrg    defined = key->symsDefined | key->actsDefined | key->typesDefined;
182834345a63Smrg    /* get highest group number */
182934345a63Smrg    for (i = XkbNumKbdGroups - 1; i >= 0; i--)
183034345a63Smrg    {
18316930ead5Smrg        if (defined & (1U << i))
183234345a63Smrg            break;
1833f46a6179Smrg    }
1834f46a6179Smrg    lastGroup = i;
1835f46a6179Smrg
1836f46a6179Smrg    if (lastGroup == 0)
183734345a63Smrg        return;
1838f46a6179Smrg
1839f46a6179Smrg    /* If there are empty groups between non-empty ones fill them with data */
1840f46a6179Smrg    /* from the first group. */
1841f46a6179Smrg    /* We can make a wrong assumption here. But leaving gaps is worse. */
184234345a63Smrg    for (i = lastGroup; i > 0; i--)
184334345a63Smrg    {
18446930ead5Smrg        int width;
18456930ead5Smrg
18466930ead5Smrg        if (defined & (1U << i))
1847f46a6179Smrg            continue;
1848f46a6179Smrg        width = key->numLevels[0];
184934345a63Smrg        if (key->typesDefined & 1)
185034345a63Smrg        {
18516930ead5Smrg            for (int j = 0; j < width; j++)
185234345a63Smrg            {
1853f46a6179Smrg                key->types[i] = key->types[0];
1854f46a6179Smrg            }
18556930ead5Smrg            key->typesDefined |= 1U << i;
1856f46a6179Smrg        }
185734345a63Smrg        if ((key->actsDefined & 1) && key->acts[0])
185834345a63Smrg        {
18596930ead5Smrg            key->acts[i] = calloc(width, sizeof(XkbAction));
1860f46a6179Smrg            if (key->acts[i] == NULL)
1861f46a6179Smrg                continue;
18626930ead5Smrg            memcpy(key->acts[i], key->acts[0], width * sizeof(XkbAction));
18636930ead5Smrg            key->actsDefined |= 1U << i;
1864f46a6179Smrg        }
186534345a63Smrg        if ((key->symsDefined & 1) && key->syms[0])
186634345a63Smrg        {
18676930ead5Smrg            key->syms[i] = calloc(width, sizeof(KeySym));
1868f46a6179Smrg            if (key->syms[i] == NULL)
1869f46a6179Smrg                continue;
18706930ead5Smrg            memcpy(key->syms[i], key->syms[0], width * sizeof(KeySym));
18716930ead5Smrg            key->symsDefined |= 1U << i;
1872f46a6179Smrg        }
187334345a63Smrg        if (defined & 1)
187434345a63Smrg        {
1875f46a6179Smrg            key->numLevels[i] = key->numLevels[0];
1876f46a6179Smrg        }
1877f46a6179Smrg    }
1878f46a6179Smrg    /* If all groups are completely identical remove them all */
1879bfe6082cSmrg    /* except the first one. */
1880f46a6179Smrg    identical = True;
188134345a63Smrg    for (i = lastGroup; i > 0; i--)
188234345a63Smrg    {
1883f46a6179Smrg        if ((key->numLevels[i] != key->numLevels[0]) ||
188434345a63Smrg            (key->types[i] != key->types[0]))
188534345a63Smrg        {
1886f46a6179Smrg            identical = False;
1887f46a6179Smrg            break;
1888f46a6179Smrg        }
1889f46a6179Smrg        if ((key->syms[i] != key->syms[0]) &&
189034345a63Smrg            (key->syms[i] == NULL || key->syms[0] == NULL ||
189134345a63Smrg             memcmp((void *) key->syms[i], (void *) key->syms[0],
189234345a63Smrg                    sizeof(KeySym) * key->numLevels[0])))
189334345a63Smrg        {
189434345a63Smrg            identical = False;
189534345a63Smrg            break;
189634345a63Smrg        }
1897f46a6179Smrg        if ((key->acts[i] != key->acts[0]) &&
189834345a63Smrg            (key->acts[i] == NULL || key->acts[0] == NULL ||
189934345a63Smrg             memcmp((void *) key->acts[i], (void *) key->acts[0],
190034345a63Smrg                    sizeof(XkbAction) * key->numLevels[0])))
190134345a63Smrg        {
1902f46a6179Smrg            identical = False;
1903f46a6179Smrg            break;
190434345a63Smrg        }
190534345a63Smrg    }
190634345a63Smrg    if (identical)
190734345a63Smrg    {
190834345a63Smrg        for (i = lastGroup; i > 0; i--)
190934345a63Smrg        {
191034345a63Smrg            key->numLevels[i] = 0;
19116930ead5Smrg            free(key->syms[i]);
191234345a63Smrg            key->syms[i] = (KeySym *) NULL;
19136930ead5Smrg            free(key->acts[i]);
191434345a63Smrg            key->acts[i] = (XkbAction *) NULL;
191534345a63Smrg            key->types[i] = (Atom) 0;
191634345a63Smrg        }
191734345a63Smrg        key->symsDefined &= 1;
191834345a63Smrg        key->actsDefined &= 1;
191934345a63Smrg        key->typesDefined &= 1;
1920f46a6179Smrg    }
1921f46a6179Smrg    return;
1922f46a6179Smrg}
1923f46a6179Smrg
192434345a63Smrg/**
192534345a63Smrg * Copy the KeyInfo into result.
192634345a63Smrg *
192734345a63Smrg * This function recurses.
192834345a63Smrg */
1929f46a6179Smrgstatic Bool
193034345a63SmrgCopySymbolsDef(XkbFileInfo * result, KeyInfo * key, int start_from)
1931f46a6179Smrg{
19326930ead5Smrg    int i;
19336930ead5Smrg    unsigned kc, width, nGroups;
193434345a63Smrg    XkbKeyTypePtr type;
193534345a63Smrg    Bool haveActions, autoType, useAlias;
193634345a63Smrg    KeySym *outSyms;
193734345a63Smrg    XkbAction *outActs;
193834345a63Smrg    XkbDescPtr xkb;
193934345a63Smrg    unsigned types[XkbNumKbdGroups];
194034345a63Smrg
194134345a63Smrg    xkb = result->xkb;
194234345a63Smrg    useAlias = (start_from == 0);
194334345a63Smrg
194434345a63Smrg    /* get the keycode for the key. */
194534345a63Smrg    if (!FindNamedKey(xkb, key->name, &kc, useAlias, CreateKeyNames(xkb),
194634345a63Smrg                      start_from))
194734345a63Smrg    {
194834345a63Smrg        if ((start_from == 0) && (warningLevel >= 5))
194934345a63Smrg        {
1950bfe6082cSmrg            WARN("Key %s not found in %s keycodes\n",
195134345a63Smrg                  longText(key->name, XkbMessage),
195234345a63Smrg                  XkbAtomText(NULL, xkb->names->keycodes, XkbMessage));
195334345a63Smrg            ACTION("Symbols ignored\n");
195434345a63Smrg        }
195534345a63Smrg        return False;
195634345a63Smrg    }
195734345a63Smrg
195834345a63Smrg    haveActions = False;
195934345a63Smrg    for (i = width = nGroups = 0; i < XkbNumKbdGroups; i++)
196034345a63Smrg    {
196134345a63Smrg        if (((i + 1) > nGroups)
19626930ead5Smrg            && (((key->symsDefined | key->actsDefined) & (1U << i))
19636930ead5Smrg                || (key->typesDefined) & (1U << i)))
196434345a63Smrg            nGroups = i + 1;
196534345a63Smrg        if (key->acts[i])
196634345a63Smrg            haveActions = True;
196734345a63Smrg        autoType = False;
196834345a63Smrg        /* Assign the type to the key, if it is missing. */
196934345a63Smrg        if (key->types[i] == None)
197034345a63Smrg        {
197134345a63Smrg            if (key->dfltType != None)
197234345a63Smrg                key->types[i] = key->dfltType;
197334345a63Smrg            else if (FindAutomaticType(key->numLevels[i], key->syms[i],
197434345a63Smrg                                       &key->types[i], &autoType))
197534345a63Smrg            {
197634345a63Smrg            }
197734345a63Smrg            else
197834345a63Smrg            {
197934345a63Smrg                if (warningLevel >= 5)
198034345a63Smrg                {
1981bfe6082cSmrg                    WARN("No automatic type for %d symbols\n",
198234345a63Smrg                          (unsigned int) key->numLevels[i]);
1983bfe6082cSmrg                    ACTION("Using %s for the %s key (keycode %d)\n",
198434345a63Smrg                            XkbAtomText(NULL, key->types[i],
198534345a63Smrg                                        XkbMessage),
198634345a63Smrg                            longText(key->name, XkbMessage), kc);
198734345a63Smrg                }
198834345a63Smrg            }
198934345a63Smrg        }
199034345a63Smrg        if (FindNamedType(xkb, key->types[i], &types[i]))
199134345a63Smrg        {
199234345a63Smrg            if (!autoType || key->numLevels[i] > 2)
19936930ead5Smrg                xkb->server->explicit[kc] |= (1U << i);
199434345a63Smrg        }
199534345a63Smrg        else
199634345a63Smrg        {
199734345a63Smrg            if (warningLevel >= 3)
199834345a63Smrg            {
1999bfe6082cSmrg                WARN("Type \"%s\" is not defined\n",
200034345a63Smrg                      XkbAtomText(NULL, key->types[i], XkbMessage));
2001bfe6082cSmrg                ACTION("Using TWO_LEVEL for the %s key (keycode %d)\n",
200234345a63Smrg                        longText(key->name, XkbMessage), kc);
200334345a63Smrg            }
200434345a63Smrg            types[i] = XkbTwoLevelIndex;
200534345a63Smrg        }
200634345a63Smrg        /* if the type specifies less syms than the key has, shrink the key */
200734345a63Smrg        type = &xkb->map->types[types[i]];
200834345a63Smrg        if (type->num_levels < key->numLevels[i])
200934345a63Smrg        {
20103fb1fa07Smrg            if (warningLevel > 5)
201134345a63Smrg            {
2012bfe6082cSmrg                WARN
201334345a63Smrg                    ("Type \"%s\" has %d levels, but %s has %d symbols\n",
201434345a63Smrg                     XkbAtomText(NULL, type->name, XkbMessage),
201534345a63Smrg                     (unsigned int) type->num_levels,
201634345a63Smrg                     longText(key->name, XkbMessage),
201734345a63Smrg                     (unsigned int) key->numLevels[i]);
201834345a63Smrg                ACTION("Ignoring extra symbols\n");
201934345a63Smrg            }
202034345a63Smrg            key->numLevels[i] = type->num_levels;
202134345a63Smrg        }
202234345a63Smrg        if (key->numLevels[i] > width)
202334345a63Smrg            width = key->numLevels[i];
202434345a63Smrg        if (type->num_levels > width)
202534345a63Smrg            width = type->num_levels;
202634345a63Smrg    }
202734345a63Smrg
202834345a63Smrg    /* width is now the largest width found */
202934345a63Smrg
203034345a63Smrg    i = width * nGroups;
203134345a63Smrg    outSyms = XkbResizeKeySyms(xkb, kc, i);
203234345a63Smrg    if (outSyms == NULL)
203334345a63Smrg    {
2034bfe6082cSmrg        WSGO("Could not enlarge symbols for %s (keycode %d)\n",
203534345a63Smrg              longText(key->name, XkbMessage), kc);
203634345a63Smrg        return False;
203734345a63Smrg    }
203834345a63Smrg    if (haveActions)
203934345a63Smrg    {
204034345a63Smrg        outActs = XkbResizeKeyActions(xkb, kc, i);
204134345a63Smrg        if (outActs == NULL)
204234345a63Smrg        {
2043bfe6082cSmrg            WSGO("Could not enlarge actions for %s (key %d)\n",
204434345a63Smrg                  longText(key->name, XkbMessage), kc);
204534345a63Smrg            return False;
204634345a63Smrg        }
204734345a63Smrg        xkb->server->explicit[kc] |= XkbExplicitInterpretMask;
204834345a63Smrg    }
204934345a63Smrg    else
205034345a63Smrg        outActs = NULL;
205134345a63Smrg    if (key->defs.defined & _Key_GroupInfo)
205234345a63Smrg        i = key->groupInfo;
205334345a63Smrg    else
205434345a63Smrg        i = xkb->map->key_sym_map[kc].group_info;
205534345a63Smrg
205634345a63Smrg    xkb->map->key_sym_map[kc].group_info = XkbSetNumGroups(i, nGroups);
205734345a63Smrg    xkb->map->key_sym_map[kc].width = width;
205834345a63Smrg    for (i = 0; i < nGroups; i++)
205934345a63Smrg    {
206034345a63Smrg        /* assign kt_index[i] to the index of the type in map->types.
206134345a63Smrg         * kt_index[i] may have been set by a previous run (if we have two
206234345a63Smrg         * layouts specified). Let's not overwrite it with the ONE_LEVEL
2063bfe6082cSmrg         * default group if we don't even have keys for this group anyway.
206434345a63Smrg         *
206534345a63Smrg         * FIXME: There should be a better fix for this.
206634345a63Smrg         */
206734345a63Smrg        if (key->numLevels[i])
206834345a63Smrg            xkb->map->key_sym_map[kc].kt_index[i] = types[i];
206934345a63Smrg        if (key->syms[i] != NULL)
207034345a63Smrg        {
207134345a63Smrg            /* fill key to "width" symbols*/
20726930ead5Smrg            for (unsigned tmp = 0; tmp < width; tmp++)
207334345a63Smrg            {
207434345a63Smrg                if (tmp < key->numLevels[i])
207534345a63Smrg                    outSyms[tmp] = key->syms[i][tmp];
207634345a63Smrg                else
207734345a63Smrg                    outSyms[tmp] = NoSymbol;
207834345a63Smrg                if ((outActs != NULL) && (key->acts[i] != NULL))
207934345a63Smrg                {
208034345a63Smrg                    if (tmp < key->numLevels[i])
208134345a63Smrg                        outActs[tmp] = key->acts[i][tmp];
208234345a63Smrg                    else
208334345a63Smrg                        outActs[tmp].type = XkbSA_NoAction;
208434345a63Smrg                }
208534345a63Smrg            }
208634345a63Smrg        }
208734345a63Smrg        outSyms += width;
208834345a63Smrg        if (outActs)
208934345a63Smrg            outActs += width;
209034345a63Smrg    }
209134345a63Smrg    switch (key->behavior.type & XkbKB_OpMask)
209234345a63Smrg    {
209334345a63Smrg    case XkbKB_Default:
209434345a63Smrg        break;
209534345a63Smrg    case XkbKB_Overlay1:
209634345a63Smrg    case XkbKB_Overlay2:
20976930ead5Smrg    {
20986930ead5Smrg        unsigned okc;
209934345a63Smrg        /* find key by name! */
210034345a63Smrg        if (!FindNamedKey(xkb, key->nameForOverlayKey, &okc, True,
210134345a63Smrg                          CreateKeyNames(xkb), 0))
210234345a63Smrg        {
210334345a63Smrg            if (warningLevel >= 1)
210434345a63Smrg            {
2105bfe6082cSmrg                WARN("Key %s not found in %s keycodes\n",
210634345a63Smrg                      longText(key->nameForOverlayKey, XkbMessage),
210734345a63Smrg                      XkbAtomText(NULL, xkb->names->keycodes, XkbMessage));
2108bfe6082cSmrg                ACTION("Not treating %s as an overlay key \n",
210934345a63Smrg                        longText(key->name, XkbMessage));
211034345a63Smrg            }
211134345a63Smrg            break;
211234345a63Smrg        }
211334345a63Smrg        key->behavior.data = okc;
21146930ead5Smrg    }
211534345a63Smrg    default:
211634345a63Smrg        xkb->server->behaviors[kc] = key->behavior;
211734345a63Smrg        xkb->server->explicit[kc] |= XkbExplicitBehaviorMask;
211834345a63Smrg        break;
211934345a63Smrg    }
212034345a63Smrg    if (key->defs.defined & _Key_VModMap)
212134345a63Smrg    {
212234345a63Smrg        xkb->server->vmodmap[kc] = key->vmodmap;
212334345a63Smrg        xkb->server->explicit[kc] |= XkbExplicitVModMapMask;
212434345a63Smrg    }
212534345a63Smrg    if (key->repeat != RepeatUndefined)
212634345a63Smrg    {
212734345a63Smrg        if (key->repeat == RepeatYes)
21286930ead5Smrg            xkb->ctrls->per_key_repeat[kc / 8] |= (1U << (kc % 8));
212934345a63Smrg        else
21306930ead5Smrg            xkb->ctrls->per_key_repeat[kc / 8] &= ~(1U << (kc % 8));
213134345a63Smrg        xkb->server->explicit[kc] |= XkbExplicitAutoRepeatMask;
213234345a63Smrg    }
213334345a63Smrg
213434345a63Smrg    /* do the same thing for the next key */
213534345a63Smrg    CopySymbolsDef(result, key, kc + 1);
2136f46a6179Smrg    return True;
2137f46a6179Smrg}
2138f46a6179Smrg
2139f46a6179Smrgstatic Bool
214034345a63SmrgCopyModMapDef(XkbFileInfo * result, ModMapEntry * entry)
2141f46a6179Smrg{
214234345a63Smrg    unsigned kc;
214334345a63Smrg    XkbDescPtr xkb;
214434345a63Smrg
214534345a63Smrg    xkb = result->xkb;
214634345a63Smrg    if ((!entry->haveSymbol)
214734345a63Smrg        &&
214834345a63Smrg        (!FindNamedKey
214934345a63Smrg         (xkb, entry->u.keyName, &kc, True, CreateKeyNames(xkb), 0)))
215034345a63Smrg    {
215134345a63Smrg        if (warningLevel >= 5)
215234345a63Smrg        {
2153bfe6082cSmrg            WARN("Key %s not found in %s keycodes\n",
215434345a63Smrg                  longText(entry->u.keyName, XkbMessage),
215534345a63Smrg                  XkbAtomText(NULL, xkb->names->keycodes, XkbMessage));
2156bfe6082cSmrg            ACTION("Modifier map entry for %s not updated\n",
215734345a63Smrg                    XkbModIndexText(entry->modifier, XkbMessage));
215834345a63Smrg        }
215934345a63Smrg        return False;
216034345a63Smrg    }
216134345a63Smrg    else if (entry->haveSymbol
216234345a63Smrg             && (!FindKeyForSymbol(xkb, entry->u.keySym, &kc)))
216334345a63Smrg    {
216434345a63Smrg        if (warningLevel > 5)
216534345a63Smrg        {
2166bfe6082cSmrg            WARN("Key \"%s\" not found in %s symbol map\n",
216734345a63Smrg                  XkbKeysymText(entry->u.keySym, XkbMessage),
216834345a63Smrg                  XkbAtomText(NULL, xkb->names->symbols, XkbMessage));
2169bfe6082cSmrg            ACTION("Modifier map entry for %s not updated\n",
217034345a63Smrg                    XkbModIndexText(entry->modifier, XkbMessage));
217134345a63Smrg        }
217234345a63Smrg        return False;
217334345a63Smrg    }
21746930ead5Smrg    xkb->map->modmap[kc] |= (1U << entry->modifier);
2175f46a6179Smrg    return True;
2176f46a6179Smrg}
2177f46a6179Smrg
217834345a63Smrg/**
217934345a63Smrg * Handle the xkb_symbols section of an xkb file.
218034345a63Smrg *
218134345a63Smrg * @param file The parsed xkb_symbols section of the xkb file.
218234345a63Smrg * @param result Handle to the data to store the result in.
218334345a63Smrg * @param merge Merge strategy (e.g. MergeOverride).
218434345a63Smrg */
2185f46a6179SmrgBool
218634345a63SmrgCompileSymbols(XkbFile * file, XkbFileInfo * result, unsigned merge)
2187f46a6179Smrg{
218834345a63Smrg    SymbolsInfo info;
218934345a63Smrg    XkbDescPtr xkb;
2190f46a6179Smrg
219134345a63Smrg    xkb = result->xkb;
219234345a63Smrg    InitSymbolsInfo(&info, xkb);
219334345a63Smrg    info.dflt.defs.fileID = file->id;
219434345a63Smrg    info.dflt.defs.merge = merge;
219534345a63Smrg    HandleSymbolsFile(file, xkb, merge, &info);
2196f46a6179Smrg
2197f46a6179Smrg    if (info.nKeys == 0)
2198f46a6179Smrg        return True;
219934345a63Smrg    if (info.errorCount == 0)
220034345a63Smrg    {
22016930ead5Smrg        int i;
220234345a63Smrg        KeyInfo *key;
220334345a63Smrg
220434345a63Smrg        /* alloc memory in the xkb struct */
220534345a63Smrg        if (XkbAllocNames(xkb, XkbSymbolsNameMask | XkbGroupNamesMask, 0, 0)
220634345a63Smrg            != Success)
220734345a63Smrg        {
220834345a63Smrg            WSGO("Can not allocate names in CompileSymbols\n");
220934345a63Smrg            ACTION("Symbols not added\n");
221034345a63Smrg            return False;
221134345a63Smrg        }
221234345a63Smrg        if (XkbAllocClientMap(xkb, XkbKeySymsMask | XkbModifierMapMask, 0)
221334345a63Smrg            != Success)
221434345a63Smrg        {
221534345a63Smrg            WSGO("Could not allocate client map in CompileSymbols\n");
221634345a63Smrg            ACTION("Symbols not added\n");
221734345a63Smrg            return False;
221834345a63Smrg        }
221934345a63Smrg        if (XkbAllocServerMap(xkb, XkbAllServerInfoMask, 32) != Success)
222034345a63Smrg        {
222134345a63Smrg            WSGO("Could not allocate server map in CompileSymbols\n");
222234345a63Smrg            ACTION("Symbols not added\n");
222334345a63Smrg            return False;
222434345a63Smrg        }
222534345a63Smrg        if (XkbAllocControls(xkb, XkbPerKeyRepeatMask) != Success)
222634345a63Smrg        {
222734345a63Smrg            WSGO("Could not allocate controls in CompileSymbols\n");
222834345a63Smrg            ACTION("Symbols not added\n");
222934345a63Smrg            return False;
223034345a63Smrg        }
223134345a63Smrg
223234345a63Smrg        /* now copy info into xkb. */
223334345a63Smrg        xkb->names->symbols = XkbInternAtom(xkb->dpy, info.name, False);
223434345a63Smrg        if (info.aliases)
223534345a63Smrg            ApplyAliases(xkb, False, &info.aliases);
223634345a63Smrg        for (i = 0; i < XkbNumKbdGroups; i++)
223734345a63Smrg        {
223834345a63Smrg            if (info.groupNames[i] != None)
223934345a63Smrg                xkb->names->groups[i] = info.groupNames[i];
224034345a63Smrg        }
224134345a63Smrg        /* sanitize keys */
224234345a63Smrg        for (key = info.keys, i = 0; i < info.nKeys; i++, key++)
224334345a63Smrg        {
224434345a63Smrg            PrepareKeyDef(key);
224534345a63Smrg        }
224634345a63Smrg        /* copy! */
224734345a63Smrg        for (key = info.keys, i = 0; i < info.nKeys; i++, key++)
224834345a63Smrg        {
224934345a63Smrg            if (!CopySymbolsDef(result, key, 0))
225034345a63Smrg                info.errorCount++;
225134345a63Smrg        }
225234345a63Smrg        if (warningLevel > 3)
225334345a63Smrg        {
225434345a63Smrg            for (i = xkb->min_key_code; i <= xkb->max_key_code; i++)
225534345a63Smrg            {
225634345a63Smrg                if (xkb->names->keys[i].name[0] == '\0')
225734345a63Smrg                    continue;
225834345a63Smrg                if (XkbKeyNumGroups(xkb, i) < 1)
225934345a63Smrg                {
226034345a63Smrg                    char buf[5];
226134345a63Smrg                    memcpy(buf, xkb->names->keys[i].name, 4);
226234345a63Smrg                    buf[4] = '\0';
2263bfe6082cSmrg                    INFO("No symbols defined for <%s> (keycode %d)\n",
226434345a63Smrg                         buf, i);
226534345a63Smrg                }
226634345a63Smrg            }
226734345a63Smrg        }
226834345a63Smrg        if (info.modMap)
226934345a63Smrg        {
227034345a63Smrg            ModMapEntry *mm, *next;
227134345a63Smrg            for (mm = info.modMap; mm != NULL; mm = next)
227234345a63Smrg            {
227334345a63Smrg                if (!CopyModMapDef(result, mm))
227434345a63Smrg                    info.errorCount++;
227534345a63Smrg                next = (ModMapEntry *) mm->defs.next;
227634345a63Smrg            }
227734345a63Smrg        }
227834345a63Smrg        return True;
2279f46a6179Smrg    }
2280f46a6179Smrg    return False;
2281f46a6179Smrg}
2282