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