compat.c revision f46a6179
1/* $Xorg: compat.c,v 1.3 2000/08/17 19:54:30 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/compat.c,v 3.3 2001/01/17 23:45:43 dawes Exp $ */
28
29#include <X11/Xos.h>
30#include "xkbcomp.h"
31#include "tokens.h"
32#include "expr.h"
33#include "vmod.h"
34#include "misc.h"
35#include "indicators.h"
36#include "action.h"
37
38typedef struct _SymInterpInfo {
39    CommonInfo		defs;
40    XkbSymInterpretRec	interp;
41} SymInterpInfo;
42
43#define	_SI_VirtualMod		(1<<0)
44#define	_SI_Action		(1<<1)
45#define	_SI_AutoRepeat		(1<<2)
46#define	_SI_LockingKey		(1<<3)
47#define	_SI_LevelOneOnly	(1<<4)
48
49typedef struct _GroupCompatInfo {
50    unsigned char	fileID;
51    unsigned char	merge;
52    unsigned char	real_mods;
53    unsigned short	vmods;
54} GroupCompatInfo;
55
56typedef struct _CompatInfo {
57    char *		name;
58    unsigned 		fileID;
59    int			errorCount;
60    int			nInterps;
61    SymInterpInfo *	interps;
62    SymInterpInfo 	dflt;
63    LEDInfo		ledDflt;
64    GroupCompatInfo	groupCompat[XkbNumKbdGroups];
65    LEDInfo *		leds;
66    VModInfo		vmods;
67    ActionInfo *	act;
68    XkbDescPtr		xkb;
69} CompatInfo;
70
71/***====================================================================***/
72
73#define	ReportSINotArray(si,f,i) \
74	ReportNotArray("symbol interpretation",(f),siText((si),(i)))
75#define	ReportSIBadType(si,f,w,i) \
76	ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
77
78/***====================================================================***/
79
80static char *
81siText(SymInterpInfo *	si,CompatInfo *	info)
82{
83static char buf[128];
84
85    if (si==&info->dflt) {
86	sprintf(buf,"default");
87    }
88    else {
89	sprintf(buf,"%s+%s(%s)",XkbKeysymText(si->interp.sym,XkbMessage),
90				XkbSIMatchText(si->interp.match,XkbMessage),
91				XkbModMaskText(si->interp.mods,XkbMessage));
92    }
93    return buf;
94}
95
96static void
97InitCompatInfo(CompatInfo *info,XkbDescPtr xkb)
98{
99register int i;
100
101    info->xkb= xkb;
102    info->name= NULL;
103    info->fileID= 0;
104    info->errorCount= 0;
105    info->nInterps= 0;
106    info->interps= NULL;
107    info->act= NULL;
108    info->dflt.defs.fileID= info->fileID;
109    info->dflt.defs.defined= 0;
110    info->dflt.defs.merge= MergeOverride;
111    info->dflt.interp.flags=	0;
112    info->dflt.interp.virtual_mod= XkbNoModifier;
113    info->dflt.interp.act.type= XkbSA_NoAction;
114    for (i=0;i<XkbAnyActionDataSize;i++) {
115	info->dflt.interp.act.data[i]= 0;
116    }
117    ClearIndicatorMapInfo(xkb->dpy,&info->ledDflt);
118    info->ledDflt.defs.fileID= info->fileID;
119    info->ledDflt.defs.defined= 0;
120    info->ledDflt.defs.merge= MergeOverride;
121    bzero((char *)&info->groupCompat[0],XkbNumKbdGroups*sizeof(GroupCompatInfo));
122    info->leds= NULL;
123    InitVModInfo(&info->vmods,xkb);
124    return;
125}
126
127static void
128ClearCompatInfo(CompatInfo *info,XkbDescPtr xkb)
129{
130register int i;
131
132    if (info->name!=NULL)
133	uFree(info->name);
134    info->name= NULL;
135    info->dflt.defs.defined= 0;
136    info->dflt.defs.merge= MergeAugment;
137    info->dflt.interp.flags= 0;
138    info->dflt.interp.virtual_mod= XkbNoModifier;
139    info->dflt.interp.act.type= XkbSA_NoAction;
140    for (i=0;i<XkbAnyActionDataSize;i++) {
141	info->dflt.interp.act.data[i]= 0;
142    }
143    ClearIndicatorMapInfo(xkb->dpy,&info->ledDflt);
144    info->nInterps= 0;
145    info->interps= (SymInterpInfo *)ClearCommonInfo(&info->interps->defs);
146    bzero((char *)&info->groupCompat[0],XkbNumKbdGroups*sizeof(GroupCompatInfo));
147    info->leds= (LEDInfo *)ClearCommonInfo(&info->leds->defs);
148    /* 3/30/94 (ef) -- XXX! Should free action info here */
149    ClearVModInfo(&info->vmods,xkb);
150    return;
151}
152
153static SymInterpInfo *
154NextInterp(CompatInfo *info)
155{
156SymInterpInfo *	si;
157
158    si= uTypedAlloc(SymInterpInfo);
159    if (si) {
160	bzero((char *)si,sizeof(SymInterpInfo));
161	info->interps= (SymInterpInfo *)AddCommonInfo(&info->interps->defs,
162							(CommonInfo *)si);
163	info->nInterps++;
164    }
165    return si;
166}
167
168static SymInterpInfo *
169FindMatchingInterp(CompatInfo *info,SymInterpInfo *new)
170{
171SymInterpInfo *	old;
172
173    for (old= info->interps;old!=NULL;old=(SymInterpInfo *)old->defs.next) {
174	if ((old->interp.sym==new->interp.sym)&&
175				(old->interp.mods==new->interp.mods)&&
176				(old->interp.match==new->interp.match)) {
177	    return  old;
178	}
179    }
180    return NULL;
181}
182
183static Bool
184AddInterp(CompatInfo *info,SymInterpInfo *new)
185{
186unsigned		collide;
187SymInterpInfo	*	old;
188
189    collide= 0;
190    old= FindMatchingInterp(info,new);
191    if (old!=NULL) {
192	if (new->defs.merge==MergeReplace) {
193	    SymInterpInfo *next= (SymInterpInfo *)old->defs.next;
194	    if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
195		    					(warningLevel>9)) {
196		WARN1("Multiple definitions for \"%s\"\n",siText(new,info));
197		ACTION("Earlier interpretation ignored\n");
198	    }
199	    *old= *new;
200	    old->defs.next= &next->defs;
201	    return True;
202	}
203	if (UseNewField(_SI_VirtualMod,&old->defs,&new->defs,&collide)) {
204	    old->interp.virtual_mod= new->interp.virtual_mod;
205	    old->defs.defined|= _SI_VirtualMod;
206	}
207	if (UseNewField(_SI_Action,&old->defs,&new->defs,&collide)) {
208	    old->interp.act= new->interp.act;
209	    old->defs.defined|= _SI_Action;
210	}
211	if (UseNewField(_SI_AutoRepeat,&old->defs,&new->defs,&collide)) {
212	    old->interp.flags&= ~XkbSI_AutoRepeat;
213	    old->interp.flags|= (new->interp.flags&XkbSI_AutoRepeat);
214	    old->defs.defined|= _SI_AutoRepeat;
215	}
216	if (UseNewField(_SI_LockingKey,&old->defs,&new->defs,&collide)) {
217	    old->interp.flags&= ~XkbSI_LockingKey;
218	    old->interp.flags|= (new->interp.flags&XkbSI_LockingKey);
219	    old->defs.defined|= _SI_LockingKey;
220	}
221	if (UseNewField(_SI_LevelOneOnly,&old->defs,&new->defs,&collide)) {
222	    old->interp.match&= ~XkbSI_LevelOneOnly;
223	    old->interp.match|= (new->interp.match&XkbSI_LevelOneOnly);
224	    old->defs.defined|= _SI_LevelOneOnly;
225	}
226	if (collide) {
227	    WARN1("Multiple interpretations of \"%s\"\n",siText(new,info));
228	    ACTION1("Using %s definition for duplicate fields\n",
229				(new->defs.merge!=MergeAugment?"last":"first"));
230	}
231	return True;
232    }
233    old= new;
234    if ((new= NextInterp(info))==NULL)
235	return False;
236    *new= *old;
237    new->defs.next= NULL;
238    return True;
239}
240
241static Bool
242AddGroupCompat(CompatInfo *info,unsigned group,GroupCompatInfo *newGC)
243{
244GroupCompatInfo *	gc;
245unsigned		merge;
246
247    merge= newGC->merge;
248    gc= &info->groupCompat[group];
249    if (((gc->real_mods==newGC->real_mods)&&(gc->vmods==newGC->vmods))) {
250	return True;
251    }
252    if (((gc->fileID==newGC->fileID)&&(warningLevel>0))||(warningLevel>9)) {
253	WARN1("Compat map for group %d redefined\n",group+1);
254	ACTION1("Using %s definition\n",(merge==MergeAugment?"old":"new"));
255    }
256    if (merge!=MergeAugment)
257	*gc= *newGC;
258    return True;
259}
260
261/***====================================================================***/
262
263static Bool
264ResolveStateAndPredicate(	ExprDef *	expr,
265				unsigned *	pred_rtrn,
266				unsigned *	mods_rtrn,
267				CompatInfo *	info)
268{
269ExprResult	result;
270
271    if (expr==NULL) {
272	*pred_rtrn= XkbSI_AnyOfOrNone;
273	*mods_rtrn= ~0;
274	return True;
275    }
276
277    *pred_rtrn= XkbSI_Exactly;
278    if (expr->op==ExprActionDecl) {
279	char *pred_txt= XkbAtomText(NULL,expr->value.action.name,XkbMessage);
280	if (uStrCaseCmp(pred_txt,"noneof")==0)
281	     *pred_rtrn= XkbSI_NoneOf;
282	else if (uStrCaseCmp(pred_txt,"anyofornone")==0)
283	     *pred_rtrn= XkbSI_AnyOfOrNone;
284	else if (uStrCaseCmp(pred_txt,"anyof")==0)
285	     *pred_rtrn= XkbSI_AnyOf;
286	else if (uStrCaseCmp(pred_txt,"allof")==0)
287	     *pred_rtrn= XkbSI_AllOf;
288	else if (uStrCaseCmp(pred_txt,"exactly")==0)
289	     *pred_rtrn= XkbSI_Exactly;
290	else {
291	     ERROR1("Illegal modifier predicate \"%s\"\n",pred_txt);
292	     ACTION("Ignored\n");
293	     return False;
294	}
295	expr= expr->value.action.args;
296    }
297    else if (expr->op==ExprIdent) {
298	char *pred_txt= XkbAtomText(NULL,expr->value.str,XkbMessage);
299	if ((pred_txt)&&(uStrCaseCmp(pred_txt,"any")==0)) {
300	    *pred_rtrn= XkbSI_AnyOf;
301	    *mods_rtrn= 0xff;
302	    return True;
303	}
304    }
305
306    if (ExprResolveModMask(expr,&result,NULL,NULL)) {
307	*mods_rtrn= result.uval;
308	return True;
309    }
310    return False;
311}
312
313/***====================================================================***/
314
315static void
316MergeIncludedCompatMaps(	CompatInfo *	into,
317				CompatInfo *	from,
318				unsigned	merge)
319{
320SymInterpInfo * 	si;
321LEDInfo *		led,*rtrn,*next;
322GroupCompatInfo *	gcm;
323register int		i;
324
325    if (from->errorCount>0) {
326	into->errorCount+= from->errorCount;
327	return;
328    }
329    if (into->name==NULL) {
330	into->name= from->name;
331	from->name= NULL;
332    }
333    for (si=from->interps;si;si=(SymInterpInfo *)si->defs.next) {
334	if (merge!=MergeDefault)
335	    si->defs.merge= merge;
336	if (!AddInterp(into,si))
337	    into->errorCount++;
338    }
339    for (i=0,gcm=&from->groupCompat[0];i<XkbNumKbdGroups;i++,gcm++) {
340	if (merge!=MergeDefault)
341	    gcm->merge= merge;
342	if (!AddGroupCompat(into,i,gcm))
343	    into->errorCount++;
344    }
345    for (led=from->leds;led!=NULL;led=next) {
346	next= (LEDInfo *)led->defs.next;
347	if (merge!=MergeDefault)
348	    led->defs.merge= merge;
349	rtrn= AddIndicatorMap(into->leds,led);
350	if (rtrn!=NULL)
351	     into->leds= rtrn;
352	else into->errorCount++;
353    }
354    return;
355}
356
357typedef void	(*FileHandler)(
358	XkbFile *	/* rtrn */,
359	XkbDescPtr	/* xkb */,
360	unsigned	/* merge */,
361	CompatInfo *	/* info */
362);
363
364static Bool
365HandleIncludeCompatMap(	IncludeStmt *	  stmt,
366			XkbDescPtr	  xkb,
367			CompatInfo *	  info,
368			FileHandler	  hndlr)
369{
370unsigned 	newMerge;
371XkbFile	*	rtrn;
372CompatInfo	included;
373Bool		haveSelf;
374
375    haveSelf= False;
376    if ((stmt->file==NULL)&&(stmt->map==NULL)) {
377	haveSelf= True;
378	included= *info;
379	bzero(info,sizeof(CompatInfo));
380    }
381    else if (ProcessIncludeFile(stmt,XkmCompatMapIndex,&rtrn,&newMerge)) {
382	InitCompatInfo(&included,xkb);
383	included.fileID= rtrn->id;
384	included.dflt= info->dflt;
385	included.dflt.defs.fileID= rtrn->id;
386	included.dflt.defs.merge= newMerge;
387	included.ledDflt.defs.fileID= rtrn->id;
388	included.ledDflt.defs.merge= newMerge;
389	included.act= info->act;
390	(*hndlr)(rtrn,xkb,MergeOverride,&included);
391	if (stmt->stmt!=NULL) {
392	    if (included.name!=NULL)
393		uFree(included.name);
394	    included.name= stmt->stmt;
395	    stmt->stmt= NULL;
396	}
397    }
398    else {
399	info->errorCount+= 10;
400	return False;
401    }
402    if ((stmt->next!=NULL)&&(included.errorCount<1)) {
403	IncludeStmt *	next;
404	unsigned	op;
405	CompatInfo	next_incl;
406
407	for (next=stmt->next;next!=NULL;next=next->next) {
408	    if ((next->file==NULL)&&(next->map==NULL)) {
409		haveSelf= True;
410		MergeIncludedCompatMaps(&included,info,next->merge);
411		ClearCompatInfo(info,xkb);
412	    }
413	    else if (ProcessIncludeFile(next,XkmCompatMapIndex,&rtrn,&op)) {
414		InitCompatInfo(&next_incl,xkb);
415		next_incl.fileID= rtrn->id;
416		next_incl.dflt= info->dflt;
417		next_incl.dflt.defs.fileID= rtrn->id;
418		next_incl.dflt.defs.merge= op;
419		next_incl.ledDflt.defs.fileID= rtrn->id;
420		next_incl.ledDflt.defs.merge= op;
421		next_incl.act= info->act;
422		(*hndlr)(rtrn,xkb,MergeOverride,&next_incl);
423		MergeIncludedCompatMaps(&included,&next_incl,op);
424		ClearCompatInfo(&next_incl,xkb);
425	    }
426	    else {
427		info->errorCount+= 10;
428		return False;
429	    }
430	}
431    }
432    if (haveSelf)
433	*info= included;
434    else {
435	MergeIncludedCompatMaps(info,&included,newMerge);
436	ClearCompatInfo(&included,xkb);
437    }
438    return (info->errorCount==0);
439}
440
441static LookupEntry useModMapValues[] = {
442	{	"levelone",	1	},
443	{	"level1",	1	},
444	{	"anylevel",	0	},
445	{	"any",		0	},
446	{	NULL,		0	}
447};
448
449static int
450SetInterpField(	SymInterpInfo *	si,
451		XkbDescPtr	xkb,
452		char *		field,
453		ExprDef *	arrayNdx,
454		ExprDef *	value,
455		CompatInfo *	info)
456{
457int 		ok= 1;
458ExprResult	tmp;
459
460    if (uStrCaseCmp(field,"action")==0) {
461	if (arrayNdx!=NULL)
462	    return ReportSINotArray(si,field,info);
463	ok= HandleActionDef(value,xkb,&si->interp.act,si->defs.merge,info->act);
464	if (ok)
465	     si->defs.defined|= _SI_Action;
466    }
467    else if ((uStrCaseCmp(field,"virtualmodifier")==0)||
468	     (uStrCaseCmp(field,"virtualmod")==0)) {
469	if (arrayNdx!=NULL)
470	    return ReportSINotArray(si,field,info);
471	ok= ResolveVirtualModifier(value,&tmp,&info->vmods);
472	if (ok) {
473	    si->interp.virtual_mod= tmp.uval;
474	    si->defs.defined|= _SI_VirtualMod;
475	}
476	else return ReportSIBadType(si,field,"virtual modifier",info);
477    }
478    else if (uStrCaseCmp(field,"repeat")==0) {
479	if (arrayNdx!=NULL)
480	    return ReportSINotArray(si,field,info);
481	ok= ExprResolveBoolean(value,&tmp,NULL,NULL);
482	if (ok) {
483	    if (tmp.uval)	si->interp.flags|= XkbSI_AutoRepeat;
484	    else		si->interp.flags&= ~XkbSI_AutoRepeat;
485	    si->defs.defined|= _SI_AutoRepeat;
486	}
487	else return ReportSIBadType(si,field,"boolean",info);
488    }
489    else if (uStrCaseCmp(field,"locking")==0) {
490	if (arrayNdx!=NULL)
491	    return ReportSINotArray(si,field,info);
492	ok= ExprResolveBoolean(value,&tmp,NULL,NULL);
493	if (ok) {
494	    if (tmp.uval)	si->interp.flags|= XkbSI_LockingKey;
495	    else		si->interp.flags&= ~XkbSI_LockingKey;
496	    si->defs.defined|= _SI_LockingKey;
497	}
498	else return ReportSIBadType(si,field,"boolean",info);
499    }
500    else if ((uStrCaseCmp(field,"usemodmap")==0)||
501	 	(uStrCaseCmp(field,"usemodmapmods")==0)) {
502	if (arrayNdx!=NULL)
503	    return ReportSINotArray(si,field,info);
504	ok= ExprResolveEnum(value,&tmp,useModMapValues);
505	if (ok) {
506	    if (tmp.uval)	si->interp.match|= XkbSI_LevelOneOnly;
507	    else		si->interp.match&= ~XkbSI_LevelOneOnly;
508	    si->defs.defined|= _SI_LevelOneOnly;
509	}
510	else return ReportSIBadType(si,field,"level specification",info);
511    }
512    else {
513	ok= ReportBadField("symbol interpretation",field,siText(si,info));
514    }
515    return ok;
516}
517
518LookupEntry groupNames[]= {
519	{	"group1",	0x01	},
520	{	"group2",	0x02	},
521	{	"group3",	0x04	},
522	{	"group4",	0x08	},
523	{	"group5",	0x10	},
524	{	"group6",	0x20	},
525	{	"group7",	0x40	},
526	{	"group8",	0x80	},
527	{	"none",		0x00	},
528	{	"all",		0xff	},
529	{	NULL,		0	}
530};
531
532static int
533HandleInterpVar(VarDef *stmt,XkbDescPtr xkb,CompatInfo *info)
534{
535ExprResult	elem,field;
536ExprDef *	ndx;
537
538    if (ExprResolveLhs(stmt->name,&elem,&field,&ndx)==0)
539	return 0; /* internal error, already reported */
540    if (elem.str&&(uStrCaseCmp(elem.str,"interpret")==0))
541	return SetInterpField(&info->dflt,xkb,field.str,ndx,stmt->value,info);
542    if (elem.str&&(uStrCaseCmp(elem.str,"indicator")==0)) {
543	return SetIndicatorMapField(&info->ledDflt,xkb,field.str,ndx,
544								stmt->value);
545    }
546    return SetActionField(xkb,elem.str,field.str,ndx,stmt->value,&info->act);
547}
548
549static int
550HandleInterpBody(VarDef *def,XkbDescPtr xkb,SymInterpInfo *si,CompatInfo *info)
551{
552int		ok= 1;
553ExprResult	tmp,field;
554ExprDef *	arrayNdx;
555
556    for (;def!=NULL;def= (VarDef *)def->common.next) {
557	if ((def->name)&&(def->name->type==ExprFieldRef)) {
558	    ok= HandleInterpVar(def,xkb,info);
559	    continue;
560	}
561	ok= ExprResolveLhs(def->name,&tmp,&field,&arrayNdx);
562	if (ok)
563	    ok= SetInterpField(si,xkb,field.str,arrayNdx,def->value,info);
564    }
565    return ok;
566}
567
568static int
569HandleInterpDef(InterpDef *def,XkbDescPtr xkb,unsigned merge,CompatInfo *info)
570{
571unsigned		pred,mods;
572SymInterpInfo		si;
573
574    if (!ResolveStateAndPredicate(def->match,&pred,&mods,info)) {
575	ERROR("Couldn't determine matching modifiers\n");
576	ACTION("Symbol interpretation ignored\n");
577	return False;
578    }
579    if (def->merge!=MergeDefault)
580	merge= def->merge;
581
582    si= info->dflt;
583    si.defs.merge= merge;
584    si.interp.sym= def->sym;
585    si.interp.match= pred & XkbSI_OpMask;
586    si.interp.mods= mods;
587    if (!HandleInterpBody(def->def,xkb,&si,info)) {
588	info->errorCount++;
589	return False;
590    }
591
592    if (!AddInterp(info,&si)) {
593	info->errorCount++;
594	return False;
595    }
596    return True;
597}
598
599static int
600HandleGroupCompatDef(	GroupCompatDef *	def,
601			XkbDescPtr		xkb,
602			unsigned 		merge,
603			CompatInfo *		info)
604{
605ExprResult	val;
606GroupCompatInfo	tmp;
607
608    if (def->merge!=MergeDefault)
609	merge= def->merge;
610    if (!XkbIsLegalGroup(def->group-1)) {
611	ERROR1("Keyboard group must be in the range 1..%d\n",XkbNumKbdGroups+1);
612	ACTION1("Compatibility map for illegal group %d ignored\n",def->group);
613	return False;
614    }
615    tmp.fileID= info->fileID;
616    tmp.merge= merge;
617    if (!ExprResolveModMask(def->def,&val,LookupVModMask,(XPointer)xkb)) {
618	ERROR("Expected a modifier mask in group compatibility definition\n");
619	ACTION1("Ignoring illegal compatibility map for group %d\n",def->group);
620	return False;
621    }
622    tmp.real_mods= val.uval&0xff;
623    tmp.vmods= (val.uval>>8)&0xffff;
624    return AddGroupCompat(info,def->group-1,&tmp);
625}
626
627static void
628HandleCompatMapFile(	XkbFile	*	file,
629			XkbDescPtr 	 xkb,
630			unsigned	 merge,
631			CompatInfo *	info)
632{
633ParseCommon	*stmt;
634
635    if (merge==MergeDefault)
636	merge= MergeAugment;
637    info->name= uStringDup(file->name);
638    stmt= file->defs;
639    while (stmt) {
640	switch (stmt->stmtType) {
641	    case StmtInclude:
642		if (!HandleIncludeCompatMap((IncludeStmt *)stmt,xkb,info,
643						HandleCompatMapFile))
644		    info->errorCount++;
645		break;
646	    case StmtInterpDef:
647		if (!HandleInterpDef((InterpDef *)stmt,xkb,merge,info))
648		    info->errorCount++;
649		break;
650	    case StmtGroupCompatDef:
651		if (!HandleGroupCompatDef((GroupCompatDef*)stmt,xkb,merge,info))
652		    info->errorCount++;
653		break;
654	    case StmtIndicatorMapDef:
655		{
656		    LEDInfo *rtrn;
657		    rtrn= HandleIndicatorMapDef((IndicatorMapDef *)stmt,xkb,
658						&info->ledDflt,info->leds,
659						merge);
660		    if (rtrn!=NULL)
661		 	 info->leds= rtrn;
662		    else info->errorCount++;
663		}
664		break;
665	    case StmtVarDef:
666		if (!HandleInterpVar((VarDef *)stmt,xkb,info))
667		    info->errorCount++;
668		break;
669	    case StmtVModDef:
670		if (!HandleVModDef((VModDef *)stmt,merge,&info->vmods))
671		    info->errorCount++;
672		break;
673	    case StmtKeycodeDef:
674		ERROR("Interpretation files may not include other types\n");
675		ACTION("Ignoring definition of key name\n");
676		info->errorCount++;
677		break;
678	    default:
679		WSGO1("Unexpected statement type %d in HandleCompatMapFile\n",
680								stmt->stmtType);
681		break;
682	}
683	stmt= stmt->next;
684	if (info->errorCount>10) {
685#ifdef NOISY
686	    ERROR("Too many errors\n");
687#endif
688	    ACTION1("Abandoning compatibility map \"%s\"\n",file->topName);
689	    break;
690	}
691    }
692    return;
693}
694
695static void
696CopyInterps(	CompatInfo *	info,
697		XkbCompatMapPtr	compat,
698		Bool		needSymbol,
699		unsigned	pred)
700{
701SymInterpInfo *		si;
702
703    for (si=info->interps;si;si=(SymInterpInfo *)si->defs.next) {
704	if (((si->interp.match&XkbSI_OpMask)!=pred)||
705		(needSymbol&&(si->interp.sym==NoSymbol))||
706		((!needSymbol)&&(si->interp.sym!=NoSymbol)))
707	    continue;
708	if (compat->num_si>=compat->size_si) {
709	    WSGO("No room to merge symbol interpretations\n");
710	    ACTION("Symbol interpretations lost\n");
711	    return;
712	}
713	compat->sym_interpret[compat->num_si++]= si->interp;
714    }
715    return;
716}
717
718Bool
719CompileCompatMap(	XkbFile *	file,
720			XkbFileInfo *	result,
721			unsigned	merge,
722			LEDInfo **	unboundLEDs)
723{
724int			i;
725CompatInfo		info;
726XkbDescPtr		xkb;
727GroupCompatInfo *	gcm;
728
729    xkb= result->xkb;
730    InitCompatInfo(&info,xkb);
731    info.dflt.defs.merge= merge;
732    info.ledDflt.defs.merge= merge;
733    HandleCompatMapFile(file,xkb,merge,&info);
734
735    if (info.errorCount==0) {
736	int size;
737	if (XkbAllocCompatMap(xkb,XkbAllCompatMask,info.nInterps)!=Success) {
738	    WSGO("Couldn't allocate compatibility map\n");
739	    ACTION("Exiting\n");
740	    return False;
741	}
742	if (info.name!=NULL) {
743	    if (XkbAllocNames(xkb,XkbCompatNameMask,0,0)==Success)
744		xkb->names->compat= XkbInternAtom(xkb->dpy,info.name,False);
745	    else {
746		WSGO("Couldn't allocate space for compat name\n");
747		ACTION2("Name \"%s\" (from %s) NOT assigned\n",scanFile,
748								info.name);
749	    }
750	}
751	size= info.nInterps*sizeof(XkbSymInterpretRec);
752	if (size>0) {
753	    CopyInterps(&info,xkb->compat,True,XkbSI_Exactly);
754	    CopyInterps(&info,xkb->compat,True,XkbSI_AllOf|XkbSI_NoneOf);
755	    CopyInterps(&info,xkb->compat,True,XkbSI_AnyOf);
756	    CopyInterps(&info,xkb->compat,True,XkbSI_AnyOfOrNone);
757	    CopyInterps(&info,xkb->compat,False,XkbSI_Exactly);
758	    CopyInterps(&info,xkb->compat,False,XkbSI_AllOf|XkbSI_NoneOf);
759	    CopyInterps(&info,xkb->compat,False,XkbSI_AnyOf);
760	    CopyInterps(&info,xkb->compat,False,XkbSI_AnyOfOrNone);
761	}
762	for (i=0,gcm=&info.groupCompat[0];i<XkbNumKbdGroups;i++,gcm++) {
763	    if ((gcm->fileID!=0)||(gcm->real_mods!=0)||(gcm->vmods!=0)) {
764	 	xkb->compat->groups[i].mask= gcm->real_mods;
765	 	xkb->compat->groups[i].real_mods= gcm->real_mods;
766	 	xkb->compat->groups[i].vmods= gcm->vmods;
767	    }
768	}
769	if (info.leds!=NULL) {
770	    if (!CopyIndicatorMapDefs(result,info.leds,unboundLEDs))
771		info.errorCount++;
772	    info.leds= NULL;
773	}
774	ClearCompatInfo(&info,xkb);
775	return True;
776    }
777    if (info.interps!=NULL)
778	uFree(info.interps);
779    return False;
780}
781