symbols.c revision f46a6179
1f46a6179Smrg/* $Xorg: symbols.c,v 1.3 2000/08/17 19:54:33 cpqbld Exp $ */
2f46a6179Smrg/************************************************************
3f46a6179Smrg Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
4f46a6179Smrg
5f46a6179Smrg Permission to use, copy, modify, and distribute this
6f46a6179Smrg software and its documentation for any purpose and without
7f46a6179Smrg fee is hereby granted, provided that the above copyright
8f46a6179Smrg notice appear in all copies and that both that copyright
9f46a6179Smrg notice and this permission notice appear in supporting
10f46a6179Smrg documentation, and that the name of Silicon Graphics not be
11f46a6179Smrg used in advertising or publicity pertaining to distribution
12f46a6179Smrg of the software without specific prior written permission.
13f46a6179Smrg Silicon Graphics makes no representation about the suitability
14f46a6179Smrg of this software for any purpose. It is provided "as is"
15f46a6179Smrg without any express or implied warranty.
16f46a6179Smrg
17f46a6179Smrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18f46a6179Smrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19f46a6179Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
20f46a6179Smrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
21f46a6179Smrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22f46a6179Smrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
23f46a6179Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
24f46a6179Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
25f46a6179Smrg
26f46a6179Smrg ********************************************************/
27f46a6179Smrg/* $XFree86: xc/programs/xkbcomp/symbols.c,v 3.15 2003/04/19 12:25:31 pascal Exp $ */
28f46a6179Smrg
29f46a6179Smrg#include "xkbcomp.h"
30f46a6179Smrg#include "tokens.h"
31f46a6179Smrg#include "expr.h"
32f46a6179Smrg
33f46a6179Smrg#include <X11/keysym.h>
34f46a6179Smrg#include <X11/Xutil.h>
35f46a6179Smrg#include <stdlib.h>
36f46a6179Smrg
37f46a6179Smrg#include "expr.h"
38f46a6179Smrg#include "vmod.h"
39f46a6179Smrg#include "action.h"
40f46a6179Smrg#include "keycodes.h"
41f46a6179Smrg#include "misc.h"
42f46a6179Smrg#include "alias.h"
43f46a6179Smrg
44f46a6179Smrgextern Atom	tok_ONE_LEVEL;
45f46a6179Smrgextern Atom	tok_TWO_LEVEL;
46f46a6179Smrgextern Atom	tok_KEYPAD;
47f46a6179Smrg
48f46a6179Smrg/***====================================================================***/
49f46a6179Smrg
50f46a6179Smrg#define	RepeatYes	1
51f46a6179Smrg#define	RepeatNo	0
52f46a6179Smrg#define	RepeatUndefined	~((unsigned)0)
53f46a6179Smrg
54f46a6179Smrg#define	_Key_Syms	(1<<0)
55f46a6179Smrg#define	_Key_Acts	(1<<1)
56f46a6179Smrg#define	_Key_Repeat	(1<<2)
57f46a6179Smrg#define	_Key_Behavior	(1<<3)
58f46a6179Smrg#define	_Key_Type_Dflt	(1<<4)
59f46a6179Smrg#define	_Key_Types	(1<<5)
60f46a6179Smrg#define	_Key_GroupInfo	(1<<6)
61f46a6179Smrg#define	_Key_VModMap	(1<<7)
62f46a6179Smrg
63f46a6179Smrgtypedef struct _KeyInfo {
64f46a6179Smrg    CommonInfo 		defs;
65f46a6179Smrg    unsigned long	name;
66f46a6179Smrg    unsigned char	groupInfo;
67f46a6179Smrg    unsigned char	typesDefined;
68f46a6179Smrg    unsigned char	symsDefined;
69f46a6179Smrg    unsigned char	actsDefined;
70f46a6179Smrg    short		numLevels[XkbNumKbdGroups];
71f46a6179Smrg    KeySym *		syms[XkbNumKbdGroups];
72f46a6179Smrg    XkbAction *		acts[XkbNumKbdGroups];
73f46a6179Smrg    Atom		types[XkbNumKbdGroups];
74f46a6179Smrg    unsigned		repeat;
75f46a6179Smrg    XkbBehavior		behavior;
76f46a6179Smrg    unsigned short	vmodmap;
77f46a6179Smrg    unsigned long	nameForOverlayKey;
78f46a6179Smrg    unsigned long	allowNone;
79f46a6179Smrg    Atom		dfltType;
80f46a6179Smrg} KeyInfo;
81f46a6179Smrg
82f46a6179Smrgstatic void
83f46a6179SmrgInitKeyInfo(KeyInfo *info)
84f46a6179Smrg{
85f46a6179Smrgregister int i;
86f46a6179Smrgstatic char dflt[4]= "*";
87f46a6179Smrg
88f46a6179Smrg    info->defs.defined= 0;
89f46a6179Smrg    info->defs.fileID= 0;
90f46a6179Smrg    info->defs.merge= MergeOverride;
91f46a6179Smrg    info->defs.next= NULL;
92f46a6179Smrg    info->name= KeyNameToLong(dflt);
93f46a6179Smrg    info->groupInfo= 0;
94f46a6179Smrg    info->typesDefined= info->symsDefined= info->actsDefined= 0;
95f46a6179Smrg    for (i=0;i<XkbNumKbdGroups;i++) {
96f46a6179Smrg	info->numLevels[i]= 0;
97f46a6179Smrg	info->types[i]= None;
98f46a6179Smrg	info->syms[i]= NULL;
99f46a6179Smrg	info->acts[i]= NULL;
100f46a6179Smrg    }
101f46a6179Smrg    info->dfltType= None;
102f46a6179Smrg    info->behavior.type= XkbKB_Default;
103f46a6179Smrg    info->behavior.data= 0;
104f46a6179Smrg    info->vmodmap= 0;
105f46a6179Smrg    info->nameForOverlayKey= 0;
106f46a6179Smrg    info->repeat= RepeatUndefined;
107f46a6179Smrg    info->allowNone= 0;
108f46a6179Smrg    return;
109f46a6179Smrg}
110f46a6179Smrg
111f46a6179Smrgstatic void
112f46a6179SmrgFreeKeyInfo(KeyInfo *info)
113f46a6179Smrg{
114f46a6179Smrgregister int i;
115f46a6179Smrg
116f46a6179Smrg    info->defs.defined= 0;
117f46a6179Smrg    info->defs.fileID= 0;
118f46a6179Smrg    info->defs.merge= MergeOverride;
119f46a6179Smrg    info->defs.next= NULL;
120f46a6179Smrg    info->groupInfo= 0;
121f46a6179Smrg    info->typesDefined= info->symsDefined= info->actsDefined= 0;
122f46a6179Smrg    for (i=0;i<XkbNumKbdGroups;i++) {
123f46a6179Smrg	info->numLevels[i]= 0;
124f46a6179Smrg	info->types[i]= None;
125f46a6179Smrg	if (info->syms[i]!=NULL)
126f46a6179Smrg	    uFree(info->syms[i]);
127f46a6179Smrg	info->syms[i]= NULL;
128f46a6179Smrg	if (info->acts[i]!=NULL)
129f46a6179Smrg	    uFree(info->acts[i]);
130f46a6179Smrg	info->acts[i]= NULL;
131f46a6179Smrg    }
132f46a6179Smrg    info->dfltType= None;
133f46a6179Smrg    info->behavior.type= XkbKB_Default;
134f46a6179Smrg    info->behavior.data= 0;
135f46a6179Smrg    info->vmodmap= 0;
136f46a6179Smrg    info->nameForOverlayKey= 0;
137f46a6179Smrg    info->repeat= RepeatUndefined;
138f46a6179Smrg    return;
139f46a6179Smrg}
140f46a6179Smrg
141f46a6179Smrgstatic Bool
142f46a6179SmrgCopyKeyInfo(KeyInfo *old,KeyInfo *new,Bool clearOld)
143f46a6179Smrg{
144f46a6179Smrgregister int i;
145f46a6179Smrg
146f46a6179Smrg    *new= *old;
147f46a6179Smrg    new->defs.next= NULL;
148f46a6179Smrg    if (clearOld) {
149f46a6179Smrg	for (i=0;i<XkbNumKbdGroups;i++) {
150f46a6179Smrg	    old->numLevels[i]= 0;
151f46a6179Smrg	    old->syms[i]= NULL;
152f46a6179Smrg	    old->acts[i]= NULL;
153f46a6179Smrg	}
154f46a6179Smrg    }
155f46a6179Smrg    else {
156f46a6179Smrg	int width;
157f46a6179Smrg	for (i=0;i<XkbNumKbdGroups;i++) {
158f46a6179Smrg	    width= new->numLevels[i];
159f46a6179Smrg	    if (old->syms[i]!=NULL) {
160f46a6179Smrg		new->syms[i]= uTypedCalloc(width,KeySym);
161f46a6179Smrg		if (!new->syms[i]) {
162f46a6179Smrg		    new->syms[i]= NULL;
163f46a6179Smrg		    new->numLevels[i]= 0;
164f46a6179Smrg		    return False;
165f46a6179Smrg		}
166f46a6179Smrg		memcpy((char *)new->syms[i],(char *)old->syms[i],
167f46a6179Smrg						width*sizeof(KeySym));
168f46a6179Smrg	    }
169f46a6179Smrg	    if (old->acts[i]!=NULL) {
170f46a6179Smrg		new->acts[i]= uTypedCalloc(width,XkbAction);
171f46a6179Smrg		if (!new->acts[i]) {
172f46a6179Smrg		    new->acts[i]= NULL;
173f46a6179Smrg		    return False;
174f46a6179Smrg		}
175f46a6179Smrg		memcpy((char *)new->acts[i],(char *)old->acts[i],
176f46a6179Smrg						width*sizeof(XkbAction));
177f46a6179Smrg	    }
178f46a6179Smrg	}
179f46a6179Smrg    }
180f46a6179Smrg    return True;
181f46a6179Smrg}
182f46a6179Smrg
183f46a6179Smrg/***====================================================================***/
184f46a6179Smrg
185f46a6179Smrgtypedef struct _ModMapEntry {
186f46a6179Smrg    CommonInfo 			defs;
187f46a6179Smrg    Bool			haveSymbol;
188f46a6179Smrg    int				modifier;
189f46a6179Smrg    union {
190f46a6179Smrg	unsigned long		keyName;
191f46a6179Smrg	KeySym			keySym;
192f46a6179Smrg    } u;
193f46a6179Smrg} ModMapEntry;
194f46a6179Smrg
195f46a6179Smrg#define	SYMBOLS_INIT_SIZE	110
196f46a6179Smrg#define	SYMBOLS_CHUNK		20
197f46a6179Smrgtypedef struct _SymbolsInfo {
198f46a6179Smrg    char *			name;
199f46a6179Smrg    int				errorCount;
200f46a6179Smrg    unsigned			fileID;
201f46a6179Smrg    unsigned			merge;
202f46a6179Smrg    unsigned			explicit_group;
203f46a6179Smrg    unsigned			groupInfo;
204f46a6179Smrg    unsigned			szKeys;
205f46a6179Smrg    unsigned			nKeys;
206f46a6179Smrg    KeyInfo *			keys;
207f46a6179Smrg    KeyInfo			dflt;
208f46a6179Smrg    VModInfo			vmods;
209f46a6179Smrg    ActionInfo *		action;
210f46a6179Smrg    Atom			groupNames[XkbNumKbdGroups];
211f46a6179Smrg
212f46a6179Smrg    ModMapEntry *		modMap;
213f46a6179Smrg    AliasInfo *			aliases;
214f46a6179Smrg} SymbolsInfo;
215f46a6179Smrg
216f46a6179Smrgstatic void
217f46a6179SmrgInitSymbolsInfo(SymbolsInfo *info,XkbDescPtr xkb)
218f46a6179Smrg{
219f46a6179Smrgregister int i;
220f46a6179Smrg
221f46a6179Smrg    tok_ONE_LEVEL= XkbInternAtom(NULL,"ONE_LEVEL",False);
222f46a6179Smrg    tok_TWO_LEVEL= XkbInternAtom(NULL,"TWO_LEVEL",False);
223f46a6179Smrg    tok_KEYPAD= XkbInternAtom(NULL,"KEYPAD",False);
224f46a6179Smrg    info->name= NULL;
225f46a6179Smrg    info->explicit_group= 0;
226f46a6179Smrg    info->errorCount= 0;
227f46a6179Smrg    info->fileID= 0;
228f46a6179Smrg    info->merge= MergeOverride;
229f46a6179Smrg    info->groupInfo= 0;
230f46a6179Smrg    info->szKeys= SYMBOLS_INIT_SIZE;
231f46a6179Smrg    info->nKeys= 0;
232f46a6179Smrg    info->keys= uTypedCalloc(SYMBOLS_INIT_SIZE,KeyInfo);
233f46a6179Smrg    info->modMap= NULL;
234f46a6179Smrg    for (i=0;i<XkbNumKbdGroups;i++)
235f46a6179Smrg	info->groupNames[i]= None;
236f46a6179Smrg    InitKeyInfo(&info->dflt);
237f46a6179Smrg    InitVModInfo(&info->vmods,xkb);
238f46a6179Smrg    info->action= NULL;
239f46a6179Smrg    info->aliases= NULL;
240f46a6179Smrg    return;
241f46a6179Smrg}
242f46a6179Smrg
243f46a6179Smrgstatic void
244f46a6179SmrgFreeSymbolsInfo(SymbolsInfo *info)
245f46a6179Smrg{
246f46a6179Smrgregister int	i;
247f46a6179Smrg
248f46a6179Smrg    if (info->name)
249f46a6179Smrg	uFree(info->name);
250f46a6179Smrg    info->name= NULL;
251f46a6179Smrg    if (info->keys) {
252f46a6179Smrg	for (i=0;i<info->nKeys;i++) {
253f46a6179Smrg	    FreeKeyInfo(&info->keys[i]);
254f46a6179Smrg	}
255f46a6179Smrg	uFree(info->keys);
256f46a6179Smrg	info->keys= NULL;
257f46a6179Smrg    }
258f46a6179Smrg    if (info->modMap) {
259f46a6179Smrg	ClearCommonInfo(&info->modMap->defs);
260f46a6179Smrg	info->modMap= NULL;
261f46a6179Smrg    }
262f46a6179Smrg    if (info->aliases) {
263f46a6179Smrg	ClearAliases(&info->aliases);
264f46a6179Smrg	info->aliases= NULL;
265f46a6179Smrg    }
266f46a6179Smrg    bzero((char *)info,sizeof(SymbolsInfo));
267f46a6179Smrg    return;
268f46a6179Smrg}
269f46a6179Smrg
270f46a6179Smrgstatic Bool
271f46a6179SmrgResizeKeyGroup(	KeyInfo *	key,
272f46a6179Smrg		unsigned	group,
273f46a6179Smrg		unsigned 	atLeastSize,
274f46a6179Smrg		Bool 		forceActions)
275f46a6179Smrg{
276f46a6179SmrgBool		tooSmall;
277f46a6179Smrgunsigned	newWidth;
278f46a6179Smrg
279f46a6179Smrg    tooSmall= (key->numLevels[group]<atLeastSize);
280f46a6179Smrg    if (tooSmall)	newWidth= atLeastSize;
281f46a6179Smrg    else		newWidth= key->numLevels[group];
282f46a6179Smrg
283f46a6179Smrg    if ((key->syms[group]==NULL)||tooSmall) {
284f46a6179Smrg	key->syms[group]= uTypedRecalloc(key->syms[group],
285f46a6179Smrg					key->numLevels[group],newWidth,
286f46a6179Smrg					KeySym);
287f46a6179Smrg	if (!key->syms[group])
288f46a6179Smrg	    return False;
289f46a6179Smrg    }
290f46a6179Smrg    if (((forceActions)&&(tooSmall||(key->acts[group]==NULL)))||
291f46a6179Smrg				(tooSmall&&(key->acts[group]!=NULL))) {
292f46a6179Smrg	key->acts[group]= uTypedRecalloc(key->acts[group],
293f46a6179Smrg					key->numLevels[group],newWidth,
294f46a6179Smrg					XkbAction);
295f46a6179Smrg	if (!key->acts[group])
296f46a6179Smrg	    return False;
297f46a6179Smrg    }
298f46a6179Smrg    key->numLevels[group]= newWidth;
299f46a6179Smrg    return True;
300f46a6179Smrg}
301f46a6179Smrg
302f46a6179Smrgstatic Bool
303f46a6179SmrgMergeKeyGroups(	SymbolsInfo *	info,
304f46a6179Smrg		KeyInfo *	into,
305f46a6179Smrg		KeyInfo *	from,
306f46a6179Smrg		unsigned	group)
307f46a6179Smrg{
308f46a6179SmrgKeySym	*	resultSyms;
309f46a6179SmrgXkbAction *	resultActs;
310f46a6179Smrgint		resultWidth;
311f46a6179Smrgregister int	i;
312f46a6179SmrgBool		report,clobber;
313f46a6179Smrg
314f46a6179Smrg    clobber= (from->defs.merge!=MergeAugment);
315f46a6179Smrg    report= (warningLevel>9)||
316f46a6179Smrg	    ((into->defs.fileID==from->defs.fileID)&&(warningLevel>0));
317f46a6179Smrg    if (into->numLevels[group]>=from->numLevels[group]) {
318f46a6179Smrg	resultSyms= into->syms[group];
319f46a6179Smrg	resultActs= into->acts[group];
320f46a6179Smrg	resultWidth= into->numLevels[group];
321f46a6179Smrg    }
322f46a6179Smrg    else {
323f46a6179Smrg	resultSyms= from->syms[group];
324f46a6179Smrg	resultActs= from->acts[group];
325f46a6179Smrg	resultWidth= from->numLevels[group];
326f46a6179Smrg    }
327f46a6179Smrg    if (resultSyms==NULL) {
328f46a6179Smrg	resultSyms= uTypedCalloc(resultWidth,KeySym);
329f46a6179Smrg	if (!resultSyms) {
330f46a6179Smrg	    WSGO("Could not allocate symbols for group merge\n");
331f46a6179Smrg	    ACTION2("Group %d of key %s not merged\n",group,
332f46a6179Smrg					longText(into->name,XkbMessage));
333f46a6179Smrg	    return False;
334f46a6179Smrg	}
335f46a6179Smrg    }
336f46a6179Smrg    if ((resultActs==NULL)&&(into->acts[group]||from->acts[group])) {
337f46a6179Smrg	resultActs= uTypedCalloc(resultWidth,XkbAction);
338f46a6179Smrg	if (!resultActs) {
339f46a6179Smrg	    WSGO("Could not allocate actions for group merge\n");
340f46a6179Smrg	    ACTION2("Group %d of key %s not merged\n",group,
341f46a6179Smrg					longText(into->name,XkbMessage));
342f46a6179Smrg	    return False;
343f46a6179Smrg	}
344f46a6179Smrg    }
345f46a6179Smrg    for (i=0;i<resultWidth;i++) {
346f46a6179Smrg	KeySym fromSym,toSym;
347f46a6179Smrg	if (from->syms[group] && (i<from->numLevels[group]))
348f46a6179Smrg	     fromSym= from->syms[group][i];
349f46a6179Smrg	else fromSym= NoSymbol;
350f46a6179Smrg	if (into->syms[group] && (i<into->numLevels[group]))
351f46a6179Smrg	     toSym= into->syms[group][i];
352f46a6179Smrg	else toSym= NoSymbol;
353f46a6179Smrg	if ((fromSym==NoSymbol)||(fromSym==toSym))
354f46a6179Smrg	    resultSyms[i]= toSym;
355f46a6179Smrg	else if (toSym==NoSymbol)
356f46a6179Smrg	    resultSyms[i]= fromSym;
357f46a6179Smrg	else {
358f46a6179Smrg	    KeySym use,ignore;
359f46a6179Smrg	    if (clobber) 	{ use= fromSym; ignore= toSym; 		}
360f46a6179Smrg	    else 		{ use= toSym;	ignore= fromSym;	}
361f46a6179Smrg	    if (report) {
362f46a6179Smrg		WARN3("Multiple symbols for level %d/group %d on key %s\n",
363f46a6179Smrg				i+1,group+1,longText(into->name,XkbMessage));
364f46a6179Smrg		ACTION2("Using %s, ignoring %s\n",XkbKeysymText(use,XkbMessage),
365f46a6179Smrg					XkbKeysymText(ignore,XkbMessage));
366f46a6179Smrg	    }
367f46a6179Smrg	    resultSyms[i]= use;
368f46a6179Smrg	}
369f46a6179Smrg	if (resultActs!=NULL) {
370f46a6179Smrg	    XkbAction *fromAct,*toAct;
371f46a6179Smrg	    fromAct= (from->acts[group]?&from->acts[group][i]:NULL);
372f46a6179Smrg	    toAct= (into->acts[group]?&into->acts[group][i]:NULL);
373f46a6179Smrg	    if (((fromAct==NULL)||(fromAct->type==XkbSA_NoAction))&&
374f46a6179Smrg						(toAct!=NULL)) {
375f46a6179Smrg		resultActs[i]= *toAct;
376f46a6179Smrg	    }
377f46a6179Smrg	    else if (((toAct==NULL)||(toAct->type==XkbSA_NoAction))&&
378f46a6179Smrg						(fromAct!=NULL)) {
379f46a6179Smrg		resultActs[i]= *fromAct;
380f46a6179Smrg	    }
381f46a6179Smrg	    else {
382f46a6179Smrg		XkbAction *use,*ignore;
383f46a6179Smrg		if (clobber) 	{ use= fromAct; ignore= toAct; 		}
384f46a6179Smrg		else 		{ use= toAct;	ignore= fromAct;	}
385f46a6179Smrg		if (report) {
386f46a6179Smrg		  WARN3("Multiple actions for level %d/group %d on key %s\n",
387f46a6179Smrg				i+1,group+1,longText(into->name,XkbMessage));
388f46a6179Smrg		  ACTION2("Using %s, ignoring %s\n",
389f46a6179Smrg				XkbActionTypeText(use->type,XkbMessage),
390f46a6179Smrg				XkbActionTypeText(ignore->type,XkbMessage));
391f46a6179Smrg		}
392f46a6179Smrg		resultActs[i]= *use;
393f46a6179Smrg	    }
394f46a6179Smrg	}
395f46a6179Smrg    }
396f46a6179Smrg    if ((into->syms[group]!=NULL)&&(resultSyms!=into->syms[group]))
397f46a6179Smrg	uFree(into->syms[group]);
398f46a6179Smrg    if ((from->syms[group]!=NULL)&&(resultSyms!=from->syms[group]))
399f46a6179Smrg	uFree(from->syms[group]);
400f46a6179Smrg    if ((into->acts[group]!=NULL)&&(resultActs!=into->acts[group]))
401f46a6179Smrg	uFree(into->acts[group]);
402f46a6179Smrg    if ((from->acts[group]!=NULL)&&(resultActs!=from->acts[group]))
403f46a6179Smrg	uFree(from->acts[group]);
404f46a6179Smrg    into->numLevels[group]= resultWidth;
405f46a6179Smrg    into->syms[group]= resultSyms;
406f46a6179Smrg    from->syms[group]= NULL;
407f46a6179Smrg    into->acts[group]= resultActs;
408f46a6179Smrg    from->acts[group]= NULL;
409f46a6179Smrg    into->symsDefined|= (1<<group);
410f46a6179Smrg    from->symsDefined&= ~(1<<group);
411f46a6179Smrg    into->actsDefined|= (1<<group);
412f46a6179Smrg    from->actsDefined&= ~(1<<group);
413f46a6179Smrg    return True;
414f46a6179Smrg}
415f46a6179Smrg
416f46a6179Smrgstatic Bool
417f46a6179SmrgMergeKeys(SymbolsInfo *info,KeyInfo *into,KeyInfo *from)
418f46a6179Smrg{
419f46a6179Smrgregister int	i;
420f46a6179Smrgunsigned	collide= 0;
421f46a6179SmrgBool		report;
422f46a6179Smrg
423f46a6179Smrg    if (from->defs.merge==MergeReplace) {
424f46a6179Smrg	for (i=0;i<XkbNumKbdGroups;i++) {
425f46a6179Smrg	    if (into->numLevels[i]!=0) {
426f46a6179Smrg		if (into->syms[i])
427f46a6179Smrg		    uFree(into->syms[i]);
428f46a6179Smrg		if (into->acts[i])
429f46a6179Smrg		    uFree(into->acts[i]);
430f46a6179Smrg	    }
431f46a6179Smrg	}
432f46a6179Smrg	*into= *from;
433f46a6179Smrg	bzero(from,sizeof(KeyInfo));
434f46a6179Smrg	return True;
435f46a6179Smrg    }
436f46a6179Smrg    report= ((warningLevel>9)||
437f46a6179Smrg	     ((into->defs.fileID==from->defs.fileID)&&(warningLevel>0)));
438f46a6179Smrg    for (i=0;i<XkbNumKbdGroups;i++) {
439f46a6179Smrg	if (from->numLevels[i]>0) {
440f46a6179Smrg	    if (into->numLevels[i]==0) {
441f46a6179Smrg		into->numLevels[i]= from->numLevels[i];
442f46a6179Smrg		into->syms[i]= from->syms[i];
443f46a6179Smrg		into->acts[i]= from->acts[i];
444f46a6179Smrg		into->symsDefined|= (1<<i);
445f46a6179Smrg		from->syms[i]= NULL;
446f46a6179Smrg		from->acts[i]= NULL;
447f46a6179Smrg		from->numLevels[i]= 0;
448f46a6179Smrg		from->symsDefined&= ~(1<<i);
449f46a6179Smrg		if (into->syms[i])	into->defs.defined|= _Key_Syms;
450f46a6179Smrg		if (into->acts[i])	into->defs.defined|= _Key_Acts;
451f46a6179Smrg	    }
452f46a6179Smrg	    else {
453f46a6179Smrg		if (report) {
454f46a6179Smrg		    if (into->syms[i])	collide|= _Key_Syms;
455f46a6179Smrg		    if (into->acts[i])	collide|= _Key_Acts;
456f46a6179Smrg		}
457f46a6179Smrg		MergeKeyGroups(info,into,from,(unsigned)i);
458f46a6179Smrg	    }
459f46a6179Smrg	}
460f46a6179Smrg	if (from->types[i]!=None) {
461f46a6179Smrg	    if ((into->types[i]!=None)&&(report)&&
462f46a6179Smrg				(into->types[i]!=from->types[i])) {
463f46a6179Smrg		Atom	use,ignore;
464f46a6179Smrg		collide|= _Key_Types;
465f46a6179Smrg		if (from->defs.merge!=MergeAugment) {
466f46a6179Smrg		    use= from->types[i];
467f46a6179Smrg		    ignore= into->types[i];
468f46a6179Smrg		}
469f46a6179Smrg		else {
470f46a6179Smrg		    use= into->types[i];
471f46a6179Smrg		    ignore= from->types[i];
472f46a6179Smrg		}
473f46a6179Smrg		WARN2("Multiple definitions for group %d type of key %s\n",
474f46a6179Smrg	    				i,longText(into->name,XkbMessage));
475f46a6179Smrg		ACTION2("Using %s, ignoring %s\n",
476f46a6179Smrg	    				XkbAtomText(NULL,use,XkbMessage),
477f46a6179Smrg					XkbAtomText(NULL,ignore,XkbMessage));
478f46a6179Smrg	    }
479f46a6179Smrg	    if ((from->defs.merge!=MergeAugment)||(into->types[i]==None)) {
480f46a6179Smrg		into->types[i]= from->types[i];
481f46a6179Smrg	    }
482f46a6179Smrg	}
483f46a6179Smrg    }
484f46a6179Smrg    if (UseNewField(_Key_Behavior,&into->defs,&from->defs,&collide)) {
485f46a6179Smrg	into->behavior= from->behavior;
486f46a6179Smrg	into->nameForOverlayKey= from->nameForOverlayKey;
487f46a6179Smrg	into->defs.defined|= _Key_Behavior;
488f46a6179Smrg    }
489f46a6179Smrg    if (UseNewField(_Key_VModMap,&into->defs,&from->defs,&collide)) {
490f46a6179Smrg	into->vmodmap= from->vmodmap;
491f46a6179Smrg	into->defs.defined|= _Key_VModMap;
492f46a6179Smrg    }
493f46a6179Smrg    if (UseNewField(_Key_Repeat,&into->defs,&from->defs,&collide)) {
494f46a6179Smrg	into->repeat= from->repeat;
495f46a6179Smrg	into->defs.defined|= _Key_Repeat;
496f46a6179Smrg    }
497f46a6179Smrg    if (UseNewField(_Key_Type_Dflt,&into->defs,&from->defs,&collide)) {
498f46a6179Smrg	into->dfltType= from->dfltType;
499f46a6179Smrg	into->defs.defined|= _Key_Type_Dflt;
500f46a6179Smrg    }
501f46a6179Smrg    if (UseNewField(_Key_GroupInfo,&into->defs,&from->defs,&collide)) {
502f46a6179Smrg	into->groupInfo= from->groupInfo;
503f46a6179Smrg	into->defs.defined|= _Key_GroupInfo;
504f46a6179Smrg    }
505f46a6179Smrg    if ( collide ) {
506f46a6179Smrg	WARN1("Symbol map for key %s redefined\n",
507f46a6179Smrg			longText(into->name,XkbMessage));
508f46a6179Smrg	ACTION1("Using %s definition for conflicting fields\n",
509f46a6179Smrg			(from->defs.merge==MergeAugment?"first":"last"));
510f46a6179Smrg    }
511f46a6179Smrg    return True;
512f46a6179Smrg}
513f46a6179Smrg
514f46a6179Smrgstatic Bool
515f46a6179SmrgAddKeySymbols(SymbolsInfo *info,KeyInfo *key,XkbDescPtr xkb)
516f46a6179Smrg{
517f46a6179Smrgregister int i;
518f46a6179Smrgunsigned long real_name;
519f46a6179Smrg
520f46a6179Smrg    for (i=0;i<info->nKeys;i++) {
521f46a6179Smrg	if (info->keys[i].name==key->name)
522f46a6179Smrg	    return MergeKeys(info,&info->keys[i],key);
523f46a6179Smrg    }
524f46a6179Smrg    if(FindKeyNameForAlias(xkb, key->name, &real_name)) {
525f46a6179Smrg        for (i=0;i<info->nKeys;i++) {
526f46a6179Smrg	    if (info->keys[i].name==real_name)
527f46a6179Smrg	        return MergeKeys(info,&info->keys[i],key);
528f46a6179Smrg        }
529f46a6179Smrg    }
530f46a6179Smrg    if (info->nKeys>=info->szKeys) {
531f46a6179Smrg	info->szKeys+= SYMBOLS_CHUNK;
532f46a6179Smrg	info->keys= uTypedRecalloc(info->keys,info->nKeys,info->szKeys,KeyInfo);
533f46a6179Smrg	if (!info->keys) {
534f46a6179Smrg	    WSGO("Could not allocate key symbols descriptions\n");
535f46a6179Smrg	    ACTION("Some key symbols definitions may be lost\n");
536f46a6179Smrg	    return False;
537f46a6179Smrg	}
538f46a6179Smrg    }
539f46a6179Smrg    return CopyKeyInfo(key,&info->keys[info->nKeys++],True);
540f46a6179Smrg}
541f46a6179Smrg
542f46a6179Smrgstatic Bool
543f46a6179SmrgAddModMapEntry(SymbolsInfo *info,ModMapEntry *new)
544f46a6179Smrg{
545f46a6179SmrgModMapEntry *	mm;
546f46a6179SmrgBool		clobber;
547f46a6179Smrg
548f46a6179Smrg    clobber= (new->defs.merge!=MergeAugment);
549f46a6179Smrg    for (mm=info->modMap;mm!=NULL;mm= (ModMapEntry *)mm->defs.next) {
550f46a6179Smrg	if (new->haveSymbol&&mm->haveSymbol&&(new->u.keySym==mm->u.keySym)) {
551f46a6179Smrg	    unsigned	use,ignore;
552f46a6179Smrg	    if (mm->modifier!=new->modifier) {
553f46a6179Smrg		if (clobber) {
554f46a6179Smrg		    use= new->modifier;
555f46a6179Smrg		    ignore= mm->modifier;
556f46a6179Smrg		}
557f46a6179Smrg		else {
558f46a6179Smrg		    use= mm->modifier;
559f46a6179Smrg		    ignore= new->modifier;
560f46a6179Smrg		}
561f46a6179Smrg		ERROR1("%s added to symbol map for multiple modifiers\n",
562f46a6179Smrg				XkbKeysymText(new->u.keySym,XkbMessage));
563f46a6179Smrg		ACTION2("Using %s, ignoring %s.\n",
564f46a6179Smrg					XkbModIndexText(use,XkbMessage),
565f46a6179Smrg					XkbModIndexText(ignore,XkbMessage));
566f46a6179Smrg		mm->modifier= use;
567f46a6179Smrg	    }
568f46a6179Smrg	    return True;
569f46a6179Smrg	}
570f46a6179Smrg	if ((!new->haveSymbol)&&(!mm->haveSymbol)&&
571f46a6179Smrg					(new->u.keyName==mm->u.keyName)) {
572f46a6179Smrg	    unsigned use,ignore;
573f46a6179Smrg	    if (mm->modifier!=new->modifier) {
574f46a6179Smrg		if (clobber) {
575f46a6179Smrg		    use= new->modifier;
576f46a6179Smrg		    ignore= mm->modifier;
577f46a6179Smrg		}
578f46a6179Smrg		else {
579f46a6179Smrg		    use= mm->modifier;
580f46a6179Smrg		    ignore= new->modifier;
581f46a6179Smrg		}
582f46a6179Smrg		ERROR1("Key %s added to map for multiple modifiers\n",
583f46a6179Smrg					longText(new->u.keyName,XkbMessage));
584f46a6179Smrg		ACTION2("Using %s, ignoring %s.\n",
585f46a6179Smrg					XkbModIndexText(use,XkbMessage),
586f46a6179Smrg					XkbModIndexText(ignore,XkbMessage));
587f46a6179Smrg		mm->modifier= use;
588f46a6179Smrg	    }
589f46a6179Smrg	    return True;
590f46a6179Smrg	}
591f46a6179Smrg    }
592f46a6179Smrg    mm= uTypedAlloc(ModMapEntry);
593f46a6179Smrg    if (mm==NULL) {
594f46a6179Smrg	WSGO("Could not allocate modifier map entry\n");
595f46a6179Smrg	ACTION1("Modifier map for %s will be incomplete\n",
596f46a6179Smrg				XkbModIndexText(new->modifier,XkbMessage));
597f46a6179Smrg	return False;
598f46a6179Smrg    }
599f46a6179Smrg    *mm= *new;
600f46a6179Smrg    mm->defs.next= &info->modMap->defs;
601f46a6179Smrg    info->modMap= mm;
602f46a6179Smrg    return True;
603f46a6179Smrg}
604f46a6179Smrg
605f46a6179Smrg/***====================================================================***/
606f46a6179Smrg
607f46a6179Smrgstatic void
608f46a6179SmrgMergeIncludedSymbols(SymbolsInfo *into,SymbolsInfo *from,
609f46a6179Smrg                     unsigned merge,XkbDescPtr xkb)
610f46a6179Smrg{
611f46a6179Smrgregister int 	i;
612f46a6179SmrgKeyInfo *	key;
613f46a6179Smrg
614f46a6179Smrg    if (from->errorCount>0) {
615f46a6179Smrg	into->errorCount+= from->errorCount;
616f46a6179Smrg	return;
617f46a6179Smrg    }
618f46a6179Smrg    if (into->name==NULL) {
619f46a6179Smrg	into->name= from->name;
620f46a6179Smrg	from->name= NULL;
621f46a6179Smrg    }
622f46a6179Smrg    for (i=0;i<XkbNumKbdGroups;i++) {
623f46a6179Smrg	if (from->groupNames[i]!=None) {
624f46a6179Smrg	    if ((merge!=MergeAugment)||(into->groupNames[i]==None))
625f46a6179Smrg		into->groupNames[i]= from->groupNames[i];
626f46a6179Smrg	}
627f46a6179Smrg    }
628f46a6179Smrg    for (i=0,key=from->keys;i<from->nKeys;i++,key++) {
629f46a6179Smrg	if (merge!=MergeDefault)
630f46a6179Smrg	    key->defs.merge= merge;
631f46a6179Smrg	if (!AddKeySymbols(into,key,xkb))
632f46a6179Smrg	    into->errorCount++;
633f46a6179Smrg    }
634f46a6179Smrg    if (from->modMap!=NULL) {
635f46a6179Smrg	ModMapEntry *mm,*next;
636f46a6179Smrg	for (mm=from->modMap;mm!=NULL;mm=next) {
637f46a6179Smrg	    if (merge!=MergeDefault)
638f46a6179Smrg		mm->defs.merge= merge;
639f46a6179Smrg	    if (!AddModMapEntry(into,mm))
640f46a6179Smrg		into->errorCount++;
641f46a6179Smrg	    next= (ModMapEntry *)mm->defs.next;
642f46a6179Smrg	    uFree(mm);
643f46a6179Smrg	}
644f46a6179Smrg	from->modMap= NULL;
645f46a6179Smrg    }
646f46a6179Smrg    if (!MergeAliases(&into->aliases,&from->aliases,merge))
647f46a6179Smrg	into->errorCount++;
648f46a6179Smrg    return;
649f46a6179Smrg}
650f46a6179Smrg
651f46a6179Smrgtypedef void	(*FileHandler)(
652f46a6179Smrg	XkbFile *	/* rtrn */,
653f46a6179Smrg	XkbDescPtr	/* xkb */,
654f46a6179Smrg	unsigned	/* merge */,
655f46a6179Smrg	SymbolsInfo *	/* included */
656f46a6179Smrg);
657f46a6179Smrg
658f46a6179Smrgstatic Bool
659f46a6179SmrgHandleIncludeSymbols(	IncludeStmt *	stmt,
660f46a6179Smrg			XkbDescPtr	xkb,
661f46a6179Smrg			SymbolsInfo *	info,
662f46a6179Smrg			FileHandler	hndlr)
663f46a6179Smrg{
664f46a6179Smrgunsigned 	newMerge;
665f46a6179SmrgXkbFile	*	rtrn;
666f46a6179SmrgSymbolsInfo	included;
667f46a6179SmrgBool		haveSelf;
668f46a6179Smrg
669f46a6179Smrg    haveSelf= False;
670f46a6179Smrg    if ((stmt->file==NULL)&&(stmt->map==NULL)) {
671f46a6179Smrg	haveSelf= True;
672f46a6179Smrg	included= *info;
673f46a6179Smrg	bzero(info,sizeof(SymbolsInfo));
674f46a6179Smrg    }
675f46a6179Smrg    else if (ProcessIncludeFile(stmt,XkmSymbolsIndex,&rtrn,&newMerge)) {
676f46a6179Smrg	InitSymbolsInfo(&included,xkb);
677f46a6179Smrg	included.fileID= included.dflt.defs.fileID= rtrn->id;
678f46a6179Smrg	included.merge= included.dflt.defs.merge= MergeOverride;
679f46a6179Smrg        if (stmt->modifier) {
680f46a6179Smrg           included.explicit_group= atoi(stmt->modifier) - 1;
681f46a6179Smrg        } else {
682f46a6179Smrg           included.explicit_group= info->explicit_group;
683f46a6179Smrg        }
684f46a6179Smrg	(*hndlr)(rtrn,xkb,MergeOverride,&included);
685f46a6179Smrg	if (stmt->stmt!=NULL) {
686f46a6179Smrg	    if (included.name!=NULL)
687f46a6179Smrg		uFree(included.name);
688f46a6179Smrg	    included.name= stmt->stmt;
689f46a6179Smrg	    stmt->stmt= NULL;
690f46a6179Smrg	}
691f46a6179Smrg    }
692f46a6179Smrg    else {
693f46a6179Smrg	info->errorCount+= 10;
694f46a6179Smrg	return False;
695f46a6179Smrg    }
696f46a6179Smrg    if ((stmt->next!=NULL)&&(included.errorCount<1)) {
697f46a6179Smrg	IncludeStmt *	next;
698f46a6179Smrg	unsigned	op;
699f46a6179Smrg	SymbolsInfo	next_incl;
700f46a6179Smrg
701f46a6179Smrg	for (next=stmt->next;next!=NULL;next=next->next) {
702f46a6179Smrg	    if ((next->file==NULL)&&(next->map==NULL)) {
703f46a6179Smrg		haveSelf= True;
704f46a6179Smrg		MergeIncludedSymbols(&included,info,next->merge,xkb);
705f46a6179Smrg		FreeSymbolsInfo(info);
706f46a6179Smrg	    }
707f46a6179Smrg	    else if (ProcessIncludeFile(next,XkmSymbolsIndex,&rtrn,&op)) {
708f46a6179Smrg		InitSymbolsInfo(&next_incl,xkb);
709f46a6179Smrg		next_incl.fileID= next_incl.dflt.defs.fileID= rtrn->id;
710f46a6179Smrg		next_incl.merge= next_incl.dflt.defs.merge= MergeOverride;
711f46a6179Smrg                if (next->modifier) {
712f46a6179Smrg                   next_incl.explicit_group= atoi(next->modifier) - 1;
713f46a6179Smrg                } else {
714f46a6179Smrg                   next_incl.explicit_group= info->explicit_group;
715f46a6179Smrg                }
716f46a6179Smrg		(*hndlr)(rtrn,xkb,MergeOverride,&next_incl);
717f46a6179Smrg		MergeIncludedSymbols(&included,&next_incl,op,xkb);
718f46a6179Smrg		FreeSymbolsInfo(&next_incl);
719f46a6179Smrg	    }
720f46a6179Smrg	    else {
721f46a6179Smrg		info->errorCount+= 10;
722f46a6179Smrg		return False;
723f46a6179Smrg	    }
724f46a6179Smrg	}
725f46a6179Smrg    }
726f46a6179Smrg    if (haveSelf)
727f46a6179Smrg	*info= included;
728f46a6179Smrg    else {
729f46a6179Smrg	MergeIncludedSymbols(info,&included,newMerge,xkb);
730f46a6179Smrg	FreeSymbolsInfo(&included);
731f46a6179Smrg    }
732f46a6179Smrg    return (info->errorCount==0);
733f46a6179Smrg}
734f46a6179Smrg
735f46a6179Smrgstatic LookupEntry	groupNames[]= {
736f46a6179Smrg	{	"group1",	1	},
737f46a6179Smrg	{	"group2",	2	},
738f46a6179Smrg	{	"group3",	3	},
739f46a6179Smrg	{	"group4",	4	},
740f46a6179Smrg	{	"group5",	5	},
741f46a6179Smrg	{	"group6",	6	},
742f46a6179Smrg	{	"group7",	7	},
743f46a6179Smrg	{	"group8",	8	},
744f46a6179Smrg	{	    NULL,	0	}
745f46a6179Smrg};
746f46a6179Smrg
747f46a6179Smrg
748f46a6179Smrg#define	SYMBOLS 1
749f46a6179Smrg#define	ACTIONS	2
750f46a6179Smrg
751f46a6179Smrgstatic Bool
752f46a6179SmrgGetGroupIndex(	KeyInfo *	key,
753f46a6179Smrg		ExprDef *	arrayNdx,
754f46a6179Smrg		unsigned	what,
755f46a6179Smrg		unsigned *	ndx_rtrn)
756f46a6179Smrg{
757f46a6179Smrgconst char *name;
758f46a6179SmrgExprResult	tmp;
759f46a6179Smrg
760f46a6179Smrg    if (what==SYMBOLS)	name= "symbols";
761f46a6179Smrg    else		name= "actions";
762f46a6179Smrg
763f46a6179Smrg    if (arrayNdx==NULL) {
764f46a6179Smrg	register int	i;
765f46a6179Smrg	unsigned	defined;
766f46a6179Smrg	if (what==SYMBOLS)	defined= key->symsDefined;
767f46a6179Smrg	else			defined= key->actsDefined;
768f46a6179Smrg
769f46a6179Smrg	for (i=0;i<XkbNumKbdGroups;i++) {
770f46a6179Smrg	    if ((defined&(1<<i))==0) {
771f46a6179Smrg		*ndx_rtrn= i;
772f46a6179Smrg		return True;
773f46a6179Smrg	    }
774f46a6179Smrg	}
775f46a6179Smrg	ERROR3("Too many groups of %s for key %s (max %d)\n",name,
776f46a6179Smrg						longText(key->name,XkbMessage),
777f46a6179Smrg						XkbNumKbdGroups+1);
778f46a6179Smrg	ACTION1("Ignoring %s defined for extra groups\n",name);
779f46a6179Smrg	return False;
780f46a6179Smrg    }
781f46a6179Smrg    if (!ExprResolveInteger(arrayNdx,&tmp,SimpleLookup,(XPointer)groupNames)) {
782f46a6179Smrg	ERROR2("Illegal group index for %s of key %s\n",name,
783f46a6179Smrg						longText(key->name,XkbMessage));
784f46a6179Smrg	ACTION("Definition with non-integer array index ignored\n");
785f46a6179Smrg	return False;
786f46a6179Smrg    }
787f46a6179Smrg    if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) {
788f46a6179Smrg	ERROR3("Group index for %s of key %s is out of range (1..%d)\n",name,
789f46a6179Smrg						longText(key->name,XkbMessage),
790f46a6179Smrg						XkbNumKbdGroups+1);
791f46a6179Smrg	ACTION2("Ignoring %s for group %d\n",name,tmp.uval);
792f46a6179Smrg	return False;
793f46a6179Smrg    }
794f46a6179Smrg    *ndx_rtrn= tmp.uval-1;
795f46a6179Smrg    return True;
796f46a6179Smrg}
797f46a6179Smrg
798f46a6179Smrgstatic Bool
799f46a6179SmrgAddSymbolsToKey(	KeyInfo *	key,
800f46a6179Smrg			XkbDescPtr	xkb,
801f46a6179Smrg			char *		field,
802f46a6179Smrg			ExprDef *	arrayNdx,
803f46a6179Smrg			ExprDef *	value,
804f46a6179Smrg			SymbolsInfo *	info)
805f46a6179Smrg{
806f46a6179Smrgunsigned	ndx,nSyms;
807f46a6179Smrgint		i;
808f46a6179Smrg
809f46a6179Smrg    if (!GetGroupIndex(key,arrayNdx,SYMBOLS,&ndx))
810f46a6179Smrg	return False;
811f46a6179Smrg    if (value==NULL) {
812f46a6179Smrg	key->symsDefined|= (1<<ndx);
813f46a6179Smrg	return True;
814f46a6179Smrg    }
815f46a6179Smrg    if (value->op!=ExprKeysymList) {
816f46a6179Smrg	ERROR1("Expected a list of symbols, found %s\n",exprOpText(value->op));
817f46a6179Smrg	ACTION2("Ignoring symbols for group %d of %s\n",ndx,
818f46a6179Smrg						longText(key->name,XkbMessage));
819f46a6179Smrg	return False;
820f46a6179Smrg    }
821f46a6179Smrg    if (key->syms[ndx]!=NULL) {
822f46a6179Smrg	WSGO2("Symbols for key %s, group %d already defined\n",
823f46a6179Smrg						longText(key->name,XkbMessage),
824f46a6179Smrg						ndx);
825f46a6179Smrg	return False;
826f46a6179Smrg    }
827f46a6179Smrg    nSyms= value->value.list.nSyms;
828f46a6179Smrg    if (((key->numLevels[ndx]<nSyms)||(key->syms[ndx]==NULL))&&
829f46a6179Smrg				(!ResizeKeyGroup(key,ndx,nSyms,False))) {
830f46a6179Smrg	WSGO2("Could not resize group %d of key %s\n",ndx,
831f46a6179Smrg						longText(key->name,XkbMessage));
832f46a6179Smrg	ACTION("Symbols lost\n");
833f46a6179Smrg	return False;
834f46a6179Smrg    }
835f46a6179Smrg    key->symsDefined|= (1<<ndx);
836f46a6179Smrg    memcpy((char *)key->syms[ndx],(char *)value->value.list.syms,
837f46a6179Smrg							nSyms*sizeof(KeySym));
838f46a6179Smrg    for (i=key->numLevels[ndx]-1;(i>=0)&&(key->syms[ndx][i]==NoSymbol);i--) {
839f46a6179Smrg	key->numLevels[ndx]--;
840f46a6179Smrg    }
841f46a6179Smrg    return True;
842f46a6179Smrg}
843f46a6179Smrg
844f46a6179Smrgstatic Bool
845f46a6179SmrgAddActionsToKey(	KeyInfo *	key,
846f46a6179Smrg			XkbDescPtr	xkb,
847f46a6179Smrg			char *		field,
848f46a6179Smrg			ExprDef *	arrayNdx,
849f46a6179Smrg			ExprDef *	value,
850f46a6179Smrg			SymbolsInfo *	info)
851f46a6179Smrg{
852f46a6179Smrgregister int	i;
853f46a6179Smrgunsigned	ndx,nActs;
854f46a6179SmrgExprDef	*	act;
855f46a6179SmrgXkbAnyAction *	toAct;
856f46a6179Smrg
857f46a6179Smrg    if (!GetGroupIndex(key,arrayNdx,ACTIONS,&ndx))
858f46a6179Smrg	return False;
859f46a6179Smrg
860f46a6179Smrg    if (value==NULL) {
861f46a6179Smrg	key->actsDefined|= (1<<ndx);
862f46a6179Smrg	return True;
863f46a6179Smrg    }
864f46a6179Smrg    if (value->op!=ExprActionList) {
865f46a6179Smrg	WSGO1("Bad expression type (%d) for action list value\n",value->op);
866f46a6179Smrg	ACTION2("Ignoring actions for group %d of %s\n",ndx,
867f46a6179Smrg						longText(key->name,XkbMessage));
868f46a6179Smrg	return False;
869f46a6179Smrg    }
870f46a6179Smrg    if (key->acts[ndx]!=NULL) {
871f46a6179Smrg	WSGO2("Actions for key %s, group %d already defined\n",
872f46a6179Smrg						longText(key->name,XkbMessage),
873f46a6179Smrg						ndx);
874f46a6179Smrg	return False;
875f46a6179Smrg    }
876f46a6179Smrg    for (nActs=0,act= value->value.child;act!=NULL;nActs++) {
877f46a6179Smrg	act= (ExprDef *)act->common.next;
878f46a6179Smrg    }
879f46a6179Smrg    if (nActs<1) {
880f46a6179Smrg	WSGO("Action list but not actions in AddActionsToKey\n");
881f46a6179Smrg	return False;
882f46a6179Smrg    }
883f46a6179Smrg    if (((key->numLevels[ndx]<nActs)||(key->acts[ndx]==NULL))&&
884f46a6179Smrg				(!ResizeKeyGroup(key,ndx,nActs,True))) {
885f46a6179Smrg	WSGO2("Could not resize group %d of key %s\n",ndx,
886f46a6179Smrg					longText(key->name,XkbMessage));
887f46a6179Smrg	ACTION("Actions lost\n");
888f46a6179Smrg	return False;
889f46a6179Smrg    }
890f46a6179Smrg    key->actsDefined|= (1<<ndx);
891f46a6179Smrg
892f46a6179Smrg    toAct= (XkbAnyAction *)key->acts[ndx];
893f46a6179Smrg    act= value->value.child;
894f46a6179Smrg    for (i=0;i<nActs;i++,toAct++) {
895f46a6179Smrg	if (!HandleActionDef(act,xkb,toAct,MergeOverride,info->action)) {
896f46a6179Smrg	    ERROR1("Illegal action definition for %s\n",
897f46a6179Smrg	    				longText(key->name,XkbMessage));
898f46a6179Smrg	    ACTION2("Action for group %d/level %d ignored\n",ndx+1,i+1);
899f46a6179Smrg	}
900f46a6179Smrg	act= (ExprDef *)act->common.next;
901f46a6179Smrg    }
902f46a6179Smrg    return True;
903f46a6179Smrg}
904f46a6179Smrg
905f46a6179Smrgstatic int
906f46a6179SmrgSetAllowNone(KeyInfo *key,ExprDef *arrayNdx,ExprDef *value)
907f46a6179Smrg{
908f46a6179SmrgExprResult	tmp;
909f46a6179Smrgunsigned	radio_groups= 0;
910f46a6179Smrg
911f46a6179Smrg    if (arrayNdx==NULL) {
912f46a6179Smrg	radio_groups= XkbAllRadioGroupsMask;
913f46a6179Smrg    }
914f46a6179Smrg    else {
915f46a6179Smrg        if (!ExprResolveInteger(arrayNdx,&tmp,RadioLookup,NULL)){
916f46a6179Smrg	    ERROR("Illegal index in group name definition\n");
917f46a6179Smrg	    ACTION("Definition with non-integer array index ignored\n");
918f46a6179Smrg	    return False;
919f46a6179Smrg	}
920f46a6179Smrg	if ((tmp.uval<1)||(tmp.uval>XkbMaxRadioGroups)) {
921f46a6179Smrg	    ERROR1("Illegal radio group specified (must be 1..%d)\n",
922f46a6179Smrg							XkbMaxRadioGroups+1);
923f46a6179Smrg	    ACTION1("Value of \"allow none\" for group %d ignored\n",tmp.uval);
924f46a6179Smrg	    return False;
925f46a6179Smrg	}
926f46a6179Smrg	radio_groups|= (1<<(tmp.uval-1));
927f46a6179Smrg    }
928f46a6179Smrg    if (!ExprResolveBoolean(value,&tmp,NULL,NULL)) {
929f46a6179Smrg	ERROR1("Illegal \"allow none\" value for %s\n",
930f46a6179Smrg	    					longText(key->name,XkbMessage));
931f46a6179Smrg	ACTION("Non-boolean value ignored\n");
932f46a6179Smrg	return False;
933f46a6179Smrg    }
934f46a6179Smrg    if (tmp.uval)	key->allowNone|= radio_groups;
935f46a6179Smrg    else		key->allowNone&= ~radio_groups;
936f46a6179Smrg    return True;
937f46a6179Smrg}
938f46a6179Smrg
939f46a6179Smrg
940f46a6179Smrgstatic LookupEntry	lockingEntries[] = {
941f46a6179Smrg	{	"true",		XkbKB_Lock	},
942f46a6179Smrg	{	"yes",		XkbKB_Lock	},
943f46a6179Smrg	{	"on",		XkbKB_Lock	},
944f46a6179Smrg	{	"false",	XkbKB_Default	},
945f46a6179Smrg	{	"no",		XkbKB_Default	},
946f46a6179Smrg	{	"off",		XkbKB_Default	},
947f46a6179Smrg	{	"permanent",	XkbKB_Lock|XkbKB_Permanent },
948f46a6179Smrg	{	NULL,		0	}
949f46a6179Smrg};
950f46a6179Smrg
951f46a6179Smrgstatic LookupEntry	repeatEntries[]= {
952f46a6179Smrg	{	"true",		RepeatYes	},
953f46a6179Smrg	{	"yes",		RepeatYes	},
954f46a6179Smrg	{	"on",		RepeatYes	},
955f46a6179Smrg	{	"false",	RepeatNo	},
956f46a6179Smrg	{	"no",		RepeatNo	},
957f46a6179Smrg	{	"off",		RepeatNo	},
958f46a6179Smrg	{	"default",	RepeatUndefined	},
959f46a6179Smrg	{	NULL,		0	}
960f46a6179Smrg};
961f46a6179Smrg
962f46a6179Smrgstatic	LookupEntry	rgEntries[]= {
963f46a6179Smrg	{	"none",		0	},
964f46a6179Smrg	{	NULL,		0	}
965f46a6179Smrg};
966f46a6179Smrg
967f46a6179Smrgstatic Bool
968f46a6179SmrgSetSymbolsField(	KeyInfo *	key,
969f46a6179Smrg			XkbDescPtr	xkb,
970f46a6179Smrg			char *		field,
971f46a6179Smrg			ExprDef *	arrayNdx,
972f46a6179Smrg			ExprDef *	value,
973f46a6179Smrg			SymbolsInfo *	info)
974f46a6179Smrg{
975f46a6179SmrgBool 		ok= True;
976f46a6179SmrgExprResult	tmp;
977f46a6179Smrg
978f46a6179Smrg    if (uStrCaseCmp(field,"type")==0) {
979f46a6179Smrg	ExprResult	ndx;
980f46a6179Smrg	if ((!ExprResolveString(value,&tmp,NULL,NULL))&&(warningLevel>0)) {
981f46a6179Smrg	    WARN("The type field of a key symbol map must be a string\n");
982f46a6179Smrg	    ACTION("Ignoring illegal type definition\n");
983f46a6179Smrg	}
984f46a6179Smrg	if (arrayNdx==NULL) {
985f46a6179Smrg	    key->dfltType= XkbInternAtom(NULL,tmp.str,False);
986f46a6179Smrg	    key->defs.defined|= _Key_Type_Dflt;
987f46a6179Smrg	}
988f46a6179Smrg	else if (!ExprResolveInteger(arrayNdx,&ndx,SimpleLookup,
989f46a6179Smrg							(XPointer)groupNames)) {
990f46a6179Smrg	    ERROR1("Illegal group index for type of key %s\n",
991f46a6179Smrg						longText(key->name,XkbMessage));
992f46a6179Smrg	    ACTION("Definition with non-integer array index ignored\n");
993f46a6179Smrg	    return False;
994f46a6179Smrg	}
995f46a6179Smrg	else if ((ndx.uval<1)||(ndx.uval>XkbNumKbdGroups)) {
996f46a6179Smrg	    ERROR2("Group index for type of key %s is out of range (1..%d)\n",
997f46a6179Smrg						longText(key->name,XkbMessage),
998f46a6179Smrg						XkbNumKbdGroups+1);
999f46a6179Smrg	    ACTION1("Ignoring type for group %d\n",ndx.uval);
1000f46a6179Smrg	    return False;
1001f46a6179Smrg        }
1002f46a6179Smrg	else {
1003f46a6179Smrg	    key->types[ndx.uval-1]= XkbInternAtom(NULL,tmp.str,False);
1004f46a6179Smrg	    key->typesDefined|= (1<<(ndx.uval-1));
1005f46a6179Smrg	}
1006f46a6179Smrg    }
1007f46a6179Smrg    else if (uStrCaseCmp(field,"symbols")==0)
1008f46a6179Smrg	return AddSymbolsToKey(key,xkb,field,arrayNdx,value,info);
1009f46a6179Smrg    else if (uStrCaseCmp(field,"actions")==0)
1010f46a6179Smrg	return AddActionsToKey(key,xkb,field,arrayNdx,value,info);
1011f46a6179Smrg    else if ((uStrCaseCmp(field,"vmods")==0)||
1012f46a6179Smrg	     (uStrCaseCmp(field,"virtualmods")==0)||
1013f46a6179Smrg	     (uStrCaseCmp(field,"virtualmodifiers")==0)) {
1014f46a6179Smrg	ok= ExprResolveModMask(value,&tmp,LookupVModMask,(XPointer)xkb);
1015f46a6179Smrg	if (ok) {
1016f46a6179Smrg	    key->vmodmap= (tmp.uval>>8);
1017f46a6179Smrg	    key->defs.defined|= _Key_VModMap;
1018f46a6179Smrg	}
1019f46a6179Smrg	else {
1020f46a6179Smrg	    ERROR1("Expected a virtual modifier mask, found %s\n",
1021f46a6179Smrg							exprOpText(value->op));
1022f46a6179Smrg	    ACTION1("Ignoring virtual modifiers definition for key %s\n",
1023f46a6179Smrg						longText(key->name,XkbMessage));
1024f46a6179Smrg	}
1025f46a6179Smrg    }
1026f46a6179Smrg    else if ((uStrCaseCmp(field,"locking")==0)||(uStrCaseCmp(field,"lock")==0)||
1027f46a6179Smrg   	     (uStrCaseCmp(field,"locks")==0)) {
1028f46a6179Smrg	ok= ExprResolveEnum(value,&tmp,lockingEntries);
1029f46a6179Smrg	if (ok)
1030f46a6179Smrg	    key->behavior.type= tmp.uval;
1031f46a6179Smrg	key->defs.defined|= _Key_Behavior;
1032f46a6179Smrg    }
1033f46a6179Smrg    else if ((uStrCaseCmp(field,"radiogroup")==0)||
1034f46a6179Smrg	     (uStrCaseCmp(field,"permanentradiogroup")==0)) {
1035f46a6179Smrg	Bool permanent= False;
1036f46a6179Smrg	if (uStrCaseCmp(field,"permanentradiogroup")==0)
1037f46a6179Smrg	    permanent= True;
1038f46a6179Smrg	ok= ExprResolveInteger(value,&tmp,SimpleLookup,(XPointer)rgEntries);
1039f46a6179Smrg	if (!ok) {
1040f46a6179Smrg	    ERROR1("Illegal radio group specification for %s\n",
1041f46a6179Smrg					longText(key->name,XkbMessage));
1042f46a6179Smrg	    ACTION("Non-integer radio group ignored\n");
1043f46a6179Smrg	    return False;
1044f46a6179Smrg	}
1045f46a6179Smrg	if (tmp.uval==0) {
1046f46a6179Smrg	    key->behavior.type= XkbKB_Default;
1047f46a6179Smrg	    key->behavior.data= 0;
1048f46a6179Smrg	    return ok;
1049f46a6179Smrg	}
1050f46a6179Smrg	if ((tmp.uval<1)||(tmp.uval>XkbMaxRadioGroups)) {
1051f46a6179Smrg	    ERROR1("Radio group specification for %s out of range (1..32)\n",
1052f46a6179Smrg						longText(key->name,XkbMessage));
1053f46a6179Smrg	    ACTION1("Illegal radio group %d ignored\n",tmp.uval);
1054f46a6179Smrg	    return False;
1055f46a6179Smrg	}
1056f46a6179Smrg	key->behavior.type= XkbKB_RadioGroup|(permanent?XkbKB_Permanent:0);
1057f46a6179Smrg	key->behavior.data= tmp.uval-1;
1058f46a6179Smrg	if (key->allowNone&(1<<(tmp.uval-1)))
1059f46a6179Smrg	    key->behavior.data|= XkbKB_RGAllowNone;
1060f46a6179Smrg	key->defs.defined|= _Key_Behavior;
1061f46a6179Smrg    }
1062f46a6179Smrg    else if (uStrCaseEqual(field,"allownone")) {
1063f46a6179Smrg	ok= SetAllowNone(key,arrayNdx,value);
1064f46a6179Smrg    }
1065f46a6179Smrg    else if (uStrCasePrefix("overlay",field)||
1066f46a6179Smrg	     uStrCasePrefix("permanentoverlay",field)) {
1067f46a6179Smrg	Bool permanent= False;
1068f46a6179Smrg	char *which;
1069f46a6179Smrg	int  overlayNdx;
1070f46a6179Smrg	if (uStrCasePrefix("permanent",field)) {
1071f46a6179Smrg	    permanent= True;
1072f46a6179Smrg	    which= &field[sizeof("permanentoverlay")-1];
1073f46a6179Smrg	}
1074f46a6179Smrg	else {
1075f46a6179Smrg	    which= &field[sizeof("overlay")-1];
1076f46a6179Smrg	}
1077f46a6179Smrg	if (sscanf(which,"%d",&overlayNdx)==1) {
1078f46a6179Smrg	    if (((overlayNdx<1)||(overlayNdx>2))&&(warningLevel>0)) {
1079f46a6179Smrg		ERROR2("Illegal overlay %d specified for %s\n",
1080f46a6179Smrg						overlayNdx,
1081f46a6179Smrg						longText(key->name,XkbMessage));
1082f46a6179Smrg		ACTION("Ignored\n");
1083f46a6179Smrg		return False;
1084f46a6179Smrg	    }
1085f46a6179Smrg	}
1086f46a6179Smrg	else if (*which=='\0')
1087f46a6179Smrg	    overlayNdx=1;
1088f46a6179Smrg	else if (warningLevel>0) {
1089f46a6179Smrg	    ERROR2("Illegal overlay \"%s\" specified for %s\n",
1090f46a6179Smrg						which,
1091f46a6179Smrg						longText(key->name,XkbMessage));
1092f46a6179Smrg	    ACTION("Ignored\n");
1093f46a6179Smrg	    return False;
1094f46a6179Smrg	}
1095f46a6179Smrg	ok= ExprResolveKeyName(value,&tmp,NULL,NULL);
1096f46a6179Smrg	if (!ok) {
1097f46a6179Smrg	    ERROR1("Illegal overlay key specification for %s\n",
1098f46a6179Smrg						longText(key->name,XkbMessage));
1099f46a6179Smrg	    ACTION("Overlay key must be specified by name\n");
1100f46a6179Smrg	    return False;
1101f46a6179Smrg	}
1102f46a6179Smrg	if (overlayNdx==1)	key->behavior.type= XkbKB_Overlay1;
1103f46a6179Smrg	else			key->behavior.type= XkbKB_Overlay2;
1104f46a6179Smrg	if (permanent)
1105f46a6179Smrg	    key->behavior.type|= XkbKB_Permanent;
1106f46a6179Smrg
1107f46a6179Smrg	key->behavior.data= 0;
1108f46a6179Smrg	key->nameForOverlayKey= KeyNameToLong(tmp.keyName.name);
1109f46a6179Smrg	key->defs.defined|= _Key_Behavior;
1110f46a6179Smrg    }
1111f46a6179Smrg    else if ((uStrCaseCmp(field,"repeating")==0)||
1112f46a6179Smrg	     (uStrCaseCmp(field,"repeats")==0)||
1113f46a6179Smrg	     (uStrCaseCmp(field,"repeat")==0)){
1114f46a6179Smrg	ok= ExprResolveEnum(value,&tmp,repeatEntries);
1115f46a6179Smrg	if (!ok) {
1116f46a6179Smrg	    ERROR1("Illegal repeat setting for %s\n",
1117f46a6179Smrg	    					longText(key->name,XkbMessage));
1118f46a6179Smrg	    ACTION("Non-boolean repeat setting ignored\n");
1119f46a6179Smrg	    return False;
1120f46a6179Smrg	}
1121f46a6179Smrg	key->repeat= tmp.uval;
1122f46a6179Smrg	key->defs.defined|= _Key_Repeat;
1123f46a6179Smrg    }
1124f46a6179Smrg    else if ((uStrCaseCmp(field,"groupswrap")==0)||
1125f46a6179Smrg   	     (uStrCaseCmp(field,"wrapgroups")==0)) {
1126f46a6179Smrg	ok= ExprResolveBoolean(value,&tmp,NULL,NULL);
1127f46a6179Smrg	if (!ok) {
1128f46a6179Smrg	    ERROR1("Illegal groupsWrap setting for %s\n",
1129f46a6179Smrg	    					longText(key->name,XkbMessage));
1130f46a6179Smrg	    ACTION("Non-boolean value ignored\n");
1131f46a6179Smrg	    return False;
1132f46a6179Smrg	}
1133f46a6179Smrg	if (tmp.uval) 	key->groupInfo= XkbWrapIntoRange;
1134f46a6179Smrg	else		key->groupInfo= XkbClampIntoRange;
1135f46a6179Smrg	key->defs.defined|= _Key_GroupInfo;
1136f46a6179Smrg    }
1137f46a6179Smrg    else if ((uStrCaseCmp(field,"groupsclamp")==0)||
1138f46a6179Smrg   	     (uStrCaseCmp(field,"clampgroups")==0)) {
1139f46a6179Smrg	ok= ExprResolveBoolean(value,&tmp,NULL,NULL);
1140f46a6179Smrg	if (!ok) {
1141f46a6179Smrg	    ERROR1("Illegal groupsClamp setting for %s\n",
1142f46a6179Smrg	    					longText(key->name,XkbMessage));
1143f46a6179Smrg	    ACTION("Non-boolean value ignored\n");
1144f46a6179Smrg	    return False;
1145f46a6179Smrg	}
1146f46a6179Smrg	if (tmp.uval)	key->groupInfo= XkbClampIntoRange;
1147f46a6179Smrg	else		key->groupInfo= XkbWrapIntoRange;
1148f46a6179Smrg	key->defs.defined|= _Key_GroupInfo;
1149f46a6179Smrg    }
1150f46a6179Smrg    else if ((uStrCaseCmp(field,"groupsredirect")==0)||
1151f46a6179Smrg	     (uStrCaseCmp(field,"redirectgroups")==0)) {
1152f46a6179Smrg	if (!ExprResolveInteger(value,&tmp,SimpleLookup,(XPointer)groupNames)) {
1153f46a6179Smrg	    ERROR1("Illegal group index for redirect of key %s\n",
1154f46a6179Smrg						longText(key->name,XkbMessage));
1155f46a6179Smrg	    ACTION("Definition with non-integer group ignored\n");
1156f46a6179Smrg	    return False;
1157f46a6179Smrg	}
1158f46a6179Smrg	if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) {
1159f46a6179Smrg	    ERROR2("Out-of-range (1..%d) group for redirect of key %s\n",
1160f46a6179Smrg						XkbNumKbdGroups,
1161f46a6179Smrg						longText(key->name,XkbMessage));
1162f46a6179Smrg	    ERROR1("Ignoring illegal group %d\n",tmp.uval);
1163f46a6179Smrg	    return False;
1164f46a6179Smrg	}
1165f46a6179Smrg	key->groupInfo= XkbSetGroupInfo(0,XkbRedirectIntoRange,tmp.uval-1);
1166f46a6179Smrg	key->defs.defined|= _Key_GroupInfo;
1167f46a6179Smrg    }
1168f46a6179Smrg    else {
1169f46a6179Smrg	ERROR1("Unknown field %s in a symbol interpretation\n",field);
1170f46a6179Smrg	ACTION("Definition ignored\n");
1171f46a6179Smrg	ok= False;
1172f46a6179Smrg    }
1173f46a6179Smrg    return ok;
1174f46a6179Smrg}
1175f46a6179Smrg
1176f46a6179Smrgstatic int
1177f46a6179SmrgSetGroupName(SymbolsInfo *info,ExprDef *arrayNdx,ExprDef *value)
1178f46a6179Smrg{
1179f46a6179SmrgExprResult	tmp,name;
1180f46a6179Smrg
1181f46a6179Smrg    if ((arrayNdx==NULL)&&(warningLevel>0)) {
1182f46a6179Smrg	WARN("You must specify an index when specifying a group name\n");
1183f46a6179Smrg	ACTION("Group name definition without array subscript ignored\n");
1184f46a6179Smrg	return False;
1185f46a6179Smrg    }
1186f46a6179Smrg    if (!ExprResolveInteger(arrayNdx,&tmp,SimpleLookup,(XPointer)groupNames)) {
1187f46a6179Smrg	ERROR("Illegal index in group name definition\n");
1188f46a6179Smrg	ACTION("Definition with non-integer array index ignored\n");
1189f46a6179Smrg	return False;
1190f46a6179Smrg    }
1191f46a6179Smrg    if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) {
1192f46a6179Smrg	ERROR1("Attempt to specify name for illegal group (must be 1..%d)\n",
1193f46a6179Smrg							XkbNumKbdGroups+1);
1194f46a6179Smrg	ACTION1("Name for group %d ignored\n",tmp.uval);
1195f46a6179Smrg	return False;
1196f46a6179Smrg    }
1197f46a6179Smrg    if (!ExprResolveString(value,&name,NULL,NULL)) {
1198f46a6179Smrg	ERROR("Group name must be a string\n");
1199f46a6179Smrg	ACTION1("Illegal name for group %d ignored\n",tmp.uval);
1200f46a6179Smrg	return False;
1201f46a6179Smrg    }
1202f46a6179Smrg    info->groupNames[tmp.uval-1+info->explicit_group]=
1203f46a6179Smrg        XkbInternAtom(NULL,name.str,False);
1204f46a6179Smrg
1205f46a6179Smrg    return True;
1206f46a6179Smrg}
1207f46a6179Smrg
1208f46a6179Smrgstatic int
1209f46a6179SmrgHandleSymbolsVar(VarDef *stmt,XkbDescPtr xkb,SymbolsInfo *info)
1210f46a6179Smrg{
1211f46a6179SmrgExprResult	elem,field,tmp;
1212f46a6179SmrgExprDef *	arrayNdx;
1213f46a6179Smrg
1214f46a6179Smrg    if (ExprResolveLhs(stmt->name,&elem,&field,&arrayNdx)==0)
1215f46a6179Smrg	return 0; /* internal error, already reported */
1216f46a6179Smrg    if (elem.str&&(uStrCaseCmp(elem.str,"key")==0)) {
1217f46a6179Smrg	return SetSymbolsField(&info->dflt,xkb,field.str,arrayNdx,stmt->value,
1218f46a6179Smrg							     		info);
1219f46a6179Smrg    }
1220f46a6179Smrg    else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"name")==0)||
1221f46a6179Smrg				(uStrCaseCmp(field.str,"groupname")==0))) {
1222f46a6179Smrg	return SetGroupName(info,arrayNdx,stmt->value);
1223f46a6179Smrg    }
1224f46a6179Smrg    else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"groupswrap")==0)||
1225f46a6179Smrg				(uStrCaseCmp(field.str,"wrapgroups")==0))) {
1226f46a6179Smrg	if (!ExprResolveBoolean(stmt->value,&tmp,NULL,NULL)) {
1227f46a6179Smrg	    ERROR("Illegal setting for global groupsWrap\n");
1228f46a6179Smrg	    ACTION("Non-boolean value ignored\n");
1229f46a6179Smrg	    return False;
1230f46a6179Smrg	}
1231f46a6179Smrg	if (tmp.uval) 	info->groupInfo= XkbWrapIntoRange;
1232f46a6179Smrg	else		info->groupInfo= XkbClampIntoRange;
1233f46a6179Smrg	return True;
1234f46a6179Smrg    }
1235f46a6179Smrg    else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"groupsclamp")==0)||
1236f46a6179Smrg				(uStrCaseCmp(field.str,"clampgroups")==0))) {
1237f46a6179Smrg	if (!ExprResolveBoolean(stmt->value,&tmp,NULL,NULL)) {
1238f46a6179Smrg	    ERROR("Illegal setting for global groupsClamp\n");
1239f46a6179Smrg	    ACTION("Non-boolean value ignored\n");
1240f46a6179Smrg	    return False;
1241f46a6179Smrg	}
1242f46a6179Smrg	if (tmp.uval)	info->groupInfo= XkbClampIntoRange;
1243f46a6179Smrg	else		info->groupInfo= XkbWrapIntoRange;
1244f46a6179Smrg	return True;
1245f46a6179Smrg    }
1246f46a6179Smrg    else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"groupsredirect")==0)||
1247f46a6179Smrg				(uStrCaseCmp(field.str,"redirectgroups")==0))) {
1248f46a6179Smrg	if (!ExprResolveInteger(stmt->value,&tmp,
1249f46a6179Smrg					SimpleLookup,(XPointer)groupNames)) {
1250f46a6179Smrg	    ERROR("Illegal group index for global groupsRedirect\n");
1251f46a6179Smrg	    ACTION("Definition with non-integer group ignored\n");
1252f46a6179Smrg	    return False;
1253f46a6179Smrg	}
1254f46a6179Smrg	if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) {
1255f46a6179Smrg	    ERROR1("Out-of-range (1..%d) group for global groupsRedirect\n",
1256f46a6179Smrg	    						XkbNumKbdGroups);
1257f46a6179Smrg	    ACTION1("Ignoring illegal group %d\n",tmp.uval);
1258f46a6179Smrg	    return False;
1259f46a6179Smrg	}
1260f46a6179Smrg	info->groupInfo= XkbSetGroupInfo(0,XkbRedirectIntoRange,tmp.uval);
1261f46a6179Smrg	return True;
1262f46a6179Smrg    }
1263f46a6179Smrg    else if ((elem.str==NULL)&&(uStrCaseCmp(field.str,"allownone")==0)) {
1264f46a6179Smrg	return SetAllowNone(&info->dflt,arrayNdx,stmt->value);
1265f46a6179Smrg    }
1266f46a6179Smrg    return SetActionField(xkb,elem.str,field.str,arrayNdx,stmt->value,
1267f46a6179Smrg							     &info->action);
1268f46a6179Smrg}
1269f46a6179Smrg
1270f46a6179Smrgstatic Bool
1271f46a6179SmrgHandleSymbolsBody(	VarDef *	def,
1272f46a6179Smrg			XkbDescPtr	xkb,
1273f46a6179Smrg			KeyInfo *	key,
1274f46a6179Smrg			SymbolsInfo *	info)
1275f46a6179Smrg{
1276f46a6179SmrgBool		ok= True;
1277f46a6179SmrgExprResult	tmp,field;
1278f46a6179SmrgExprDef *	arrayNdx;
1279f46a6179Smrg
1280f46a6179Smrg    for (;def!=NULL;def= (VarDef *)def->common.next) {
1281f46a6179Smrg	if ((def->name)&&(def->name->type==ExprFieldRef)) {
1282f46a6179Smrg	    ok= HandleSymbolsVar(def,xkb,info);
1283f46a6179Smrg	    continue;
1284f46a6179Smrg	}
1285f46a6179Smrg	else {
1286f46a6179Smrg	    if (def->name==NULL) {
1287f46a6179Smrg		if ((def->value==NULL)||(def->value->op==ExprKeysymList))
1288f46a6179Smrg		     field.str= "symbols";
1289f46a6179Smrg		else field.str= "actions";
1290f46a6179Smrg		arrayNdx= NULL;
1291f46a6179Smrg	    }
1292f46a6179Smrg	    else {
1293f46a6179Smrg		ok= ExprResolveLhs(def->name,&tmp,&field,&arrayNdx);
1294f46a6179Smrg	    }
1295f46a6179Smrg	    if (ok)
1296f46a6179Smrg		ok= SetSymbolsField(key,xkb,field.str,arrayNdx,def->value,info);
1297f46a6179Smrg	}
1298f46a6179Smrg    }
1299f46a6179Smrg    return ok;
1300f46a6179Smrg}
1301f46a6179Smrg
1302f46a6179Smrgstatic Bool
1303f46a6179SmrgSetExplicitGroup(      SymbolsInfo *   info,
1304f46a6179Smrg                       KeyInfo *       key)
1305f46a6179Smrg{
1306f46a6179Smrg    unsigned group = info->explicit_group;
1307f46a6179Smrg
1308f46a6179Smrg    if (group == 0)
1309f46a6179Smrg       return True;
1310f46a6179Smrg
1311f46a6179Smrg   if ((key->typesDefined|key->symsDefined|key->actsDefined) & ~1) {
1312f46a6179Smrg       int i;
1313f46a6179Smrg       WARN1("For the map %s an explicit group specified\n", info->name);
1314f46a6179Smrg       WARN1("but key %s has more than one group defined\n",
1315f46a6179Smrg                       longText(key->name,XkbMessage));
1316f46a6179Smrg       ACTION("All groups except first one will be ignored\n");
1317f46a6179Smrg           for (i = 1; i < XkbNumKbdGroups ; i++) {
1318f46a6179Smrg	       key->numLevels[i]= 0;
1319f46a6179Smrg	       if (key->syms[i]!=NULL)
1320f46a6179Smrg	          uFree(key->syms[i]);
1321f46a6179Smrg	       key->syms[i]= (KeySym*) NULL;
1322f46a6179Smrg	       if (key->acts[i]!=NULL)
1323f46a6179Smrg	          uFree(key->acts[i]);
1324f46a6179Smrg	       key->acts[i]= (XkbAction*) NULL;
1325f46a6179Smrg	       key->types[i]= (Atom) 0;
1326f46a6179Smrg	   }
1327f46a6179Smrg   }
1328f46a6179Smrg   key->typesDefined = key->symsDefined = key->actsDefined = 1 << group;
1329f46a6179Smrg
1330f46a6179Smrg   key->numLevels[group]= key->numLevels[0];
1331f46a6179Smrg   key->numLevels[0]= 0;
1332f46a6179Smrg   key->syms[group]= key->syms[0];
1333f46a6179Smrg   key->syms[0]= (KeySym*) NULL;
1334f46a6179Smrg   key->acts[group]= key->acts[0];
1335f46a6179Smrg   key->acts[0]= (XkbAction*) NULL;
1336f46a6179Smrg   key->types[group]= key->types[0];
1337f46a6179Smrg   key->types[0]= (Atom) 0;
1338f46a6179Smrg   return True;
1339f46a6179Smrg}
1340f46a6179Smrg
1341f46a6179Smrgstatic int
1342f46a6179SmrgHandleSymbolsDef(	SymbolsDef *	stmt,
1343f46a6179Smrg			XkbDescPtr 	xkb,
1344f46a6179Smrg			unsigned 	merge,
1345f46a6179Smrg			SymbolsInfo *	info)
1346f46a6179Smrg{
1347f46a6179SmrgKeyInfo			key;
1348f46a6179Smrg
1349f46a6179Smrg    InitKeyInfo(&key);
1350f46a6179Smrg    CopyKeyInfo(&info->dflt,&key,False);
1351f46a6179Smrg    key.defs.merge= stmt->merge;
1352f46a6179Smrg    key.name= KeyNameToLong(stmt->keyName);
1353f46a6179Smrg    if (!HandleSymbolsBody((VarDef *)stmt->symbols,xkb,&key,info)) {
1354f46a6179Smrg	info->errorCount++;
1355f46a6179Smrg	return False;
1356f46a6179Smrg    }
1357f46a6179Smrg
1358f46a6179Smrg    if (!SetExplicitGroup(info,&key)) {
1359f46a6179Smrg        info->errorCount++;
1360f46a6179Smrg        return False;
1361f46a6179Smrg    }
1362f46a6179Smrg
1363f46a6179Smrg    if (!AddKeySymbols(info,&key,xkb)) {
1364f46a6179Smrg	info->errorCount++;
1365f46a6179Smrg	return False;
1366f46a6179Smrg    }
1367f46a6179Smrg    return True;
1368f46a6179Smrg}
1369f46a6179Smrg
1370f46a6179Smrgstatic Bool
1371f46a6179SmrgHandleModMapDef(	ModMapDef *	def,
1372f46a6179Smrg			XkbDescPtr	xkb,
1373f46a6179Smrg			unsigned	merge,
1374f46a6179Smrg			SymbolsInfo *	info)
1375f46a6179Smrg{
1376f46a6179SmrgExprDef	*	key;
1377f46a6179SmrgModMapEntry	tmp;
1378f46a6179SmrgExprResult	rtrn;
1379f46a6179SmrgBool 		ok;
1380f46a6179Smrg
1381f46a6179Smrg    if (!LookupModIndex(NULL,None,def->modifier,TypeInt,&rtrn)) {
1382f46a6179Smrg	ERROR("Illegal modifier map definition\n");
1383f46a6179Smrg	ACTION1("Ignoring map for non-modifier \"%s\"\n",
1384f46a6179Smrg				XkbAtomText(NULL,def->modifier,XkbMessage));
1385f46a6179Smrg	return False;
1386f46a6179Smrg    }
1387f46a6179Smrg    ok= True;
1388f46a6179Smrg    tmp.modifier= rtrn.uval;
1389f46a6179Smrg    for (key=def->keys;key!=NULL;key=(ExprDef *)key->common.next) {
1390f46a6179Smrg	if ((key->op==ExprValue)&&(key->type==TypeKeyName)) {
1391f46a6179Smrg	    tmp.haveSymbol= False;
1392f46a6179Smrg	    tmp.u.keyName= KeyNameToLong(key->value.keyName);
1393f46a6179Smrg	}
1394f46a6179Smrg	else if (ExprResolveKeySym(key,&rtrn,NULL,NULL)) {
1395f46a6179Smrg	    tmp.haveSymbol= True;
1396f46a6179Smrg	    tmp.u.keySym= rtrn.uval;
1397f46a6179Smrg	}
1398f46a6179Smrg	else {
1399f46a6179Smrg	    ERROR("Modmap entries may contain only key names or keysyms\n");
1400f46a6179Smrg	    ACTION1("Illegal definition for %s modifier ignored\n",
1401f46a6179Smrg				XkbModIndexText(tmp.modifier,XkbMessage));
1402f46a6179Smrg	    continue;
1403f46a6179Smrg	}
1404f46a6179Smrg
1405f46a6179Smrg	ok= AddModMapEntry(info,&tmp)&&ok;
1406f46a6179Smrg    }
1407f46a6179Smrg    return ok;
1408f46a6179Smrg}
1409f46a6179Smrg
1410f46a6179Smrgstatic void
1411f46a6179SmrgHandleSymbolsFile(	XkbFile	*	file,
1412f46a6179Smrg			XkbDescPtr	xkb,
1413f46a6179Smrg			unsigned	merge,
1414f46a6179Smrg			SymbolsInfo *	info)
1415f46a6179Smrg{
1416f46a6179SmrgParseCommon	*stmt;
1417f46a6179Smrg
1418f46a6179Smrg    info->name= uStringDup(file->name);
1419f46a6179Smrg    stmt= file->defs;
1420f46a6179Smrg    while (stmt) {
1421f46a6179Smrg	switch (stmt->stmtType) {
1422f46a6179Smrg	    case StmtInclude:
1423f46a6179Smrg		if (!HandleIncludeSymbols((IncludeStmt *)stmt,xkb,info,
1424f46a6179Smrg						HandleSymbolsFile))
1425f46a6179Smrg		    info->errorCount++;
1426f46a6179Smrg		break;
1427f46a6179Smrg	    case StmtSymbolsDef:
1428f46a6179Smrg		if (!HandleSymbolsDef((SymbolsDef *)stmt,xkb,merge,info))
1429f46a6179Smrg		    info->errorCount++;
1430f46a6179Smrg		break;
1431f46a6179Smrg	    case StmtVarDef:
1432f46a6179Smrg		if (!HandleSymbolsVar((VarDef *)stmt,xkb,info))
1433f46a6179Smrg		    info->errorCount++;
1434f46a6179Smrg		break;
1435f46a6179Smrg	    case StmtVModDef:
1436f46a6179Smrg		if (!HandleVModDef((VModDef *)stmt,merge,&info->vmods))
1437f46a6179Smrg		    info->errorCount++;
1438f46a6179Smrg		break;
1439f46a6179Smrg	    case StmtInterpDef:
1440f46a6179Smrg		ERROR("Interpretation files may not include other types\n");
1441f46a6179Smrg		ACTION("Ignoring definition of symbol interpretation\n");
1442f46a6179Smrg		info->errorCount++;
1443f46a6179Smrg		break;
1444f46a6179Smrg	    case StmtKeycodeDef:
1445f46a6179Smrg		ERROR("Interpretation files may not include other types\n");
1446f46a6179Smrg		ACTION("Ignoring definition of key name\n");
1447f46a6179Smrg		info->errorCount++;
1448f46a6179Smrg		break;
1449f46a6179Smrg	    case StmtModMapDef:
1450f46a6179Smrg		if (!HandleModMapDef((ModMapDef *)stmt,xkb,merge,info))
1451f46a6179Smrg		    info->errorCount++;
1452f46a6179Smrg		break;
1453f46a6179Smrg	    default:
1454f46a6179Smrg		WSGO1("Unexpected statement type %d in HandleSymbolsFile\n",
1455f46a6179Smrg			stmt->stmtType);
1456f46a6179Smrg		break;
1457f46a6179Smrg	}
1458f46a6179Smrg	stmt= stmt->next;
1459f46a6179Smrg	if (info->errorCount>10) {
1460f46a6179Smrg#ifdef NOISY
1461f46a6179Smrg	    ERROR("Too many errors\n");
1462f46a6179Smrg#endif
1463f46a6179Smrg	    ACTION1("Abandoning symbols file \"%s\"\n",file->topName);
1464f46a6179Smrg	    break;
1465f46a6179Smrg	}
1466f46a6179Smrg    }
1467f46a6179Smrg    return;
1468f46a6179Smrg}
1469f46a6179Smrg
1470f46a6179Smrgstatic Bool
1471f46a6179SmrgFindKeyForSymbol(XkbDescPtr xkb,KeySym sym,unsigned int *kc_rtrn)
1472f46a6179Smrg{
1473f46a6179Smrgregister int 	i, j;
1474f46a6179Smrgregister Bool	gotOne;
1475f46a6179Smrg
1476f46a6179Smrg    j= 0;
1477f46a6179Smrg    do {
1478f46a6179Smrg        gotOne= False;
1479f46a6179Smrg        for (i = xkb->min_key_code; i <= (int)xkb->max_key_code; i++) {
1480f46a6179Smrg            if ( j<(int)XkbKeyNumSyms(xkb,i) ) {
1481f46a6179Smrg                gotOne = True;
1482f46a6179Smrg                if ((XkbKeySym(xkb,i,j)==sym)) {
1483f46a6179Smrg		    *kc_rtrn= i;
1484f46a6179Smrg                    return True;
1485f46a6179Smrg		}
1486f46a6179Smrg            }
1487f46a6179Smrg        }
1488f46a6179Smrg        j++;
1489f46a6179Smrg    } while (gotOne);
1490f46a6179Smrg    return False;
1491f46a6179Smrg}
1492f46a6179Smrg
1493f46a6179Smrgstatic Bool
1494f46a6179SmrgFindNamedType(XkbDescPtr xkb,Atom name,unsigned *type_rtrn)
1495f46a6179Smrg{
1496f46a6179Smrgregister unsigned n;
1497f46a6179Smrg
1498f46a6179Smrg    if (xkb&&xkb->map&&xkb->map->types) {
1499f46a6179Smrg	for (n=0;n<xkb->map->num_types;n++) {
1500f46a6179Smrg	    if (xkb->map->types[n].name==(Atom)name) {
1501f46a6179Smrg		*type_rtrn= n;
1502f46a6179Smrg		return True;
1503f46a6179Smrg	    }
1504f46a6179Smrg	}
1505f46a6179Smrg    }
1506f46a6179Smrg    return False;
1507f46a6179Smrg}
1508f46a6179Smrg
1509f46a6179Smrgstatic Bool
1510f46a6179SmrgKSIsLower (KeySym ks)
1511f46a6179Smrg{
1512f46a6179Smrg    KeySym lower, upper;
1513f46a6179Smrg    XConvertCase(ks, &lower, &upper);
1514f46a6179Smrg
1515f46a6179Smrg    if (lower == upper)
1516f46a6179Smrg        return False;
1517f46a6179Smrg    return (ks == lower ? True : False);
1518f46a6179Smrg}
1519f46a6179Smrg
1520f46a6179Smrgstatic Bool
1521f46a6179SmrgKSIsUpper (KeySym ks)
1522f46a6179Smrg{
1523f46a6179Smrg    KeySym lower, upper;
1524f46a6179Smrg    XConvertCase(ks, &lower, &upper);
1525f46a6179Smrg
1526f46a6179Smrg    if (lower == upper)
1527f46a6179Smrg        return False;
1528f46a6179Smrg    return (ks == upper ? True : False);
1529f46a6179Smrg}
1530f46a6179Smrg
1531f46a6179Smrgstatic Bool
1532f46a6179SmrgFindAutomaticType(int width,KeySym *syms,Atom *typeNameRtrn, Bool *autoType)
1533f46a6179Smrg{
1534f46a6179Smrg    *autoType = False;
1535f46a6179Smrg    if ((width==1)||(width==0)) {
1536f46a6179Smrg	 *typeNameRtrn= XkbInternAtom(NULL,"ONE_LEVEL",False);
1537f46a6179Smrg	 *autoType = True;
1538f46a6179Smrg    } else if (width == 2) {
1539f46a6179Smrg        if ( syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]) ) {
1540f46a6179Smrg	     *typeNameRtrn= XkbInternAtom(NULL,"ALPHABETIC",False);
1541f46a6179Smrg	} else if ( syms &&
1542f46a6179Smrg                    (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])) ) {
1543f46a6179Smrg	     *typeNameRtrn= XkbInternAtom(NULL,"KEYPAD",False);
1544f46a6179Smrg	     *autoType = True;
1545f46a6179Smrg	} else {
1546f46a6179Smrg             *typeNameRtrn= XkbInternAtom(NULL,"TWO_LEVEL",False);
1547f46a6179Smrg             *autoType = True;
1548f46a6179Smrg        }
1549f46a6179Smrg    } else if (width <= 4 ) {
1550f46a6179Smrg        if ( syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]) )
1551f46a6179Smrg             if (    KSIsLower(syms[2]) && KSIsUpper(syms[3]) )
1552f46a6179Smrg	        *typeNameRtrn= XkbInternAtom(NULL,
1553f46a6179Smrg                                            "FOUR_LEVEL_ALPHABETIC",False);
1554f46a6179Smrg             else
1555f46a6179Smrg	        *typeNameRtrn= XkbInternAtom(NULL,
1556f46a6179Smrg                                            "FOUR_LEVEL_SEMIALPHABETIC",False);
1557f46a6179Smrg
1558f46a6179Smrg        else if ( syms && (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])) )
1559f46a6179Smrg	     *typeNameRtrn= XkbInternAtom(NULL,
1560f46a6179Smrg                            "FOUR_LEVEL_KEYPAD",False);
1561f46a6179Smrg        else *typeNameRtrn= XkbInternAtom(NULL,"FOUR_LEVEL",False);
1562f46a6179Smrg    }
1563f46a6179Smrg    return ((width>=0)&&(width<=4));
1564f46a6179Smrg}
1565f46a6179Smrg
1566f46a6179Smrgstatic void
1567f46a6179SmrgPrepareKeyDef(KeyInfo *key)
1568f46a6179Smrg{
1569f46a6179Smrg    int i, j, width, defined, lastGroup;
1570f46a6179Smrg    Bool identical;
1571f46a6179Smrg
1572f46a6179Smrg    defined = key->symsDefined | key->actsDefined | key->typesDefined;
1573f46a6179Smrg    for (i = XkbNumKbdGroups - 1; i >= 0; i--) {
1574f46a6179Smrg	if (defined & (1<<i))
1575f46a6179Smrg	    break;
1576f46a6179Smrg    }
1577f46a6179Smrg    lastGroup = i;
1578f46a6179Smrg
1579f46a6179Smrg    if (lastGroup == 0)
1580f46a6179Smrg       return;
1581f46a6179Smrg
1582f46a6179Smrg    /* If there are empty groups between non-empty ones fill them with data */
1583f46a6179Smrg    /* from the first group. */
1584f46a6179Smrg    /* We can make a wrong assumption here. But leaving gaps is worse. */
1585f46a6179Smrg    for (i = lastGroup; i > 0; i--) {
1586f46a6179Smrg        if (defined & (1<<i))
1587f46a6179Smrg            continue;
1588f46a6179Smrg        width = key->numLevels[0];
1589f46a6179Smrg        if (key->typesDefined & 1) {
1590f46a6179Smrg            for (j = 0; j < width; j++) {
1591f46a6179Smrg                key->types[i] = key->types[0];
1592f46a6179Smrg            }
1593f46a6179Smrg            key->typesDefined |= 1 << i;
1594f46a6179Smrg        }
1595f46a6179Smrg        if ((key->actsDefined & 1) && key->acts[0]) {
1596f46a6179Smrg            key->acts[i]= uTypedCalloc(width, XkbAction);
1597f46a6179Smrg            if (key->acts[i] == NULL)
1598f46a6179Smrg                continue;
1599f46a6179Smrg            memcpy((void *) key->acts[i], (void *) key->acts[0],
1600f46a6179Smrg                   width * sizeof(XkbAction));
1601f46a6179Smrg            key->actsDefined |= 1 << i;
1602f46a6179Smrg        }
1603f46a6179Smrg        if ((key->symsDefined & 1) && key->syms[0]) {
1604f46a6179Smrg            key->syms[i]= uTypedCalloc(width, KeySym);
1605f46a6179Smrg            if (key->syms[i] == NULL)
1606f46a6179Smrg                continue;
1607f46a6179Smrg            memcpy((void *) key->syms[i], (void *) key->syms[0],
1608f46a6179Smrg                   width * sizeof(KeySym));
1609f46a6179Smrg            key->symsDefined |= 1 << i;
1610f46a6179Smrg        }
1611f46a6179Smrg        if (defined & 1) {
1612f46a6179Smrg            key->numLevels[i] = key->numLevels[0];
1613f46a6179Smrg        }
1614f46a6179Smrg    }
1615f46a6179Smrg    /* If all groups are completely identical remove them all */
1616f46a6179Smrg    /* exept the first one. */
1617f46a6179Smrg    identical = True;
1618f46a6179Smrg    for (i = lastGroup; i > 0; i--) {
1619f46a6179Smrg        if ((key->numLevels[i] != key->numLevels[0]) ||
1620f46a6179Smrg            (key->types[i] != key->types[0])) {
1621f46a6179Smrg            identical = False;
1622f46a6179Smrg            break;
1623f46a6179Smrg        }
1624f46a6179Smrg        if ((key->syms[i] != key->syms[0]) &&
1625f46a6179Smrg	    (key->syms[i] == NULL || key->syms[0] == NULL ||
1626f46a6179Smrg	    memcmp((void*) key->syms[i], (void*) key->syms[0],
1627f46a6179Smrg                       sizeof(KeySym) * key->numLevels[0])) ) {
1628f46a6179Smrg             identical = False;
1629f46a6179Smrg             break;
1630f46a6179Smrg	}
1631f46a6179Smrg        if ((key->acts[i] != key->acts[0]) &&
1632f46a6179Smrg	    (key->acts[i] == NULL || key->acts[0] == NULL ||
1633f46a6179Smrg	    memcmp((void*) key->acts[i], (void*) key->acts[0],
1634f46a6179Smrg                       sizeof(XkbAction) * key->numLevels[0]))) {
1635f46a6179Smrg            identical = False;
1636f46a6179Smrg            break;
1637f46a6179Smrg	}
1638f46a6179Smrg    }
1639f46a6179Smrg    if (identical) {
1640f46a6179Smrg        for (i = lastGroup; i > 0; i--) {
1641f46a6179Smrg            key->numLevels[i]= 0;
1642f46a6179Smrg	    if (key->syms[i] != NULL)
1643f46a6179Smrg	        uFree(key->syms[i]);
1644f46a6179Smrg	    key->syms[i]= (KeySym*) NULL;
1645f46a6179Smrg	    if (key->acts[i] != NULL)
1646f46a6179Smrg	        uFree(key->acts[i]);
1647f46a6179Smrg	    key->acts[i]= (XkbAction*) NULL;
1648f46a6179Smrg	    key->types[i]= (Atom) 0;
1649f46a6179Smrg        }
1650f46a6179Smrg	key->symsDefined &= 1;
1651f46a6179Smrg	key->actsDefined &= 1;
1652f46a6179Smrg	key->typesDefined &= 1;
1653f46a6179Smrg    }
1654f46a6179Smrg    return;
1655f46a6179Smrg}
1656f46a6179Smrg
1657f46a6179Smrgstatic Bool
1658f46a6179SmrgCopySymbolsDef(XkbFileInfo *result,KeyInfo *key,int start_from)
1659f46a6179Smrg{
1660f46a6179Smrgregister int	i;
1661f46a6179Smrgunsigned	okc,kc,width,tmp,nGroups;
1662f46a6179SmrgXkbKeyTypePtr	type;
1663f46a6179SmrgBool		haveActions,autoType,useAlias;
1664f46a6179SmrgKeySym *	outSyms;
1665f46a6179SmrgXkbAction *	outActs;
1666f46a6179SmrgXkbDescPtr	xkb;
1667f46a6179Smrgunsigned	types[XkbNumKbdGroups];
1668f46a6179Smrg
1669f46a6179Smrg    xkb= result->xkb;
1670f46a6179Smrg    useAlias= (start_from==0);
1671f46a6179Smrg    if (!FindNamedKey(xkb,key->name,&kc,useAlias,CreateKeyNames(xkb),
1672f46a6179Smrg								start_from)) {
1673f46a6179Smrg	if ((start_from==0)&&(warningLevel>=5)) {
1674f46a6179Smrg	    WARN2("Key %s not found in %s keycodes\n",
1675f46a6179Smrg	    		longText(key->name,XkbMessage),
1676f46a6179Smrg			XkbAtomText(NULL,xkb->names->keycodes,XkbMessage));
1677f46a6179Smrg	    ACTION("Symbols ignored\n");
1678f46a6179Smrg	}
1679f46a6179Smrg	return False;
1680f46a6179Smrg    }
1681f46a6179Smrg
1682f46a6179Smrg    haveActions= False;
1683f46a6179Smrg    for (i=width=nGroups=0;i<XkbNumKbdGroups;i++) {
1684f46a6179Smrg	if (((i+1)>nGroups)&&(((key->symsDefined|key->actsDefined)&(1<<i))||
1685f46a6179Smrg						(key->typesDefined)&(1<<i)))
1686f46a6179Smrg	    nGroups= i+1;
1687f46a6179Smrg	if (key->acts[i])
1688f46a6179Smrg	    haveActions= True;
1689f46a6179Smrg	autoType= False;
1690f46a6179Smrg	if (key->types[i]==None) {
1691f46a6179Smrg	    if (key->dfltType!=None)
1692f46a6179Smrg		key->types[i]= key->dfltType;
1693f46a6179Smrg	    else if (FindAutomaticType(key->numLevels[i],key->syms[i],
1694f46a6179Smrg  				       &key->types[i], &autoType)) {
1695f46a6179Smrg	    }
1696f46a6179Smrg	    else {
1697f46a6179Smrg		if (warningLevel>=5) {
1698f46a6179Smrg		    WARN1("No automatic type for %d symbols\n",
1699f46a6179Smrg						(unsigned int)key->numLevels[i]);
1700f46a6179Smrg		    ACTION3("Using %s for the %s key (keycode %d)\n",
1701f46a6179Smrg				XkbAtomText(NULL,key->types[i],XkbMessage),
1702f46a6179Smrg				longText(key->name,XkbMessage),kc);
1703f46a6179Smrg		}
1704f46a6179Smrg	    }
1705f46a6179Smrg	}
1706f46a6179Smrg	if (FindNamedType(xkb,key->types[i],&types[i]))  {
1707f46a6179Smrg	    if (!autoType || key->numLevels[i] > 2)
1708f46a6179Smrg		xkb->server->explicit[kc]|= (1<<i);
1709f46a6179Smrg	}
1710f46a6179Smrg	else {
1711f46a6179Smrg	    if (warningLevel>=3) {
1712f46a6179Smrg		WARN1("Type \"%s\" is not defined\n",
1713f46a6179Smrg	    			XkbAtomText(NULL,key->types[i],XkbMessage));
1714f46a6179Smrg		ACTION2("Using TWO_LEVEL for the %s key (keycode %d)\n",
1715f46a6179Smrg					longText(key->name,XkbMessage),kc);
1716f46a6179Smrg	    }
1717f46a6179Smrg	    types[i]= XkbTwoLevelIndex;
1718f46a6179Smrg	}
1719f46a6179Smrg	type= &xkb->map->types[types[i]];
1720f46a6179Smrg	if (type->num_levels<key->numLevels[i]) {
1721f46a6179Smrg	    if (warningLevel>0) {
1722f46a6179Smrg		WARN4("Type \"%s\" has %d levels, but %s has %d symbols\n",
1723f46a6179Smrg					XkbAtomText(NULL,type->name,XkbMessage),
1724f46a6179Smrg					(unsigned int)type->num_levels,
1725f46a6179Smrg					longText(key->name,XkbMessage),
1726f46a6179Smrg					(unsigned int)key->numLevels[i]);
1727f46a6179Smrg		ACTION("Ignoring extra symbols\n");
1728f46a6179Smrg	    }
1729f46a6179Smrg	    key->numLevels[i]= type->num_levels;
1730f46a6179Smrg	}
1731f46a6179Smrg	if (key->numLevels[i]>width)
1732f46a6179Smrg	    width= key->numLevels[i];
1733f46a6179Smrg	if (type->num_levels>width)
1734f46a6179Smrg	    width= type->num_levels;
1735f46a6179Smrg    }
1736f46a6179Smrg
1737f46a6179Smrg    i= width*nGroups;
1738f46a6179Smrg    outSyms= XkbResizeKeySyms(xkb,kc,i);
1739f46a6179Smrg    if (outSyms==NULL) {
1740f46a6179Smrg	WSGO2("Could not enlarge symbols for %s (keycode %d)\n",
1741f46a6179Smrg					longText(key->name,XkbMessage),kc);
1742f46a6179Smrg	return False;
1743f46a6179Smrg    }
1744f46a6179Smrg    if (haveActions) {
1745f46a6179Smrg	outActs= XkbResizeKeyActions(xkb,kc,i);
1746f46a6179Smrg	if (outActs==NULL) {
1747f46a6179Smrg		WSGO2("Could not enlarge actions for %s (key %d)\n",
1748f46a6179Smrg					longText(key->name,XkbMessage),kc);
1749f46a6179Smrg		return False;
1750f46a6179Smrg	}
1751f46a6179Smrg	xkb->server->explicit[kc]|= XkbExplicitInterpretMask;
1752f46a6179Smrg    }
1753f46a6179Smrg    else outActs= NULL;
1754f46a6179Smrg    if (key->defs.defined&_Key_GroupInfo)
1755f46a6179Smrg	 i= key->groupInfo;
1756f46a6179Smrg    else i= xkb->map->key_sym_map[kc].group_info;
1757f46a6179Smrg    xkb->map->key_sym_map[kc].group_info= XkbSetNumGroups(i,nGroups);
1758f46a6179Smrg    xkb->map->key_sym_map[kc].width= width;
1759f46a6179Smrg    for (i=0;i<nGroups;i++) {
1760f46a6179Smrg	xkb->map->key_sym_map[kc].kt_index[i]= types[i];
1761f46a6179Smrg	if (key->syms[i]!=NULL) {
1762f46a6179Smrg	    for (tmp=0;tmp<width;tmp++) {
1763f46a6179Smrg		if (tmp<key->numLevels[i])
1764f46a6179Smrg		     outSyms[tmp]= key->syms[i][tmp];
1765f46a6179Smrg		else outSyms[tmp]= NoSymbol;
1766f46a6179Smrg		if ((outActs!=NULL)&&(key->acts[i]!=NULL)) {
1767f46a6179Smrg		    if (tmp<key->numLevels[i])
1768f46a6179Smrg			 outActs[tmp]= key->acts[i][tmp];
1769f46a6179Smrg		    else outActs[tmp].type= XkbSA_NoAction;
1770f46a6179Smrg		}
1771f46a6179Smrg	    }
1772f46a6179Smrg	}
1773f46a6179Smrg	outSyms+= width;
1774f46a6179Smrg	if (outActs)
1775f46a6179Smrg	    outActs+= width;
1776f46a6179Smrg    }
1777f46a6179Smrg    switch (key->behavior.type&XkbKB_OpMask) {
1778f46a6179Smrg	case XkbKB_Default:
1779f46a6179Smrg	    break;
1780f46a6179Smrg	case XkbKB_Overlay1:
1781f46a6179Smrg	case XkbKB_Overlay2:
1782f46a6179Smrg	    /* find key by name! */
1783f46a6179Smrg	    if (!FindNamedKey(xkb,key->nameForOverlayKey,&okc,True,
1784f46a6179Smrg    						CreateKeyNames(xkb),0)) {
1785f46a6179Smrg		if (warningLevel>=1) {
1786f46a6179Smrg		    WARN2("Key %s not found in %s keycodes\n",
1787f46a6179Smrg			longText(key->nameForOverlayKey,XkbMessage),
1788f46a6179Smrg			XkbAtomText(NULL,xkb->names->keycodes,XkbMessage));
1789f46a6179Smrg		    ACTION1("Not treating %s as an overlay key \n",
1790f46a6179Smrg					longText(key->name,XkbMessage));
1791f46a6179Smrg		}
1792f46a6179Smrg		break;
1793f46a6179Smrg	    }
1794f46a6179Smrg	    key->behavior.data= okc;
1795f46a6179Smrg	default:
1796f46a6179Smrg	    xkb->server->behaviors[kc]= key->behavior;
1797f46a6179Smrg	    xkb->server->explicit[kc]|= XkbExplicitBehaviorMask;
1798f46a6179Smrg	    break;
1799f46a6179Smrg    }
1800f46a6179Smrg    if (key->defs.defined&_Key_VModMap) {
1801f46a6179Smrg	xkb->server->vmodmap[kc]= key->vmodmap;
1802f46a6179Smrg	xkb->server->explicit[kc]|= XkbExplicitVModMapMask;
1803f46a6179Smrg    }
1804f46a6179Smrg    if (key->repeat!=RepeatUndefined) {
1805f46a6179Smrg	if (key->repeat==RepeatYes)
1806f46a6179Smrg	     xkb->ctrls->per_key_repeat[kc/8]|= (1<<(kc%8));
1807f46a6179Smrg	else xkb->ctrls->per_key_repeat[kc/8]&= ~(1<<(kc%8));
1808f46a6179Smrg	xkb->server->explicit[kc]|= XkbExplicitAutoRepeatMask;
1809f46a6179Smrg    }
1810f46a6179Smrg    CopySymbolsDef(result,key,kc+1);
1811f46a6179Smrg    return True;
1812f46a6179Smrg}
1813f46a6179Smrg
1814f46a6179Smrgstatic Bool
1815f46a6179SmrgCopyModMapDef(XkbFileInfo *result,ModMapEntry *entry)
1816f46a6179Smrg{
1817f46a6179Smrgunsigned	kc;
1818f46a6179SmrgXkbDescPtr	xkb;
1819f46a6179Smrg
1820f46a6179Smrg    xkb= result->xkb;
1821f46a6179Smrg    if ((!entry->haveSymbol)&&(!FindNamedKey(xkb,entry->u.keyName,&kc,True,
1822f46a6179Smrg    						CreateKeyNames(xkb),0))) {
1823f46a6179Smrg	if (warningLevel>=5) {
1824f46a6179Smrg	    WARN2("Key %s not found in %s keycodes\n",
1825f46a6179Smrg			longText(entry->u.keyName,XkbMessage),
1826f46a6179Smrg			XkbAtomText(NULL,xkb->names->keycodes,XkbMessage));
1827f46a6179Smrg	    ACTION1("Modifier map entry for %s not updated\n",
1828f46a6179Smrg				XkbModIndexText(entry->modifier,XkbMessage));
1829f46a6179Smrg	}
1830f46a6179Smrg	return False;
1831f46a6179Smrg    }
1832f46a6179Smrg    else if (entry->haveSymbol&&(!FindKeyForSymbol(xkb,entry->u.keySym,&kc))) {
1833f46a6179Smrg	if (warningLevel>5) {
1834f46a6179Smrg	    WARN2("Key \"%s\" not found in %s symbol map\n",
1835f46a6179Smrg			XkbKeysymText(entry->u.keySym,XkbMessage),
1836f46a6179Smrg			XkbAtomText(NULL,xkb->names->symbols,XkbMessage));
1837f46a6179Smrg	    ACTION1("Modifier map entry for %s not updated\n",
1838f46a6179Smrg				XkbModIndexText(entry->modifier,XkbMessage));
1839f46a6179Smrg	}
1840f46a6179Smrg	return False;
1841f46a6179Smrg    }
1842f46a6179Smrg    xkb->map->modmap[kc]|= (1<<entry->modifier);
1843f46a6179Smrg    return True;
1844f46a6179Smrg}
1845f46a6179Smrg
1846f46a6179SmrgBool
1847f46a6179SmrgCompileSymbols(XkbFile *file,XkbFileInfo *result,unsigned merge)
1848f46a6179Smrg{
1849f46a6179Smrgregister int	i;
1850f46a6179SmrgSymbolsInfo	info;
1851f46a6179SmrgXkbDescPtr	xkb;
1852f46a6179Smrg
1853f46a6179Smrg    xkb= result->xkb;
1854f46a6179Smrg    InitSymbolsInfo(&info,xkb);
1855f46a6179Smrg    info.dflt.defs.fileID= file->id;
1856f46a6179Smrg    info.dflt.defs.merge= merge;
1857f46a6179Smrg    HandleSymbolsFile(file,xkb,merge,&info);
1858f46a6179Smrg
1859f46a6179Smrg    if (info.nKeys == 0)
1860f46a6179Smrg        return True;
1861f46a6179Smrg    if (info.errorCount==0) {
1862f46a6179Smrg	KeyInfo *key;
1863f46a6179Smrg	if (XkbAllocNames(xkb,XkbSymbolsNameMask|XkbGroupNamesMask,0,0)
1864f46a6179Smrg								!=Success) {
1865f46a6179Smrg	    WSGO("Can not allocate names in CompileSymbols\n");
1866f46a6179Smrg	    ACTION("Symbols not added\n");
1867f46a6179Smrg	    return False;
1868f46a6179Smrg	}
1869f46a6179Smrg	if(XkbAllocClientMap(xkb,XkbKeySymsMask|XkbModifierMapMask,0)!=Success){
1870f46a6179Smrg	    WSGO("Could not allocate client map in CompileSymbols\n");
1871f46a6179Smrg	    ACTION("Symbols not added\n");
1872f46a6179Smrg	    return False;
1873f46a6179Smrg	}
1874f46a6179Smrg	if (XkbAllocServerMap(xkb,XkbAllServerInfoMask,32)!=Success) {
1875f46a6179Smrg	    WSGO("Could not allocate server map in CompileSymbols\n");
1876f46a6179Smrg	    ACTION("Symbols not added\n");
1877f46a6179Smrg	    return False;
1878f46a6179Smrg	}
1879f46a6179Smrg	if (XkbAllocControls(xkb,XkbPerKeyRepeatMask)!=Success) {
1880f46a6179Smrg	    WSGO("Could not allocate controls in CompileSymbols\n");
1881f46a6179Smrg	    ACTION("Symbols not added\n");
1882f46a6179Smrg	    return False;
1883f46a6179Smrg	}
1884f46a6179Smrg	xkb->names->symbols= XkbInternAtom(xkb->dpy,info.name,False);
1885f46a6179Smrg	if (info.aliases)
1886f46a6179Smrg	    ApplyAliases(xkb,False,&info.aliases);
1887f46a6179Smrg	for (i=0;i<XkbNumKbdGroups;i++) {
1888f46a6179Smrg	    if (info.groupNames[i]!=None)
1889f46a6179Smrg		xkb->names->groups[i]= info.groupNames[i];
1890f46a6179Smrg	}
1891f46a6179Smrg	for (key=info.keys,i=0;i<info.nKeys;i++,key++) {
1892f46a6179Smrg	    PrepareKeyDef(key);
1893f46a6179Smrg	}
1894f46a6179Smrg	for (key=info.keys,i=0;i<info.nKeys;i++,key++) {
1895f46a6179Smrg	    if (!CopySymbolsDef(result,key,0))
1896f46a6179Smrg		info.errorCount++;
1897f46a6179Smrg	}
1898f46a6179Smrg	if (warningLevel>3) {
1899f46a6179Smrg	    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
1900f46a6179Smrg		if (xkb->names->keys[i].name[0]=='\0')
1901f46a6179Smrg		    continue;
1902f46a6179Smrg		if (XkbKeyNumGroups(xkb,i)<1) {
1903f46a6179Smrg		    char buf[5];
1904f46a6179Smrg		    memcpy(buf,xkb->names->keys[i].name,4);
1905f46a6179Smrg		    buf[4]= '\0';
1906f46a6179Smrg		    WARN2("No symbols defined for <%s> (keycode %d)\n",buf,i);
1907f46a6179Smrg		}
1908f46a6179Smrg	    }
1909f46a6179Smrg	}
1910f46a6179Smrg	if (info.modMap) {
1911f46a6179Smrg	    ModMapEntry	*mm,*next;
1912f46a6179Smrg	    for (mm=info.modMap;mm!=NULL;mm=next) {
1913f46a6179Smrg		if (!CopyModMapDef(result,mm))
1914f46a6179Smrg		    info.errorCount++;
1915f46a6179Smrg		next= (ModMapEntry *)mm->defs.next;
1916f46a6179Smrg	    }
1917f46a6179Smrg	}
1918f46a6179Smrg	return True;
1919f46a6179Smrg    }
1920f46a6179Smrg    return False;
1921f46a6179Smrg}
1922