diff options
Diffstat (limited to 'keytypes.c')
-rw-r--r-- | keytypes.c | 1353 |
1 files changed, 1353 insertions, 0 deletions
diff --git a/keytypes.c b/keytypes.c new file mode 100644 index 0000000..2b2db13 --- /dev/null +++ b/keytypes.c @@ -0,0 +1,1353 @@ +/* $Xorg: keytypes.c,v 1.3 2000/08/17 19:54:32 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. + + ********************************************************/ + +#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)) + +/***====================================================================***/ + +_XFUNCPROTOBEGIN + +extern Bool AddMapEntry( +#if NeedFunctionPrototypes + XkbDescPtr /* xkb */, + KeyTypeInfo * /* type */, + XkbKTMapEntryPtr /* new */, + Bool /* clobber */, + Bool /* report */ +#endif +); + +extern Bool AddPreserve( +#if NeedFunctionPrototypes + XkbDescPtr /* xkb */, + KeyTypeInfo * /* type */, + PreserveInfo * /* new */, + Bool /* clobber */, + Bool /* report */ +#endif +); + +extern Bool AddLevelName( +#if NeedFunctionPrototypes + KeyTypeInfo * /* type */, + unsigned /* level */, + Atom /* name */, + Bool /* clobber */, + Bool /* report */ +#endif +); + +_XFUNCPROTOEND + +#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 +#if NeedFunctionPrototypes +InitKeyTypesInfo(KeyTypesInfo *info,XkbDescPtr xkb,KeyTypesInfo *from) +#else +InitKeyTypesInfo(info,xkb,from) + KeyTypesInfo * info; + XkbDescPtr xkb; + KeyTypesInfo * from; +#endif +{ + 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 +#if NeedFunctionPrototypes +FreeKeyTypeInfo(KeyTypeInfo *type) +#else +FreeKeyTypeInfo(type) + KeyTypeInfo * type; +#endif +{ + 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 +#if NeedFunctionPrototypes +FreeKeyTypesInfo(KeyTypesInfo *info) +#else +FreeKeyTypesInfo(info) + KeyTypesInfo * info; +#endif +{ + 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 * +#if NeedFunctionPrototypes +NextKeyType(KeyTypesInfo *info) +#else +NextKeyType(info) + KeyTypesInfo * info; +#endif +{ +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 * +#if NeedFunctionPrototypes +FindMatchingKeyType(KeyTypesInfo *info,KeyTypeInfo *new) +#else +FindMatchingKeyType(info,new) + KeyTypesInfo * info; + KeyTypeInfo * new; +#endif +{ +KeyTypeInfo *old; + + for (old=info->types;old;old=(KeyTypeInfo *)old->defs.next) { + if (old->name==new->name) + return old; + } + return NULL; +} + +static Bool +#if NeedFunctionPrototypes +ReportTypeBadWidth(char *type,int has,int needs) +#else +ReportTypeBadWidth(type,has,needs) + char * type; + int has; + int needs; +#endif +{ + ERROR3("Key type \"%s\" has %d levels, must have %d\n",type,has,needs); + ACTION("Illegal type definition ignored\n"); + return False; +} + +static Bool +#if NeedFunctionPrototypes +AddKeyType(XkbDescPtr xkb,KeyTypesInfo *info,KeyTypeInfo *new) +#else +AddKeyType(xkb,info,new) + XkbDescPtr xkb; + KeyTypesInfo * info; + KeyTypeInfo * new; +#endif +{ +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 +#if NeedFunctionPrototypes +MergeIncludedKeyTypes( KeyTypesInfo * into, + KeyTypesInfo * from, + unsigned merge, + XkbDescPtr xkb) +#else +MergeIncludedKeyTypes(into,from,merge,xkb) + KeyTypesInfo *into; + KeyTypesInfo *from; + unsigned merge; + XkbDescPtr xkb; +#endif +{ +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)( +#if NeedFunctionPrototypes + XkbFile * /* file */, + XkbDescPtr /* xkb */, + unsigned /* merge */, + KeyTypesInfo * /* included */ +#endif +); + +static Bool +#if NeedFunctionPrototypes +HandleIncludeKeyTypes( IncludeStmt * stmt, + XkbDescPtr xkb, + KeyTypesInfo * info, + FileHandler hndlr) +#else +HandleIncludeKeyTypes(stmt,xkb,info,hndlr) + IncludeStmt * stmt; + XkbDescPtr xkb; + KeyTypesInfo * info; + FileHandler hndlr; +#endif +{ +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 +#if NeedFunctionPrototypes +FindMatchingMapEntry(KeyTypeInfo *type,unsigned mask,unsigned vmask) +#else +FindMatchingMapEntry(type,mask,vmask) + KeyTypeInfo * type; + unsigned mask; + unsigned vmask; +#endif +{ +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 +#if NeedFunctionPrototypes +DeleteLevel1MapEntries(KeyTypeInfo *type) +#else +DeleteLevel1MapEntries(type) + KeyTypeInfo * type; +#endif +{ +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 +#if NeedFunctionPrototypes +NextMapEntry(KeyTypeInfo *type) +#else +NextMapEntry(type) + KeyTypeInfo * type; +#endif +{ + 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 +#if NeedFunctionPrototypes +AddPreserve( XkbDescPtr xkb, + KeyTypeInfo * type, + PreserveInfo * new, + Bool clobber, + Bool report) +#else +AddPreserve(xkb,type,new,clobber,report) + XkbDescPtr xkb; + KeyTypeInfo * type; + PreserveInfo * new; + Bool clobber; + Bool report; +#endif +{ +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 +#if NeedFunctionPrototypes +AddMapEntry( XkbDescPtr xkb, + KeyTypeInfo * type, + XkbKTMapEntryPtr new, + Bool clobber, + Bool report) +#else +AddMapEntry(xkb,type,new,clobber,report) + XkbDescPtr xkb; + KeyTypeInfo * type; + XkbKTMapEntryPtr new; + Bool clobber; + Bool report; +#endif +{ +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; /* allocation failure, already reported */ + 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 +#if NeedFunctionPrototypes +SetMapEntry( KeyTypeInfo * type, + XkbDescPtr xkb, + ExprDef * arrayNdx, + ExprDef * value) +#else +SetMapEntry(type,xkb,arrayNdx,value) + KeyTypeInfo * type; + XkbDescPtr xkb; + ExprDef * arrayNdx; + ExprDef * value; +#endif +{ +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 +#if NeedFunctionPrototypes +SetPreserve( KeyTypeInfo * type, + XkbDescPtr xkb, + ExprDef * arrayNdx, + ExprDef * value) +#else +SetPreserve(type,xkb,arrayNdx,value) + KeyTypeInfo * type; + XkbDescPtr xkb; + ExprDef * arrayNdx; + ExprDef * value; +#endif +{ +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 +#if NeedFunctionPrototypes +AddLevelName( KeyTypeInfo * type, + unsigned level, + Atom name, + Bool clobber, + Bool report) +#else +AddLevelName(type,level,name,clobber,report) + KeyTypeInfo * type; + unsigned level; + Atom name; + Bool clobber; + Bool report; +#endif +{ + 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 +#if NeedFunctionPrototypes +SetLevelName(KeyTypeInfo *type,ExprDef *arrayNdx,ExprDef *value) +#else +SetLevelName(type,arrayNdx,value) + KeyTypeInfo * type; + ExprDef * arrayNdx; + ExprDef * value; +#endif +{ +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 +#if NeedFunctionPrototypes +SetKeyTypeField( KeyTypeInfo * type, + XkbDescPtr xkb, + char * field, + ExprDef * arrayNdx, + ExprDef * value, + KeyTypesInfo * info) +#else +SetKeyTypeField(type,xkb,field,arrayNdx,value,info) + KeyTypeInfo * type; + XkbDescPtr xkb; + char * field; + ExprDef * arrayNdx; + ExprDef * value; + KeyTypesInfo * info; +#endif +{ +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 +#if NeedFunctionPrototypes +HandleKeyTypeVar(VarDef *stmt,XkbDescPtr xkb,KeyTypesInfo *info) +#else +HandleKeyTypeVar(stmt,xkb,info) + VarDef * stmt; + XkbDescPtr xkb; + KeyTypesInfo * info; +#endif +{ +ExprResult elem,field; +ExprDef * arrayNdx; + + if (!ExprResolveLhs(stmt->name,&elem,&field,&arrayNdx)) + return False; /* internal error, already reported */ + 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 +#if NeedFunctionPrototypes +HandleKeyTypeBody( VarDef * def, + XkbDescPtr xkb, + KeyTypeInfo * type, + KeyTypesInfo * info) +#else +HandleKeyTypeBody(def,xkb,type,info) + VarDef * def; + XkbDescPtr xkb; + KeyTypeInfo * type; + KeyTypesInfo * info; +#endif +{ +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 +#if NeedFunctionPrototypes +HandleKeyTypeDef( KeyTypeDef * def, + XkbDescPtr xkb, + unsigned merge, + KeyTypesInfo * info) +#else +HandleKeyTypeDef(def,xkb,merge,info) + KeyTypeDef * def; + XkbDescPtr xkb; + unsigned merge; + KeyTypesInfo * info; +#endif +{ +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; + } + + /* now copy any appropriate map, preserve or level names from the */ + /* default type */ + 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 +#if NeedFunctionPrototypes +HandleKeyTypesFile( XkbFile * file, + XkbDescPtr xkb, + unsigned merge, + KeyTypesInfo * info) +#else +HandleKeyTypesFile(file,xkb,merge,info) + XkbFile *file; + XkbDescPtr xkb; + unsigned merge; + KeyTypesInfo *info; +#endif +{ +ParseCommon *stmt; + + if ((merge==MergeOverride)||(info->name==None)) + info->name= file->name; + + info->name= 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 +#if NeedFunctionPrototypes +CopyDefToKeyType(XkbDescPtr xkb,XkbKeyTypePtr type,KeyTypeInfo *def) +#else +CopyDefToKeyType(xkb,type,def) + XkbDescPtr xkb; + XkbKeyTypePtr type; + KeyTypeInfo * def; +#endif +{ +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); + + /* assert def->szNames<=def->numLevels */ + 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 +#if NeedFunctionPrototypes +CompileKeyTypes(XkbFile *file,XkbFileInfo *result,unsigned merge) +#else +CompileKeyTypes(file,result,merge) + XkbFile * file; + XkbFileInfo * result; + unsigned merge; +#endif +{ +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; +} + |