782 lines
21 KiB
C
782 lines
21 KiB
C
|
/* $Xorg: compat.c,v 1.3 2000/08/17 19:54:30 cpqbld Exp $ */
|
||
|
/************************************************************
|
||
|
Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
|
||
|
|
||
|
Permission to use, copy, modify, and distribute this
|
||
|
software and its documentation for any purpose and without
|
||
|
fee is hereby granted, provided that the above copyright
|
||
|
notice appear in all copies and that both that copyright
|
||
|
notice and this permission notice appear in supporting
|
||
|
documentation, and that the name of Silicon Graphics not be
|
||
|
used in advertising or publicity pertaining to distribution
|
||
|
of the software without specific prior written permission.
|
||
|
Silicon Graphics makes no representation about the suitability
|
||
|
of this software for any purpose. It is provided "as is"
|
||
|
without any express or implied warranty.
|
||
|
|
||
|
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||
|
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
||
|
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
|
||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||
|
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||
|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
|
||
|
THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
|
||
|
********************************************************/
|
||
|
/* $XFree86: xc/programs/xkbcomp/compat.c,v 3.3 2001/01/17 23:45:43 dawes Exp $ */
|
||
|
|
||
|
#include <X11/Xos.h>
|
||
|
#include "xkbcomp.h"
|
||
|
#include "tokens.h"
|
||
|
#include "expr.h"
|
||
|
#include "vmod.h"
|
||
|
#include "misc.h"
|
||
|
#include "indicators.h"
|
||
|
#include "action.h"
|
||
|
|
||
|
typedef struct _SymInterpInfo {
|
||
|
CommonInfo defs;
|
||
|
XkbSymInterpretRec interp;
|
||
|
} SymInterpInfo;
|
||
|
|
||
|
#define _SI_VirtualMod (1<<0)
|
||
|
#define _SI_Action (1<<1)
|
||
|
#define _SI_AutoRepeat (1<<2)
|
||
|
#define _SI_LockingKey (1<<3)
|
||
|
#define _SI_LevelOneOnly (1<<4)
|
||
|
|
||
|
typedef struct _GroupCompatInfo {
|
||
|
unsigned char fileID;
|
||
|
unsigned char merge;
|
||
|
unsigned char real_mods;
|
||
|
unsigned short vmods;
|
||
|
} GroupCompatInfo;
|
||
|
|
||
|
typedef struct _CompatInfo {
|
||
|
char * name;
|
||
|
unsigned fileID;
|
||
|
int errorCount;
|
||
|
int nInterps;
|
||
|
SymInterpInfo * interps;
|
||
|
SymInterpInfo dflt;
|
||
|
LEDInfo ledDflt;
|
||
|
GroupCompatInfo groupCompat[XkbNumKbdGroups];
|
||
|
LEDInfo * leds;
|
||
|
VModInfo vmods;
|
||
|
ActionInfo * act;
|
||
|
XkbDescPtr xkb;
|
||
|
} CompatInfo;
|
||
|
|
||
|
/***====================================================================***/
|
||
|
|
||
|
#define ReportSINotArray(si,f,i) \
|
||
|
ReportNotArray("symbol interpretation",(f),siText((si),(i)))
|
||
|
#define ReportSIBadType(si,f,w,i) \
|
||
|
ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
|
||
|
|
||
|
/***====================================================================***/
|
||
|
|
||
|
static char *
|
||
|
siText(SymInterpInfo * si,CompatInfo * info)
|
||
|
{
|
||
|
static char buf[128];
|
||
|
|
||
|
if (si==&info->dflt) {
|
||
|
sprintf(buf,"default");
|
||
|
}
|
||
|
else {
|
||
|
sprintf(buf,"%s+%s(%s)",XkbKeysymText(si->interp.sym,XkbMessage),
|
||
|
XkbSIMatchText(si->interp.match,XkbMessage),
|
||
|
XkbModMaskText(si->interp.mods,XkbMessage));
|
||
|
}
|
||
|
return buf;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
InitCompatInfo(CompatInfo *info,XkbDescPtr xkb)
|
||
|
{
|
||
|
register int i;
|
||
|
|
||
|
info->xkb= xkb;
|
||
|
info->name= NULL;
|
||
|
info->fileID= 0;
|
||
|
info->errorCount= 0;
|
||
|
info->nInterps= 0;
|
||
|
info->interps= NULL;
|
||
|
info->act= NULL;
|
||
|
info->dflt.defs.fileID= info->fileID;
|
||
|
info->dflt.defs.defined= 0;
|
||
|
info->dflt.defs.merge= MergeOverride;
|
||
|
info->dflt.interp.flags= 0;
|
||
|
info->dflt.interp.virtual_mod= XkbNoModifier;
|
||
|
info->dflt.interp.act.type= XkbSA_NoAction;
|
||
|
for (i=0;i<XkbAnyActionDataSize;i++) {
|
||
|
info->dflt.interp.act.data[i]= 0;
|
||
|
}
|
||
|
ClearIndicatorMapInfo(xkb->dpy,&info->ledDflt);
|
||
|
info->ledDflt.defs.fileID= info->fileID;
|
||
|
info->ledDflt.defs.defined= 0;
|
||
|
info->ledDflt.defs.merge= MergeOverride;
|
||
|
bzero((char *)&info->groupCompat[0],XkbNumKbdGroups*sizeof(GroupCompatInfo));
|
||
|
info->leds= NULL;
|
||
|
InitVModInfo(&info->vmods,xkb);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ClearCompatInfo(CompatInfo *info,XkbDescPtr xkb)
|
||
|
{
|
||
|
register int i;
|
||
|
|
||
|
if (info->name!=NULL)
|
||
|
uFree(info->name);
|
||
|
info->name= NULL;
|
||
|
info->dflt.defs.defined= 0;
|
||
|
info->dflt.defs.merge= MergeAugment;
|
||
|
info->dflt.interp.flags= 0;
|
||
|
info->dflt.interp.virtual_mod= XkbNoModifier;
|
||
|
info->dflt.interp.act.type= XkbSA_NoAction;
|
||
|
for (i=0;i<XkbAnyActionDataSize;i++) {
|
||
|
info->dflt.interp.act.data[i]= 0;
|
||
|
}
|
||
|
ClearIndicatorMapInfo(xkb->dpy,&info->ledDflt);
|
||
|
info->nInterps= 0;
|
||
|
info->interps= (SymInterpInfo *)ClearCommonInfo(&info->interps->defs);
|
||
|
bzero((char *)&info->groupCompat[0],XkbNumKbdGroups*sizeof(GroupCompatInfo));
|
||
|
info->leds= (LEDInfo *)ClearCommonInfo(&info->leds->defs);
|
||
|
/* 3/30/94 (ef) -- XXX! Should free action info here */
|
||
|
ClearVModInfo(&info->vmods,xkb);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static SymInterpInfo *
|
||
|
NextInterp(CompatInfo *info)
|
||
|
{
|
||
|
SymInterpInfo * si;
|
||
|
|
||
|
si= uTypedAlloc(SymInterpInfo);
|
||
|
if (si) {
|
||
|
bzero((char *)si,sizeof(SymInterpInfo));
|
||
|
info->interps= (SymInterpInfo *)AddCommonInfo(&info->interps->defs,
|
||
|
(CommonInfo *)si);
|
||
|
info->nInterps++;
|
||
|
}
|
||
|
return si;
|
||
|
}
|
||
|
|
||
|
static SymInterpInfo *
|
||
|
FindMatchingInterp(CompatInfo *info,SymInterpInfo *new)
|
||
|
{
|
||
|
SymInterpInfo * old;
|
||
|
|
||
|
for (old= info->interps;old!=NULL;old=(SymInterpInfo *)old->defs.next) {
|
||
|
if ((old->interp.sym==new->interp.sym)&&
|
||
|
(old->interp.mods==new->interp.mods)&&
|
||
|
(old->interp.match==new->interp.match)) {
|
||
|
return old;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
AddInterp(CompatInfo *info,SymInterpInfo *new)
|
||
|
{
|
||
|
unsigned collide;
|
||
|
SymInterpInfo * old;
|
||
|
|
||
|
collide= 0;
|
||
|
old= FindMatchingInterp(info,new);
|
||
|
if (old!=NULL) {
|
||
|
if (new->defs.merge==MergeReplace) {
|
||
|
SymInterpInfo *next= (SymInterpInfo *)old->defs.next;
|
||
|
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
|
||
|
(warningLevel>9)) {
|
||
|
WARN1("Multiple definitions for \"%s\"\n",siText(new,info));
|
||
|
ACTION("Earlier interpretation ignored\n");
|
||
|
}
|
||
|
*old= *new;
|
||
|
old->defs.next= &next->defs;
|
||
|
return True;
|
||
|
}
|
||
|
if (UseNewField(_SI_VirtualMod,&old->defs,&new->defs,&collide)) {
|
||
|
old->interp.virtual_mod= new->interp.virtual_mod;
|
||
|
old->defs.defined|= _SI_VirtualMod;
|
||
|
}
|
||
|
if (UseNewField(_SI_Action,&old->defs,&new->defs,&collide)) {
|
||
|
old->interp.act= new->interp.act;
|
||
|
old->defs.defined|= _SI_Action;
|
||
|
}
|
||
|
if (UseNewField(_SI_AutoRepeat,&old->defs,&new->defs,&collide)) {
|
||
|
old->interp.flags&= ~XkbSI_AutoRepeat;
|
||
|
old->interp.flags|= (new->interp.flags&XkbSI_AutoRepeat);
|
||
|
old->defs.defined|= _SI_AutoRepeat;
|
||
|
}
|
||
|
if (UseNewField(_SI_LockingKey,&old->defs,&new->defs,&collide)) {
|
||
|
old->interp.flags&= ~XkbSI_LockingKey;
|
||
|
old->interp.flags|= (new->interp.flags&XkbSI_LockingKey);
|
||
|
old->defs.defined|= _SI_LockingKey;
|
||
|
}
|
||
|
if (UseNewField(_SI_LevelOneOnly,&old->defs,&new->defs,&collide)) {
|
||
|
old->interp.match&= ~XkbSI_LevelOneOnly;
|
||
|
old->interp.match|= (new->interp.match&XkbSI_LevelOneOnly);
|
||
|
old->defs.defined|= _SI_LevelOneOnly;
|
||
|
}
|
||
|
if (collide) {
|
||
|
WARN1("Multiple interpretations of \"%s\"\n",siText(new,info));
|
||
|
ACTION1("Using %s definition for duplicate fields\n",
|
||
|
(new->defs.merge!=MergeAugment?"last":"first"));
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
old= new;
|
||
|
if ((new= NextInterp(info))==NULL)
|
||
|
return False;
|
||
|
*new= *old;
|
||
|
new->defs.next= NULL;
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
AddGroupCompat(CompatInfo *info,unsigned group,GroupCompatInfo *newGC)
|
||
|
{
|
||
|
GroupCompatInfo * gc;
|
||
|
unsigned merge;
|
||
|
|
||
|
merge= newGC->merge;
|
||
|
gc= &info->groupCompat[group];
|
||
|
if ((newGC->fileID<0)||
|
||
|
((gc->real_mods==newGC->real_mods)&&(gc->vmods==newGC->vmods))) {
|
||
|
return True;
|
||
|
}
|
||
|
if (((gc->fileID==newGC->fileID)&&(warningLevel>0))||(warningLevel>9)) {
|
||
|
WARN1("Compat map for group %d redefined\n",group+1);
|
||
|
ACTION1("Using %s definition\n",(merge==MergeAugment?"old":"new"));
|
||
|
}
|
||
|
if (merge!=MergeAugment)
|
||
|
*gc= *newGC;
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
/***====================================================================***/
|
||
|
|
||
|
static Bool
|
||
|
ResolveStateAndPredicate( ExprDef * expr,
|
||
|
unsigned * pred_rtrn,
|
||
|
unsigned * mods_rtrn,
|
||
|
CompatInfo * info)
|
||
|
{
|
||
|
ExprResult result;
|
||
|
|
||
|
if (expr==NULL) {
|
||
|
*pred_rtrn= XkbSI_AnyOfOrNone;
|
||
|
*mods_rtrn= ~0;
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
*pred_rtrn= XkbSI_Exactly;
|
||
|
if (expr->op==ExprActionDecl) {
|
||
|
char *pred_txt= XkbAtomText(NULL,expr->value.action.name,XkbMessage);
|
||
|
if (uStrCaseCmp(pred_txt,"noneof")==0)
|
||
|
*pred_rtrn= XkbSI_NoneOf;
|
||
|
else if (uStrCaseCmp(pred_txt,"anyofornone")==0)
|
||
|
*pred_rtrn= XkbSI_AnyOfOrNone;
|
||
|
else if (uStrCaseCmp(pred_txt,"anyof")==0)
|
||
|
*pred_rtrn= XkbSI_AnyOf;
|
||
|
else if (uStrCaseCmp(pred_txt,"allof")==0)
|
||
|
*pred_rtrn= XkbSI_AllOf;
|
||
|
else if (uStrCaseCmp(pred_txt,"exactly")==0)
|
||
|
*pred_rtrn= XkbSI_Exactly;
|
||
|
else {
|
||
|
ERROR1("Illegal modifier predicate \"%s\"\n",pred_txt);
|
||
|
ACTION("Ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
expr= expr->value.action.args;
|
||
|
}
|
||
|
else if (expr->op==ExprIdent) {
|
||
|
char *pred_txt= XkbAtomText(NULL,expr->value.str,XkbMessage);
|
||
|
if ((pred_txt)&&(uStrCaseCmp(pred_txt,"any")==0)) {
|
||
|
*pred_rtrn= XkbSI_AnyOf;
|
||
|
*mods_rtrn= 0xff;
|
||
|
return True;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ExprResolveModMask(expr,&result,NULL,NULL)) {
|
||
|
*mods_rtrn= result.uval;
|
||
|
return True;
|
||
|
}
|
||
|
return False;
|
||
|
}
|
||
|
|
||
|
/***====================================================================***/
|
||
|
|
||
|
static void
|
||
|
MergeIncludedCompatMaps( CompatInfo * into,
|
||
|
CompatInfo * from,
|
||
|
unsigned merge)
|
||
|
{
|
||
|
SymInterpInfo * si;
|
||
|
LEDInfo * led,*rtrn,*next;
|
||
|
GroupCompatInfo * gcm;
|
||
|
register int i;
|
||
|
|
||
|
if (from->errorCount>0) {
|
||
|
into->errorCount+= from->errorCount;
|
||
|
return;
|
||
|
}
|
||
|
if (into->name==NULL) {
|
||
|
into->name= from->name;
|
||
|
from->name= NULL;
|
||
|
}
|
||
|
for (si=from->interps;si;si=(SymInterpInfo *)si->defs.next) {
|
||
|
if (merge!=MergeDefault)
|
||
|
si->defs.merge= merge;
|
||
|
if (!AddInterp(into,si))
|
||
|
into->errorCount++;
|
||
|
}
|
||
|
for (i=0,gcm=&from->groupCompat[0];i<XkbNumKbdGroups;i++,gcm++) {
|
||
|
if (merge!=MergeDefault)
|
||
|
gcm->merge= merge;
|
||
|
if (!AddGroupCompat(into,i,gcm))
|
||
|
into->errorCount++;
|
||
|
}
|
||
|
for (led=from->leds;led!=NULL;led=next) {
|
||
|
next= (LEDInfo *)led->defs.next;
|
||
|
if (merge!=MergeDefault)
|
||
|
led->defs.merge= merge;
|
||
|
rtrn= AddIndicatorMap(into->leds,led);
|
||
|
if (rtrn!=NULL)
|
||
|
into->leds= rtrn;
|
||
|
else into->errorCount++;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
typedef void (*FileHandler)(
|
||
|
XkbFile * /* rtrn */,
|
||
|
XkbDescPtr /* xkb */,
|
||
|
unsigned /* merge */,
|
||
|
CompatInfo * /* info */
|
||
|
);
|
||
|
|
||
|
static Bool
|
||
|
HandleIncludeCompatMap( IncludeStmt * stmt,
|
||
|
XkbDescPtr xkb,
|
||
|
CompatInfo * info,
|
||
|
FileHandler hndlr)
|
||
|
{
|
||
|
unsigned newMerge;
|
||
|
XkbFile * rtrn;
|
||
|
CompatInfo included;
|
||
|
Bool haveSelf;
|
||
|
|
||
|
haveSelf= False;
|
||
|
if ((stmt->file==NULL)&&(stmt->map==NULL)) {
|
||
|
haveSelf= True;
|
||
|
included= *info;
|
||
|
bzero(info,sizeof(CompatInfo));
|
||
|
}
|
||
|
else if (ProcessIncludeFile(stmt,XkmCompatMapIndex,&rtrn,&newMerge)) {
|
||
|
InitCompatInfo(&included,xkb);
|
||
|
included.fileID= rtrn->id;
|
||
|
included.dflt= info->dflt;
|
||
|
included.dflt.defs.fileID= rtrn->id;
|
||
|
included.dflt.defs.merge= newMerge;
|
||
|
included.ledDflt.defs.fileID= rtrn->id;
|
||
|
included.ledDflt.defs.merge= newMerge;
|
||
|
included.act= info->act;
|
||
|
(*hndlr)(rtrn,xkb,MergeOverride,&included);
|
||
|
if (stmt->stmt!=NULL) {
|
||
|
if (included.name!=NULL)
|
||
|
uFree(included.name);
|
||
|
included.name= stmt->stmt;
|
||
|
stmt->stmt= NULL;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
info->errorCount+= 10;
|
||
|
return False;
|
||
|
}
|
||
|
if ((stmt->next!=NULL)&&(included.errorCount<1)) {
|
||
|
IncludeStmt * next;
|
||
|
unsigned op;
|
||
|
CompatInfo next_incl;
|
||
|
|
||
|
for (next=stmt->next;next!=NULL;next=next->next) {
|
||
|
if ((next->file==NULL)&&(next->map==NULL)) {
|
||
|
haveSelf= True;
|
||
|
MergeIncludedCompatMaps(&included,info,next->merge);
|
||
|
ClearCompatInfo(info,xkb);
|
||
|
}
|
||
|
else if (ProcessIncludeFile(next,XkmCompatMapIndex,&rtrn,&op)) {
|
||
|
InitCompatInfo(&next_incl,xkb);
|
||
|
next_incl.fileID= rtrn->id;
|
||
|
next_incl.dflt= info->dflt;
|
||
|
next_incl.dflt.defs.fileID= rtrn->id;
|
||
|
next_incl.dflt.defs.merge= op;
|
||
|
next_incl.ledDflt.defs.fileID= rtrn->id;
|
||
|
next_incl.ledDflt.defs.merge= op;
|
||
|
next_incl.act= info->act;
|
||
|
(*hndlr)(rtrn,xkb,MergeOverride,&next_incl);
|
||
|
MergeIncludedCompatMaps(&included,&next_incl,op);
|
||
|
ClearCompatInfo(&next_incl,xkb);
|
||
|
}
|
||
|
else {
|
||
|
info->errorCount+= 10;
|
||
|
return False;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (haveSelf)
|
||
|
*info= included;
|
||
|
else {
|
||
|
MergeIncludedCompatMaps(info,&included,newMerge);
|
||
|
ClearCompatInfo(&included,xkb);
|
||
|
}
|
||
|
return (info->errorCount==0);
|
||
|
}
|
||
|
|
||
|
static LookupEntry useModMapValues[] = {
|
||
|
{ "levelone", 1 },
|
||
|
{ "level1", 1 },
|
||
|
{ "anylevel", 0 },
|
||
|
{ "any", 0 },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
static int
|
||
|
SetInterpField( SymInterpInfo * si,
|
||
|
XkbDescPtr xkb,
|
||
|
char * field,
|
||
|
ExprDef * arrayNdx,
|
||
|
ExprDef * value,
|
||
|
CompatInfo * info)
|
||
|
{
|
||
|
int ok= 1;
|
||
|
ExprResult tmp;
|
||
|
|
||
|
if (uStrCaseCmp(field,"action")==0) {
|
||
|
if (arrayNdx!=NULL)
|
||
|
return ReportSINotArray(si,field,info);
|
||
|
ok= HandleActionDef(value,xkb,&si->interp.act,si->defs.merge,info->act);
|
||
|
if (ok)
|
||
|
si->defs.defined|= _SI_Action;
|
||
|
}
|
||
|
else if ((uStrCaseCmp(field,"virtualmodifier")==0)||
|
||
|
(uStrCaseCmp(field,"virtualmod")==0)) {
|
||
|
if (arrayNdx!=NULL)
|
||
|
return ReportSINotArray(si,field,info);
|
||
|
ok= ResolveVirtualModifier(value,&tmp,&info->vmods);
|
||
|
if (ok) {
|
||
|
si->interp.virtual_mod= tmp.uval;
|
||
|
si->defs.defined|= _SI_VirtualMod;
|
||
|
}
|
||
|
else return ReportSIBadType(si,field,"virtual modifier",info);
|
||
|
}
|
||
|
else if (uStrCaseCmp(field,"repeat")==0) {
|
||
|
if (arrayNdx!=NULL)
|
||
|
return ReportSINotArray(si,field,info);
|
||
|
ok= ExprResolveBoolean(value,&tmp,NULL,NULL);
|
||
|
if (ok) {
|
||
|
if (tmp.uval) si->interp.flags|= XkbSI_AutoRepeat;
|
||
|
else si->interp.flags&= ~XkbSI_AutoRepeat;
|
||
|
si->defs.defined|= _SI_AutoRepeat;
|
||
|
}
|
||
|
else return ReportSIBadType(si,field,"boolean",info);
|
||
|
}
|
||
|
else if (uStrCaseCmp(field,"locking")==0) {
|
||
|
if (arrayNdx!=NULL)
|
||
|
return ReportSINotArray(si,field,info);
|
||
|
ok= ExprResolveBoolean(value,&tmp,NULL,NULL);
|
||
|
if (ok) {
|
||
|
if (tmp.uval) si->interp.flags|= XkbSI_LockingKey;
|
||
|
else si->interp.flags&= ~XkbSI_LockingKey;
|
||
|
si->defs.defined|= _SI_LockingKey;
|
||
|
}
|
||
|
else return ReportSIBadType(si,field,"boolean",info);
|
||
|
}
|
||
|
else if ((uStrCaseCmp(field,"usemodmap")==0)||
|
||
|
(uStrCaseCmp(field,"usemodmapmods")==0)) {
|
||
|
if (arrayNdx!=NULL)
|
||
|
return ReportSINotArray(si,field,info);
|
||
|
ok= ExprResolveEnum(value,&tmp,useModMapValues);
|
||
|
if (ok) {
|
||
|
if (tmp.uval) si->interp.match|= XkbSI_LevelOneOnly;
|
||
|
else si->interp.match&= ~XkbSI_LevelOneOnly;
|
||
|
si->defs.defined|= _SI_LevelOneOnly;
|
||
|
}
|
||
|
else return ReportSIBadType(si,field,"level specification",info);
|
||
|
}
|
||
|
else {
|
||
|
ok= ReportBadField("symbol interpretation",field,siText(si,info));
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
LookupEntry groupNames[]= {
|
||
|
{ "group1", 0x01 },
|
||
|
{ "group2", 0x02 },
|
||
|
{ "group3", 0x04 },
|
||
|
{ "group4", 0x08 },
|
||
|
{ "group5", 0x10 },
|
||
|
{ "group6", 0x20 },
|
||
|
{ "group7", 0x40 },
|
||
|
{ "group8", 0x80 },
|
||
|
{ "none", 0x00 },
|
||
|
{ "all", 0xff },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
static int
|
||
|
HandleInterpVar(VarDef *stmt,XkbDescPtr xkb,CompatInfo *info)
|
||
|
{
|
||
|
ExprResult elem,field;
|
||
|
ExprDef * ndx;
|
||
|
|
||
|
if (ExprResolveLhs(stmt->name,&elem,&field,&ndx)==0)
|
||
|
return 0; /* internal error, already reported */
|
||
|
if (elem.str&&(uStrCaseCmp(elem.str,"interpret")==0))
|
||
|
return SetInterpField(&info->dflt,xkb,field.str,ndx,stmt->value,info);
|
||
|
if (elem.str&&(uStrCaseCmp(elem.str,"indicator")==0)) {
|
||
|
return SetIndicatorMapField(&info->ledDflt,xkb,field.str,ndx,
|
||
|
stmt->value);
|
||
|
}
|
||
|
return SetActionField(xkb,elem.str,field.str,ndx,stmt->value,&info->act);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
HandleInterpBody(VarDef *def,XkbDescPtr xkb,SymInterpInfo *si,CompatInfo *info)
|
||
|
{
|
||
|
int ok= 1;
|
||
|
ExprResult tmp,field;
|
||
|
ExprDef * arrayNdx;
|
||
|
|
||
|
for (;def!=NULL;def= (VarDef *)def->common.next) {
|
||
|
if ((def->name)&&(def->name->type==ExprFieldRef)) {
|
||
|
ok= HandleInterpVar(def,xkb,info);
|
||
|
continue;
|
||
|
}
|
||
|
ok= ExprResolveLhs(def->name,&tmp,&field,&arrayNdx);
|
||
|
if (ok)
|
||
|
ok= SetInterpField(si,xkb,field.str,arrayNdx,def->value,info);
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
HandleInterpDef(InterpDef *def,XkbDescPtr xkb,unsigned merge,CompatInfo *info)
|
||
|
{
|
||
|
unsigned pred,mods;
|
||
|
SymInterpInfo si;
|
||
|
|
||
|
if (!ResolveStateAndPredicate(def->match,&pred,&mods,info)) {
|
||
|
ERROR("Couldn't determine matching modifiers\n");
|
||
|
ACTION("Symbol interpretation ignored\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (def->merge!=MergeDefault)
|
||
|
merge= def->merge;
|
||
|
|
||
|
si= info->dflt;
|
||
|
si.defs.merge= merge;
|
||
|
si.interp.sym= def->sym;
|
||
|
si.interp.match= pred & XkbSI_OpMask;
|
||
|
si.interp.mods= mods;
|
||
|
if (!HandleInterpBody(def->def,xkb,&si,info)) {
|
||
|
info->errorCount++;
|
||
|
return False;
|
||
|
}
|
||
|
|
||
|
if (!AddInterp(info,&si)) {
|
||
|
info->errorCount++;
|
||
|
return False;
|
||
|
}
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
HandleGroupCompatDef( GroupCompatDef * def,
|
||
|
XkbDescPtr xkb,
|
||
|
unsigned merge,
|
||
|
CompatInfo * info)
|
||
|
{
|
||
|
ExprResult val;
|
||
|
GroupCompatInfo tmp;
|
||
|
|
||
|
if (def->merge!=MergeDefault)
|
||
|
merge= def->merge;
|
||
|
if (!XkbIsLegalGroup(def->group-1)) {
|
||
|
ERROR1("Keyboard group must be in the range 1..%d\n",XkbNumKbdGroups+1);
|
||
|
ACTION1("Compatibility map for illegal group %d ignored\n",def->group);
|
||
|
return False;
|
||
|
}
|
||
|
tmp.fileID= info->fileID;
|
||
|
tmp.merge= merge;
|
||
|
if (!ExprResolveModMask(def->def,&val,LookupVModMask,(XPointer)xkb)) {
|
||
|
ERROR("Expected a modifier mask in group compatibility definition\n");
|
||
|
ACTION1("Ignoring illegal compatibility map for group %d\n",def->group);
|
||
|
return False;
|
||
|
}
|
||
|
tmp.real_mods= val.uval&0xff;
|
||
|
tmp.vmods= (val.uval>>8)&0xffff;
|
||
|
return AddGroupCompat(info,def->group-1,&tmp);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
HandleCompatMapFile( XkbFile * file,
|
||
|
XkbDescPtr xkb,
|
||
|
unsigned merge,
|
||
|
CompatInfo * info)
|
||
|
{
|
||
|
ParseCommon *stmt;
|
||
|
|
||
|
if (merge==MergeDefault)
|
||
|
merge= MergeAugment;
|
||
|
info->name= uStringDup(file->name);
|
||
|
stmt= file->defs;
|
||
|
while (stmt) {
|
||
|
switch (stmt->stmtType) {
|
||
|
case StmtInclude:
|
||
|
if (!HandleIncludeCompatMap((IncludeStmt *)stmt,xkb,info,
|
||
|
HandleCompatMapFile))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtInterpDef:
|
||
|
if (!HandleInterpDef((InterpDef *)stmt,xkb,merge,info))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtGroupCompatDef:
|
||
|
if (!HandleGroupCompatDef((GroupCompatDef*)stmt,xkb,merge,info))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtIndicatorMapDef:
|
||
|
{
|
||
|
LEDInfo *rtrn;
|
||
|
rtrn= HandleIndicatorMapDef((IndicatorMapDef *)stmt,xkb,
|
||
|
&info->ledDflt,info->leds,
|
||
|
merge);
|
||
|
if (rtrn!=NULL)
|
||
|
info->leds= rtrn;
|
||
|
else info->errorCount++;
|
||
|
}
|
||
|
break;
|
||
|
case StmtVarDef:
|
||
|
if (!HandleInterpVar((VarDef *)stmt,xkb,info))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtVModDef:
|
||
|
if (!HandleVModDef((VModDef *)stmt,merge,&info->vmods))
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
case StmtKeycodeDef:
|
||
|
ERROR("Interpretation files may not include other types\n");
|
||
|
ACTION("Ignoring definition of key name\n");
|
||
|
info->errorCount++;
|
||
|
break;
|
||
|
default:
|
||
|
WSGO1("Unexpected statement type %d in HandleCompatMapFile\n",
|
||
|
stmt->stmtType);
|
||
|
break;
|
||
|
}
|
||
|
stmt= stmt->next;
|
||
|
if (info->errorCount>10) {
|
||
|
#ifdef NOISY
|
||
|
ERROR("Too many errors\n");
|
||
|
#endif
|
||
|
ACTION1("Abandoning compatibility map \"%s\"\n",file->topName);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
CopyInterps( CompatInfo * info,
|
||
|
XkbCompatMapPtr compat,
|
||
|
Bool needSymbol,
|
||
|
unsigned pred)
|
||
|
{
|
||
|
SymInterpInfo * si;
|
||
|
|
||
|
for (si=info->interps;si;si=(SymInterpInfo *)si->defs.next) {
|
||
|
if (((si->interp.match&XkbSI_OpMask)!=pred)||
|
||
|
(needSymbol&&(si->interp.sym==NoSymbol))||
|
||
|
((!needSymbol)&&(si->interp.sym!=NoSymbol)))
|
||
|
continue;
|
||
|
if (compat->num_si>=compat->size_si) {
|
||
|
WSGO("No room to merge symbol interpretations\n");
|
||
|
ACTION("Symbol interpretations lost\n");
|
||
|
return;
|
||
|
}
|
||
|
compat->sym_interpret[compat->num_si++]= si->interp;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
CompileCompatMap( XkbFile * file,
|
||
|
XkbFileInfo * result,
|
||
|
unsigned merge,
|
||
|
LEDInfo ** unboundLEDs)
|
||
|
{
|
||
|
int i;
|
||
|
CompatInfo info;
|
||
|
XkbDescPtr xkb;
|
||
|
GroupCompatInfo * gcm;
|
||
|
|
||
|
xkb= result->xkb;
|
||
|
InitCompatInfo(&info,xkb);
|
||
|
info.dflt.defs.merge= merge;
|
||
|
info.ledDflt.defs.merge= merge;
|
||
|
HandleCompatMapFile(file,xkb,merge,&info);
|
||
|
|
||
|
if (info.errorCount==0) {
|
||
|
int size;
|
||
|
if (XkbAllocCompatMap(xkb,XkbAllCompatMask,info.nInterps)!=Success) {
|
||
|
WSGO("Couldn't allocate compatibility map\n");
|
||
|
ACTION("Exiting\n");
|
||
|
return False;
|
||
|
}
|
||
|
if (info.name!=NULL) {
|
||
|
if (XkbAllocNames(xkb,XkbCompatNameMask,0,0)==Success)
|
||
|
xkb->names->compat= XkbInternAtom(xkb->dpy,info.name,False);
|
||
|
else {
|
||
|
WSGO("Couldn't allocate space for compat name\n");
|
||
|
ACTION2("Name \"%s\" (from %s) NOT assigned\n",scanFile,
|
||
|
info.name);
|
||
|
}
|
||
|
}
|
||
|
size= info.nInterps*sizeof(XkbSymInterpretRec);
|
||
|
if (size>0) {
|
||
|
CopyInterps(&info,xkb->compat,True,XkbSI_Exactly);
|
||
|
CopyInterps(&info,xkb->compat,True,XkbSI_AllOf|XkbSI_NoneOf);
|
||
|
CopyInterps(&info,xkb->compat,True,XkbSI_AnyOf);
|
||
|
CopyInterps(&info,xkb->compat,True,XkbSI_AnyOfOrNone);
|
||
|
CopyInterps(&info,xkb->compat,False,XkbSI_Exactly);
|
||
|
CopyInterps(&info,xkb->compat,False,XkbSI_AllOf|XkbSI_NoneOf);
|
||
|
CopyInterps(&info,xkb->compat,False,XkbSI_AnyOf);
|
||
|
CopyInterps(&info,xkb->compat,False,XkbSI_AnyOfOrNone);
|
||
|
}
|
||
|
for (i=0,gcm=&info.groupCompat[0];i<XkbNumKbdGroups;i++,gcm++) {
|
||
|
if ((gcm->fileID!=0)||(gcm->real_mods!=0)||(gcm->vmods!=0)) {
|
||
|
xkb->compat->groups[i].mask= gcm->real_mods;
|
||
|
xkb->compat->groups[i].real_mods= gcm->real_mods;
|
||
|
xkb->compat->groups[i].vmods= gcm->vmods;
|
||
|
}
|
||
|
}
|
||
|
if (info.leds!=NULL) {
|
||
|
if (!CopyIndicatorMapDefs(result,info.leds,unboundLEDs))
|
||
|
info.errorCount++;
|
||
|
info.leds= NULL;
|
||
|
}
|
||
|
ClearCompatInfo(&info,xkb);
|
||
|
return True;
|
||
|
}
|
||
|
if (info.interps!=NULL)
|
||
|
uFree(info.interps);
|
||
|
return False;
|
||
|
}
|