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