diff options
Diffstat (limited to 'xkbcomp/keytypes.c')
-rw-r--r-- | xkbcomp/keytypes.c | 2586 |
1 files changed, 1293 insertions, 1293 deletions
diff --git a/xkbcomp/keytypes.c b/xkbcomp/keytypes.c index da55d755d..d0d5302f9 100644 --- a/xkbcomp/keytypes.c +++ b/xkbcomp/keytypes.c @@ -1,1293 +1,1293 @@ -/************************************************************ - 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)) - -/***====================================================================***/ - -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(const 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; -} - -/** - * Return a pointer to the next free XkbKTMapEntry, reallocating space if - * necessary. - */ -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; -} - -/** - * Add a new KTMapEntry to the given key type. If an entry with the same mods - * already exists, the level is updated (if clobber is TRUE). Otherwise, a new - * entry is created. - * - * @param clobber Overwrite existing entry. - * @param report True if a warning is to be printed on. - */ -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; /* modifiers < 512 */ - entry.mods.vmods = (rtrn.uval >> 8) & 0xffff; /* modifiers > 512 */ - 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); -} - -/***====================================================================***/ - -/** - * Parses the fields in a type "..." { } description. - * - * @param field The field to parse (e.g. modifiers, map, level_name) - */ -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"); - } - /* get modifier mask for current type */ - 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; /* core mods */ - vmods = (tmp.uval >> 8) & 0xffff; /* xkb virtual mods */ - 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; -} - -/** - * Process a type "XYZ" { } specification in the xkb_types section. - * - */ -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 = NULL; - 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; - - /* Parse the actual content. */ - 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); - } - } - /* Now add the new keytype to the info struct */ - if (!AddKeyType(xkb, info, &type)) - { - info->errorCount++; - return False; - } - return True; -} - -/** - * Process an xkb_types section. - * - * @param file The parsed xkb_types section. - * @param merge Merge Strategy (e.g. MergeOverride) - * @param info Pointer to memory where the outcome will be stored. - */ -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: /* e.g. type "ONE_LEVEL" */ - if (!HandleKeyTypeDef((KeyTypeDef *) stmt, xkb, merge, info)) - info->errorCount++; - break; - case StmtVarDef: - if (!HandleKeyTypeVar((VarDef *) stmt, xkb, info)) - info->errorCount++; - break; - case StmtVModDef: /* virtual_modifiers NumLock, ... */ - 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 != NULL) - { - 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; -} +/************************************************************
+ 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))
+
+/***====================================================================***/
+
+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(const 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;
+}
+
+/**
+ * Return a pointer to the next free XkbKTMapEntry, reallocating space if
+ * necessary.
+ */
+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;
+}
+
+/**
+ * Add a new KTMapEntry to the given key type. If an entry with the same mods
+ * already exists, the level is updated (if clobber is TRUE). Otherwise, a new
+ * entry is created.
+ *
+ * @param clobber Overwrite existing entry.
+ * @param report True if a warning is to be printed on.
+ */
+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; /* modifiers < 512 */
+ entry.mods.vmods = (rtrn.uval >> 8) & 0xffff; /* modifiers > 512 */
+ 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);
+}
+
+/***====================================================================***/
+
+/**
+ * Parses the fields in a type "..." { } description.
+ *
+ * @param field The field to parse (e.g. modifiers, map, level_name)
+ */
+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");
+ }
+ /* get modifier mask for current type */
+ 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; /* core mods */
+ vmods = (tmp.uval >> 8) & 0xffff; /* xkb virtual mods */
+ 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;
+}
+
+/**
+ * Process a type "XYZ" { } specification in the xkb_types section.
+ *
+ */
+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 = NULL;
+ 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;
+
+ /* Parse the actual content. */
+ 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);
+ }
+ }
+ /* Now add the new keytype to the info struct */
+ if (!AddKeyType(xkb, info, &type))
+ {
+ info->errorCount++;
+ return False;
+ }
+ return True;
+}
+
+/**
+ * Process an xkb_types section.
+ *
+ * @param file The parsed xkb_types section.
+ * @param merge Merge Strategy (e.g. MergeOverride)
+ * @param info Pointer to memory where the outcome will be stored.
+ */
+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: /* e.g. type "ONE_LEVEL" */
+ if (!HandleKeyTypeDef((KeyTypeDef *) stmt, xkb, merge, info))
+ info->errorCount++;
+ break;
+ case StmtVarDef:
+ if (!HandleKeyTypeVar((VarDef *) stmt, xkb, info))
+ info->errorCount++;
+ break;
+ case StmtVModDef: /* virtual_modifiers NumLock, ... */
+ 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 != NULL)
+ {
+ 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;
+}
|