diff options
Diffstat (limited to 'xkbcomp/symbols.c')
-rw-r--r-- | xkbcomp/symbols.c | 1921 |
1 files changed, 1921 insertions, 0 deletions
diff --git a/xkbcomp/symbols.c b/xkbcomp/symbols.c new file mode 100644 index 000000000..ffc26b2fd --- /dev/null +++ b/xkbcomp/symbols.c @@ -0,0 +1,1921 @@ +/* $Xorg: symbols.c,v 1.3 2000/08/17 19:54:33 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/symbols.c,v 3.15 2003/04/19 12:25:31 pascal Exp $ */ + +#include "xkbcomp.h" +#include "tokens.h" +#include "expr.h" + +#include <X11/keysym.h> +#include <X11/Xutil.h> +#include <stdlib.h> + +#include "expr.h" +#include "vmod.h" +#include "action.h" +#include "keycodes.h" +#include "misc.h" +#include "alias.h" + +extern Atom tok_ONE_LEVEL; +extern Atom tok_TWO_LEVEL; +extern Atom tok_KEYPAD; + +/***====================================================================***/ + +#define RepeatYes 1 +#define RepeatNo 0 +#define RepeatUndefined ~((unsigned)0) + +#define _Key_Syms (1<<0) +#define _Key_Acts (1<<1) +#define _Key_Repeat (1<<2) +#define _Key_Behavior (1<<3) +#define _Key_Type_Dflt (1<<4) +#define _Key_Types (1<<5) +#define _Key_GroupInfo (1<<6) +#define _Key_VModMap (1<<7) + +typedef struct _KeyInfo { + CommonInfo defs; + unsigned long name; + unsigned char groupInfo; + unsigned char typesDefined; + unsigned char symsDefined; + unsigned char actsDefined; + short numLevels[XkbNumKbdGroups]; + KeySym * syms[XkbNumKbdGroups]; + XkbAction * acts[XkbNumKbdGroups]; + Atom types[XkbNumKbdGroups]; + unsigned repeat; + XkbBehavior behavior; + unsigned short vmodmap; + unsigned long nameForOverlayKey; + unsigned long allowNone; + Atom dfltType; +} KeyInfo; + +static void +InitKeyInfo(KeyInfo *info) +{ +register int i; +static char dflt[4]= "*"; + + info->defs.defined= 0; + info->defs.fileID= 0; + info->defs.merge= MergeOverride; + info->defs.next= NULL; + info->name= KeyNameToLong(dflt); + info->groupInfo= 0; + info->typesDefined= info->symsDefined= info->actsDefined= 0; + for (i=0;i<XkbNumKbdGroups;i++) { + info->numLevels[i]= 0; + info->types[i]= None; + info->syms[i]= NULL; + info->acts[i]= NULL; + } + info->dfltType= None; + info->behavior.type= XkbKB_Default; + info->behavior.data= 0; + info->vmodmap= 0; + info->nameForOverlayKey= 0; + info->repeat= RepeatUndefined; + info->allowNone= 0; + return; +} + +static void +FreeKeyInfo(KeyInfo *info) +{ +register int i; + + info->defs.defined= 0; + info->defs.fileID= 0; + info->defs.merge= MergeOverride; + info->defs.next= NULL; + info->groupInfo= 0; + info->typesDefined= info->symsDefined= info->actsDefined= 0; + for (i=0;i<XkbNumKbdGroups;i++) { + info->numLevels[i]= 0; + info->types[i]= None; + if (info->syms[i]!=NULL) + uFree(info->syms[i]); + info->syms[i]= NULL; + if (info->acts[i]!=NULL) + uFree(info->acts[i]); + info->acts[i]= NULL; + } + info->dfltType= None; + info->behavior.type= XkbKB_Default; + info->behavior.data= 0; + info->vmodmap= 0; + info->nameForOverlayKey= 0; + info->repeat= RepeatUndefined; + return; +} + +static Bool +CopyKeyInfo(KeyInfo *old,KeyInfo *new,Bool clearOld) +{ +register int i; + + *new= *old; + new->defs.next= NULL; + if (clearOld) { + for (i=0;i<XkbNumKbdGroups;i++) { + old->numLevels[i]= 0; + old->syms[i]= NULL; + old->acts[i]= NULL; + } + } + else { + int width; + for (i=0;i<XkbNumKbdGroups;i++) { + width= new->numLevels[i]; + if (old->syms[i]!=NULL) { + new->syms[i]= uTypedCalloc(width,KeySym); + if (!new->syms[i]) { + new->syms[i]= NULL; + new->numLevels[i]= 0; + return False; + } + memcpy((char *)new->syms[i],(char *)old->syms[i], + width*sizeof(KeySym)); + } + if (old->acts[i]!=NULL) { + new->acts[i]= uTypedCalloc(width,XkbAction); + if (!new->acts[i]) { + new->acts[i]= NULL; + return False; + } + memcpy((char *)new->acts[i],(char *)old->acts[i], + width*sizeof(XkbAction)); + } + } + } + return True; +} + +/***====================================================================***/ + +typedef struct _ModMapEntry { + CommonInfo defs; + Bool haveSymbol; + int modifier; + union { + unsigned long keyName; + KeySym keySym; + } u; +} ModMapEntry; + +#define SYMBOLS_INIT_SIZE 110 +#define SYMBOLS_CHUNK 20 +typedef struct _SymbolsInfo { + char * name; + int errorCount; + unsigned fileID; + unsigned merge; + unsigned explicit_group; + unsigned groupInfo; + unsigned szKeys; + unsigned nKeys; + KeyInfo * keys; + KeyInfo dflt; + VModInfo vmods; + ActionInfo * action; + Atom groupNames[XkbNumKbdGroups]; + + ModMapEntry * modMap; + AliasInfo * aliases; +} SymbolsInfo; + +static void +InitSymbolsInfo(SymbolsInfo *info,XkbDescPtr xkb) +{ +register int i; + + tok_ONE_LEVEL= XkbInternAtom(NULL,"ONE_LEVEL",False); + tok_TWO_LEVEL= XkbInternAtom(NULL,"TWO_LEVEL",False); + tok_KEYPAD= XkbInternAtom(NULL,"KEYPAD",False); + info->name= NULL; + info->explicit_group= 0; + info->errorCount= 0; + info->fileID= 0; + info->merge= MergeOverride; + info->groupInfo= 0; + info->szKeys= SYMBOLS_INIT_SIZE; + info->nKeys= 0; + info->keys= uTypedCalloc(SYMBOLS_INIT_SIZE,KeyInfo); + info->modMap= NULL; + for (i=0;i<XkbNumKbdGroups;i++) + info->groupNames[i]= None; + InitKeyInfo(&info->dflt); + InitVModInfo(&info->vmods,xkb); + info->action= NULL; + info->aliases= NULL; + return; +} + +static void +FreeSymbolsInfo(SymbolsInfo *info) +{ +register int i; + + if (info->name) + uFree(info->name); + info->name= NULL; + if (info->keys) { + for (i=0;i<info->nKeys;i++) { + FreeKeyInfo(&info->keys[i]); + } + uFree(info->keys); + info->keys= NULL; + } + if (info->modMap) { + ClearCommonInfo(&info->modMap->defs); + info->modMap= NULL; + } + if (info->aliases) { + ClearAliases(&info->aliases); + info->aliases= NULL; + } + bzero((char *)info,sizeof(SymbolsInfo)); + return; +} + +static Bool +ResizeKeyGroup( KeyInfo * key, + unsigned group, + unsigned atLeastSize, + Bool forceActions) +{ +Bool tooSmall; +unsigned newWidth; + + tooSmall= (key->numLevels[group]<atLeastSize); + if (tooSmall) newWidth= atLeastSize; + else newWidth= key->numLevels[group]; + + if ((key->syms[group]==NULL)||tooSmall) { + key->syms[group]= uTypedRecalloc(key->syms[group], + key->numLevels[group],newWidth, + KeySym); + if (!key->syms[group]) + return False; + } + if (((forceActions)&&(tooSmall||(key->acts[group]==NULL)))|| + (tooSmall&&(key->acts[group]!=NULL))) { + key->acts[group]= uTypedRecalloc(key->acts[group], + key->numLevels[group],newWidth, + XkbAction); + if (!key->acts[group]) + return False; + } + key->numLevels[group]= newWidth; + return True; +} + +static Bool +MergeKeyGroups( SymbolsInfo * info, + KeyInfo * into, + KeyInfo * from, + unsigned group) +{ +KeySym * resultSyms; +XkbAction * resultActs; +int resultWidth; +register int i; +Bool report,clobber; + + clobber= (from->defs.merge!=MergeAugment); + report= (warningLevel>9)|| + ((into->defs.fileID==from->defs.fileID)&&(warningLevel>0)); + if (into->numLevels[group]>=from->numLevels[group]) { + resultSyms= into->syms[group]; + resultActs= into->acts[group]; + resultWidth= into->numLevels[group]; + } + else { + resultSyms= from->syms[group]; + resultActs= from->acts[group]; + resultWidth= from->numLevels[group]; + } + if (resultSyms==NULL) { + resultSyms= uTypedCalloc(resultWidth,KeySym); + if (!resultSyms) { + WSGO("Could not allocate symbols for group merge\n"); + ACTION2("Group %d of key %s not merged\n",group, + longText(into->name,XkbMessage)); + return False; + } + } + if ((resultActs==NULL)&&(into->acts[group]||from->acts[group])) { + resultActs= uTypedCalloc(resultWidth,XkbAction); + if (!resultActs) { + WSGO("Could not allocate actions for group merge\n"); + ACTION2("Group %d of key %s not merged\n",group, + longText(into->name,XkbMessage)); + return False; + } + } + for (i=0;i<resultWidth;i++) { + KeySym fromSym,toSym; + if (from->syms[group] && (i<from->numLevels[group])) + fromSym= from->syms[group][i]; + else fromSym= NoSymbol; + if (into->syms[group] && (i<into->numLevels[group])) + toSym= into->syms[group][i]; + else toSym= NoSymbol; + if ((fromSym==NoSymbol)||(fromSym==toSym)) + resultSyms[i]= toSym; + else if (toSym==NoSymbol) + resultSyms[i]= fromSym; + else { + KeySym use,ignore; + if (clobber) { use= fromSym; ignore= toSym; } + else { use= toSym; ignore= fromSym; } + if (report) { + WARN3("Multiple symbols for level %d/group %d on key %s\n", + i+1,group+1,longText(into->name,XkbMessage)); + ACTION2("Using %s, ignoring %s\n",XkbKeysymText(use,XkbMessage), + XkbKeysymText(ignore,XkbMessage)); + } + resultSyms[i]= use; + } + if (resultActs!=NULL) { + XkbAction *fromAct,*toAct; + fromAct= (from->acts[group]?&from->acts[group][i]:NULL); + toAct= (into->acts[group]?&into->acts[group][i]:NULL); + if (((fromAct==NULL)||(fromAct->type==XkbSA_NoAction))&& + (toAct!=NULL)) { + resultActs[i]= *toAct; + } + else if (((toAct==NULL)||(toAct->type==XkbSA_NoAction))&& + (fromAct!=NULL)) { + resultActs[i]= *fromAct; + } + else { + XkbAction *use,*ignore; + if (clobber) { use= fromAct; ignore= toAct; } + else { use= toAct; ignore= fromAct; } + if (report) { + WARN3("Multiple actions for level %d/group %d on key %s\n", + i+1,group+1,longText(into->name,XkbMessage)); + ACTION2("Using %s, ignoring %s\n", + XkbActionTypeText(use->type,XkbMessage), + XkbActionTypeText(ignore->type,XkbMessage)); + } + resultActs[i]= *use; + } + } + } + if ((into->syms[group]!=NULL)&&(resultSyms!=into->syms[group])) + uFree(into->syms[group]); + if ((from->syms[group]!=NULL)&&(resultSyms!=from->syms[group])) + uFree(from->syms[group]); + if ((into->acts[group]!=NULL)&&(resultActs!=into->acts[group])) + uFree(into->acts[group]); + if ((from->acts[group]!=NULL)&&(resultActs!=from->acts[group])) + uFree(from->acts[group]); + into->numLevels[group]= resultWidth; + into->syms[group]= resultSyms; + from->syms[group]= NULL; + into->acts[group]= resultActs; + from->acts[group]= NULL; + into->symsDefined|= (1<<group); + from->symsDefined&= ~(1<<group); + into->actsDefined|= (1<<group); + from->actsDefined&= ~(1<<group); + return True; +} + +static Bool +MergeKeys(SymbolsInfo *info,KeyInfo *into,KeyInfo *from) +{ +register int i; +unsigned collide= 0; +Bool report; + + if (from->defs.merge==MergeReplace) { + for (i=0;i<XkbNumKbdGroups;i++) { + if (into->numLevels[i]!=0) { + if (into->syms[i]) + uFree(into->syms[i]); + if (into->acts[i]) + uFree(into->acts[i]); + } + } + *into= *from; + bzero(from,sizeof(KeyInfo)); + return True; + } + report= ((warningLevel>9)|| + ((into->defs.fileID==from->defs.fileID)&&(warningLevel>0))); + for (i=0;i<XkbNumKbdGroups;i++) { + if (from->numLevels[i]>0) { + if (into->numLevels[i]==0) { + into->numLevels[i]= from->numLevels[i]; + into->syms[i]= from->syms[i]; + into->acts[i]= from->acts[i]; + into->symsDefined|= (1<<i); + from->syms[i]= NULL; + from->acts[i]= NULL; + from->numLevels[i]= 0; + from->symsDefined&= ~(1<<i); + if (into->syms[i]) into->defs.defined|= _Key_Syms; + if (into->acts[i]) into->defs.defined|= _Key_Acts; + } + else { + if (report) { + if (into->syms[i]) collide|= _Key_Syms; + if (into->acts[i]) collide|= _Key_Acts; + } + MergeKeyGroups(info,into,from,(unsigned)i); + } + } + if (from->types[i]!=None) { + if ((into->types[i]!=None)&&(report)&& + (into->types[i]!=from->types[i])) { + Atom use,ignore; + collide|= _Key_Types; + if (from->defs.merge!=MergeAugment) { + use= from->types[i]; + ignore= into->types[i]; + } + else { + use= into->types[i]; + ignore= from->types[i]; + } + WARN2("Multiple definitions for group %d type of key %s\n", + i,longText(into->name,XkbMessage)); + ACTION2("Using %s, ignoring %s\n", + XkbAtomText(NULL,use,XkbMessage), + XkbAtomText(NULL,ignore,XkbMessage)); + } + if ((from->defs.merge!=MergeAugment)||(into->types[i]==None)) { + into->types[i]= from->types[i]; + } + } + } + if (UseNewField(_Key_Behavior,&into->defs,&from->defs,&collide)) { + into->behavior= from->behavior; + into->nameForOverlayKey= from->nameForOverlayKey; + into->defs.defined|= _Key_Behavior; + } + if (UseNewField(_Key_VModMap,&into->defs,&from->defs,&collide)) { + into->vmodmap= from->vmodmap; + into->defs.defined|= _Key_VModMap; + } + if (UseNewField(_Key_Repeat,&into->defs,&from->defs,&collide)) { + into->repeat= from->repeat; + into->defs.defined|= _Key_Repeat; + } + if (UseNewField(_Key_Type_Dflt,&into->defs,&from->defs,&collide)) { + into->dfltType= from->dfltType; + into->defs.defined|= _Key_Type_Dflt; + } + if (UseNewField(_Key_GroupInfo,&into->defs,&from->defs,&collide)) { + into->groupInfo= from->groupInfo; + into->defs.defined|= _Key_GroupInfo; + } + if ( collide ) { + WARN1("Symbol map for key %s redefined\n", + longText(into->name,XkbMessage)); + ACTION1("Using %s definition for conflicting fields\n", + (from->defs.merge==MergeAugment?"first":"last")); + } + return True; +} + +static Bool +AddKeySymbols(SymbolsInfo *info,KeyInfo *key,XkbDescPtr xkb) +{ +register int i; +unsigned long real_name; + + for (i=0;i<info->nKeys;i++) { + if (info->keys[i].name==key->name) + return MergeKeys(info,&info->keys[i],key); + } + if(FindKeyNameForAlias(xkb, key->name, &real_name)) { + for (i=0;i<info->nKeys;i++) { + if (info->keys[i].name==real_name) + return MergeKeys(info,&info->keys[i],key); + } + } + if (info->nKeys>=info->szKeys) { + info->szKeys+= SYMBOLS_CHUNK; + info->keys= uTypedRecalloc(info->keys,info->nKeys,info->szKeys,KeyInfo); + if (!info->keys) { + WSGO("Could not allocate key symbols descriptions\n"); + ACTION("Some key symbols definitions may be lost\n"); + return False; + } + } + return CopyKeyInfo(key,&info->keys[info->nKeys++],True); +} + +static Bool +AddModMapEntry(SymbolsInfo *info,ModMapEntry *new) +{ +ModMapEntry * mm; +Bool clobber; + + clobber= (new->defs.merge!=MergeAugment); + for (mm=info->modMap;mm!=NULL;mm= (ModMapEntry *)mm->defs.next) { + if (new->haveSymbol&&mm->haveSymbol&&(new->u.keySym==mm->u.keySym)) { + unsigned use,ignore; + if (mm->modifier!=new->modifier) { + if (clobber) { + use= new->modifier; + ignore= mm->modifier; + } + else { + use= mm->modifier; + ignore= new->modifier; + } + ERROR1("%s added to symbol map for multiple modifiers\n", + XkbKeysymText(new->u.keySym,XkbMessage)); + ACTION2("Using %s, ignoring %s.\n", + XkbModIndexText(use,XkbMessage), + XkbModIndexText(ignore,XkbMessage)); + mm->modifier= use; + } + return True; + } + if ((!new->haveSymbol)&&(!mm->haveSymbol)&& + (new->u.keyName==mm->u.keyName)) { + unsigned use,ignore; + if (mm->modifier!=new->modifier) { + if (clobber) { + use= new->modifier; + ignore= mm->modifier; + } + else { + use= mm->modifier; + ignore= new->modifier; + } + ERROR1("Key %s added to map for multiple modifiers\n", + longText(new->u.keyName,XkbMessage)); + ACTION2("Using %s, ignoring %s.\n", + XkbModIndexText(use,XkbMessage), + XkbModIndexText(ignore,XkbMessage)); + mm->modifier= use; + } + return True; + } + } + mm= uTypedAlloc(ModMapEntry); + if (mm==NULL) { + WSGO("Could not allocate modifier map entry\n"); + ACTION1("Modifier map for %s will be incomplete\n", + XkbModIndexText(new->modifier,XkbMessage)); + return False; + } + *mm= *new; + mm->defs.next= &info->modMap->defs; + info->modMap= mm; + return True; +} + +/***====================================================================***/ + +static void +MergeIncludedSymbols(SymbolsInfo *into,SymbolsInfo *from, + unsigned merge,XkbDescPtr xkb) +{ +register int i; +KeyInfo * key; + + if (from->errorCount>0) { + into->errorCount+= from->errorCount; + return; + } + if (into->name==NULL) { + into->name= from->name; + from->name= NULL; + } + for (i=0;i<XkbNumKbdGroups;i++) { + if (from->groupNames[i]!=None) { + if ((merge!=MergeAugment)||(into->groupNames[i]==None)) + into->groupNames[i]= from->groupNames[i]; + } + } + for (i=0,key=from->keys;i<from->nKeys;i++,key++) { + if (merge!=MergeDefault) + key->defs.merge= merge; + if (!AddKeySymbols(into,key,xkb)) + into->errorCount++; + } + if (from->modMap!=NULL) { + ModMapEntry *mm,*next; + for (mm=from->modMap;mm!=NULL;mm=next) { + if (merge!=MergeDefault) + mm->defs.merge= merge; + if (!AddModMapEntry(into,mm)) + into->errorCount++; + next= (ModMapEntry *)mm->defs.next; + uFree(mm); + } + from->modMap= NULL; + } + if (!MergeAliases(&into->aliases,&from->aliases,merge)) + into->errorCount++; + return; +} + +typedef void (*FileHandler)( + XkbFile * /* rtrn */, + XkbDescPtr /* xkb */, + unsigned /* merge */, + SymbolsInfo * /* included */ +); + +static Bool +HandleIncludeSymbols( IncludeStmt * stmt, + XkbDescPtr xkb, + SymbolsInfo * info, + FileHandler hndlr) +{ +unsigned newMerge; +XkbFile * rtrn; +SymbolsInfo included; +Bool haveSelf; + + haveSelf= False; + if ((stmt->file==NULL)&&(stmt->map==NULL)) { + haveSelf= True; + included= *info; + bzero(info,sizeof(SymbolsInfo)); + } + else if (ProcessIncludeFile(stmt,XkmSymbolsIndex,&rtrn,&newMerge)) { + InitSymbolsInfo(&included,xkb); + included.fileID= included.dflt.defs.fileID= rtrn->id; + included.merge= included.dflt.defs.merge= MergeOverride; + if (stmt->modifier) { + included.explicit_group= atoi(stmt->modifier) - 1; + } else { + included.explicit_group= info->explicit_group; + } + (*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; + SymbolsInfo next_incl; + + for (next=stmt->next;next!=NULL;next=next->next) { + if ((next->file==NULL)&&(next->map==NULL)) { + haveSelf= True; + MergeIncludedSymbols(&included,info,next->merge,xkb); + FreeSymbolsInfo(info); + } + else if (ProcessIncludeFile(next,XkmSymbolsIndex,&rtrn,&op)) { + InitSymbolsInfo(&next_incl,xkb); + next_incl.fileID= next_incl.dflt.defs.fileID= rtrn->id; + next_incl.merge= next_incl.dflt.defs.merge= MergeOverride; + if (next->modifier) { + next_incl.explicit_group= atoi(next->modifier) - 1; + } else { + next_incl.explicit_group= info->explicit_group; + } + (*hndlr)(rtrn,xkb,MergeOverride,&next_incl); + MergeIncludedSymbols(&included,&next_incl,op,xkb); + FreeSymbolsInfo(&next_incl); + } + else { + info->errorCount+= 10; + return False; + } + } + } + if (haveSelf) + *info= included; + else { + MergeIncludedSymbols(info,&included,newMerge,xkb); + FreeSymbolsInfo(&included); + } + return (info->errorCount==0); +} + +static LookupEntry groupNames[]= { + { "group1", 1 }, + { "group2", 2 }, + { "group3", 3 }, + { "group4", 4 }, + { "group5", 5 }, + { "group6", 6 }, + { "group7", 7 }, + { "group8", 8 }, + { NULL, 0 } +}; + + +#define SYMBOLS 1 +#define ACTIONS 2 + +static Bool +GetGroupIndex( KeyInfo * key, + ExprDef * arrayNdx, + unsigned what, + unsigned * ndx_rtrn) +{ +const char *name; +ExprResult tmp; + + if (what==SYMBOLS) name= "symbols"; + else name= "actions"; + + if (arrayNdx==NULL) { + register int i; + unsigned defined; + if (what==SYMBOLS) defined= key->symsDefined; + else defined= key->actsDefined; + + for (i=0;i<XkbNumKbdGroups;i++) { + if ((defined&(1<<i))==0) { + *ndx_rtrn= i; + return True; + } + } + ERROR3("Too many groups of %s for key %s (max %d)\n",name, + longText(key->name,XkbMessage), + XkbNumKbdGroups+1); + ACTION1("Ignoring %s defined for extra groups\n",name); + return False; + } + if (!ExprResolveInteger(arrayNdx,&tmp,SimpleLookup,(XPointer)groupNames)) { + ERROR2("Illegal group index for %s of key %s\n",name, + longText(key->name,XkbMessage)); + ACTION("Definition with non-integer array index ignored\n"); + return False; + } + if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) { + ERROR3("Group index for %s of key %s is out of range (1..%d)\n",name, + longText(key->name,XkbMessage), + XkbNumKbdGroups+1); + ACTION2("Ignoring %s for group %d\n",name,tmp.uval); + return False; + } + *ndx_rtrn= tmp.uval-1; + return True; +} + +static Bool +AddSymbolsToKey( KeyInfo * key, + XkbDescPtr xkb, + char * field, + ExprDef * arrayNdx, + ExprDef * value, + SymbolsInfo * info) +{ +unsigned ndx,nSyms; +int i; + + if (!GetGroupIndex(key,arrayNdx,SYMBOLS,&ndx)) + return False; + if (value==NULL) { + key->symsDefined|= (1<<ndx); + return True; + } + if (value->op!=ExprKeysymList) { + ERROR1("Expected a list of symbols, found %s\n",exprOpText(value->op)); + ACTION2("Ignoring symbols for group %d of %s\n",ndx, + longText(key->name,XkbMessage)); + return False; + } + if (key->syms[ndx]!=NULL) { + WSGO2("Symbols for key %s, group %d already defined\n", + longText(key->name,XkbMessage), + ndx); + return False; + } + nSyms= value->value.list.nSyms; + if (((key->numLevels[ndx]<nSyms)||(key->syms[ndx]==NULL))&& + (!ResizeKeyGroup(key,ndx,nSyms,False))) { + WSGO2("Could not resize group %d of key %s\n",ndx, + longText(key->name,XkbMessage)); + ACTION("Symbols lost\n"); + return False; + } + key->symsDefined|= (1<<ndx); + memcpy((char *)key->syms[ndx],(char *)value->value.list.syms, + nSyms*sizeof(KeySym)); + for (i=key->numLevels[ndx]-1;(i>=0)&&(key->syms[ndx][i]==NoSymbol);i--) { + key->numLevels[ndx]--; + } + return True; +} + +static Bool +AddActionsToKey( KeyInfo * key, + XkbDescPtr xkb, + char * field, + ExprDef * arrayNdx, + ExprDef * value, + SymbolsInfo * info) +{ +register int i; +unsigned ndx,nActs; +ExprDef * act; +XkbAnyAction * toAct; + + if (!GetGroupIndex(key,arrayNdx,ACTIONS,&ndx)) + return False; + + if (value==NULL) { + key->actsDefined|= (1<<ndx); + return True; + } + if (value->op!=ExprActionList) { + WSGO1("Bad expression type (%d) for action list value\n",value->op); + ACTION2("Ignoring actions for group %d of %s\n",ndx, + longText(key->name,XkbMessage)); + return False; + } + if (key->acts[ndx]!=NULL) { + WSGO2("Actions for key %s, group %d already defined\n", + longText(key->name,XkbMessage), + ndx); + return False; + } + for (nActs=0,act= value->value.child;act!=NULL;nActs++) { + act= (ExprDef *)act->common.next; + } + if (nActs<1) { + WSGO("Action list but not actions in AddActionsToKey\n"); + return False; + } + if (((key->numLevels[ndx]<nActs)||(key->acts[ndx]==NULL))&& + (!ResizeKeyGroup(key,ndx,nActs,True))) { + WSGO2("Could not resize group %d of key %s\n",ndx, + longText(key->name,XkbMessage)); + ACTION("Actions lost\n"); + return False; + } + key->actsDefined|= (1<<ndx); + + toAct= (XkbAnyAction *)key->acts[ndx]; + act= value->value.child; + for (i=0;i<nActs;i++,toAct++) { + if (!HandleActionDef(act,xkb,toAct,MergeOverride,info->action)) { + ERROR1("Illegal action definition for %s\n", + longText(key->name,XkbMessage)); + ACTION2("Action for group %d/level %d ignored\n",ndx+1,i+1); + } + act= (ExprDef *)act->common.next; + } + return True; +} + +static int +SetAllowNone(KeyInfo *key,ExprDef *arrayNdx,ExprDef *value) +{ +ExprResult tmp; +unsigned radio_groups= 0; + + if (arrayNdx==NULL) { + radio_groups= XkbAllRadioGroupsMask; + } + else { + if (!ExprResolveInteger(arrayNdx,&tmp,RadioLookup,NULL)){ + ERROR("Illegal index in group name definition\n"); + ACTION("Definition with non-integer array index ignored\n"); + return False; + } + if ((tmp.uval<1)||(tmp.uval>XkbMaxRadioGroups)) { + ERROR1("Illegal radio group specified (must be 1..%d)\n", + XkbMaxRadioGroups+1); + ACTION1("Value of \"allow none\" for group %d ignored\n",tmp.uval); + return False; + } + radio_groups|= (1<<(tmp.uval-1)); + } + if (!ExprResolveBoolean(value,&tmp,NULL,NULL)) { + ERROR1("Illegal \"allow none\" value for %s\n", + longText(key->name,XkbMessage)); + ACTION("Non-boolean value ignored\n"); + return False; + } + if (tmp.uval) key->allowNone|= radio_groups; + else key->allowNone&= ~radio_groups; + return True; +} + + +static LookupEntry lockingEntries[] = { + { "true", XkbKB_Lock }, + { "yes", XkbKB_Lock }, + { "on", XkbKB_Lock }, + { "false", XkbKB_Default }, + { "no", XkbKB_Default }, + { "off", XkbKB_Default }, + { "permanent", XkbKB_Lock|XkbKB_Permanent }, + { NULL, 0 } +}; + +static LookupEntry repeatEntries[]= { + { "true", RepeatYes }, + { "yes", RepeatYes }, + { "on", RepeatYes }, + { "false", RepeatNo }, + { "no", RepeatNo }, + { "off", RepeatNo }, + { "default", RepeatUndefined }, + { NULL, 0 } +}; + +static LookupEntry rgEntries[]= { + { "none", 0 }, + { NULL, 0 } +}; + +static Bool +SetSymbolsField( KeyInfo * key, + XkbDescPtr xkb, + char * field, + ExprDef * arrayNdx, + ExprDef * value, + SymbolsInfo * info) +{ +Bool ok= True; +ExprResult tmp; + + if (uStrCaseCmp(field,"type")==0) { + ExprResult ndx; + if ((!ExprResolveString(value,&tmp,NULL,NULL))&&(warningLevel>0)) { + WARN("The type field of a key symbol map must be a string\n"); + ACTION("Ignoring illegal type definition\n"); + } + if (arrayNdx==NULL) { + key->dfltType= XkbInternAtom(NULL,tmp.str,False); + key->defs.defined|= _Key_Type_Dflt; + } + else if (!ExprResolveInteger(arrayNdx,&ndx,SimpleLookup, + (XPointer)groupNames)) { + ERROR1("Illegal group index for type of key %s\n", + longText(key->name,XkbMessage)); + ACTION("Definition with non-integer array index ignored\n"); + return False; + } + else if ((ndx.uval<1)||(ndx.uval>XkbNumKbdGroups)) { + ERROR2("Group index for type of key %s is out of range (1..%d)\n", + longText(key->name,XkbMessage), + XkbNumKbdGroups+1); + ACTION1("Ignoring type for group %d\n",ndx.uval); + return False; + } + else { + key->types[ndx.uval-1]= XkbInternAtom(NULL,tmp.str,False); + key->typesDefined|= (1<<(ndx.uval-1)); + } + } + else if (uStrCaseCmp(field,"symbols")==0) + return AddSymbolsToKey(key,xkb,field,arrayNdx,value,info); + else if (uStrCaseCmp(field,"actions")==0) + return AddActionsToKey(key,xkb,field,arrayNdx,value,info); + else if ((uStrCaseCmp(field,"vmods")==0)|| + (uStrCaseCmp(field,"virtualmods")==0)|| + (uStrCaseCmp(field,"virtualmodifiers")==0)) { + ok= ExprResolveModMask(value,&tmp,LookupVModMask,(XPointer)xkb); + if (ok) { + key->vmodmap= (tmp.uval>>8); + key->defs.defined|= _Key_VModMap; + } + else { + ERROR1("Expected a virtual modifier mask, found %s\n", + exprOpText(value->op)); + ACTION1("Ignoring virtual modifiers definition for key %s\n", + longText(key->name,XkbMessage)); + } + } + else if ((uStrCaseCmp(field,"locking")==0)||(uStrCaseCmp(field,"lock")==0)|| + (uStrCaseCmp(field,"locks")==0)) { + ok= ExprResolveEnum(value,&tmp,lockingEntries); + if (ok) + key->behavior.type= tmp.uval; + key->defs.defined|= _Key_Behavior; + } + else if ((uStrCaseCmp(field,"radiogroup")==0)|| + (uStrCaseCmp(field,"permanentradiogroup")==0)) { + Bool permanent= False; + if (uStrCaseCmp(field,"permanentradiogroup")==0) + permanent= True; + ok= ExprResolveInteger(value,&tmp,SimpleLookup,(XPointer)rgEntries); + if (!ok) { + ERROR1("Illegal radio group specification for %s\n", + longText(key->name,XkbMessage)); + ACTION("Non-integer radio group ignored\n"); + return False; + } + if (tmp.uval==0) { + key->behavior.type= XkbKB_Default; + key->behavior.data= 0; + return ok; + } + if ((tmp.uval<1)||(tmp.uval>XkbMaxRadioGroups)) { + ERROR1("Radio group specification for %s out of range (1..32)\n", + longText(key->name,XkbMessage)); + ACTION1("Illegal radio group %d ignored\n",tmp.uval); + return False; + } + key->behavior.type= XkbKB_RadioGroup|(permanent?XkbKB_Permanent:0); + key->behavior.data= tmp.uval-1; + if (key->allowNone&(1<<(tmp.uval-1))) + key->behavior.data|= XkbKB_RGAllowNone; + key->defs.defined|= _Key_Behavior; + } + else if (uStrCaseEqual(field,"allownone")) { + ok= SetAllowNone(key,arrayNdx,value); + } + else if (uStrCasePrefix("overlay",field)|| + uStrCasePrefix("permanentoverlay",field)) { + Bool permanent= False; + char *which; + int overlayNdx; + if (uStrCasePrefix("permanent",field)) { + permanent= True; + which= &field[sizeof("permanentoverlay")-1]; + } + else { + which= &field[sizeof("overlay")-1]; + } + if (sscanf(which,"%d",&overlayNdx)==1) { + if (((overlayNdx<1)||(overlayNdx>2))&&(warningLevel>0)) { + ERROR2("Illegal overlay %d specified for %s\n", + overlayNdx, + longText(key->name,XkbMessage)); + ACTION("Ignored\n"); + return False; + } + } + else if (*which=='\0') + overlayNdx=1; + else if (warningLevel>0) { + ERROR2("Illegal overlay \"%s\" specified for %s\n", + which, + longText(key->name,XkbMessage)); + ACTION("Ignored\n"); + return False; + } + ok= ExprResolveKeyName(value,&tmp,NULL,NULL); + if (!ok) { + ERROR1("Illegal overlay key specification for %s\n", + longText(key->name,XkbMessage)); + ACTION("Overlay key must be specified by name\n"); + return False; + } + if (overlayNdx==1) key->behavior.type= XkbKB_Overlay1; + else key->behavior.type= XkbKB_Overlay2; + if (permanent) + key->behavior.type|= XkbKB_Permanent; + + key->behavior.data= 0; + key->nameForOverlayKey= KeyNameToLong(tmp.keyName.name); + key->defs.defined|= _Key_Behavior; + } + else if ((uStrCaseCmp(field,"repeating")==0)|| + (uStrCaseCmp(field,"repeats")==0)|| + (uStrCaseCmp(field,"repeat")==0)){ + ok= ExprResolveEnum(value,&tmp,repeatEntries); + if (!ok) { + ERROR1("Illegal repeat setting for %s\n", + longText(key->name,XkbMessage)); + ACTION("Non-boolean repeat setting ignored\n"); + return False; + } + key->repeat= tmp.uval; + key->defs.defined|= _Key_Repeat; + } + else if ((uStrCaseCmp(field,"groupswrap")==0)|| + (uStrCaseCmp(field,"wrapgroups")==0)) { + ok= ExprResolveBoolean(value,&tmp,NULL,NULL); + if (!ok) { + ERROR1("Illegal groupsWrap setting for %s\n", + longText(key->name,XkbMessage)); + ACTION("Non-boolean value ignored\n"); + return False; + } + if (tmp.uval) key->groupInfo= XkbWrapIntoRange; + else key->groupInfo= XkbClampIntoRange; + key->defs.defined|= _Key_GroupInfo; + } + else if ((uStrCaseCmp(field,"groupsclamp")==0)|| + (uStrCaseCmp(field,"clampgroups")==0)) { + ok= ExprResolveBoolean(value,&tmp,NULL,NULL); + if (!ok) { + ERROR1("Illegal groupsClamp setting for %s\n", + longText(key->name,XkbMessage)); + ACTION("Non-boolean value ignored\n"); + return False; + } + if (tmp.uval) key->groupInfo= XkbClampIntoRange; + else key->groupInfo= XkbWrapIntoRange; + key->defs.defined|= _Key_GroupInfo; + } + else if ((uStrCaseCmp(field,"groupsredirect")==0)|| + (uStrCaseCmp(field,"redirectgroups")==0)) { + if (!ExprResolveInteger(value,&tmp,SimpleLookup,(XPointer)groupNames)) { + ERROR1("Illegal group index for redirect of key %s\n", + longText(key->name,XkbMessage)); + ACTION("Definition with non-integer group ignored\n"); + return False; + } + if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) { + ERROR2("Out-of-range (1..%d) group for redirect of key %s\n", + XkbNumKbdGroups, + longText(key->name,XkbMessage)); + ERROR1("Ignoring illegal group %d\n",tmp.uval); + return False; + } + key->groupInfo= XkbSetGroupInfo(0,XkbRedirectIntoRange,tmp.uval-1); + key->defs.defined|= _Key_GroupInfo; + } + else { + ERROR1("Unknown field %s in a symbol interpretation\n",field); + ACTION("Definition ignored\n"); + ok= False; + } + return ok; +} + +static int +SetGroupName(SymbolsInfo *info,ExprDef *arrayNdx,ExprDef *value) +{ +ExprResult tmp,name; + + if ((arrayNdx==NULL)&&(warningLevel>0)) { + WARN("You must specify an index when specifying a group name\n"); + ACTION("Group name definition without array subscript ignored\n"); + return False; + } + if (!ExprResolveInteger(arrayNdx,&tmp,SimpleLookup,(XPointer)groupNames)) { + ERROR("Illegal index in group name definition\n"); + ACTION("Definition with non-integer array index ignored\n"); + return False; + } + if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) { + ERROR1("Attempt to specify name for illegal group (must be 1..%d)\n", + XkbNumKbdGroups+1); + ACTION1("Name for group %d ignored\n",tmp.uval); + return False; + } + if (!ExprResolveString(value,&name,NULL,NULL)) { + ERROR("Group name must be a string\n"); + ACTION1("Illegal name for group %d ignored\n",tmp.uval); + return False; + } + info->groupNames[tmp.uval-1+info->explicit_group]= + XkbInternAtom(NULL,name.str,False); + + return True; +} + +static int +HandleSymbolsVar(VarDef *stmt,XkbDescPtr xkb,SymbolsInfo *info) +{ +ExprResult elem,field,tmp; +ExprDef * arrayNdx; + + if (ExprResolveLhs(stmt->name,&elem,&field,&arrayNdx)==0) + return 0; /* internal error, already reported */ + if (elem.str&&(uStrCaseCmp(elem.str,"key")==0)) { + return SetSymbolsField(&info->dflt,xkb,field.str,arrayNdx,stmt->value, + info); + } + else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"name")==0)|| + (uStrCaseCmp(field.str,"groupname")==0))) { + return SetGroupName(info,arrayNdx,stmt->value); + } + else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"groupswrap")==0)|| + (uStrCaseCmp(field.str,"wrapgroups")==0))) { + if (!ExprResolveBoolean(stmt->value,&tmp,NULL,NULL)) { + ERROR("Illegal setting for global groupsWrap\n"); + ACTION("Non-boolean value ignored\n"); + return False; + } + if (tmp.uval) info->groupInfo= XkbWrapIntoRange; + else info->groupInfo= XkbClampIntoRange; + return True; + } + else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"groupsclamp")==0)|| + (uStrCaseCmp(field.str,"clampgroups")==0))) { + if (!ExprResolveBoolean(stmt->value,&tmp,NULL,NULL)) { + ERROR("Illegal setting for global groupsClamp\n"); + ACTION("Non-boolean value ignored\n"); + return False; + } + if (tmp.uval) info->groupInfo= XkbClampIntoRange; + else info->groupInfo= XkbWrapIntoRange; + return True; + } + else if ((elem.str==NULL)&&((uStrCaseCmp(field.str,"groupsredirect")==0)|| + (uStrCaseCmp(field.str,"redirectgroups")==0))) { + if (!ExprResolveInteger(stmt->value,&tmp, + SimpleLookup,(XPointer)groupNames)) { + ERROR("Illegal group index for global groupsRedirect\n"); + ACTION("Definition with non-integer group ignored\n"); + return False; + } + if ((tmp.uval<1)||(tmp.uval>XkbNumKbdGroups)) { + ERROR1("Out-of-range (1..%d) group for global groupsRedirect\n", + XkbNumKbdGroups); + ACTION1("Ignoring illegal group %d\n",tmp.uval); + return False; + } + info->groupInfo= XkbSetGroupInfo(0,XkbRedirectIntoRange,tmp.uval); + return True; + } + else if ((elem.str==NULL)&&(uStrCaseCmp(field.str,"allownone")==0)) { + return SetAllowNone(&info->dflt,arrayNdx,stmt->value); + } + return SetActionField(xkb,elem.str,field.str,arrayNdx,stmt->value, + &info->action); +} + +static Bool +HandleSymbolsBody( VarDef * def, + XkbDescPtr xkb, + KeyInfo * key, + SymbolsInfo * info) +{ +Bool ok= True; +ExprResult tmp,field; +ExprDef * arrayNdx; + + for (;def!=NULL;def= (VarDef *)def->common.next) { + if ((def->name)&&(def->name->type==ExprFieldRef)) { + ok= HandleSymbolsVar(def,xkb,info); + continue; + } + else { + if (def->name==NULL) { + if ((def->value==NULL)||(def->value->op==ExprKeysymList)) + field.str= "symbols"; + else field.str= "actions"; + arrayNdx= NULL; + } + else { + ok= ExprResolveLhs(def->name,&tmp,&field,&arrayNdx); + } + if (ok) + ok= SetSymbolsField(key,xkb,field.str,arrayNdx,def->value,info); + } + } + return ok; +} + +static Bool +SetExplicitGroup( SymbolsInfo * info, + KeyInfo * key) +{ + unsigned group = info->explicit_group; + + if (group == 0) + return True; + + if ((key->typesDefined|key->symsDefined|key->actsDefined) & ~1) { + int i; + WARN1("For the map %s an explicit group specified\n", info->name); + WARN1("but key %s has more than one group defined\n", + longText(key->name,XkbMessage)); + ACTION("All groups except first one will be ignored\n"); + for (i = 1; i < XkbNumKbdGroups ; i++) { + key->numLevels[i]= 0; + if (key->syms[i]!=NULL) + uFree(key->syms[i]); + key->syms[i]= (KeySym*) NULL; + if (key->acts[i]!=NULL) + uFree(key->acts[i]); + key->acts[i]= (XkbAction*) NULL; + key->types[i]= (Atom) 0; + } + } + key->typesDefined = key->symsDefined = key->actsDefined = 1 << group; + + key->numLevels[group]= key->numLevels[0]; + key->numLevels[0]= 0; + key->syms[group]= key->syms[0]; + key->syms[0]= (KeySym*) NULL; + key->acts[group]= key->acts[0]; + key->acts[0]= (XkbAction*) NULL; + key->types[group]= key->types[0]; + key->types[0]= (Atom) 0; + return True; +} + +static int +HandleSymbolsDef( SymbolsDef * stmt, + XkbDescPtr xkb, + unsigned merge, + SymbolsInfo * info) +{ +KeyInfo key; + + InitKeyInfo(&key); + CopyKeyInfo(&info->dflt,&key,False); + key.defs.merge= stmt->merge; + key.name= KeyNameToLong(stmt->keyName); + if (!HandleSymbolsBody((VarDef *)stmt->symbols,xkb,&key,info)) { + info->errorCount++; + return False; + } + + if (!SetExplicitGroup(info,&key)) { + info->errorCount++; + return False; + } + + if (!AddKeySymbols(info,&key,xkb)) { + info->errorCount++; + return False; + } + return True; +} + +static Bool +HandleModMapDef( ModMapDef * def, + XkbDescPtr xkb, + unsigned merge, + SymbolsInfo * info) +{ +ExprDef * key; +ModMapEntry tmp; +ExprResult rtrn; +Bool ok; + + if (!LookupModIndex(NULL,None,def->modifier,TypeInt,&rtrn)) { + ERROR("Illegal modifier map definition\n"); + ACTION1("Ignoring map for non-modifier \"%s\"\n", + XkbAtomText(NULL,def->modifier,XkbMessage)); + return False; + } + ok= True; + tmp.modifier= rtrn.uval; + for (key=def->keys;key!=NULL;key=(ExprDef *)key->common.next) { + if ((key->op==ExprValue)&&(key->type==TypeKeyName)) { + tmp.haveSymbol= False; + tmp.u.keyName= KeyNameToLong(key->value.keyName); + } + else if (ExprResolveKeySym(key,&rtrn,NULL,NULL)) { + tmp.haveSymbol= True; + tmp.u.keySym= rtrn.uval; + } + else { + ERROR("Modmap entries may contain only key names or keysyms\n"); + ACTION1("Illegal definition for %s modifier ignored\n", + XkbModIndexText(tmp.modifier,XkbMessage)); + continue; + } + + ok= AddModMapEntry(info,&tmp)&&ok; + } + return ok; +} + +static void +HandleSymbolsFile( XkbFile * file, + XkbDescPtr xkb, + unsigned merge, + SymbolsInfo * info) +{ +ParseCommon *stmt; + + info->name= uStringDup(file->name); + stmt= file->defs; + while (stmt) { + switch (stmt->stmtType) { + case StmtInclude: + if (!HandleIncludeSymbols((IncludeStmt *)stmt,xkb,info, + HandleSymbolsFile)) + info->errorCount++; + break; + case StmtSymbolsDef: + if (!HandleSymbolsDef((SymbolsDef *)stmt,xkb,merge,info)) + info->errorCount++; + break; + case StmtVarDef: + if (!HandleSymbolsVar((VarDef *)stmt,xkb,info)) + info->errorCount++; + break; + case StmtVModDef: + if (!HandleVModDef((VModDef *)stmt,merge,&info->vmods)) + info->errorCount++; + break; + case StmtInterpDef: + ERROR("Interpretation files may not include other types\n"); + ACTION("Ignoring definition of symbol interpretation\n"); + info->errorCount++; + break; + case StmtKeycodeDef: + ERROR("Interpretation files may not include other types\n"); + ACTION("Ignoring definition of key name\n"); + info->errorCount++; + break; + case StmtModMapDef: + if (!HandleModMapDef((ModMapDef *)stmt,xkb,merge,info)) + info->errorCount++; + break; + default: + WSGO1("Unexpected statement type %d in HandleSymbolsFile\n", + stmt->stmtType); + break; + } + stmt= stmt->next; + if (info->errorCount>10) { +#ifdef NOISY + ERROR("Too many errors\n"); +#endif + ACTION1("Abandoning symbols file \"%s\"\n",file->topName); + break; + } + } + return; +} + +static Bool +FindKeyForSymbol(XkbDescPtr xkb,KeySym sym,unsigned int *kc_rtrn) +{ +register int i, j; +register Bool gotOne; + + j= 0; + do { + gotOne= False; + for (i = xkb->min_key_code; i <= (int)xkb->max_key_code; i++) { + if ( j<(int)XkbKeyNumSyms(xkb,i) ) { + gotOne = True; + if ((XkbKeySym(xkb,i,j)==sym)) { + *kc_rtrn= i; + return True; + } + } + } + j++; + } while (gotOne); + return False; +} + +static Bool +FindNamedType(XkbDescPtr xkb,Atom name,unsigned *type_rtrn) +{ +register unsigned n; + + if (xkb&&xkb->map&&xkb->map->types) { + for (n=0;n<xkb->map->num_types;n++) { + if (xkb->map->types[n].name==(Atom)name) { + *type_rtrn= n; + return True; + } + } + } + return False; +} + +static Bool +KSIsLower (KeySym ks) +{ + KeySym lower, upper; + XConvertCase(ks, &lower, &upper); + + if (lower == upper) + return False; + return (ks == lower ? True : False); +} + +static Bool +KSIsUpper (KeySym ks) +{ + KeySym lower, upper; + XConvertCase(ks, &lower, &upper); + + if (lower == upper) + return False; + return (ks == upper ? True : False); +} + +static Bool +FindAutomaticType(int width,KeySym *syms,Atom *typeNameRtrn, Bool *autoType) +{ + *autoType = False; + if ((width==1)||(width==0)) { + *typeNameRtrn= XkbInternAtom(NULL,"ONE_LEVEL",False); + *autoType = True; + } else if (width == 2) { + if ( syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]) ) { + *typeNameRtrn= XkbInternAtom(NULL,"ALPHABETIC",False); + } else if ( syms && + (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])) ) { + *typeNameRtrn= XkbInternAtom(NULL,"KEYPAD",False); + *autoType = True; + } else { + *typeNameRtrn= XkbInternAtom(NULL,"TWO_LEVEL",False); + *autoType = True; + } + } else if (width <= 4 ) { + if ( syms && KSIsLower(syms[0]) && KSIsUpper(syms[1]) ) + if ( KSIsLower(syms[2]) && KSIsUpper(syms[3]) ) + *typeNameRtrn= XkbInternAtom(NULL, + "FOUR_LEVEL_ALPHABETIC",False); + else + *typeNameRtrn= XkbInternAtom(NULL, + "FOUR_LEVEL_SEMIALPHABETIC",False); + + else if ( syms && (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1])) ) + *typeNameRtrn= XkbInternAtom(NULL, + "FOUR_LEVEL_KEYPAD",False); + else *typeNameRtrn= XkbInternAtom(NULL,"FOUR_LEVEL",False); + } + return ((width>=0)&&(width<=4)); +} + +static void +PrepareKeyDef(KeyInfo *key) +{ + int i, j, width, defined, lastGroup; + Bool identical; + + defined = key->symsDefined | key->actsDefined | key->typesDefined; + for (i = XkbNumKbdGroups - 1; i >= 0; i--) { + if (defined & (1<<i)) + break; + } + lastGroup = i; + + if (lastGroup == 0) + return; + + /* If there are empty groups between non-empty ones fill them with data */ + /* from the first group. */ + /* We can make a wrong assumption here. But leaving gaps is worse. */ + for (i = lastGroup; i > 0; i--) { + if (defined & (1<<i)) + continue; + width = key->numLevels[0]; + if (key->typesDefined & 1) { + for (j = 0; j < width; j++) { + key->types[i] = key->types[0]; + } + key->typesDefined |= 1 << i; + } + if ((key->actsDefined & 1) && key->acts[0]) { + key->acts[i]= uTypedCalloc(width, XkbAction); + if (key->acts[i] == NULL) + continue; + memcpy((void *) key->acts[i], (void *) key->acts[0], + width * sizeof(XkbAction)); + key->actsDefined |= 1 << i; + } + if ((key->symsDefined & 1) && key->syms[0]) { + key->syms[i]= uTypedCalloc(width, KeySym); + if (key->syms[i] == NULL) + continue; + memcpy((void *) key->syms[i], (void *) key->syms[0], + width * sizeof(KeySym)); + key->symsDefined |= 1 << i; + } + if (defined & 1) { + key->numLevels[i] = key->numLevels[0]; + } + } + /* If all groups are completely identical remove them all */ + /* exept the first one. */ + identical = True; + for (i = lastGroup; i > 0; i--) { + if ((key->numLevels[i] != key->numLevels[0]) || + (key->types[i] != key->types[0])) { + identical = False; + break; + } + if ((key->syms[i] != key->syms[0]) && + (key->syms[i] == NULL || key->syms[0] == NULL || + memcmp((void*) key->syms[i], (void*) key->syms[0], + sizeof(KeySym) * key->numLevels[0])) ) { + identical = False; + break; + } + if ((key->acts[i] != key->acts[0]) && + (key->acts[i] == NULL || key->acts[0] == NULL || + memcmp((void*) key->acts[i], (void*) key->acts[0], + sizeof(XkbAction) * key->numLevels[0]))) { + identical = False; + break; + } + } + if (identical) { + for (i = lastGroup; i > 0; i--) { + key->numLevels[i]= 0; + if (key->syms[i] != NULL) + uFree(key->syms[i]); + key->syms[i]= (KeySym*) NULL; + if (key->acts[i] != NULL) + uFree(key->acts[i]); + key->acts[i]= (XkbAction*) NULL; + key->types[i]= (Atom) 0; + } + key->symsDefined &= 1; + key->actsDefined &= 1; + key->typesDefined &= 1; + } + return; +} + +static Bool +CopySymbolsDef(XkbFileInfo *result,KeyInfo *key,int start_from) +{ +register int i; +unsigned okc,kc,width,tmp,nGroups; +XkbKeyTypePtr type; +Bool haveActions,autoType,useAlias; +KeySym * outSyms; +XkbAction * outActs; +XkbDescPtr xkb; +unsigned types[XkbNumKbdGroups]; + + xkb= result->xkb; + useAlias= (start_from==0); + if (!FindNamedKey(xkb,key->name,&kc,useAlias,CreateKeyNames(xkb), + start_from)) { + if ((start_from==0)&&(warningLevel>=5)) { + WARN2("Key %s not found in %s keycodes\n", + longText(key->name,XkbMessage), + XkbAtomText(NULL,xkb->names->keycodes,XkbMessage)); + ACTION("Symbols ignored\n"); + } + return False; + } + + haveActions= False; + for (i=width=nGroups=0;i<XkbNumKbdGroups;i++) { + if (((i+1)>nGroups)&&(((key->symsDefined|key->actsDefined)&(1<<i))|| + (key->typesDefined)&(1<<i))) + nGroups= i+1; + if (key->acts[i]) + haveActions= True; + autoType= False; + if (key->types[i]==None) { + if (key->dfltType!=None) + key->types[i]= key->dfltType; + else if (FindAutomaticType(key->numLevels[i],key->syms[i], + &key->types[i], &autoType)) { + } + else { + if (warningLevel>=5) { + WARN1("No automatic type for %d symbols\n", + (unsigned int)key->numLevels[i]); + ACTION3("Using %s for the %s key (keycode %d)\n", + XkbAtomText(NULL,key->types[i],XkbMessage), + longText(key->name,XkbMessage),kc); + } + } + } + if (FindNamedType(xkb,key->types[i],&types[i])) { + if (!autoType || key->numLevels[i] > 2) + xkb->server->explicit[kc]|= (1<<i); + } + else { + if (warningLevel>=3) { + WARN1("Type \"%s\" is not defined\n", + XkbAtomText(NULL,key->types[i],XkbMessage)); + ACTION2("Using TWO_LEVEL for the %s key (keycode %d)\n", + longText(key->name,XkbMessage),kc); + } + types[i]= XkbTwoLevelIndex; + } + type= &xkb->map->types[types[i]]; + if (type->num_levels<key->numLevels[i]) { + if (warningLevel>0) { + WARN4("Type \"%s\" has %d levels, but %s has %d symbols\n", + XkbAtomText(NULL,type->name,XkbMessage), + (unsigned int)type->num_levels, + longText(key->name,XkbMessage), + (unsigned int)key->numLevels[i]); + ACTION("Ignoring extra symbols\n"); + } + key->numLevels[i]= type->num_levels; + } + if (key->numLevels[i]>width) + width= key->numLevels[i]; + if (type->num_levels>width) + width= type->num_levels; + } + + i= width*nGroups; + outSyms= XkbResizeKeySyms(xkb,kc,i); + if (outSyms==NULL) { + WSGO2("Could not enlarge symbols for %s (keycode %d)\n", + longText(key->name,XkbMessage),kc); + return False; + } + if (haveActions) { + outActs= XkbResizeKeyActions(xkb,kc,i); + if (outActs==NULL) { + WSGO2("Could not enlarge actions for %s (key %d)\n", + longText(key->name,XkbMessage),kc); + return False; + } + xkb->server->explicit[kc]|= XkbExplicitInterpretMask; + } + else outActs= NULL; + if (key->defs.defined&_Key_GroupInfo) + i= key->groupInfo; + else i= xkb->map->key_sym_map[kc].group_info; + xkb->map->key_sym_map[kc].group_info= XkbSetNumGroups(i,nGroups); + xkb->map->key_sym_map[kc].width= width; + for (i=0;i<nGroups;i++) { + xkb->map->key_sym_map[kc].kt_index[i]= types[i]; + if (key->syms[i]!=NULL) { + for (tmp=0;tmp<width;tmp++) { + if (tmp<key->numLevels[i]) + outSyms[tmp]= key->syms[i][tmp]; + else outSyms[tmp]= NoSymbol; + if ((outActs!=NULL)&&(key->acts[i]!=NULL)) { + if (tmp<key->numLevels[i]) + outActs[tmp]= key->acts[i][tmp]; + else outActs[tmp].type= XkbSA_NoAction; + } + } + } + outSyms+= width; + if (outActs) + outActs+= width; + } + switch (key->behavior.type&XkbKB_OpMask) { + case XkbKB_Default: + break; + case XkbKB_Overlay1: + case XkbKB_Overlay2: + /* find key by name! */ + if (!FindNamedKey(xkb,key->nameForOverlayKey,&okc,True, + CreateKeyNames(xkb),0)) { + if (warningLevel>=1) { + WARN2("Key %s not found in %s keycodes\n", + longText(key->nameForOverlayKey,XkbMessage), + XkbAtomText(NULL,xkb->names->keycodes,XkbMessage)); + ACTION1("Not treating %s as an overlay key \n", + longText(key->name,XkbMessage)); + } + break; + } + key->behavior.data= okc; + default: + xkb->server->behaviors[kc]= key->behavior; + xkb->server->explicit[kc]|= XkbExplicitBehaviorMask; + break; + } + if (key->defs.defined&_Key_VModMap) { + xkb->server->vmodmap[kc]= key->vmodmap; + xkb->server->explicit[kc]|= XkbExplicitVModMapMask; + } + if (key->repeat!=RepeatUndefined) { + if (key->repeat==RepeatYes) + xkb->ctrls->per_key_repeat[kc/8]|= (1<<(kc%8)); + else xkb->ctrls->per_key_repeat[kc/8]&= ~(1<<(kc%8)); + xkb->server->explicit[kc]|= XkbExplicitAutoRepeatMask; + } + CopySymbolsDef(result,key,kc+1); + return True; +} + +static Bool +CopyModMapDef(XkbFileInfo *result,ModMapEntry *entry) +{ +unsigned kc; +XkbDescPtr xkb; + + xkb= result->xkb; + if ((!entry->haveSymbol)&&(!FindNamedKey(xkb,entry->u.keyName,&kc,True, + CreateKeyNames(xkb),0))) { + if (warningLevel>=5) { + WARN2("Key %s not found in %s keycodes\n", + longText(entry->u.keyName,XkbMessage), + XkbAtomText(NULL,xkb->names->keycodes,XkbMessage)); + ACTION1("Modifier map entry for %s not updated\n", + XkbModIndexText(entry->modifier,XkbMessage)); + } + return False; + } + else if (entry->haveSymbol&&(!FindKeyForSymbol(xkb,entry->u.keySym,&kc))) { + if (warningLevel>5) { + WARN2("Key \"%s\" not found in %s symbol map\n", + XkbKeysymText(entry->u.keySym,XkbMessage), + XkbAtomText(NULL,xkb->names->symbols,XkbMessage)); + ACTION1("Modifier map entry for %s not updated\n", + XkbModIndexText(entry->modifier,XkbMessage)); + } + return False; + } + xkb->map->modmap[kc]|= (1<<entry->modifier); + return True; +} + +Bool +CompileSymbols(XkbFile *file,XkbFileInfo *result,unsigned merge) +{ +register int i; +SymbolsInfo info; +XkbDescPtr xkb; + + xkb= result->xkb; + InitSymbolsInfo(&info,xkb); + info.dflt.defs.fileID= file->id; + info.dflt.defs.merge= merge; + HandleSymbolsFile(file,xkb,merge,&info); + + if (info.nKeys == 0) + return True; + if (info.errorCount==0) { + KeyInfo *key; + if (XkbAllocNames(xkb,XkbSymbolsNameMask|XkbGroupNamesMask,0,0) + !=Success) { + WSGO("Can not allocate names in CompileSymbols\n"); + ACTION("Symbols not added\n"); + return False; + } + if(XkbAllocClientMap(xkb,XkbKeySymsMask|XkbModifierMapMask,0)!=Success){ + WSGO("Could not allocate client map in CompileSymbols\n"); + ACTION("Symbols not added\n"); + return False; + } + if (XkbAllocServerMap(xkb,XkbAllServerInfoMask,32)!=Success) { + WSGO("Could not allocate server map in CompileSymbols\n"); + ACTION("Symbols not added\n"); + return False; + } + if (XkbAllocControls(xkb,XkbPerKeyRepeatMask)!=Success) { + WSGO("Could not allocate controls in CompileSymbols\n"); + ACTION("Symbols not added\n"); + return False; + } + xkb->names->symbols= XkbInternAtom(xkb->dpy,info.name,False); + if (info.aliases) + ApplyAliases(xkb,False,&info.aliases); + for (i=0;i<XkbNumKbdGroups;i++) { + if (info.groupNames[i]!=None) + xkb->names->groups[i]= info.groupNames[i]; + } + for (key=info.keys,i=0;i<info.nKeys;i++,key++) { + PrepareKeyDef(key); + } + for (key=info.keys,i=0;i<info.nKeys;i++,key++) { + if (!CopySymbolsDef(result,key,0)) + info.errorCount++; + } + if (warningLevel>3) { + for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) { + if (xkb->names->keys[i].name[0]=='\0') + continue; + if (XkbKeyNumGroups(xkb,i)<1) { + char buf[5]; + memcpy(buf,xkb->names->keys[i].name,4); + buf[4]= '\0'; + WARN2("No symbols defined for <%s> (keycode %d)\n",buf,i); + } + } + } + if (info.modMap) { + ModMapEntry *mm,*next; + for (mm=info.modMap;mm!=NULL;mm=next) { + if (!CopyModMapDef(result,mm)) + info.errorCount++; + next= (ModMapEntry *)mm->defs.next; + } + } + return True; + } + return False; +} |