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