summaryrefslogtreecommitdiff
path: root/app/xkbcomp/keytypes.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/xkbcomp/keytypes.c')
-rw-r--r--app/xkbcomp/keytypes.c1159
1 files changed, 1159 insertions, 0 deletions
diff --git a/app/xkbcomp/keytypes.c b/app/xkbcomp/keytypes.c
new file mode 100644
index 000000000..e43613688
--- /dev/null
+++ b/app/xkbcomp/keytypes.c
@@ -0,0 +1,1159 @@
+/* $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.
+
+ ********************************************************/
+/* $XFree86: xc/programs/xkbcomp/keytypes.c,v 1.4 2001/01/17 23:45:44 dawes Exp $ */
+
+#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 /* xkb */,
+ KeyTypeInfo * /* type */,
+ XkbKTMapEntryPtr /* new */,
+ Bool /* clobber */,
+ Bool /* report */
+);
+
+extern Bool AddPreserve(
+ XkbDescPtr /* xkb */,
+ KeyTypeInfo * /* type */,
+ PreserveInfo * /* new */,
+ Bool /* clobber */,
+ Bool /* report */
+);
+
+extern Bool AddLevelName(
+ KeyTypeInfo * /* type */,
+ unsigned /* level */,
+ Atom /* name */,
+ Bool /* clobber */,
+ Bool /* report */
+);
+
+#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 * /* file */,
+ XkbDescPtr /* xkb */,
+ unsigned /* merge */,
+ KeyTypesInfo * /* included */
+);
+
+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; /* 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
+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; /* 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
+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;
+ }
+
+ /* 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
+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);
+
+ /* 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
+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;
+}
+