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