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