#include "xkbcomp.h"
#include "tokens.h"
#include "expr.h"
#include "vmod.h"
#include "action.h"
#include "misc.h"
typedef struct _PreserveInfo {
CommonInfo defs;
short matchingMapIndex;
unsigned char indexMods;
unsigned char preMods;
unsigned short indexVMods;
unsigned short preVMods;
} PreserveInfo;
#define _KT_Name (1<<0)
#define _KT_Mask (1<<1)
#define _KT_Map (1<<2)
#define _KT_Preserve (1<<3)
#define _KT_LevelNames (1<<4)
typedef struct _KeyTypeInfo {
CommonInfo defs;
Display * dpy;
Atom name;
int fileID;
unsigned mask;
unsigned vmask;
Bool groupInfo;
int numLevels;
int nEntries;
int szEntries;
XkbKTMapEntryPtr entries;
PreserveInfo * preserve;
int szNames;
Atom * lvlNames;
} KeyTypeInfo;
typedef struct _KeyTypesInfo {
Display * dpy;
char * name;
int errorCount;
int fileID;
unsigned stdPresent;
int nTypes;
KeyTypeInfo * types;
KeyTypeInfo dflt;
VModInfo vmods;
} KeyTypesInfo;
Atom tok_ONE_LEVEL;
Atom tok_TWO_LEVEL;
Atom tok_ALPHABETIC;
Atom tok_KEYPAD;
#define ReportTypeShouldBeArray(t,f) \
ReportShouldBeArray("key type",(f),TypeTxt(t))
#define ReportTypeBadType(t,f,w) \
ReportBadType("key type",(f),TypeTxt(t),(w))
extern Bool AddMapEntry(
XkbDescPtr ,
KeyTypeInfo * ,
XkbKTMapEntryPtr ,
Bool ,
Bool
);
extern Bool AddPreserve(
XkbDescPtr ,
KeyTypeInfo * ,
PreserveInfo * ,
Bool ,
Bool
);
extern Bool AddLevelName(
KeyTypeInfo * ,
unsigned ,
Atom ,
Bool ,
Bool
);
#define MapEntryTxt(t,x,e) \
XkbVModMaskText((t)->dpy,(x),(e)->mods.real_mods,(e)->mods.vmods,XkbMessage)
#define PreserveIndexTxt(t,x,p) \
XkbVModMaskText((t)->dpy,(x),(p)->indexMods,(p)->indexVMods,XkbMessage)
#define PreserveTxt(t,x,p) \
XkbVModMaskText((t)->dpy,(x),(p)->preMods,(p)->preVMods,XkbMessage)
#define TypeTxt(t) XkbAtomText((t)->dpy,(t)->name,XkbMessage)
#define TypeMaskTxt(t,x) \
XkbVModMaskText((t)->dpy,(x),(t)->mask,(t)->vmask,XkbMessage)
static void
InitKeyTypesInfo(KeyTypesInfo *info,XkbDescPtr xkb,KeyTypesInfo *from)
{
tok_ONE_LEVEL= XkbInternAtom(NULL,"ONE_LEVEL",False);
tok_TWO_LEVEL= XkbInternAtom(NULL,"TWO_LEVEL",False);
tok_ALPHABETIC= XkbInternAtom(NULL,"ALPHABETIC",False);
tok_KEYPAD= XkbInternAtom(NULL,"KEYPAD",False);
info->dpy= NULL;
info->name= uStringDup("default");
info->errorCount= 0;
info->stdPresent= 0;
info->nTypes= 0;
info->types= NULL;
info->dflt.defs.defined= 0;
info->dflt.defs.fileID= 0;
info->dflt.defs.merge= MergeOverride;
info->dflt.defs.next= NULL;
info->dflt.name= None;
info->dflt.mask= 0;
info->dflt.vmask= 0;
info->dflt.groupInfo= False;
info->dflt.numLevels= 1;
info->dflt.nEntries= info->dflt.szEntries= 0;
info->dflt.entries= NULL;
info->dflt.szNames= 0;
info->dflt.lvlNames= NULL;
info->dflt.preserve= NULL;
InitVModInfo(&info->vmods,xkb);
if (from!=NULL) {
info->dpy= from->dpy;
info->dflt= from->dflt;
if (from->dflt.entries) {
info->dflt.entries= uTypedCalloc(from->dflt.szEntries,
XkbKTMapEntryRec);
if (info->dflt.entries) {
unsigned sz = from->dflt.nEntries*sizeof(XkbKTMapEntryRec);
memcpy(info->dflt.entries,from->dflt.entries,sz);
}
}
if (from->dflt.lvlNames) {
info->dflt.lvlNames= uTypedCalloc(from->dflt.szNames,Atom);
if (info->dflt.lvlNames) {
register unsigned sz = from->dflt.szNames*sizeof(Atom);
memcpy(info->dflt.lvlNames,from->dflt.lvlNames,sz);
}
}
if (from->dflt.preserve) {
PreserveInfo *old,*new,*last;
last= NULL;
old= from->dflt.preserve;
for (;old;old=(PreserveInfo *)old->defs.next) {
new= uTypedAlloc(PreserveInfo);
if (!new)
return;
*new= *old;
new->defs.next= NULL;
if (last) last->defs.next= (CommonInfo *)new;
else info->dflt.preserve= new;
last= new;
}
}
}
return;
}
static void
FreeKeyTypeInfo(KeyTypeInfo *type)
{
if (type->entries!=NULL) {
uFree(type->entries);
type->entries= NULL;
}
if (type->lvlNames!=NULL) {
uFree(type->lvlNames);
type->lvlNames= NULL;
}
if (type->preserve!=NULL) {
ClearCommonInfo(&type->preserve->defs);
type->preserve= NULL;
}
return;
}
static void
FreeKeyTypesInfo(KeyTypesInfo *info)
{
info->dpy= NULL;
if (info->name)
uFree(info->name);
info->name= NULL;
if (info->types) {
register KeyTypeInfo *type;
for (type= info->types;type;type=(KeyTypeInfo *)type->defs.next) {
FreeKeyTypeInfo(type);
}
info->types= (KeyTypeInfo *)ClearCommonInfo(&info->types->defs);
}
FreeKeyTypeInfo(&info->dflt);
return;
}
static KeyTypeInfo *
NextKeyType(KeyTypesInfo *info)
{
KeyTypeInfo * type;
type= uTypedAlloc(KeyTypeInfo);
if (type!=NULL) {
bzero(type,sizeof(KeyTypeInfo));
type->defs.fileID= info->fileID;
type->dpy= info->dpy;
info->types= (KeyTypeInfo *)AddCommonInfo(&info->types->defs,
(CommonInfo *)type);
info->nTypes++;
}
return type;
}
static KeyTypeInfo *
FindMatchingKeyType(KeyTypesInfo *info,KeyTypeInfo *new)
{
KeyTypeInfo *old;
for (old=info->types;old;old=(KeyTypeInfo *)old->defs.next) {
if (old->name==new->name)
return old;
}
return NULL;
}
static Bool
ReportTypeBadWidth(char *type,int has,int needs)
{
ERROR3("Key type \"%s\" has %d levels, must have %d\n",type,has,needs);
ACTION("Illegal type definition ignored\n");
return False;
}
static Bool
AddKeyType(XkbDescPtr xkb,KeyTypesInfo *info,KeyTypeInfo *new)
{
KeyTypeInfo * old;
if (new->name==tok_ONE_LEVEL) {
if (new->numLevels>1)
return ReportTypeBadWidth("ONE_LEVEL",new->numLevels,1);
info->stdPresent|= XkbOneLevelMask;
}
else if (new->name==tok_TWO_LEVEL) {
if (new->numLevels>2)
return ReportTypeBadWidth("TWO_LEVEL",new->numLevels,2);
else if (new->numLevels<2)
new->numLevels= 2;
info->stdPresent|= XkbTwoLevelMask;
}
else if (new->name==tok_ALPHABETIC) {
if (new->numLevels>2)
return ReportTypeBadWidth("ALPHABETIC",new->numLevels,2);
else if (new->numLevels<2)
new->numLevels= 2;
info->stdPresent|= XkbAlphabeticMask;
}
else if (new->name==tok_KEYPAD) {
if (new->numLevels>2)
return ReportTypeBadWidth("KEYPAD",new->numLevels,2);
else if (new->numLevels<2)
new->numLevels= 2;
info->stdPresent|= XkbKeypadMask;
}
old= FindMatchingKeyType(info,new);
if (old!=NULL) {
Bool report;
if ((new->defs.merge==MergeReplace)||(new->defs.merge==MergeOverride)) {
KeyTypeInfo *next= (KeyTypeInfo *)old->defs.next;
if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
(warningLevel>9)) {
WARN1("Multiple definitions of the %s key type\n",
XkbAtomGetString(NULL,new->name));
ACTION("Earlier definition ignored\n");
}
FreeKeyTypeInfo(old);
*old= *new;
new->szEntries= new->nEntries= 0;
new->entries= NULL;
new->preserve= NULL;
new->lvlNames= NULL;
old->defs.next= &next->defs;
return True;
}
report= (old->defs.fileID==new->defs.fileID)&&(warningLevel>0);
if (report) {
WARN1("Multiple definitions of the %s key type\n",
XkbAtomGetString(NULL,new->name));
ACTION("Later definition ignored\n");
}
FreeKeyTypeInfo(new);
return True;
}
old= NextKeyType(info);
if (old==NULL)
return False;
*old= *new;
old->defs.next= NULL;
new->nEntries= new->szEntries= 0;
new->entries= NULL;
new->szNames= 0;
new->lvlNames= NULL;
new->preserve= NULL;
return True;
}
static void
MergeIncludedKeyTypes( KeyTypesInfo * into,
KeyTypesInfo * from,
unsigned merge,
XkbDescPtr xkb)
{
KeyTypeInfo * type;
if (from->errorCount>0) {
into->errorCount+= from->errorCount;
return;
}
if (into->name==NULL) {
into->name= from->name;
from->name= NULL;
}
for (type=from->types;type;type=(KeyTypeInfo *)type->defs.next) {
if (merge!=MergeDefault)
type->defs.merge= merge;
if (!AddKeyType(xkb,into,type))
into->errorCount++;
}
into->stdPresent|= from->stdPresent;
return;
}
typedef void (*FileHandler)(
XkbFile * ,
XkbDescPtr ,
unsigned ,
KeyTypesInfo *
);
static Bool
HandleIncludeKeyTypes( IncludeStmt * stmt,
XkbDescPtr xkb,
KeyTypesInfo * info,
FileHandler hndlr)
{
unsigned newMerge;
XkbFile * rtrn;
KeyTypesInfo included;
Bool haveSelf;
haveSelf= False;
if ((stmt->file==NULL)&&(stmt->map==NULL)) {
haveSelf= True;
included= *info;
bzero(info,sizeof(KeyTypesInfo));
}
else if (ProcessIncludeFile(stmt,XkmTypesIndex,&rtrn,&newMerge)) {
InitKeyTypesInfo(&included,xkb,info);
included.fileID= included.dflt.defs.fileID= rtrn->id;
included.dflt.defs.merge= newMerge;
(*hndlr)(rtrn,xkb,newMerge,&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;
KeyTypesInfo next_incl;
for (next=stmt->next;next!=NULL;next=next->next) {
if ((next->file==NULL)&&(next->map==NULL)) {
haveSelf= True;
MergeIncludedKeyTypes(&included,info,next->merge,xkb);
FreeKeyTypesInfo(info);
}
else if (ProcessIncludeFile(next,XkmTypesIndex,&rtrn,&op)) {
InitKeyTypesInfo(&next_incl,xkb,&included);
next_incl.fileID= next_incl.dflt.defs.fileID= rtrn->id;
next_incl.dflt.defs.merge= op;
(*hndlr)(rtrn,xkb,op,&next_incl);
MergeIncludedKeyTypes(&included,&next_incl,op,xkb);
FreeKeyTypesInfo(&next_incl);
}
else {
info->errorCount+= 10;
return False;
}
}
}
if (haveSelf)
*info= included;
else {
MergeIncludedKeyTypes(info,&included,newMerge,xkb);
FreeKeyTypesInfo(&included);
}
return (info->errorCount==0);
}
static XkbKTMapEntryPtr
FindMatchingMapEntry(KeyTypeInfo *type,unsigned mask,unsigned vmask)
{
register int i;
XkbKTMapEntryPtr entry;
for (i=0,entry=type->entries;i<type->nEntries;i++,entry++) {
if ((entry->mods.real_mods==mask)&&(entry->mods.vmods==vmask))
return entry;
}
return NULL;
}
static void
DeleteLevel1MapEntries(KeyTypeInfo *type)
{
register int i,n;
for (i=0;i<type->nEntries;i++) {
if (type->entries[i].level==0) {
for (n=i;n<type->nEntries-1;n++) {
type->entries[n]= type->entries[n+1];
}
type->nEntries--;
}
}
return;
}
static XkbKTMapEntryPtr
NextMapEntry(KeyTypeInfo *type)
{
if (type->entries==NULL) {
type->entries= uTypedCalloc(2,XkbKTMapEntryRec);
if (type->entries==NULL) {
ERROR1("Couldn't allocate map entries for %s\n",TypeTxt(type));
ACTION("Map entries lost\n");
return NULL;
}
type->szEntries= 2;
type->nEntries= 0;
}
else if (type->nEntries>=type->szEntries) {
type->szEntries*=2;
type->entries= uTypedRecalloc(type->entries,
type->nEntries,type->szEntries,
XkbKTMapEntryRec);
if (type->entries==NULL) {
ERROR1("Couldn't reallocate map entries for %s\n",TypeTxt(type));
ACTION("Map entries lost\n");
return NULL;
}
}
return &type->entries[type->nEntries++];
}
Bool
AddPreserve( XkbDescPtr xkb,
KeyTypeInfo * type,
PreserveInfo * new,
Bool clobber,
Bool report)
{
PreserveInfo *old;
old= type->preserve;
while (old!=NULL) {
if ((old->indexMods!=new->indexMods)||
(old->indexVMods!=new->indexVMods)) {
old= (PreserveInfo *)old->defs.next;
continue;
}
if ((old->preMods==new->preMods)&&(old->preVMods==new->preVMods)) {
if (warningLevel>9) {
WARN2("Identical definitions for preserve[%s] in %s\n",
PreserveIndexTxt(type,xkb,old),TypeTxt(type));
ACTION("Ignored\n");
}
return True;
}
if (report && (warningLevel>0)) {
char *str;
WARN2("Multiple definitions for preserve[%s] in %s\n",
PreserveIndexTxt(type,xkb,old),TypeTxt(type));
if (clobber) str= PreserveTxt(type,xkb,new);
else str= PreserveTxt(type,xkb,old);
ACTION1("Using %s, ",str);
if (clobber) str= PreserveTxt(type,xkb,old);
else str= PreserveTxt(type,xkb,new);
INFO1("ignoring %s\n",str);
}
if (clobber) {
old->preMods= new->preMods;
old->preVMods= new->preVMods;
}
return True;
}
old= uTypedAlloc(PreserveInfo);
if (!old) {
WSGO1("Couldn't allocate preserve in %s\n",TypeTxt(type));
ACTION1("Preserve[%s] lost\n",PreserveIndexTxt(type,xkb,old));
return False;
}
*old= *new;
old->matchingMapIndex= -1;
type->preserve=(PreserveInfo*)AddCommonInfo(&type->preserve->defs,&old->defs);
return True;
}
Bool
AddMapEntry( XkbDescPtr xkb,
KeyTypeInfo * type,
XkbKTMapEntryPtr new,
Bool clobber,
Bool report)
{
XkbKTMapEntryPtr old;
if ((old=FindMatchingMapEntry(type,new->mods.real_mods,new->mods.vmods))) {
if (report&&(old->level!=new->level)) {
unsigned use,ignore;
if (clobber) {
use= new->level+1;
ignore= old->level+1;
}
else {
use= old->level+1;
ignore= new->level+1;
}
WARN2("Multiple map entries for %s in %s\n",
MapEntryTxt(type,xkb,new),TypeTxt(type));
ACTION2("Using %d, ignoring %d\n",use,ignore);
}
else if (warningLevel>9) {
WARN3("Multiple occurences of map[%s]= %d in %s\n",
MapEntryTxt(type,xkb,new),new->level+1,TypeTxt(type));
ACTION("Ignored\n");
return True;
}
if (clobber)
old->level= new->level;
return True;
}
if ((old=NextMapEntry(type))==NULL)
return False;
if (new->level>=type->numLevels)
type->numLevels= new->level+1;
if (new->mods.vmods==0) old->active= True;
else old->active= False;
old->mods.mask= new->mods.real_mods;
old->mods.real_mods= new->mods.real_mods;
old->mods.vmods= new->mods.vmods;
old->level= new->level;
return True;
}
static LookupEntry lnames[] = {
{ "level1", 1 },
{ "level2", 2 },
{ "level3", 3 },
{ "level4", 4 },
{ "level5", 5 },
{ "level6", 6 },
{ "level7", 7 },
{ "level8", 8 },
{ NULL, 0 }
};
static Bool
SetMapEntry( KeyTypeInfo * type,
XkbDescPtr xkb,
ExprDef * arrayNdx,
ExprDef * value)
{
ExprResult rtrn;
XkbKTMapEntryRec entry;
if (arrayNdx==NULL)
return ReportTypeShouldBeArray(type,"map entry");
if (!ExprResolveModMask(arrayNdx,&rtrn,LookupVModMask,(XPointer)xkb))
return ReportTypeBadType(type,"map entry","modifier mask");
entry.mods.real_mods= rtrn.uval&0xff;
entry.mods.vmods= (rtrn.uval>>8)&0xffff;
if ((entry.mods.real_mods&(~type->mask))||
((entry.mods.vmods&(~type->vmask))!=0)) {
if (warningLevel>0) {
WARN1("Map entry for unused modifiers in %s\n",TypeTxt(type));
ACTION1("Using %s instead of ",XkbVModMaskText(type->dpy,xkb,
entry.mods.real_mods&type->mask,
entry.mods.vmods&type->vmask,
XkbMessage));
INFO1("%s\n",MapEntryTxt(type,xkb,&entry));
}
entry.mods.real_mods&= type->mask;
entry.mods.vmods&= type->vmask;
}
if (!ExprResolveInteger(value,&rtrn,SimpleLookup,(XPointer)lnames)) {
ERROR("Level specifications in a key type must be integer\n");
ACTION("Ignoring malformed level specification\n");
return False;
}
if ((rtrn.ival<1)||(rtrn.ival>XkbMaxShiftLevel+1)) {
ERROR3("Shift level %d out of range (1..%d) in key type %s\n",
XkbMaxShiftLevel+1,
rtrn.ival,TypeTxt(type));
ACTION1("Ignoring illegal definition of map[%s]\n",
MapEntryTxt(type,xkb,&entry));
return False;
}
entry.level= rtrn.ival-1;
return AddMapEntry(xkb,type,&entry,True,True);
}
static Bool
SetPreserve( KeyTypeInfo * type,
XkbDescPtr xkb,
ExprDef * arrayNdx,
ExprDef * value)
{
ExprResult rtrn;
PreserveInfo new;
if (arrayNdx==NULL)
return ReportTypeShouldBeArray(type,"preserve entry");
if (!ExprResolveModMask(arrayNdx,&rtrn,LookupVModMask,(XPointer)xkb))
return ReportTypeBadType(type,"preserve entry","modifier mask");
new.defs= type->defs;
new.defs.next= NULL;
new.indexMods= rtrn.uval&0xff;
new.indexVMods= (rtrn.uval>>8)&0xffff;
if ((new.indexMods&(~type->mask))||(new.indexVMods&(~type->vmask))) {
if (warningLevel>0) {
WARN1("Preserve for modifiers not used by the %s type\n",
TypeTxt(type));
ACTION1("Index %s converted to ",PreserveIndexTxt(type,xkb,&new));
}
new.indexMods&= type->mask;
new.indexVMods&= type->vmask;
if (warningLevel>0)
INFO1("%s\n",PreserveIndexTxt(type,xkb,&new));
}
if (!ExprResolveModMask(value,&rtrn,LookupVModMask,(XPointer)xkb)) {
ERROR("Preserve value in a key type is not a modifier mask\n");
ACTION2("Ignoring preserve[%s] in type %s\n",
PreserveIndexTxt(type,xkb,&new),
TypeTxt(type));
return False;
}
new.preMods= rtrn.uval&0xff;
new.preVMods= (rtrn.uval>>16)&0xffff;
if ((new.preMods&(~new.indexMods))||(new.preVMods&&(~new.indexVMods))) {
if (warningLevel>0) {
WARN2("Illegal value for preserve[%s] in type %s\n",
PreserveTxt(type,xkb,&new),
TypeTxt(type));
ACTION1("Converted %s to ",PreserveIndexTxt(type,xkb,&new));
}
new.preMods&= new.indexMods;
new.preVMods&= new.indexVMods;
if (warningLevel>0) {
INFO1("%s\n",PreserveIndexTxt(type,xkb,&new));
}
}
return AddPreserve(xkb,type,&new,True,True);
}
Bool
AddLevelName( KeyTypeInfo * type,
unsigned level,
Atom name,
Bool clobber,
Bool report)
{
if ((type->lvlNames==NULL)||(type->szNames<=level)) {
type->lvlNames=
uTypedRecalloc(type->lvlNames,type->szNames,level+1,Atom);
if (type->lvlNames==NULL) {
ERROR1("Couldn't allocate level names for type %s\n",TypeTxt(type));
ACTION("Level names lost\n");
type->szNames= 0;
return False;
}
type->szNames= level+1;
}
else if (type->lvlNames[level]==name) {
if (warningLevel>9) {
WARN2("Duplicate names for level %d of key type %s\n",level+1,
TypeTxt(type));
ACTION("Ignored\n");
}
return True;
}
else if (type->lvlNames[level]!=None) {
if (warningLevel>0) {
char *old,*new;
old= XkbAtomText(type->dpy,type->lvlNames[level],XkbMessage);
new= XkbAtomText(type->dpy,name,XkbMessage);
WARN2("Multiple names for level %d of key type %s\n",level+1,
TypeTxt(type));
if (clobber)
ACTION2("Using %s, ignoring %s\n",new,old);
else ACTION2("Using %s, ignoring %s\n",old,new);
}
if (!clobber)
return True;
}
if (level>=type->numLevels)
type->numLevels= level+1;
type->lvlNames[level]= name;
return True;
}
static Bool
SetLevelName(KeyTypeInfo *type,ExprDef *arrayNdx,ExprDef *value)
{
ExprResult rtrn;
unsigned level;
if (arrayNdx==NULL)
return ReportTypeShouldBeArray(type,"level name");
if (!ExprResolveInteger(arrayNdx,&rtrn,SimpleLookup,(XPointer)lnames))
return ReportTypeBadType(type,"level name","integer");
if ((rtrn.ival<1)||(rtrn.ival>XkbMaxShiftLevel+1)) {
ERROR3("Level name %d out of range (1..%d) in key type %s\n",
rtrn.ival,
XkbMaxShiftLevel+1,
XkbAtomText(type->dpy,type->name,XkbMessage));
ACTION("Ignoring illegal level name definition\n");
return False;
}
level= rtrn.ival-1;
if (!ExprResolveString(value,&rtrn,NULL,NULL)) {
ERROR2("Non-string name for level %d in key type %s\n",level+1,
XkbAtomText(type->dpy,type->name,XkbMessage));
ACTION("Ignoring illegal level name definition\n");
return False;
}
return
AddLevelName(type,level,XkbInternAtom(NULL,rtrn.str,False),True,True);
}
static Bool
SetKeyTypeField( KeyTypeInfo * type,
XkbDescPtr xkb,
char * field,
ExprDef * arrayNdx,
ExprDef * value,
KeyTypesInfo * info)
{
ExprResult tmp;
if (uStrCaseCmp(field,"modifiers")==0) {
unsigned mods,vmods;
if (arrayNdx!=NULL) {
WARN("The modifiers field of a key type is not an array\n");
ACTION("Illegal array subscript ignored\n");
}
if (!ExprResolveModMask(value,&tmp,LookupVModMask,(XPointer)xkb)) {
ERROR("Key type mask field must be a modifier mask\n");
ACTION("Key type definition ignored\n");
return False;
}
mods= tmp.uval&0xff;
vmods= (tmp.uval>>8)&0xffff;
if (type->defs.defined&_KT_Mask) {
WARN1("Multiple modifier mask definitions for key type %s\n",
XkbAtomText(type->dpy,type->name,XkbMessage));
ACTION1("Using %s, ",TypeMaskTxt(type,xkb));
INFO1("ignoring %s\n",XkbVModMaskText(type->dpy,xkb,mods,
vmods,
XkbMessage));
return False;
}
type->mask= mods;
type->vmask= vmods;
type->defs.defined|= _KT_Mask;
return True;
}
else if (uStrCaseCmp(field,"map")==0) {
type->defs.defined|= _KT_Map;
return SetMapEntry(type,xkb,arrayNdx,value);
}
else if (uStrCaseCmp(field,"preserve")==0) {
type->defs.defined|= _KT_Preserve;
return SetPreserve(type,xkb,arrayNdx,value);
}
else if ((uStrCaseCmp(field,"levelname")==0)||
(uStrCaseCmp(field,"level_name")==0)) {
type->defs.defined|= _KT_LevelNames;
return SetLevelName(type,arrayNdx,value);
}
ERROR2("Unknown field %s in key type %s\n",field,TypeTxt(type));
ACTION("Definition ignored\n");
return False;
}
static Bool
HandleKeyTypeVar(VarDef *stmt,XkbDescPtr xkb,KeyTypesInfo *info)
{
ExprResult elem,field;
ExprDef * arrayNdx;
if (!ExprResolveLhs(stmt->name,&elem,&field,&arrayNdx))
return False;
if (elem.str&&(uStrCaseCmp(elem.str,"type")==0))
return SetKeyTypeField(&info->dflt,xkb,field.str,arrayNdx,stmt->value,
info);
if (elem.str!=NULL) {
ERROR1("Default for unknown element %s\n",uStringText(elem.str));
ACTION1("Value for field %s ignored\n",uStringText(field.str));
}
else if (field.str!=NULL) {
ERROR1("Default defined for unknown field %s\n",uStringText(field.str));
ACTION("Ignored\n");
}
return False;
}
static int
HandleKeyTypeBody( VarDef * def,
XkbDescPtr xkb,
KeyTypeInfo * type,
KeyTypesInfo * 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= HandleKeyTypeVar(def,xkb,info);
continue;
}
ok= ExprResolveLhs(def->name,&tmp,&field,&arrayNdx);
if (ok)
ok= SetKeyTypeField(type,xkb,field.str,arrayNdx,def->value,info);
}
return ok;
}
static int
HandleKeyTypeDef( KeyTypeDef * def,
XkbDescPtr xkb,
unsigned merge,
KeyTypesInfo * info)
{
register int i;
KeyTypeInfo type;
if (def->merge!=MergeDefault)
merge= def->merge;
type.defs.defined= 0;
type.defs.fileID= info->fileID;
type.defs.merge= merge;
type.defs.next= 0;
type.dpy= info->dpy;
type.name= def->name;
type.mask= info->dflt.mask;
type.vmask= info->dflt.vmask;
type.groupInfo= info->dflt.groupInfo;
type.numLevels= 1;
type.nEntries= type.szEntries= 0;
type.entries= NULL;
type.szNames= 0;
type.lvlNames= NULL;
type.preserve= NULL;
if (!HandleKeyTypeBody(def->body,xkb,&type,info)) {
info->errorCount++;
return False;
}
for (i=0;i<info->dflt.nEntries;i++) {
XkbKTMapEntryPtr dflt;
dflt= &info->dflt.entries[i];
if (((dflt->mods.real_mods&type.mask)==dflt->mods.real_mods)&&
((dflt->mods.vmods&type.vmask)==dflt->mods.vmods)) {
AddMapEntry(xkb,&type,dflt,False,False);
}
}
if (info->dflt.preserve) {
PreserveInfo *dflt= info->dflt.preserve;
while (dflt) {
if (((dflt->indexMods&type.mask)==dflt->indexMods)&&
((dflt->indexVMods&type.vmask)==dflt->indexVMods)) {
AddPreserve(xkb,&type,dflt,False,False);
}
dflt= (PreserveInfo *)dflt->defs.next;
}
}
for (i=0;i<info->dflt.szNames;i++) {
if ((i<type.numLevels)&&(info->dflt.lvlNames[i]!=None)) {
AddLevelName(&type,i,info->dflt.lvlNames[i],False,False);
}
}
if (!AddKeyType(xkb,info,&type)) {
info->errorCount++;
return False;
}
return True;
}
static void
HandleKeyTypesFile( XkbFile * file,
XkbDescPtr xkb,
unsigned merge,
KeyTypesInfo * info)
{
ParseCommon *stmt;
info->name= uStringDup(file->name);
stmt= file->defs;
while (stmt) {
switch (stmt->stmtType) {
case StmtInclude:
if (!HandleIncludeKeyTypes((IncludeStmt *)stmt,xkb,info,
HandleKeyTypesFile))
info->errorCount++;
break;
case StmtKeyTypeDef:
if (!HandleKeyTypeDef((KeyTypeDef *)stmt,xkb,merge,info))
info->errorCount++;
break;
case StmtVarDef:
if (!HandleKeyTypeVar((VarDef *)stmt,xkb,info))
info->errorCount++;
break;
case StmtVModDef:
if (!HandleVModDef((VModDef *)stmt,merge,&info->vmods))
info->errorCount++;
break;
case StmtKeyAliasDef:
ERROR("Key type files may not include other declarations\n");
ACTION("Ignoring definition of key alias\n");
info->errorCount++;
break;
case StmtKeycodeDef:
ERROR("Key type files may not include other declarations\n");
ACTION("Ignoring definition of key name\n");
info->errorCount++;
break;
case StmtInterpDef:
ERROR("Key type files may not include other declarations\n");
ACTION("Ignoring definition of symbol interpretation\n");
info->errorCount++;
break;
default:
WSGO1("Unexpected statement type %d in HandleKeyTypesFile\n",
stmt->stmtType);
break;
}
stmt= stmt->next;
if (info->errorCount>10) {
#ifdef NOISY
ERROR("Too many errors\n");
#endif
ACTION1("Abandoning keytypes file \"%s\"\n",file->topName);
break;
}
}
return;
}
static Bool
CopyDefToKeyType(XkbDescPtr xkb,XkbKeyTypePtr type,KeyTypeInfo *def)
{
register int i;
PreserveInfo *pre;
for (pre=def->preserve;pre!=NULL;pre=(PreserveInfo *)pre->defs.next) {
XkbKTMapEntryPtr match;
XkbKTMapEntryRec tmp;
tmp.mods.real_mods= pre->indexMods;
tmp.mods.vmods= pre->indexVMods;
tmp.level= 0;
AddMapEntry(xkb,def,&tmp,False,False);
match= FindMatchingMapEntry(def,pre->indexMods,pre->indexVMods);
if (!match) {
WSGO("Couldn't find matching entry for preserve\n");
ACTION("Aborting\n");
return False;
}
pre->matchingMapIndex= match-def->entries;
}
type->mods.real_mods= def->mask;
type->mods.vmods= def->vmask;
type->num_levels= def->numLevels;
type->map_count= def->nEntries;
type->map= def->entries;
if (def->preserve) {
type->preserve= uTypedCalloc(type->map_count,XkbModsRec);
if (!type->preserve) {
WARN("Couldn't allocate preserve array in CopyDefToKeyType\n");
ACTION1("Preserve setting for type %s lost\n",
XkbAtomText(def->dpy,def->name,XkbMessage));
}
else {
pre= def->preserve;
for (;pre!=NULL;pre=(PreserveInfo *)pre->defs.next) {
int ndx= pre->matchingMapIndex;
type->preserve[ndx].mask= pre->preMods;
type->preserve[ndx].real_mods= pre->preMods;
type->preserve[ndx].vmods= pre->preVMods;
}
}
}
else type->preserve= NULL;
type->name= (Atom)def->name;
if (def->szNames>0) {
type->level_names= uTypedCalloc(def->numLevels,Atom);
for (i=0;i<def->szNames;i++) {
type->level_names[i]= (Atom)def->lvlNames[i];
}
}
else {
type->level_names= NULL;
}
def->nEntries= def->szEntries= 0;
def->entries= NULL;
return XkbComputeEffectiveMap(xkb,type,NULL);
}
Bool
CompileKeyTypes(XkbFile *file,XkbFileInfo *result,unsigned merge)
{
KeyTypesInfo info;
XkbDescPtr xkb;
xkb= result->xkb;
InitKeyTypesInfo(&info,xkb,NULL);
info.fileID= file->id;
HandleKeyTypesFile(file,xkb,merge,&info);
if (info.errorCount==0) {
register int i;
register KeyTypeInfo *def;
register XkbKeyTypePtr type,next;
if (info.name!=None) {
if (XkbAllocNames(xkb,XkbTypesNameMask,0,0)==Success)
xkb->names->types= XkbInternAtom(xkb->dpy,info.name,False);
else {
WSGO("Couldn't allocate space for types name\n");
ACTION2("Name \"%s\" (from %s) NOT assigned\n",scanFile,
info.name);
}
}
i= info.nTypes;
if ((info.stdPresent&XkbOneLevelMask)==0)
i++;
if ((info.stdPresent&XkbTwoLevelMask)==0)
i++;
if ((info.stdPresent&XkbKeypadMask)==0)
i++;
if ((info.stdPresent&XkbAlphabeticMask)==0)
i++;
if (XkbAllocClientMap(xkb,XkbKeyTypesMask,i)!=Success) {
WSGO("Couldn't allocate client map\n");
ACTION("Exiting\n");
return False;
}
xkb->map->num_types= i;
if (XkbAllRequiredTypes&(~info.stdPresent)) {
unsigned missing,keypadVMod;
missing= XkbAllRequiredTypes&(~info.stdPresent);
keypadVMod= FindKeypadVMod(xkb);
if (XkbInitCanonicalKeyTypes(xkb,missing,keypadVMod)!=Success) {
WSGO("Couldn't initialize canonical key types\n");
ACTION("Exiting\n");
return False;
}
if (missing&XkbOneLevelMask)
xkb->map->types[XkbOneLevelIndex].name= tok_ONE_LEVEL;
if (missing&XkbTwoLevelMask)
xkb->map->types[XkbTwoLevelIndex].name= tok_TWO_LEVEL;
if (missing&XkbAlphabeticMask)
xkb->map->types[XkbAlphabeticIndex].name= tok_ALPHABETIC;
if (missing&XkbKeypadMask)
xkb->map->types[XkbKeypadIndex].name= tok_KEYPAD;
}
next= &xkb->map->types[XkbLastRequiredType+1];
for (i=0,def=info.types;i<info.nTypes;i++) {
if (def->name==tok_ONE_LEVEL)
type= &xkb->map->types[XkbOneLevelIndex];
else if (def->name==tok_TWO_LEVEL)
type= &xkb->map->types[XkbTwoLevelIndex];
else if (def->name==tok_ALPHABETIC)
type= &xkb->map->types[XkbAlphabeticIndex];
else if (def->name==tok_KEYPAD)
type= &xkb->map->types[XkbKeypadIndex];
else type= next++;
DeleteLevel1MapEntries(def);
if (!CopyDefToKeyType(xkb,type,def))
return False;
def= (KeyTypeInfo *)def->defs.next;
}
return True;
}
return False;
}