summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Nicholson <dbn.lists@gmail.com>2009-03-27 06:55:32 -0700
committerDan Nicholson <dbn.lists@gmail.com>2009-03-27 06:55:32 -0700
commit0c1bbb05d975cf7b3411259900500cc122fc136b (patch)
tree6e5c9c6adf8674c48da18c55993b530e69fac5fa /src
parentf4d8e2932cdd60653d2f762ad7502e6ec5710fe5 (diff)
downloadlibxkbcommon-0c1bbb05d975cf7b3411259900500cc122fc136b.tar.gz
libxkbcommon-0c1bbb05d975cf7b3411259900500cc122fc136b.tar.bz2
libxkbcommon-0c1bbb05d975cf7b3411259900500cc122fc136b.zip
Import xkbcomp sources for CompileKeymap
A copy of the xkbcomp sources (except the frontend) have been copied in to provide a means to compile a XkbDescPtr. This definitely doesn't build or do the right thing yet.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/xkbcomp/Makefile.am40
-rw-r--r--src/xkbcomp/action.c1468
-rw-r--r--src/xkbcomp/action.h86
-rw-r--r--src/xkbcomp/alias.c289
-rw-r--r--src/xkbcomp/alias.h56
-rw-r--r--src/xkbcomp/compat.c880
-rw-r--r--src/xkbcomp/compat.h7
-rw-r--r--src/xkbcomp/expr.c1065
-rw-r--r--src/xkbcomp/expr.h172
-rw-r--r--src/xkbcomp/geometry.c3768
-rw-r--r--src/xkbcomp/indicators.c575
-rw-r--r--src/xkbcomp/indicators.h88
-rw-r--r--src/xkbcomp/keycodes.c896
-rw-r--r--src/xkbcomp/keycodes.h40
-rw-r--r--src/xkbcomp/keymap.c183
-rw-r--r--src/xkbcomp/keytypes.c1293
-rw-r--r--src/xkbcomp/listing.c495
-rw-r--r--src/xkbcomp/misc.c576
-rw-r--r--src/xkbcomp/misc.h111
-rw-r--r--src/xkbcomp/parseutils.c834
-rw-r--r--src/xkbcomp/parseutils.h208
-rw-r--r--src/xkbcomp/symbols.c2301
-rw-r--r--src/xkbcomp/tokens.h104
-rw-r--r--src/xkbcomp/utils.c434
-rw-r--r--src/xkbcomp/utils.h381
-rw-r--r--src/xkbcomp/vmod.c271
-rw-r--r--src/xkbcomp/vmod.h78
-rw-r--r--src/xkbcomp/xkbcomp.h396
-rw-r--r--src/xkbcomp/xkbparse.c3242
-rw-r--r--src/xkbcomp/xkbparse.y799
-rw-r--r--src/xkbcomp/xkbpath.c420
-rw-r--r--src/xkbcomp/xkbpath.h65
-rw-r--r--src/xkbcomp/xkbscan.c723
34 files changed, 22346 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 72c29af..a440050 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,9 +1,10 @@
-SUBDIRS = makekeys
+SUBDIRS = makekeys xkbcomp
INCLUDES = -I$(top_srcdir)/include -I$(builddir)/makekeys
AM_CFLAGS = $(X11_CFLAGS) $(CWARNFLAGS) $(XMALLOC_ZERO_CFLAGS)
lib_LTLIBRARIES = libxkbcommon.la
+libxkbcommon_la_LIBADD = xkbcomp/libxkbcomp.la
libxkbcommon_la_SOURCES = \
XKBcommonint.h \
alloc.c \
diff --git a/src/xkbcomp/Makefile.am b/src/xkbcomp/Makefile.am
new file mode 100644
index 0000000..d7beacf
--- /dev/null
+++ b/src/xkbcomp/Makefile.am
@@ -0,0 +1,40 @@
+INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src
+AM_CFLAGS = $(X11_CFLAGS) $(CWARNFLAGS) \
+ -DDFLT_XKB_CONFIG_ROOT='"$(XKBCONFIGROOT)"'
+
+BUILT_SOURCES = xkbparse.c
+MAINTAINERCLEANFILES = $(BUILT_SOURCES)
+
+noinst_LTLIBRARIES = libxkbcomp.la
+libxkbcomp_la_SOURCES = \
+ action.c \
+ action.h \
+ alias.c \
+ alias.h \
+ compat.c \
+ compat.h \
+ expr.c \
+ expr.h \
+ geometry.c \
+ indicators.c \
+ indicators.h \
+ keycodes.c \
+ keycodes.h \
+ keymap.c \
+ keytypes.c \
+ listing.c \
+ misc.c \
+ misc.h \
+ parseutils.c \
+ parseutils.h \
+ symbols.c \
+ tokens.h \
+ utils.c \
+ utils.h \
+ vmod.c \
+ vmod.h \
+ xkbcomp.h \
+ xkbparse.y \
+ xkbpath.c \
+ xkbpath.h \
+ xkbscan.c
diff --git a/src/xkbcomp/action.c b/src/xkbcomp/action.c
new file mode 100644
index 0000000..3b82e64
--- /dev/null
+++ b/src/xkbcomp/action.c
@@ -0,0 +1,1468 @@
+/************************************************************
+ 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 "keycodes.h"
+#include "vmod.h"
+#include "misc.h"
+#include "action.h"
+#include "misc.h"
+
+static Bool actionsInitialized;
+static ExprDef constTrue;
+static ExprDef constFalse;
+
+/***====================================================================***/
+
+static Bool
+stringToAction(char *str, unsigned *type_rtrn)
+{
+ if (str == NULL)
+ return False;
+
+ if (uStrCaseCmp(str, "noaction") == 0)
+ *type_rtrn = XkbSA_NoAction;
+ else if (uStrCaseCmp(str, "setmods") == 0)
+ *type_rtrn = XkbSA_SetMods;
+ else if (uStrCaseCmp(str, "latchmods") == 0)
+ *type_rtrn = XkbSA_LatchMods;
+ else if (uStrCaseCmp(str, "lockmods") == 0)
+ *type_rtrn = XkbSA_LockMods;
+ else if (uStrCaseCmp(str, "setgroup") == 0)
+ *type_rtrn = XkbSA_SetGroup;
+ else if (uStrCaseCmp(str, "latchgroup") == 0)
+ *type_rtrn = XkbSA_LatchGroup;
+ else if (uStrCaseCmp(str, "lockgroup") == 0)
+ *type_rtrn = XkbSA_LockGroup;
+ else if (uStrCaseCmp(str, "moveptr") == 0)
+ *type_rtrn = XkbSA_MovePtr;
+ else if (uStrCaseCmp(str, "movepointer") == 0)
+ *type_rtrn = XkbSA_MovePtr;
+ else if (uStrCaseCmp(str, "ptrbtn") == 0)
+ *type_rtrn = XkbSA_PtrBtn;
+ else if (uStrCaseCmp(str, "pointerbutton") == 0)
+ *type_rtrn = XkbSA_PtrBtn;
+ else if (uStrCaseCmp(str, "lockptrbtn") == 0)
+ *type_rtrn = XkbSA_LockPtrBtn;
+ else if (uStrCaseCmp(str, "lockpointerbutton") == 0)
+ *type_rtrn = XkbSA_LockPtrBtn;
+ else if (uStrCaseCmp(str, "lockptrbutton") == 0)
+ *type_rtrn = XkbSA_LockPtrBtn;
+ else if (uStrCaseCmp(str, "lockpointerbtn") == 0)
+ *type_rtrn = XkbSA_LockPtrBtn;
+ else if (uStrCaseCmp(str, "setptrdflt") == 0)
+ *type_rtrn = XkbSA_SetPtrDflt;
+ else if (uStrCaseCmp(str, "setpointerdefault") == 0)
+ *type_rtrn = XkbSA_SetPtrDflt;
+ else if (uStrCaseCmp(str, "isolock") == 0)
+ *type_rtrn = XkbSA_ISOLock;
+ else if (uStrCaseCmp(str, "terminate") == 0)
+ *type_rtrn = XkbSA_Terminate;
+ else if (uStrCaseCmp(str, "terminateserver") == 0)
+ *type_rtrn = XkbSA_Terminate;
+ else if (uStrCaseCmp(str, "switchscreen") == 0)
+ *type_rtrn = XkbSA_SwitchScreen;
+ else if (uStrCaseCmp(str, "setcontrols") == 0)
+ *type_rtrn = XkbSA_SetControls;
+ else if (uStrCaseCmp(str, "lockcontrols") == 0)
+ *type_rtrn = XkbSA_LockControls;
+ else if (uStrCaseCmp(str, "actionmessage") == 0)
+ *type_rtrn = XkbSA_ActionMessage;
+ else if (uStrCaseCmp(str, "messageaction") == 0)
+ *type_rtrn = XkbSA_ActionMessage;
+ else if (uStrCaseCmp(str, "message") == 0)
+ *type_rtrn = XkbSA_ActionMessage;
+ else if (uStrCaseCmp(str, "redirect") == 0)
+ *type_rtrn = XkbSA_RedirectKey;
+ else if (uStrCaseCmp(str, "redirectkey") == 0)
+ *type_rtrn = XkbSA_RedirectKey;
+ else if (uStrCaseCmp(str, "devbtn") == 0)
+ *type_rtrn = XkbSA_DeviceBtn;
+ else if (uStrCaseCmp(str, "devicebtn") == 0)
+ *type_rtrn = XkbSA_DeviceBtn;
+ else if (uStrCaseCmp(str, "devbutton") == 0)
+ *type_rtrn = XkbSA_DeviceBtn;
+ else if (uStrCaseCmp(str, "devicebutton") == 0)
+ *type_rtrn = XkbSA_DeviceBtn;
+ else if (uStrCaseCmp(str, "lockdevbtn") == 0)
+ *type_rtrn = XkbSA_DeviceBtn;
+ else if (uStrCaseCmp(str, "lockdevicebtn") == 0)
+ *type_rtrn = XkbSA_LockDeviceBtn;
+ else if (uStrCaseCmp(str, "lockdevbutton") == 0)
+ *type_rtrn = XkbSA_LockDeviceBtn;
+ else if (uStrCaseCmp(str, "lockdevicebutton") == 0)
+ *type_rtrn = XkbSA_LockDeviceBtn;
+ else if (uStrCaseCmp(str, "devval") == 0)
+ *type_rtrn = XkbSA_DeviceValuator;
+ else if (uStrCaseCmp(str, "deviceval") == 0)
+ *type_rtrn = XkbSA_DeviceValuator;
+ else if (uStrCaseCmp(str, "devvaluator") == 0)
+ *type_rtrn = XkbSA_DeviceValuator;
+ else if (uStrCaseCmp(str, "devicevaluator") == 0)
+ *type_rtrn = XkbSA_DeviceValuator;
+ else if (uStrCaseCmp(str, "private") == 0)
+ *type_rtrn = PrivateAction;
+ else
+ return False;
+ return True;
+}
+
+static Bool
+stringToField(char *str, unsigned *field_rtrn)
+{
+
+ if (str == NULL)
+ return False;
+
+ if (uStrCaseCmp(str, "clearlocks") == 0)
+ *field_rtrn = F_ClearLocks;
+ else if (uStrCaseCmp(str, "latchtolock") == 0)
+ *field_rtrn = F_LatchToLock;
+ else if (uStrCaseCmp(str, "genkeyevent") == 0)
+ *field_rtrn = F_GenKeyEvent;
+ else if (uStrCaseCmp(str, "generatekeyevent") == 0)
+ *field_rtrn = F_GenKeyEvent;
+ else if (uStrCaseCmp(str, "report") == 0)
+ *field_rtrn = F_Report;
+ else if (uStrCaseCmp(str, "default") == 0)
+ *field_rtrn = F_Default;
+ else if (uStrCaseCmp(str, "affect") == 0)
+ *field_rtrn = F_Affect;
+ else if (uStrCaseCmp(str, "increment") == 0)
+ *field_rtrn = F_Increment;
+ else if (uStrCaseCmp(str, "mods") == 0)
+ *field_rtrn = F_Modifiers;
+ else if (uStrCaseCmp(str, "modifiers") == 0)
+ *field_rtrn = F_Modifiers;
+ else if (uStrCaseCmp(str, "group") == 0)
+ *field_rtrn = F_Group;
+ else if (uStrCaseCmp(str, "x") == 0)
+ *field_rtrn = F_X;
+ else if (uStrCaseCmp(str, "y") == 0)
+ *field_rtrn = F_Y;
+ else if (uStrCaseCmp(str, "accel") == 0)
+ *field_rtrn = F_Accel;
+ else if (uStrCaseCmp(str, "accelerate") == 0)
+ *field_rtrn = F_Accel;
+ else if (uStrCaseCmp(str, "repeat") == 0)
+ *field_rtrn = F_Accel;
+ else if (uStrCaseCmp(str, "button") == 0)
+ *field_rtrn = F_Button;
+ else if (uStrCaseCmp(str, "value") == 0)
+ *field_rtrn = F_Value;
+ else if (uStrCaseCmp(str, "controls") == 0)
+ *field_rtrn = F_Controls;
+ else if (uStrCaseCmp(str, "ctrls") == 0)
+ *field_rtrn = F_Controls;
+ else if (uStrCaseCmp(str, "type") == 0)
+ *field_rtrn = F_Type;
+ else if (uStrCaseCmp(str, "count") == 0)
+ *field_rtrn = F_Count;
+ else if (uStrCaseCmp(str, "screen") == 0)
+ *field_rtrn = F_Screen;
+ else if (uStrCaseCmp(str, "same") == 0)
+ *field_rtrn = F_Same;
+ else if (uStrCaseCmp(str, "sameserver") == 0)
+ *field_rtrn = F_Same;
+ else if (uStrCaseCmp(str, "data") == 0)
+ *field_rtrn = F_Data;
+ else if (uStrCaseCmp(str, "device") == 0)
+ *field_rtrn = F_Device;
+ else if (uStrCaseCmp(str, "dev") == 0)
+ *field_rtrn = F_Device;
+ else if (uStrCaseCmp(str, "key") == 0)
+ *field_rtrn = F_Keycode;
+ else if (uStrCaseCmp(str, "keycode") == 0)
+ *field_rtrn = F_Keycode;
+ else if (uStrCaseCmp(str, "kc") == 0)
+ *field_rtrn = F_Keycode;
+ else if (uStrCaseCmp(str, "clearmods") == 0)
+ *field_rtrn = F_ModsToClear;
+ else if (uStrCaseCmp(str, "clearmodifiers") == 0)
+ *field_rtrn = F_ModsToClear;
+ else
+ return False;
+ return True;
+}
+
+static char *
+fieldText(unsigned field)
+{
+ static char buf[32];
+
+ switch (field)
+ {
+ case F_ClearLocks:
+ strcpy(buf, "clearLocks");
+ break;
+ case F_LatchToLock:
+ strcpy(buf, "latchToLock");
+ break;
+ case F_GenKeyEvent:
+ strcpy(buf, "genKeyEvent");
+ break;
+ case F_Report:
+ strcpy(buf, "report");
+ break;
+ case F_Default:
+ strcpy(buf, "default");
+ break;
+ case F_Affect:
+ strcpy(buf, "affect");
+ break;
+ case F_Increment:
+ strcpy(buf, "increment");
+ break;
+ case F_Modifiers:
+ strcpy(buf, "modifiers");
+ break;
+ case F_Group:
+ strcpy(buf, "group");
+ break;
+ case F_X:
+ strcpy(buf, "x");
+ break;
+ case F_Y:
+ strcpy(buf, "y");
+ break;
+ case F_Accel:
+ strcpy(buf, "accel");
+ break;
+ case F_Button:
+ strcpy(buf, "button");
+ break;
+ case F_Value:
+ strcpy(buf, "value");
+ break;
+ case F_Controls:
+ strcpy(buf, "controls");
+ break;
+ case F_Type:
+ strcpy(buf, "type");
+ break;
+ case F_Count:
+ strcpy(buf, "count");
+ break;
+ case F_Screen:
+ strcpy(buf, "screen");
+ break;
+ case F_Same:
+ strcpy(buf, "sameServer");
+ break;
+ case F_Data:
+ strcpy(buf, "data");
+ break;
+ case F_Device:
+ strcpy(buf, "device");
+ break;
+ case F_Keycode:
+ strcpy(buf, "keycode");
+ break;
+ case F_ModsToClear:
+ strcpy(buf, "clearmods");
+ break;
+ default:
+ strcpy(buf, "unknown");
+ break;
+ }
+ return buf;
+}
+
+/***====================================================================***/
+
+static Bool
+ReportMismatch(unsigned action, unsigned field, const char *type)
+{
+ ERROR2("Value of %s field must be of type %s\n", fieldText(field), type);
+ ACTION1("Action %s definition ignored\n",
+ XkbActionTypeText(action, XkbMessage));
+ return False;
+}
+
+static Bool
+ReportIllegal(unsigned action, unsigned field)
+{
+ ERROR2("Field %s is not defined for an action of type %s\n",
+ fieldText(field), XkbActionTypeText(action, XkbMessage));
+ ACTION("Action definition ignored\n");
+ return False;
+}
+
+static Bool
+ReportActionNotArray(unsigned action, unsigned field)
+{
+ ERROR2("The %s field in the %s action is not an array\n",
+ fieldText(field), XkbActionTypeText(action, XkbMessage));
+ ACTION("Action definition ignored\n");
+ return False;
+}
+
+static Bool
+ReportNotFound(unsigned action, unsigned field, const char *what, char *bad)
+{
+ ERROR2("%s named %s not found\n", what, bad);
+ ACTION2("Ignoring the %s field of an %s action\n", fieldText(field),
+ XkbActionTypeText(action, XkbMessage));
+ return False;
+}
+
+static Bool
+HandleNoAction(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ return ReportIllegal(action->type, field);
+}
+
+static Bool
+CheckLatchLockFlags(unsigned action,
+ unsigned field, ExprDef * value, unsigned *flags_inout)
+{
+ unsigned tmp;
+ ExprResult result;
+
+ if (field == F_ClearLocks)
+ tmp = XkbSA_ClearLocks;
+ else if (field == F_LatchToLock)
+ tmp = XkbSA_LatchToLock;
+ else
+ return False; /* WSGO! */
+ if (!ExprResolveBoolean(value, &result, NULL, NULL))
+ return ReportMismatch(action, field, "boolean");
+ if (result.uval)
+ *flags_inout |= tmp;
+ else
+ *flags_inout &= ~tmp;
+ return True;
+}
+
+static Bool
+CheckModifierField(XkbDescPtr xkb,
+ unsigned action,
+ ExprDef * value,
+ unsigned *flags_inout, unsigned *mods_rtrn)
+{
+ ExprResult rtrn;
+
+ if (value->op == ExprIdent)
+ {
+ register char *valStr;
+ valStr = XkbAtomGetString(NULL, value->value.str);
+ if (valStr && ((uStrCaseCmp(valStr, "usemodmapmods") == 0) ||
+ (uStrCaseCmp(valStr, "modmapmods") == 0)))
+ {
+
+ *mods_rtrn = 0;
+ *flags_inout |= XkbSA_UseModMapMods;
+ return True;
+ }
+ }
+ if (!ExprResolveModMask(value, &rtrn, LookupVModMask, (XPointer) xkb))
+ return ReportMismatch(action, F_Modifiers, "modifier mask");
+ *mods_rtrn = rtrn.uval;
+ *flags_inout &= ~XkbSA_UseModMapMods;
+ return True;
+}
+
+static Bool
+HandleSetLatchMods(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ XkbModAction *act;
+ unsigned rtrn;
+ unsigned t1, t2;
+
+ act = (XkbModAction *) action;
+ if (array_ndx != NULL)
+ {
+ switch (field)
+ {
+ case F_ClearLocks:
+ case F_LatchToLock:
+ case F_Modifiers:
+ return ReportActionNotArray(action->type, field);
+ }
+ }
+ switch (field)
+ {
+ case F_ClearLocks:
+ case F_LatchToLock:
+ rtrn = act->flags;
+ if (CheckLatchLockFlags(action->type, field, value, &rtrn))
+ {
+ act->flags = rtrn;
+ return True;
+ }
+ return False;
+ case F_Modifiers:
+ t1 = act->flags;
+ if (CheckModifierField(xkb, action->type, value, &t1, &t2))
+ {
+ act->flags = t1;
+ act->real_mods = act->mask = (t2 & 0xff);
+ t2 = (t2 >> 8) & 0xffff;
+ XkbSetModActionVMods(act, t2);
+ return True;
+ }
+ return False;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static Bool
+HandleLockMods(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ XkbModAction *act;
+ unsigned t1, t2;
+
+ act = (XkbModAction *) action;
+ if ((array_ndx != NULL) && (field == F_Modifiers))
+ return ReportActionNotArray(action->type, field);
+ switch (field)
+ {
+ case F_Modifiers:
+ t1 = act->flags;
+ if (CheckModifierField(xkb, action->type, value, &t1, &t2))
+ {
+ act->flags = t1;
+ act->real_mods = act->mask = (t2 & 0xff);
+ t2 = (t2 >> 8) & 0xffff;
+ XkbSetModActionVMods(act, t2);
+ return True;
+ }
+ return False;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static LookupEntry groupNames[] = {
+ {"group1", 1},
+ {"group2", 2},
+ {"group3", 3},
+ {"group4", 4},
+ {"group5", 5},
+ {"group6", 6},
+ {"group7", 7},
+ {"group8", 8},
+ {NULL, 0},
+};
+
+static Bool
+CheckGroupField(unsigned action,
+ ExprDef * value, unsigned *flags_inout, int *grp_rtrn)
+{
+ ExprDef *spec;
+ ExprResult rtrn;
+
+ if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
+ {
+ *flags_inout &= ~XkbSA_GroupAbsolute;
+ spec = value->value.child;
+ }
+ else
+ {
+ *flags_inout |= XkbSA_GroupAbsolute;
+ spec = value;
+ }
+
+ if (!ExprResolveInteger(spec, &rtrn, SimpleLookup, (XPointer) groupNames))
+ return ReportMismatch(action, F_Group, "integer (range 1..8)");
+ if ((rtrn.ival < 1) || (rtrn.ival > XkbNumKbdGroups))
+ {
+ ERROR2("Illegal group %d (must be in the range 1..%d)\n", rtrn.ival,
+ XkbNumKbdGroups);
+ ACTION1("Action %s definition ignored\n",
+ XkbActionTypeText(action, XkbMessage));
+ return False;
+ }
+ if (value->op == OpNegate)
+ *grp_rtrn = -rtrn.ival;
+ else if (value->op == OpUnaryPlus)
+ *grp_rtrn = rtrn.ival;
+ else
+ *grp_rtrn = rtrn.ival - 1;
+ return True;
+}
+
+static Bool
+HandleSetLatchGroup(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ XkbGroupAction *act;
+ unsigned rtrn;
+ unsigned t1;
+ int t2;
+
+ act = (XkbGroupAction *) action;
+ if (array_ndx != NULL)
+ {
+ switch (field)
+ {
+ case F_ClearLocks:
+ case F_LatchToLock:
+ case F_Group:
+ return ReportActionNotArray(action->type, field);
+ }
+ }
+ switch (field)
+ {
+ case F_ClearLocks:
+ case F_LatchToLock:
+ rtrn = act->flags;
+ if (CheckLatchLockFlags(action->type, field, value, &rtrn))
+ {
+ act->flags = rtrn;
+ return True;
+ }
+ return False;
+ case F_Group:
+ t1 = act->flags;
+ if (CheckGroupField(action->type, value, &t1, &t2))
+ {
+ act->flags = t1;
+ XkbSASetGroup(act, t2);
+ return True;
+ }
+ return False;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static Bool
+HandleLockGroup(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ XkbGroupAction *act;
+ unsigned t1;
+ int t2;
+
+ act = (XkbGroupAction *) action;
+ if ((array_ndx != NULL) && (field == F_Group))
+ return ReportActionNotArray(action->type, field);
+ if (field == F_Group)
+ {
+ t1 = act->flags;
+ if (CheckGroupField(action->type, value, &t1, &t2))
+ {
+ act->flags = t1;
+ XkbSASetGroup(act, t2);
+ return True;
+ }
+ return False;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static Bool
+HandleMovePtr(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbPtrAction *act;
+ Bool absolute;
+
+ act = (XkbPtrAction *) action;
+ if ((array_ndx != NULL) && ((field == F_X) || (field == F_Y)))
+ return ReportActionNotArray(action->type, field);
+
+ if ((field == F_X) || (field == F_Y))
+ {
+ if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
+ absolute = False;
+ else
+ absolute = True;
+ if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "integer");
+ if (field == F_X)
+ {
+ if (absolute)
+ act->flags |= XkbSA_MoveAbsoluteX;
+ XkbSetPtrActionX(act, rtrn.ival);
+ }
+ else
+ {
+ if (absolute)
+ act->flags |= XkbSA_MoveAbsoluteY;
+ XkbSetPtrActionY(act, rtrn.ival);
+ }
+ return True;
+ }
+ else if (field == F_Accel)
+ {
+ if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "boolean");
+ if (rtrn.uval)
+ act->flags &= ~XkbSA_NoAcceleration;
+ else
+ act->flags |= XkbSA_NoAcceleration;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static LookupEntry btnNames[] = {
+ {"button1", 1},
+ {"button2", 2},
+ {"button3", 3},
+ {"button4", 4},
+ {"button5", 5},
+ {"default", 0},
+ {NULL, 0}
+};
+
+static LookupEntry lockWhich[] = {
+ {"both", 0},
+ {"lock", XkbSA_LockNoUnlock},
+ {"neither", (XkbSA_LockNoLock | XkbSA_LockNoUnlock)},
+ {"unlock", XkbSA_LockNoLock},
+ {NULL, 0}
+};
+
+static Bool
+HandlePtrBtn(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbPtrBtnAction *act;
+
+ act = (XkbPtrBtnAction *) action;
+ if (field == F_Button)
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveInteger
+ (value, &rtrn, SimpleLookup, (XPointer) btnNames))
+ return ReportMismatch(action->type, field,
+ "integer (range 1..5)");
+ if ((rtrn.ival < 0) || (rtrn.ival > 5))
+ {
+ ERROR("Button must specify default or be in the range 1..5\n");
+ ACTION1("Illegal button value %d ignored\n", rtrn.ival);
+ return False;
+ }
+ act->button = rtrn.ival;
+ return True;
+ }
+ else if ((action->type == XkbSA_LockPtrBtn) && (field == F_Affect))
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveEnum(value, &rtrn, lockWhich))
+ return ReportMismatch(action->type, field, "lock or unlock");
+ act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
+ act->flags |= rtrn.ival;
+ return True;
+ }
+ else if (field == F_Count)
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveInteger
+ (value, &rtrn, SimpleLookup, (XPointer) btnNames))
+ return ReportMismatch(action->type, field, "integer");
+ if ((rtrn.ival < 0) || (rtrn.ival > 255))
+ {
+ ERROR("The count field must have a value in the range 0..255\n");
+ ACTION1("Illegal count %d ignored\n", rtrn.ival);
+ return False;
+ }
+ act->count = rtrn.ival;
+ return True;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static LookupEntry ptrDflts[] = {
+ {"dfltbtn", XkbSA_AffectDfltBtn},
+ {"defaultbutton", XkbSA_AffectDfltBtn},
+ {"button", XkbSA_AffectDfltBtn},
+ {NULL, 0}
+};
+
+static Bool
+HandleSetPtrDflt(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbPtrDfltAction *act;
+
+ act = (XkbPtrDfltAction *) action;
+ if (field == F_Affect)
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveEnum(value, &rtrn, ptrDflts))
+ return ReportMismatch(action->type, field, "pointer component");
+ act->affect = rtrn.uval;
+ return True;
+ }
+ else if ((field == F_Button) || (field == F_Value))
+ {
+ ExprDef *btn;
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
+ {
+ act->flags &= ~XkbSA_DfltBtnAbsolute;
+ btn = value->value.child;
+ }
+ else
+ {
+ act->flags |= XkbSA_DfltBtnAbsolute;
+ btn = value;
+ }
+
+ if (!ExprResolveInteger
+ (btn, &rtrn, SimpleLookup, (XPointer) btnNames))
+ return ReportMismatch(action->type, field,
+ "integer (range 1..5)");
+ if ((rtrn.ival < 0) || (rtrn.ival > 5))
+ {
+ ERROR("New default button value must be in the range 1..5\n");
+ ACTION1("Illegal default button value %d ignored\n", rtrn.ival);
+ return False;
+ }
+ if (rtrn.ival == 0)
+ {
+ ERROR("Cannot set default pointer button to \"default\"\n");
+ ACTION("Illegal default button setting ignored\n");
+ return False;
+ }
+ if (value->op == OpNegate)
+ XkbSASetPtrDfltValue(act, -rtrn.ival);
+ else
+ XkbSASetPtrDfltValue(act, rtrn.ival);
+ return True;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static LookupEntry isoNames[] = {
+ {"mods", XkbSA_ISONoAffectMods},
+ {"modifiers", XkbSA_ISONoAffectMods},
+ {"group", XkbSA_ISONoAffectGroup},
+ {"groups", XkbSA_ISONoAffectGroup},
+ {"ptr", XkbSA_ISONoAffectPtr},
+ {"pointer", XkbSA_ISONoAffectPtr},
+ {"ctrls", XkbSA_ISONoAffectCtrls},
+ {"controls", XkbSA_ISONoAffectCtrls},
+ {"all", ~((unsigned) 0)},
+ {"none", 0},
+ {NULL, 0},
+};
+
+static Bool
+HandleISOLock(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbISOAction *act;
+ unsigned flags, mods;
+ int group;
+
+ act = (XkbISOAction *) action;
+ switch (field)
+ {
+ case F_Modifiers:
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ flags = act->flags;
+ if (CheckModifierField(xkb, action->type, value, &flags, &mods))
+ {
+ act->flags = flags & (~XkbSA_ISODfltIsGroup);
+ act->real_mods = mods & 0xff;
+ mods = (mods >> 8) & 0xff;
+ XkbSetModActionVMods(act, mods);
+ return True;
+ }
+ return False;
+ case F_Group:
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ flags = act->flags;
+ if (CheckGroupField(action->type, value, &flags, &group))
+ {
+ act->flags = flags | XkbSA_ISODfltIsGroup;
+ XkbSASetGroup(act, group);
+ return True;
+ }
+ return False;
+ case F_Affect:
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveMask(value, &rtrn, SimpleLookup, (XPointer) isoNames))
+ return ReportMismatch(action->type, field, "keyboard component");
+ act->affect = (~rtrn.uval) & XkbSA_ISOAffectMask;
+ return True;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static Bool
+HandleSwitchScreen(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbSwitchScreenAction *act;
+
+ act = (XkbSwitchScreenAction *) action;
+ if (field == F_Screen)
+ {
+ ExprDef *scrn;
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if ((value->op == OpNegate) || (value->op == OpUnaryPlus))
+ {
+ act->flags &= ~XkbSA_SwitchAbsolute;
+ scrn = value->value.child;
+ }
+ else
+ {
+ act->flags |= XkbSA_SwitchAbsolute;
+ scrn = value;
+ }
+
+ if (!ExprResolveInteger(scrn, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "integer (0..255)");
+ if ((rtrn.ival < 0) || (rtrn.ival > 255))
+ {
+ ERROR("Screen index must be in the range 1..255\n");
+ ACTION1("Illegal screen value %d ignored\n", rtrn.ival);
+ return False;
+ }
+ if (value->op == OpNegate)
+ XkbSASetScreen(act, -rtrn.ival);
+ else
+ XkbSASetScreen(act, rtrn.ival);
+ return True;
+ }
+ else if (field == F_Same)
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "boolean");
+ if (rtrn.uval)
+ act->flags &= ~XkbSA_SwitchApplication;
+ else
+ act->flags |= XkbSA_SwitchApplication;
+ return True;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+LookupEntry ctrlNames[] = {
+ {"repeatkeys", XkbRepeatKeysMask}
+ ,
+ {"repeat", XkbRepeatKeysMask}
+ ,
+ {"autorepeat", XkbRepeatKeysMask}
+ ,
+ {"slowkeys", XkbSlowKeysMask}
+ ,
+ {"bouncekeys", XkbBounceKeysMask}
+ ,
+ {"stickykeys", XkbStickyKeysMask}
+ ,
+ {"mousekeys", XkbMouseKeysMask}
+ ,
+ {"mousekeysaccel", XkbMouseKeysAccelMask}
+ ,
+ {"accessxkeys", XkbAccessXKeysMask}
+ ,
+ {"accessxtimeout", XkbAccessXTimeoutMask}
+ ,
+ {"accessxfeedback", XkbAccessXFeedbackMask}
+ ,
+ {"audiblebell", XkbAudibleBellMask}
+ ,
+ {"overlay1", XkbOverlay1Mask}
+ ,
+ {"overlay2", XkbOverlay2Mask}
+ ,
+ {"ignoregrouplock", XkbIgnoreGroupLockMask}
+ ,
+ {"all", XkbAllBooleanCtrlsMask}
+ ,
+ {"none", 0}
+ ,
+ {NULL, 0}
+};
+
+static Bool
+HandleSetLockControls(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbCtrlsAction *act;
+
+ act = (XkbCtrlsAction *) action;
+ if (field == F_Controls)
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveMask
+ (value, &rtrn, SimpleLookup, (XPointer) ctrlNames))
+ return ReportMismatch(action->type, field, "controls mask");
+ XkbActionSetCtrls(act, rtrn.uval);
+ return True;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static LookupEntry evNames[] = {
+ {"press", XkbSA_MessageOnPress},
+ {"keypress", XkbSA_MessageOnPress},
+ {"release", XkbSA_MessageOnRelease},
+ {"keyrelease", XkbSA_MessageOnRelease},
+ {"all", XkbSA_MessageOnPress | XkbSA_MessageOnRelease},
+ {"none", 0},
+ {NULL, 0}
+};
+
+static Bool
+HandleActionMessage(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbMessageAction *act;
+
+ act = (XkbMessageAction *) action;
+ switch (field)
+ {
+ case F_Report:
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveMask(value, &rtrn, SimpleLookup, (XPointer) evNames))
+ return ReportMismatch(action->type, field, "key event mask");
+ act->flags &= ~(XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
+ act->flags =
+ rtrn.uval & (XkbSA_MessageOnPress | XkbSA_MessageOnRelease);
+ return True;
+ case F_GenKeyEvent:
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "boolean");
+ if (rtrn.uval)
+ act->flags |= XkbSA_MessageGenKeyEvent;
+ else
+ act->flags &= ~XkbSA_MessageGenKeyEvent;
+ return True;
+ case F_Data:
+ if (array_ndx == NULL)
+ {
+ if (!ExprResolveString(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "string");
+ else
+ {
+ int len = strlen(rtrn.str);
+ if ((len < 1) || (len > 6))
+ {
+ WARN("An action message can hold only 6 bytes\n");
+ ACTION1("Extra %d bytes ignored\n", len - 6);
+ }
+ strncpy((char *) act->message, rtrn.str, 6);
+ }
+ return True;
+ }
+ else
+ {
+ unsigned ndx;
+ if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
+ {
+ ERROR("Array subscript must be integer\n");
+ ACTION("Illegal subscript ignored\n");
+ return False;
+ }
+ ndx = rtrn.uval;
+ if (ndx > 5)
+ {
+ ERROR("An action message is at most 6 bytes long\n");
+ ACTION1("Attempt to use data[%d] ignored\n", ndx);
+ return False;
+ }
+ if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "integer");
+ if ((rtrn.ival < 0) || (rtrn.ival > 255))
+ {
+ ERROR("Message data must be in the range 0..255\n");
+ ACTION1("Illegal datum %d ignored\n", rtrn.ival);
+ return False;
+ }
+ act->message[ndx] = rtrn.uval;
+ }
+ return True;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static Bool
+HandleRedirectKey(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbRedirectKeyAction *act;
+ unsigned t1, t2, vmods, vmask;
+ unsigned long tmp;
+
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+
+ act = (XkbRedirectKeyAction *) action;
+ switch (field)
+ {
+ case F_Keycode:
+ if (!ExprResolveKeyName(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "key name");
+ tmp = KeyNameToLong(rtrn.keyName.name);
+ if (!FindNamedKey(xkb, tmp, &t1, True, CreateKeyNames(xkb), 0))
+ {
+ return ReportNotFound(action->type, field, "Key",
+ XkbKeyNameText(rtrn.keyName.name,
+ XkbMessage));
+ }
+ act->new_key = t1;
+ return True;
+ case F_ModsToClear:
+ case F_Modifiers:
+ t1 = 0;
+ if (CheckModifierField(xkb, action->type, value, &t1, &t2))
+ {
+ act->mods_mask |= (t2 & 0xff);
+ if (field == F_Modifiers)
+ act->mods |= (t2 & 0xff);
+ else
+ act->mods &= ~(t2 & 0xff);
+
+ t2 = (t2 >> 8) & 0xffff;
+ vmods = XkbSARedirectVMods(act);
+ vmask = XkbSARedirectVModsMask(act);
+ vmask |= t2;
+ if (field == F_Modifiers)
+ vmods |= t2;
+ else
+ vmods &= ~t2;
+ XkbSARedirectSetVMods(act, vmods);
+ XkbSARedirectSetVModsMask(act, vmask);
+ return True;
+ }
+ return True;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static Bool
+HandleDeviceBtn(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbDeviceBtnAction *act;
+
+ act = (XkbDeviceBtnAction *) action;
+ if (field == F_Button)
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field,
+ "integer (range 1..255)");
+ if ((rtrn.ival < 0) || (rtrn.ival > 255))
+ {
+ ERROR("Button must specify default or be in the range 1..255\n");
+ ACTION1("Illegal button value %d ignored\n", rtrn.ival);
+ return False;
+ }
+ act->button = rtrn.ival;
+ return True;
+ }
+ else if ((action->type == XkbSA_LockDeviceBtn) && (field == F_Affect))
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveEnum(value, &rtrn, lockWhich))
+ return ReportMismatch(action->type, field, "lock or unlock");
+ act->flags &= ~(XkbSA_LockNoLock | XkbSA_LockNoUnlock);
+ act->flags |= rtrn.ival;
+ return True;
+ }
+ else if (field == F_Count)
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveInteger
+ (value, &rtrn, SimpleLookup, (XPointer) btnNames))
+ return ReportMismatch(action->type, field, "integer");
+ if ((rtrn.ival < 0) || (rtrn.ival > 255))
+ {
+ ERROR("The count field must have a value in the range 0..255\n");
+ ACTION1("Illegal count %d ignored\n", rtrn.ival);
+ return False;
+ }
+ act->count = rtrn.ival;
+ return True;
+ }
+ else if (field == F_Device)
+ {
+ if (array_ndx != NULL)
+ return ReportActionNotArray(action->type, field);
+ if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field,
+ "integer (range 1..255)");
+ if ((rtrn.ival < 0) || (rtrn.ival > 255))
+ {
+ ERROR("Device must specify default or be in the range 1..255\n");
+ ACTION1("Illegal device value %d ignored\n", rtrn.ival);
+ return False;
+ }
+ act->device = rtrn.ival;
+ return True;
+ }
+ return ReportIllegal(action->type, field);
+}
+
+static Bool
+HandleDeviceValuator(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+#if 0
+ ExprResult rtrn;
+ XkbDeviceValuatorAction *act;
+
+ act = (XkbDeviceValuatorAction *) action;
+ /* XXX - Not yet implemented */
+#endif
+ return False;
+}
+
+static Bool
+HandlePrivate(XkbDescPtr xkb,
+ XkbAnyAction * action,
+ unsigned field, ExprDef * array_ndx, ExprDef * value)
+{
+ ExprResult rtrn;
+
+ switch (field)
+ {
+ case F_Type:
+ if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
+ return ReportMismatch(PrivateAction, field, "integer");
+ if ((rtrn.ival < 0) || (rtrn.ival > 255))
+ {
+ ERROR("Private action type must be in the range 0..255\n");
+ ACTION1("Illegal type %d ignored\n", rtrn.ival);
+ return False;
+ }
+ action->type = rtrn.uval;
+ return True;
+ case F_Data:
+ if (array_ndx == NULL)
+ {
+ if (!ExprResolveString(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "string");
+ else
+ {
+ int len = strlen(rtrn.str);
+ if ((len < 1) || (len > 7))
+ {
+ WARN("A private action has 7 data bytes\n");
+ ACTION1("Extra %d bytes ignored\n", len - 6);
+ return False;
+ }
+ strncpy((char *) action->data, rtrn.str, 7);
+ }
+ return True;
+ }
+ else
+ {
+ unsigned ndx;
+ if (!ExprResolveInteger(array_ndx, &rtrn, NULL, NULL))
+ {
+ ERROR("Array subscript must be integer\n");
+ ACTION("Illegal subscript ignored\n");
+ return False;
+ }
+ ndx = rtrn.uval;
+ if (ndx > 6)
+ {
+ ERROR("The data for a private action is 7 bytes long\n");
+ ACTION1("Attempt to use data[%d] ignored\n", ndx);
+ return False;
+ }
+ if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
+ return ReportMismatch(action->type, field, "integer");
+ if ((rtrn.ival < 0) || (rtrn.ival > 255))
+ {
+ ERROR("All data for a private action must be 0..255\n");
+ ACTION1("Illegal datum %d ignored\n", rtrn.ival);
+ return False;
+ }
+ action->data[ndx] = rtrn.uval;
+ return True;
+ }
+ }
+ return ReportIllegal(PrivateAction, field);
+}
+
+typedef Bool(*actionHandler) (XkbDescPtr /* xkb */ ,
+ XkbAnyAction * /* action */ ,
+ unsigned /* field */ ,
+ ExprDef * /* array_ndx */ ,
+ ExprDef * /* value */
+ );
+
+static actionHandler handleAction[XkbSA_NumActions + 1] = {
+ HandleNoAction /* NoAction */ ,
+ HandleSetLatchMods /* SetMods */ ,
+ HandleSetLatchMods /* LatchMods */ ,
+ HandleLockMods /* LockMods */ ,
+ HandleSetLatchGroup /* SetGroup */ ,
+ HandleSetLatchGroup /* LatchGroup */ ,
+ HandleLockGroup /* LockGroup */ ,
+ HandleMovePtr /* MovePtr */ ,
+ HandlePtrBtn /* PtrBtn */ ,
+ HandlePtrBtn /* LockPtrBtn */ ,
+ HandleSetPtrDflt /* SetPtrDflt */ ,
+ HandleISOLock /* ISOLock */ ,
+ HandleNoAction /* Terminate */ ,
+ HandleSwitchScreen /* SwitchScreen */ ,
+ HandleSetLockControls /* SetControls */ ,
+ HandleSetLockControls /* LockControls */ ,
+ HandleActionMessage /* ActionMessage */ ,
+ HandleRedirectKey /* RedirectKey */ ,
+ HandleDeviceBtn /* DeviceBtn */ ,
+ HandleDeviceBtn /* LockDeviceBtn */ ,
+ HandleDeviceValuator /* DeviceValuatr */ ,
+ HandlePrivate /* Private */
+};
+
+/***====================================================================***/
+
+static void
+ApplyActionFactoryDefaults(XkbAction * action)
+{
+ if (action->type == XkbSA_SetPtrDflt)
+ { /* increment default button */
+ action->dflt.affect = XkbSA_AffectDfltBtn;
+ action->dflt.flags = 0;
+ XkbSASetPtrDfltValue(&action->dflt, 1);
+ }
+ else if (action->type == XkbSA_ISOLock)
+ {
+ action->iso.real_mods = LockMask;
+ }
+ return;
+}
+
+
+int
+HandleActionDef(ExprDef * def,
+ XkbDescPtr xkb,
+ XkbAnyAction * action, unsigned mergeMode, ActionInfo * info)
+{
+ ExprDef *arg;
+ register char *str;
+ unsigned tmp, hndlrType;
+
+ if (!actionsInitialized)
+ ActionsInit();
+
+ if (def->op != ExprActionDecl)
+ {
+ ERROR1("Expected an action definition, found %s\n",
+ exprOpText(def->op));
+ return False;
+ }
+ str = XkbAtomGetString(NULL, def->value.action.name);
+ if (!str)
+ {
+ WSGO("Missing name in action definition!!\n");
+ return False;
+ }
+ if (!stringToAction(str, &tmp))
+ {
+ ERROR1("Unknown action %s\n", str);
+ return False;
+ }
+ action->type = hndlrType = tmp;
+ if (action->type != XkbSA_NoAction)
+ {
+ ApplyActionFactoryDefaults((XkbAction *) action);
+ while (info)
+ {
+ if ((info->action == XkbSA_NoAction)
+ || (info->action == hndlrType))
+ {
+ if (!(*handleAction[hndlrType]) (xkb, action,
+ info->field,
+ info->array_ndx,
+ info->value))
+ {
+ return False;
+ }
+ }
+ info = info->next;
+ }
+ }
+ for (arg = def->value.action.args; arg != NULL;
+ arg = (ExprDef *) arg->common.next)
+ {
+ ExprDef *field, *value, *arrayRtrn;
+ ExprResult elemRtrn, fieldRtrn;
+ unsigned fieldNdx;
+
+ if (arg->op == OpAssign)
+ {
+ field = arg->value.binary.left;
+ value = arg->value.binary.right;
+ }
+ else
+ {
+ if ((arg->op == OpNot) || (arg->op == OpInvert))
+ {
+ field = arg->value.child;
+ value = &constFalse;
+ }
+ else
+ {
+ field = arg;
+ value = &constTrue;
+ }
+ }
+ if (!ExprResolveLhs(field, &elemRtrn, &fieldRtrn, &arrayRtrn))
+ return False; /* internal error -- already reported */
+
+ if (elemRtrn.str != NULL)
+ {
+ ERROR("Cannot change defaults in an action definition\n");
+ ACTION2("Ignoring attempt to change %s.%s\n", elemRtrn.str,
+ fieldRtrn.str);
+ return False;
+ }
+ if (!stringToField(fieldRtrn.str, &fieldNdx))
+ {
+ ERROR1("Unknown field name %s\n", uStringText(fieldRtrn.str));
+ return False;
+ }
+ if (!(*handleAction[hndlrType])
+ (xkb, action, fieldNdx, arrayRtrn, value))
+ {
+ return False;
+ }
+ }
+ return True;
+}
+
+/***====================================================================***/
+
+int
+SetActionField(XkbDescPtr xkb,
+ char *elem,
+ char *field,
+ ExprDef * array_ndx, ExprDef * value, ActionInfo ** info_rtrn)
+{
+ ActionInfo *new, *old;
+
+ if (!actionsInitialized)
+ ActionsInit();
+
+ new = uTypedAlloc(ActionInfo);
+ if (new == NULL)
+ {
+ WSGO("Couldn't allocate space for action default\n");
+ return False;
+ }
+ if (uStrCaseCmp(elem, "action") == 0)
+ new->action = XkbSA_NoAction;
+ else
+ {
+ if (!stringToAction(elem, &new->action))
+ return False;
+ if (new->action == XkbSA_NoAction)
+ {
+ ERROR1("\"%s\" is not a valid field in a NoAction action\n",
+ field);
+ return False;
+ }
+ }
+ if (!stringToField(field, &new->field))
+ {
+ ERROR1("\"%s\" is not a legal field name\n", field);
+ return False;
+ }
+ new->array_ndx = array_ndx;
+ new->value = value;
+ new->next = NULL;
+ old = *info_rtrn;
+ while ((old) && (old->next))
+ old = old->next;
+ if (old == NULL)
+ *info_rtrn = new;
+ else
+ old->next = new;
+ return True;
+}
+
+/***====================================================================***/
+
+void
+ActionsInit(void)
+{
+ if (!actionsInitialized)
+ {
+ bzero((char *) &constTrue, sizeof(constTrue));
+ bzero((char *) &constFalse, sizeof(constFalse));
+ constTrue.common.stmtType = StmtExpr;
+ constTrue.common.next = NULL;
+ constTrue.op = ExprIdent;
+ constTrue.type = TypeBoolean;
+ constTrue.value.str = XkbInternAtom(NULL, "true", False);
+ constFalse.common.stmtType = StmtExpr;
+ constFalse.common.next = NULL;
+ constFalse.op = ExprIdent;
+ constFalse.type = TypeBoolean;
+ constFalse.value.str = XkbInternAtom(NULL, "false", False);
+ actionsInitialized = 1;
+ }
+ return;
+}
diff --git a/src/xkbcomp/action.h b/src/xkbcomp/action.h
new file mode 100644
index 0000000..2fb7a5e
--- /dev/null
+++ b/src/xkbcomp/action.h
@@ -0,0 +1,86 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifndef ACTION_H
+#define ACTION_H 1
+
+#define F_ClearLocks 0
+#define F_LatchToLock 1
+#define F_GenKeyEvent 2
+#define F_Report 3
+#define F_Default 4
+#define F_Affect 5
+#define F_Increment 6
+#define F_Modifiers 7
+#define F_Group 8
+#define F_X 9
+#define F_Y 10
+#define F_Accel 11
+#define F_Button 12
+#define F_Value 13
+#define F_Controls 14
+#define F_Type 15
+#define F_Count 16
+#define F_Screen 17
+#define F_Same 18
+#define F_Data 19
+#define F_Device 20
+#define F_Keycode 21
+#define F_ModsToClear 22
+#define F_LastField F_ModsToClear
+#define F_NumFields (F_LastField+1)
+
+#define PrivateAction (XkbSA_LastAction+1)
+
+typedef struct _ActionInfo
+{
+ unsigned action;
+ unsigned field;
+ ExprDef *array_ndx;
+ ExprDef *value;
+ struct _ActionInfo *next;
+} ActionInfo;
+
+extern int HandleActionDef(ExprDef * /* def */ ,
+ XkbDescPtr /* xkb */ ,
+ XkbAnyAction * /* action */ ,
+ unsigned /* mergeMode */ ,
+ ActionInfo * /* info */
+ );
+
+extern int SetActionField(XkbDescPtr /* xkb */ ,
+ char * /* elem */ ,
+ char * /* field */ ,
+ ExprDef * /* index */ ,
+ ExprDef * /* value */ ,
+ ActionInfo ** /* info_rtrn */
+ );
+
+extern void ActionsInit(void);
+
+extern LookupEntry ctrlNames[];
+
+#endif /* ACTION_H */
diff --git a/src/xkbcomp/alias.c b/src/xkbcomp/alias.c
new file mode 100644
index 0000000..ba55d3d
--- /dev/null
+++ b/src/xkbcomp/alias.c
@@ -0,0 +1,289 @@
+/************************************************************
+ Copyright (c) 1995 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 "misc.h"
+#include "alias.h"
+#include "keycodes.h"
+
+#include <X11/extensions/XKBgeom.h>
+
+static void
+HandleCollision(AliasInfo * old, AliasInfo * new)
+{
+ if (strncmp(new->real, old->real, XkbKeyNameLength) == 0)
+ {
+ if (((new->def.fileID == old->def.fileID) && (warningLevel > 0)) ||
+ (warningLevel > 9))
+ {
+ WARN2("Alias of %s for %s declared more than once\n",
+ XkbKeyNameText(new->alias, XkbMessage),
+ XkbKeyNameText(new->real, XkbMessage));
+ ACTION("First definition ignored\n");
+ }
+ }
+ else
+ {
+ char *use, *ignore;
+ if (new->def.merge == MergeAugment)
+ {
+ use = old->real;
+ ignore = new->real;
+ }
+ else
+ {
+ use = new->real;
+ ignore = old->real;
+ }
+ if (((old->def.fileID == new->def.fileID) && (warningLevel > 0)) ||
+ (warningLevel > 9))
+ {
+ WARN1("Multiple definitions for alias %s\n",
+ XkbKeyNameText(old->alias, XkbMessage));
+ ACTION2("Using %s, ignoring %s\n",
+ XkbKeyNameText(use, XkbMessage),
+ XkbKeyNameText(ignore, XkbMessage));
+ }
+ if (use != old->real)
+ memcpy(old->real, use, XkbKeyNameLength);
+ }
+ old->def.fileID = new->def.fileID;
+ old->def.merge = new->def.merge;
+ return;
+}
+
+static void
+InitAliasInfo(AliasInfo * info,
+ unsigned merge, unsigned file_id, char *alias, char *real)
+{
+ bzero(info, sizeof(AliasInfo));
+ info->def.merge = merge;
+ info->def.fileID = file_id;
+ strncpy(info->alias, alias, XkbKeyNameLength);
+ strncpy(info->real, real, XkbKeyNameLength);
+ return;
+}
+
+int
+HandleAliasDef(KeyAliasDef * def,
+ unsigned merge, unsigned file_id, AliasInfo ** info_in)
+{
+ AliasInfo *info;
+
+ for (info = *info_in; info != NULL; info = (AliasInfo *) info->def.next)
+ {
+ if (strncmp(info->alias, def->alias, XkbKeyNameLength) == 0)
+ {
+ AliasInfo new;
+ InitAliasInfo(&new, merge, file_id, def->alias, def->real);
+ HandleCollision(info, &new);
+ return True;
+ }
+ }
+ info = uTypedCalloc(1, AliasInfo);
+ if (info == NULL)
+ {
+ WSGO("Allocation failure in HandleAliasDef\n");
+ return False;
+ }
+ info->def.fileID = file_id;
+ info->def.merge = merge;
+ info->def.next = (CommonInfo *) * info_in;
+ memcpy(info->alias, def->alias, XkbKeyNameLength);
+ memcpy(info->real, def->real, XkbKeyNameLength);
+ *info_in = (AliasInfo *) AddCommonInfo(&(*info_in)->def, &info->def);
+ return True;
+}
+
+void
+ClearAliases(AliasInfo ** info_in)
+{
+ if ((info_in) && (*info_in))
+ ClearCommonInfo(&(*info_in)->def);
+ return;
+}
+
+Bool
+MergeAliases(AliasInfo ** into, AliasInfo ** merge, unsigned how_merge)
+{
+ AliasInfo *tmp;
+ KeyAliasDef def;
+
+ if ((*merge) == NULL)
+ return True;
+ if ((*into) == NULL)
+ {
+ *into = *merge;
+ *merge = NULL;
+ return True;
+ }
+ bzero((char *) &def, sizeof(KeyAliasDef));
+ for (tmp = *merge; tmp != NULL; tmp = (AliasInfo *) tmp->def.next)
+ {
+ if (how_merge == MergeDefault)
+ def.merge = tmp->def.merge;
+ else
+ def.merge = how_merge;
+ memcpy(def.alias, tmp->alias, XkbKeyNameLength);
+ memcpy(def.real, tmp->real, XkbKeyNameLength);
+ if (!HandleAliasDef(&def, def.merge, tmp->def.fileID, into))
+ return False;
+ }
+ return True;
+}
+
+int
+ApplyAliases(XkbDescPtr xkb, Bool toGeom, AliasInfo ** info_in)
+{
+ register int i;
+ XkbKeyAliasPtr old, a;
+ AliasInfo *info;
+ int nNew, nOld;
+ Status status;
+
+ if (*info_in == NULL)
+ return True;
+ if (toGeom)
+ {
+ nOld = (xkb->geom ? xkb->geom->num_key_aliases : 0);
+ old = (xkb->geom ? xkb->geom->key_aliases : NULL);
+ }
+ else
+ {
+ nOld = (xkb->names ? xkb->names->num_key_aliases : 0);
+ old = (xkb->names ? xkb->names->key_aliases : NULL);
+ }
+ for (nNew = 0, info = *info_in; info != NULL;
+ info = (AliasInfo *) info->def.next)
+ {
+ unsigned long lname;
+ unsigned int kc;
+
+ lname = KeyNameToLong(info->real);
+ if (!FindNamedKey(xkb, lname, &kc, False, CreateKeyNames(xkb), 0))
+ {
+ if (warningLevel > 4)
+ {
+ WARN2("Attempt to alias %s to non-existent key %s\n",
+ XkbKeyNameText(info->alias, XkbMessage),
+ XkbKeyNameText(info->real, XkbMessage));
+ ACTION("Ignored\n");
+ }
+ info->alias[0] = '\0';
+ continue;
+ }
+ lname = KeyNameToLong(info->alias);
+ if (FindNamedKey(xkb, lname, &kc, False, False, 0))
+ {
+ if (warningLevel > 4)
+ {
+ WARN("Attempt to create alias with the name of a real key\n");
+ ACTION2("Alias \"%s = %s\" ignored\n",
+ XkbKeyNameText(info->alias, XkbMessage),
+ XkbKeyNameText(info->real, XkbMessage));
+ }
+ info->alias[0] = '\0';
+ continue;
+ }
+ nNew++;
+ if (old)
+ {
+ for (i = 0, a = old; i < nOld; i++, a++)
+ {
+ if (strncmp(a->alias, info->alias, XkbKeyNameLength) == 0)
+ {
+ AliasInfo old;
+ InitAliasInfo(&old, MergeAugment, 0, a->alias, a->real);
+ HandleCollision(&old, info);
+ memcpy(old.real, a->real, XkbKeyNameLength);
+ info->alias[0] = '\0';
+ nNew--;
+ break;
+ }
+ }
+ }
+ }
+ if (nNew == 0)
+ {
+ ClearCommonInfo(&(*info_in)->def);
+ *info_in = NULL;
+ return True;
+ }
+ status = Success;
+ if (toGeom)
+ {
+ if (!xkb->geom)
+ {
+ XkbGeometrySizesRec sizes;
+ bzero((char *) &sizes, sizeof(XkbGeometrySizesRec));
+ sizes.which = XkbGeomKeyAliasesMask;
+ sizes.num_key_aliases = nOld + nNew;
+ status = XkbAllocGeometry(xkb, &sizes);
+ }
+ else
+ {
+ status = XkbAllocGeomKeyAliases(xkb->geom, nOld + nNew);
+ }
+ if (xkb->geom)
+ old = xkb->geom->key_aliases;
+ }
+ else
+ {
+ status = XkbAllocNames(xkb, XkbKeyAliasesMask, 0, nOld + nNew);
+ if (xkb->names)
+ old = xkb->names->key_aliases;
+ }
+ if (status != Success)
+ {
+ WSGO("Allocation failure in ApplyAliases\n");
+ return False;
+ }
+ if (toGeom)
+ a = &xkb->geom->key_aliases[nOld];
+ else
+ a = &xkb->names->key_aliases[nOld];
+ for (info = *info_in; info != NULL; info = (AliasInfo *) info->def.next)
+ {
+ if (info->alias[0] != '\0')
+ {
+ strncpy(a->alias, info->alias, XkbKeyNameLength);
+ strncpy(a->real, info->real, XkbKeyNameLength);
+ a++;
+ }
+ }
+#ifdef DEBUG
+ if ((a - old) != (nOld + nNew))
+ {
+ WSGO2("Expected %d aliases total but created %d\n", nOld + nNew,
+ a - old);
+ }
+#endif
+ if (toGeom)
+ xkb->geom->num_key_aliases += nNew;
+ ClearCommonInfo(&(*info_in)->def);
+ *info_in = NULL;
+ return True;
+}
diff --git a/src/xkbcomp/alias.h b/src/xkbcomp/alias.h
new file mode 100644
index 0000000..b6fac5b
--- /dev/null
+++ b/src/xkbcomp/alias.h
@@ -0,0 +1,56 @@
+/************************************************************
+ Copyright (c) 1995 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.
+
+ ********************************************************/
+
+#ifndef ALIAS_H
+#define ALIAS_H 1
+
+typedef struct _AliasInfo
+{
+ CommonInfo def;
+ char alias[XkbKeyNameLength + 1];
+ char real[XkbKeyNameLength + 1];
+} AliasInfo;
+
+extern int HandleAliasDef(KeyAliasDef * /* def */ ,
+ unsigned /* merge */ ,
+ unsigned /* file_id */ ,
+ AliasInfo ** /* info */
+ );
+
+extern void ClearAliases(AliasInfo ** /* info */
+ );
+
+extern Bool MergeAliases(AliasInfo ** /* into */ ,
+ AliasInfo ** /* merge */ ,
+ unsigned /* how_merge */
+ );
+
+extern int ApplyAliases(XkbDescPtr /* xkb */ ,
+ Bool /* toGeom */ ,
+ AliasInfo ** /* info */
+ );
+
+#endif /* ALIAS_H */
diff --git a/src/xkbcomp/compat.c b/src/xkbcomp/compat.c
new file mode 100644
index 0000000..03c29ef
--- /dev/null
+++ b/src/xkbcomp/compat.c
@@ -0,0 +1,880 @@
+/************************************************************
+ 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 <X11/Xos.h>
+#include "xkbcomp.h"
+#include "tokens.h"
+#include "expr.h"
+#include "vmod.h"
+#include "misc.h"
+#include "indicators.h"
+#include "action.h"
+#include "compat.h"
+
+typedef struct _SymInterpInfo
+{
+ CommonInfo defs;
+ XkbSymInterpretRec interp;
+} SymInterpInfo;
+
+#define _SI_VirtualMod (1<<0)
+#define _SI_Action (1<<1)
+#define _SI_AutoRepeat (1<<2)
+#define _SI_LockingKey (1<<3)
+#define _SI_LevelOneOnly (1<<4)
+
+typedef struct _GroupCompatInfo
+{
+ unsigned char fileID;
+ unsigned char merge;
+ unsigned char real_mods;
+ unsigned short vmods;
+} GroupCompatInfo;
+
+typedef struct _CompatInfo
+{
+ char *name;
+ unsigned fileID;
+ int errorCount;
+ int nInterps;
+ SymInterpInfo *interps;
+ SymInterpInfo dflt;
+ LEDInfo ledDflt;
+ GroupCompatInfo groupCompat[XkbNumKbdGroups];
+ LEDInfo *leds;
+ VModInfo vmods;
+ ActionInfo *act;
+ XkbDescPtr xkb;
+} CompatInfo;
+
+/***====================================================================***/
+
+#define ReportSINotArray(si,f,i) \
+ ReportNotArray("symbol interpretation",(f),siText((si),(i)))
+#define ReportSIBadType(si,f,w,i) \
+ ReportBadType("symbol interpretation",(f),siText((si),(i)),(w))
+
+/***====================================================================***/
+
+static char *
+siText(SymInterpInfo * si, CompatInfo * info)
+{
+ static char buf[128];
+
+ if (si == &info->dflt)
+ {
+ snprintf(buf, sizeof(buf), "default");
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), "%s+%s(%s)",
+ XkbKeysymText(si->interp.sym, XkbMessage),
+ XkbSIMatchText(si->interp.match, XkbMessage),
+ XkbModMaskText(si->interp.mods, XkbMessage));
+ }
+ return buf;
+}
+
+static void
+InitCompatInfo(CompatInfo * info, XkbDescPtr xkb)
+{
+ register int i;
+
+ info->xkb = xkb;
+ info->name = NULL;
+ info->fileID = 0;
+ info->errorCount = 0;
+ info->nInterps = 0;
+ info->interps = NULL;
+ info->act = NULL;
+ info->dflt.defs.fileID = info->fileID;
+ info->dflt.defs.defined = 0;
+ info->dflt.defs.merge = MergeOverride;
+ info->dflt.interp.flags = 0;
+ info->dflt.interp.virtual_mod = XkbNoModifier;
+ info->dflt.interp.act.type = XkbSA_NoAction;
+ for (i = 0; i < XkbAnyActionDataSize; i++)
+ {
+ info->dflt.interp.act.data[i] = 0;
+ }
+ ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
+ info->ledDflt.defs.fileID = info->fileID;
+ info->ledDflt.defs.defined = 0;
+ info->ledDflt.defs.merge = MergeOverride;
+ bzero((char *) &info->groupCompat[0],
+ XkbNumKbdGroups * sizeof(GroupCompatInfo));
+ info->leds = NULL;
+ InitVModInfo(&info->vmods, xkb);
+ return;
+}
+
+static void
+ClearCompatInfo(CompatInfo * info, XkbDescPtr xkb)
+{
+ register int i;
+
+ if (info->name != NULL)
+ uFree(info->name);
+ info->name = NULL;
+ info->dflt.defs.defined = 0;
+ info->dflt.defs.merge = MergeAugment;
+ info->dflt.interp.flags = 0;
+ info->dflt.interp.virtual_mod = XkbNoModifier;
+ info->dflt.interp.act.type = XkbSA_NoAction;
+ for (i = 0; i < XkbAnyActionDataSize; i++)
+ {
+ info->dflt.interp.act.data[i] = 0;
+ }
+ ClearIndicatorMapInfo(xkb->dpy, &info->ledDflt);
+ info->nInterps = 0;
+ info->interps = (SymInterpInfo *) ClearCommonInfo(&info->interps->defs);
+ bzero((char *) &info->groupCompat[0],
+ XkbNumKbdGroups * sizeof(GroupCompatInfo));
+ info->leds = (LEDInfo *) ClearCommonInfo(&info->leds->defs);
+ /* 3/30/94 (ef) -- XXX! Should free action info here */
+ ClearVModInfo(&info->vmods, xkb);
+ return;
+}
+
+static SymInterpInfo *
+NextInterp(CompatInfo * info)
+{
+ SymInterpInfo *si;
+
+ si = uTypedAlloc(SymInterpInfo);
+ if (si)
+ {
+ bzero((char *) si, sizeof(SymInterpInfo));
+ info->interps =
+ (SymInterpInfo *) AddCommonInfo(&info->interps->defs,
+ (CommonInfo *) si);
+ info->nInterps++;
+ }
+ return si;
+}
+
+static SymInterpInfo *
+FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
+{
+ SymInterpInfo *old;
+
+ for (old = info->interps; old != NULL;
+ old = (SymInterpInfo *) old->defs.next)
+ {
+ if ((old->interp.sym == new->interp.sym) &&
+ (old->interp.mods == new->interp.mods) &&
+ (old->interp.match == new->interp.match))
+ {
+ return old;
+ }
+ }
+ return NULL;
+}
+
+static Bool
+AddInterp(CompatInfo * info, SymInterpInfo * new)
+{
+ unsigned collide;
+ SymInterpInfo *old;
+
+ collide = 0;
+ old = FindMatchingInterp(info, new);
+ if (old != NULL)
+ {
+ if (new->defs.merge == MergeReplace)
+ {
+ SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
+ if (((old->defs.fileID == new->defs.fileID)
+ && (warningLevel > 0)) || (warningLevel > 9))
+ {
+ WARN1("Multiple definitions for \"%s\"\n", siText(new, info));
+ ACTION("Earlier interpretation ignored\n");
+ }
+ *old = *new;
+ old->defs.next = &next->defs;
+ return True;
+ }
+ if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide))
+ {
+ old->interp.virtual_mod = new->interp.virtual_mod;
+ old->defs.defined |= _SI_VirtualMod;
+ }
+ if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide))
+ {
+ old->interp.act = new->interp.act;
+ old->defs.defined |= _SI_Action;
+ }
+ if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide))
+ {
+ old->interp.flags &= ~XkbSI_AutoRepeat;
+ old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
+ old->defs.defined |= _SI_AutoRepeat;
+ }
+ if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide))
+ {
+ old->interp.flags &= ~XkbSI_LockingKey;
+ old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
+ old->defs.defined |= _SI_LockingKey;
+ }
+ if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs, &collide))
+ {
+ old->interp.match &= ~XkbSI_LevelOneOnly;
+ old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
+ old->defs.defined |= _SI_LevelOneOnly;
+ }
+ if (collide)
+ {
+ WARN1("Multiple interpretations of \"%s\"\n", siText(new, info));
+ ACTION1("Using %s definition for duplicate fields\n",
+ (new->defs.merge != MergeAugment ? "last" : "first"));
+ }
+ return True;
+ }
+ old = new;
+ if ((new = NextInterp(info)) == NULL)
+ return False;
+ *new = *old;
+ new->defs.next = NULL;
+ return True;
+}
+
+static Bool
+AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
+{
+ GroupCompatInfo *gc;
+ unsigned merge;
+
+ merge = newGC->merge;
+ gc = &info->groupCompat[group];
+ if (((gc->real_mods == newGC->real_mods) && (gc->vmods == newGC->vmods)))
+ {
+ return True;
+ }
+ if (((gc->fileID == newGC->fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN1("Compat map for group %d redefined\n", group + 1);
+ ACTION1("Using %s definition\n",
+ (merge == MergeAugment ? "old" : "new"));
+ }
+ if (merge != MergeAugment)
+ *gc = *newGC;
+ return True;
+}
+
+/***====================================================================***/
+
+static Bool
+ResolveStateAndPredicate(ExprDef * expr,
+ unsigned *pred_rtrn,
+ unsigned *mods_rtrn, CompatInfo * info)
+{
+ ExprResult result;
+
+ if (expr == NULL)
+ {
+ *pred_rtrn = XkbSI_AnyOfOrNone;
+ *mods_rtrn = ~0;
+ return True;
+ }
+
+ *pred_rtrn = XkbSI_Exactly;
+ if (expr->op == ExprActionDecl)
+ {
+ char *pred_txt =
+ XkbAtomText(NULL, expr->value.action.name, XkbMessage);
+ if (uStrCaseCmp(pred_txt, "noneof") == 0)
+ *pred_rtrn = XkbSI_NoneOf;
+ else if (uStrCaseCmp(pred_txt, "anyofornone") == 0)
+ *pred_rtrn = XkbSI_AnyOfOrNone;
+ else if (uStrCaseCmp(pred_txt, "anyof") == 0)
+ *pred_rtrn = XkbSI_AnyOf;
+ else if (uStrCaseCmp(pred_txt, "allof") == 0)
+ *pred_rtrn = XkbSI_AllOf;
+ else if (uStrCaseCmp(pred_txt, "exactly") == 0)
+ *pred_rtrn = XkbSI_Exactly;
+ else
+ {
+ ERROR1("Illegal modifier predicate \"%s\"\n", pred_txt);
+ ACTION("Ignored\n");
+ return False;
+ }
+ expr = expr->value.action.args;
+ }
+ else if (expr->op == ExprIdent)
+ {
+ char *pred_txt = XkbAtomText(NULL, expr->value.str, XkbMessage);
+ if ((pred_txt) && (uStrCaseCmp(pred_txt, "any") == 0))
+ {
+ *pred_rtrn = XkbSI_AnyOf;
+ *mods_rtrn = 0xff;
+ return True;
+ }
+ }
+
+ if (ExprResolveModMask(expr, &result, NULL, NULL))
+ {
+ *mods_rtrn = result.uval;
+ return True;
+ }
+ return False;
+}
+
+/***====================================================================***/
+
+static void
+MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, unsigned merge)
+{
+ SymInterpInfo *si;
+ LEDInfo *led, *rtrn, *next;
+ GroupCompatInfo *gcm;
+ register int i;
+
+ if (from->errorCount > 0)
+ {
+ into->errorCount += from->errorCount;
+ return;
+ }
+ if (into->name == NULL)
+ {
+ into->name = from->name;
+ from->name = NULL;
+ }
+ for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next)
+ {
+ if (merge != MergeDefault)
+ si->defs.merge = merge;
+ if (!AddInterp(into, si))
+ into->errorCount++;
+ }
+ for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++, gcm++)
+ {
+ if (merge != MergeDefault)
+ gcm->merge = merge;
+ if (!AddGroupCompat(into, i, gcm))
+ into->errorCount++;
+ }
+ for (led = from->leds; led != NULL; led = next)
+ {
+ next = (LEDInfo *) led->defs.next;
+ if (merge != MergeDefault)
+ led->defs.merge = merge;
+ rtrn = AddIndicatorMap(into->leds, led);
+ if (rtrn != NULL)
+ into->leds = rtrn;
+ else
+ into->errorCount++;
+ }
+ return;
+}
+
+typedef void (*FileHandler) (XkbFile * /* rtrn */ ,
+ XkbDescPtr /* xkb */ ,
+ unsigned /* merge */ ,
+ CompatInfo * /* info */
+ );
+
+static Bool
+HandleIncludeCompatMap(IncludeStmt * stmt,
+ XkbDescPtr xkb, CompatInfo * info, FileHandler hndlr)
+{
+ unsigned newMerge;
+ XkbFile *rtrn;
+ CompatInfo included;
+ Bool haveSelf;
+
+ haveSelf = False;
+ if ((stmt->file == NULL) && (stmt->map == NULL))
+ {
+ haveSelf = True;
+ included = *info;
+ bzero(info, sizeof(CompatInfo));
+ }
+ else if (ProcessIncludeFile(stmt, XkmCompatMapIndex, &rtrn, &newMerge))
+ {
+ InitCompatInfo(&included, xkb);
+ included.fileID = rtrn->id;
+ included.dflt = info->dflt;
+ included.dflt.defs.fileID = rtrn->id;
+ included.dflt.defs.merge = newMerge;
+ included.ledDflt.defs.fileID = rtrn->id;
+ included.ledDflt.defs.merge = newMerge;
+ included.act = info->act;
+ (*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;
+ CompatInfo next_incl;
+
+ for (next = stmt->next; next != NULL; next = next->next)
+ {
+ if ((next->file == NULL) && (next->map == NULL))
+ {
+ haveSelf = True;
+ MergeIncludedCompatMaps(&included, info, next->merge);
+ ClearCompatInfo(info, xkb);
+ }
+ else if (ProcessIncludeFile(next, XkmCompatMapIndex, &rtrn, &op))
+ {
+ InitCompatInfo(&next_incl, xkb);
+ next_incl.fileID = rtrn->id;
+ next_incl.dflt = info->dflt;
+ next_incl.dflt.defs.fileID = rtrn->id;
+ next_incl.dflt.defs.merge = op;
+ next_incl.ledDflt.defs.fileID = rtrn->id;
+ next_incl.ledDflt.defs.merge = op;
+ next_incl.act = info->act;
+ (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
+ MergeIncludedCompatMaps(&included, &next_incl, op);
+ ClearCompatInfo(&next_incl, xkb);
+ }
+ else
+ {
+ info->errorCount += 10;
+ return False;
+ }
+ }
+ }
+ if (haveSelf)
+ *info = included;
+ else
+ {
+ MergeIncludedCompatMaps(info, &included, newMerge);
+ ClearCompatInfo(&included, xkb);
+ }
+ return (info->errorCount == 0);
+}
+
+static LookupEntry useModMapValues[] = {
+ {"levelone", 1},
+ {"level1", 1},
+ {"anylevel", 0},
+ {"any", 0},
+ {NULL, 0}
+};
+
+static int
+SetInterpField(SymInterpInfo * si,
+ XkbDescPtr xkb,
+ char *field,
+ ExprDef * arrayNdx, ExprDef * value, CompatInfo * info)
+{
+ int ok = 1;
+ ExprResult tmp;
+
+ if (uStrCaseCmp(field, "action") == 0)
+ {
+ if (arrayNdx != NULL)
+ return ReportSINotArray(si, field, info);
+ ok = HandleActionDef(value, xkb, &si->interp.act, si->defs.merge,
+ info->act);
+ if (ok)
+ si->defs.defined |= _SI_Action;
+ }
+ else if ((uStrCaseCmp(field, "virtualmodifier") == 0) ||
+ (uStrCaseCmp(field, "virtualmod") == 0))
+ {
+ if (arrayNdx != NULL)
+ return ReportSINotArray(si, field, info);
+ ok = ResolveVirtualModifier(value, &tmp, &info->vmods);
+ if (ok)
+ {
+ si->interp.virtual_mod = tmp.uval;
+ si->defs.defined |= _SI_VirtualMod;
+ }
+ else
+ return ReportSIBadType(si, field, "virtual modifier", info);
+ }
+ else if (uStrCaseCmp(field, "repeat") == 0)
+ {
+ if (arrayNdx != NULL)
+ return ReportSINotArray(si, field, info);
+ ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
+ if (ok)
+ {
+ if (tmp.uval)
+ si->interp.flags |= XkbSI_AutoRepeat;
+ else
+ si->interp.flags &= ~XkbSI_AutoRepeat;
+ si->defs.defined |= _SI_AutoRepeat;
+ }
+ else
+ return ReportSIBadType(si, field, "boolean", info);
+ }
+ else if (uStrCaseCmp(field, "locking") == 0)
+ {
+ if (arrayNdx != NULL)
+ return ReportSINotArray(si, field, info);
+ ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
+ if (ok)
+ {
+ if (tmp.uval)
+ si->interp.flags |= XkbSI_LockingKey;
+ else
+ si->interp.flags &= ~XkbSI_LockingKey;
+ si->defs.defined |= _SI_LockingKey;
+ }
+ else
+ return ReportSIBadType(si, field, "boolean", info);
+ }
+ else if ((uStrCaseCmp(field, "usemodmap") == 0) ||
+ (uStrCaseCmp(field, "usemodmapmods") == 0))
+ {
+ if (arrayNdx != NULL)
+ return ReportSINotArray(si, field, info);
+ ok = ExprResolveEnum(value, &tmp, useModMapValues);
+ if (ok)
+ {
+ if (tmp.uval)
+ si->interp.match |= XkbSI_LevelOneOnly;
+ else
+ si->interp.match &= ~XkbSI_LevelOneOnly;
+ si->defs.defined |= _SI_LevelOneOnly;
+ }
+ else
+ return ReportSIBadType(si, field, "level specification", info);
+ }
+ else
+ {
+ ok = ReportBadField("symbol interpretation", field, siText(si, info));
+ }
+ return ok;
+}
+
+LookupEntry groupNames[] = {
+ {"group1", 0x01}
+ ,
+ {"group2", 0x02}
+ ,
+ {"group3", 0x04}
+ ,
+ {"group4", 0x08}
+ ,
+ {"group5", 0x10}
+ ,
+ {"group6", 0x20}
+ ,
+ {"group7", 0x40}
+ ,
+ {"group8", 0x80}
+ ,
+ {"none", 0x00}
+ ,
+ {"all", 0xff}
+ ,
+ {NULL, 0}
+};
+
+static int
+HandleInterpVar(VarDef * stmt, XkbDescPtr xkb, CompatInfo * info)
+{
+ ExprResult elem, field;
+ ExprDef *ndx;
+
+ if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
+ return 0; /* internal error, already reported */
+ if (elem.str && (uStrCaseCmp(elem.str, "interpret") == 0))
+ return SetInterpField(&info->dflt, xkb, field.str, ndx, stmt->value,
+ info);
+ if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
+ {
+ return SetIndicatorMapField(&info->ledDflt, xkb, field.str, ndx,
+ stmt->value);
+ }
+ return SetActionField(xkb, elem.str, field.str, ndx, stmt->value,
+ &info->act);
+}
+
+static int
+HandleInterpBody(VarDef * def, XkbDescPtr xkb, SymInterpInfo * si,
+ CompatInfo * info)
+{
+ int ok = 1;
+ ExprResult tmp, field;
+ ExprDef *arrayNdx;
+
+ for (; def != NULL; def = (VarDef *) def->common.next)
+ {
+ if ((def->name) && (def->name->type == ExprFieldRef))
+ {
+ ok = HandleInterpVar(def, xkb, info);
+ continue;
+ }
+ ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
+ if (ok)
+ ok = SetInterpField(si, xkb, field.str, arrayNdx, def->value,
+ info);
+ }
+ return ok;
+}
+
+static int
+HandleInterpDef(InterpDef * def, XkbDescPtr xkb, unsigned merge,
+ CompatInfo * info)
+{
+ unsigned pred, mods;
+ SymInterpInfo si;
+
+ if (!ResolveStateAndPredicate(def->match, &pred, &mods, info))
+ {
+ ERROR("Couldn't determine matching modifiers\n");
+ ACTION("Symbol interpretation ignored\n");
+ return False;
+ }
+ if (def->merge != MergeDefault)
+ merge = def->merge;
+
+ si = info->dflt;
+ si.defs.merge = merge;
+ si.interp.sym = def->sym;
+ si.interp.match = pred & XkbSI_OpMask;
+ si.interp.mods = mods;
+ if (!HandleInterpBody(def->def, xkb, &si, info))
+ {
+ info->errorCount++;
+ return False;
+ }
+
+ if (!AddInterp(info, &si))
+ {
+ info->errorCount++;
+ return False;
+ }
+ return True;
+}
+
+static int
+HandleGroupCompatDef(GroupCompatDef * def,
+ XkbDescPtr xkb, unsigned merge, CompatInfo * info)
+{
+ ExprResult val;
+ GroupCompatInfo tmp;
+
+ if (def->merge != MergeDefault)
+ merge = def->merge;
+ if (!XkbIsLegalGroup(def->group - 1))
+ {
+ ERROR1("Keyboard group must be in the range 1..%d\n",
+ XkbNumKbdGroups + 1);
+ ACTION1("Compatibility map for illegal group %d ignored\n",
+ def->group);
+ return False;
+ }
+ tmp.fileID = info->fileID;
+ tmp.merge = merge;
+ if (!ExprResolveModMask(def->def, &val, LookupVModMask, (XPointer) xkb))
+ {
+ ERROR("Expected a modifier mask in group compatibility definition\n");
+ ACTION1("Ignoring illegal compatibility map for group %d\n",
+ def->group);
+ return False;
+ }
+ tmp.real_mods = val.uval & 0xff;
+ tmp.vmods = (val.uval >> 8) & 0xffff;
+ return AddGroupCompat(info, def->group - 1, &tmp);
+}
+
+static void
+HandleCompatMapFile(XkbFile * file,
+ XkbDescPtr xkb, unsigned merge, CompatInfo * info)
+{
+ ParseCommon *stmt;
+
+ if (merge == MergeDefault)
+ merge = MergeAugment;
+ info->name = uStringDup(file->name);
+ stmt = file->defs;
+ while (stmt)
+ {
+ switch (stmt->stmtType)
+ {
+ case StmtInclude:
+ if (!HandleIncludeCompatMap((IncludeStmt *) stmt, xkb, info,
+ HandleCompatMapFile))
+ info->errorCount++;
+ break;
+ case StmtInterpDef:
+ if (!HandleInterpDef((InterpDef *) stmt, xkb, merge, info))
+ info->errorCount++;
+ break;
+ case StmtGroupCompatDef:
+ if (!HandleGroupCompatDef
+ ((GroupCompatDef *) stmt, xkb, merge, info))
+ info->errorCount++;
+ break;
+ case StmtIndicatorMapDef:
+ {
+ LEDInfo *rtrn;
+ rtrn = HandleIndicatorMapDef((IndicatorMapDef *) stmt, xkb,
+ &info->ledDflt, info->leds, merge);
+ if (rtrn != NULL)
+ info->leds = rtrn;
+ else
+ info->errorCount++;
+ }
+ break;
+ case StmtVarDef:
+ if (!HandleInterpVar((VarDef *) stmt, xkb, info))
+ info->errorCount++;
+ break;
+ case StmtVModDef:
+ if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
+ info->errorCount++;
+ break;
+ case StmtKeycodeDef:
+ ERROR("Interpretation files may not include other types\n");
+ ACTION("Ignoring definition of key name\n");
+ info->errorCount++;
+ break;
+ default:
+ WSGO1("Unexpected statement type %d in HandleCompatMapFile\n",
+ stmt->stmtType);
+ break;
+ }
+ stmt = stmt->next;
+ if (info->errorCount > 10)
+ {
+#ifdef NOISY
+ ERROR("Too many errors\n");
+#endif
+ ACTION1("Abandoning compatibility map \"%s\"\n", file->topName);
+ break;
+ }
+ }
+ return;
+}
+
+static void
+CopyInterps(CompatInfo * info,
+ XkbCompatMapPtr compat, Bool needSymbol, unsigned pred)
+{
+ SymInterpInfo *si;
+
+ for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next)
+ {
+ if (((si->interp.match & XkbSI_OpMask) != pred) ||
+ (needSymbol && (si->interp.sym == NoSymbol)) ||
+ ((!needSymbol) && (si->interp.sym != NoSymbol)))
+ continue;
+ if (compat->num_si >= compat->size_si)
+ {
+ WSGO("No room to merge symbol interpretations\n");
+ ACTION("Symbol interpretations lost\n");
+ return;
+ }
+ compat->sym_interpret[compat->num_si++] = si->interp;
+ }
+ return;
+}
+
+Bool
+CompileCompatMap(XkbFile * file,
+ XkbFileInfo * result, unsigned merge, LEDInfo ** unboundLEDs)
+{
+ int i;
+ CompatInfo info;
+ XkbDescPtr xkb;
+ GroupCompatInfo *gcm;
+
+ xkb = result->xkb;
+ InitCompatInfo(&info, xkb);
+ info.dflt.defs.merge = merge;
+ info.ledDflt.defs.merge = merge;
+ HandleCompatMapFile(file, xkb, merge, &info);
+
+ if (info.errorCount == 0)
+ {
+ int size;
+ if (XkbAllocCompatMap(xkb, XkbAllCompatMask, info.nInterps) !=
+ Success)
+ {
+ WSGO("Couldn't allocate compatibility map\n");
+ ACTION("Exiting\n");
+ return False;
+ }
+ if (info.name != NULL)
+ {
+ if (XkbAllocNames(xkb, XkbCompatNameMask, 0, 0) == Success)
+ xkb->names->compat =
+ XkbInternAtom(xkb->dpy, info.name, False);
+ else
+ {
+ WSGO("Couldn't allocate space for compat name\n");
+ ACTION2("Name \"%s\" (from %s) NOT assigned\n",
+ scanFile, info.name);
+ }
+ }
+ size = info.nInterps * sizeof(XkbSymInterpretRec);
+ if (size > 0)
+ {
+ CopyInterps(&info, xkb->compat, True, XkbSI_Exactly);
+ CopyInterps(&info, xkb->compat, True, XkbSI_AllOf | XkbSI_NoneOf);
+ CopyInterps(&info, xkb->compat, True, XkbSI_AnyOf);
+ CopyInterps(&info, xkb->compat, True, XkbSI_AnyOfOrNone);
+ CopyInterps(&info, xkb->compat, False, XkbSI_Exactly);
+ CopyInterps(&info, xkb->compat, False,
+ XkbSI_AllOf | XkbSI_NoneOf);
+ CopyInterps(&info, xkb->compat, False, XkbSI_AnyOf);
+ CopyInterps(&info, xkb->compat, False, XkbSI_AnyOfOrNone);
+ }
+ for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
+ i++, gcm++)
+ {
+ if ((gcm->fileID != 0) || (gcm->real_mods != 0)
+ || (gcm->vmods != 0))
+ {
+ xkb->compat->groups[i].mask = gcm->real_mods;
+ xkb->compat->groups[i].real_mods = gcm->real_mods;
+ xkb->compat->groups[i].vmods = gcm->vmods;
+ }
+ }
+ if (info.leds != NULL)
+ {
+ if (!CopyIndicatorMapDefs(result, info.leds, unboundLEDs))
+ info.errorCount++;
+ info.leds = NULL;
+ }
+ ClearCompatInfo(&info, xkb);
+ return True;
+ }
+ if (info.interps != NULL)
+ uFree(info.interps);
+ return False;
+}
diff --git a/src/xkbcomp/compat.h b/src/xkbcomp/compat.h
new file mode 100644
index 0000000..799b215
--- /dev/null
+++ b/src/xkbcomp/compat.h
@@ -0,0 +1,7 @@
+
+#ifndef COMPAT_H
+#define COMPAT_H 1
+
+extern LookupEntry groupNames[];
+
+#endif /* COMPAT_H */
diff --git a/src/xkbcomp/expr.c b/src/xkbcomp/expr.c
new file mode 100644
index 0000000..96fd956
--- /dev/null
+++ b/src/xkbcomp/expr.c
@@ -0,0 +1,1065 @@
+/************************************************************
+ 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 <ctype.h>
+
+/***====================================================================***/
+
+char *
+exprOpText(unsigned type)
+{
+ static char buf[32];
+
+ switch (type)
+ {
+ case ExprValue:
+ strcpy(buf, "literal");
+ break;
+ case ExprIdent:
+ strcpy(buf, "identifier");
+ break;
+ case ExprActionDecl:
+ strcpy(buf, "action declaration");
+ break;
+ case ExprFieldRef:
+ strcpy(buf, "field reference");
+ break;
+ case ExprArrayRef:
+ strcpy(buf, "array reference");
+ break;
+ case ExprKeysymList:
+ strcpy(buf, "list of keysyms");
+ break;
+ case ExprActionList:
+ strcpy(buf, "list of actions");
+ break;
+ case OpAdd:
+ strcpy(buf, "addition");
+ break;
+ case OpSubtract:
+ strcpy(buf, "subtraction");
+ break;
+ case OpMultiply:
+ strcpy(buf, "multiplication");
+ break;
+ case OpDivide:
+ strcpy(buf, "division");
+ break;
+ case OpAssign:
+ strcpy(buf, "assignment");
+ break;
+ case OpNot:
+ strcpy(buf, "logical not");
+ break;
+ case OpNegate:
+ strcpy(buf, "arithmetic negation");
+ break;
+ case OpInvert:
+ strcpy(buf, "bitwise inversion");
+ break;
+ case OpUnaryPlus:
+ strcpy(buf, "plus sign");
+ break;
+ default:
+ snprintf(buf, sizeof(buf), "illegal(%d)", type);
+ break;
+ }
+ return buf;
+}
+
+char *
+exprTypeText(unsigned type)
+{
+ static char buf[20];
+
+ switch (type)
+ {
+ case TypeUnknown:
+ strcpy(buf, "unknown");
+ break;
+ case TypeBoolean:
+ strcpy(buf, "boolean");
+ break;
+ case TypeInt:
+ strcpy(buf, "int");
+ break;
+ case TypeString:
+ strcpy(buf, "string");
+ break;
+ case TypeAction:
+ strcpy(buf, "action");
+ break;
+ case TypeKeyName:
+ strcpy(buf, "keyname");
+ break;
+ default:
+ snprintf(buf, sizeof(buf), "illegal(%d)", type);
+ break;
+ }
+ return buf;
+}
+
+int
+ExprResolveLhs(ExprDef * expr,
+ ExprResult * elem_rtrn,
+ ExprResult * field_rtrn, ExprDef ** index_rtrn)
+{
+ switch (expr->op)
+ {
+ case ExprIdent:
+ elem_rtrn->str = NULL;
+ field_rtrn->str = XkbAtomGetString(NULL, expr->value.str);
+ *index_rtrn = NULL;
+ return True;
+ case ExprFieldRef:
+ elem_rtrn->str = XkbAtomGetString(NULL, expr->value.field.element);
+ field_rtrn->str = XkbAtomGetString(NULL, expr->value.field.field);
+ *index_rtrn = NULL;
+ return True;
+ case ExprArrayRef:
+ elem_rtrn->str = XkbAtomGetString(NULL, expr->value.array.element);
+ field_rtrn->str = XkbAtomGetString(NULL, expr->value.array.field);
+ *index_rtrn = expr->value.array.entry;
+ return True;
+ }
+ WSGO1("Unexpected operator %d in ResolveLhs\n", expr->op);
+ return False;
+}
+
+Bool
+SimpleLookup(XPointer priv,
+ Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
+{
+ LookupEntry *entry;
+ register char *str;
+
+ if ((priv == NULL) ||
+ (field == None) || (elem != None) ||
+ ((type != TypeInt) && (type != TypeFloat)))
+ {
+ return False;
+ }
+ str = XkbAtomGetString(NULL, field);
+ for (entry = (LookupEntry *) priv;
+ (entry != NULL) && (entry->name != NULL); entry++)
+ {
+ if (uStrCaseCmp(str, entry->name) == 0)
+ {
+ val_rtrn->uval = entry->result;
+ if (type == TypeFloat)
+ val_rtrn->uval *= XkbGeomPtsPerMM;
+ return True;
+ }
+ }
+ return False;
+}
+
+Bool
+RadioLookup(XPointer priv,
+ Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
+{
+ register char *str;
+ int rg;
+
+ if ((field == None) || (elem != None) || (type != TypeInt))
+ return False;
+ str = XkbAtomGetString(NULL, field);
+ if (str)
+ {
+ if (uStrCasePrefix("group", str))
+ str += strlen("group");
+ else if (uStrCasePrefix("radiogroup", str))
+ str += strlen("radiogroup");
+ else if (uStrCasePrefix("rg", str))
+ str += strlen("rg");
+ else if (!isdigit(str[0]))
+ str = NULL;
+ }
+ if ((!str) || (sscanf(str, "%i", &rg) < 1) || (rg < 1)
+ || (rg > XkbMaxRadioGroups))
+ return False;
+ val_rtrn->uval = rg;
+ return True;
+}
+
+int
+TableLookup(XPointer priv,
+ Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
+{
+ LookupTable *tbl = (LookupTable *) priv;
+ register char *str;
+
+ if ((priv == NULL) || (field == None) || (type != TypeInt))
+ return False;
+ str = XkbAtomGetString(NULL, elem);
+ while (tbl)
+ {
+ if (((str == NULL) && (tbl->element == NULL)) ||
+ ((str != NULL) && (tbl->element != NULL) &&
+ (uStrCaseCmp(str, tbl->element) == 0)))
+ {
+ break;
+ }
+ tbl = tbl->nextElement;
+ }
+ if (tbl == NULL) /* didn't find a matching element */
+ return False;
+ priv = (XPointer) tbl->entries;
+ return SimpleLookup(priv, (Atom) None, field, type, val_rtrn);
+}
+
+static LookupEntry modIndexNames[] = {
+ {"shift", ShiftMapIndex},
+ {"control", ControlMapIndex},
+ {"lock", LockMapIndex},
+ {"mod1", Mod1MapIndex},
+ {"mod2", Mod2MapIndex},
+ {"mod3", Mod3MapIndex},
+ {"mod4", Mod4MapIndex},
+ {"mod5", Mod5MapIndex},
+ {"none", XkbNoModifier},
+ {NULL, 0}
+};
+
+int
+LookupModIndex(XPointer priv,
+ Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
+{
+ return SimpleLookup((XPointer) modIndexNames, elem, field, type,
+ val_rtrn);
+}
+
+int
+LookupModMask(XPointer priv,
+ Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
+{
+ char *str;
+
+ if ((elem != None) || (type != TypeInt))
+ return False;
+ str = XkbAtomGetString(NULL, field);
+ if (str == NULL)
+ return False;
+ if (uStrCaseCmp(str, "all") == 0)
+ val_rtrn->uval = 0xff;
+ else if (uStrCaseCmp(str, "none") == 0)
+ val_rtrn->uval = 0;
+ else if (LookupModIndex(priv, elem, field, type, val_rtrn))
+ val_rtrn->uval = (1 << val_rtrn->uval);
+ else if (priv != NULL)
+ {
+ LookupPriv *lpriv = (LookupPriv *) priv;
+ if ((lpriv->chain == NULL) ||
+ (!(*lpriv->chain) (lpriv->chainPriv, elem, field, type,
+ val_rtrn)))
+ return False;
+ }
+ else
+ return False;
+ return True;
+}
+
+int
+ExprResolveModIndex(ExprDef * expr,
+ ExprResult * val_rtrn,
+ IdentLookupFunc lookup, XPointer lookupPriv)
+{
+ int ok = 0;
+ char *bogus = NULL;
+
+ switch (expr->op)
+ {
+ case ExprValue:
+ if (expr->type != TypeInt)
+ {
+ ERROR1
+ ("Found constant of type %s where a modifier mask was expected\n",
+ exprTypeText(expr->type));
+ return False;
+ }
+ else if ((expr->value.ival >= XkbNumModifiers)
+ || (expr->value.ival < 0))
+ {
+ ERROR2("Illegal modifier index (%d, must be 0..%d)\n",
+ expr->value.ival, XkbNumModifiers - 1);
+ return False;
+ }
+ val_rtrn->ival = expr->value.ival;
+ return True;
+ case ExprIdent:
+ if (LookupModIndex(lookupPriv, (Atom) None, expr->value.str,
+ (unsigned) TypeInt, val_rtrn))
+ {
+ return True;
+ }
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ None, expr->value.str, TypeInt, val_rtrn);
+ }
+ if (!ok)
+ ERROR1("Cannot determine modifier index for \"%s\"\n",
+ XkbAtomText(NULL, expr->value.str, XkbMessage));
+ break;
+ case ExprFieldRef:
+ bogus = "field reference";
+ break;
+ case ExprArrayRef:
+ bogus = "array reference";
+ break;
+ case ExprActionDecl:
+ bogus = "function";
+ break;
+ case OpAdd:
+ case OpSubtract:
+ case OpMultiply:
+ case OpDivide:
+ case OpInvert:
+ case OpNegate:
+ case OpNot:
+ case OpUnaryPlus:
+ bogus = "arithmetic operations";
+ break;
+ case OpAssign:
+ bogus = "assignment";
+ break;
+ default:
+ WSGO1("Unknown operator %d in ResolveModIndex\n", expr->op);
+ return False;
+ }
+ if (bogus)
+ {
+ ERROR1("Modifier index must be a name or number, %s ignored\n",
+ bogus);
+ return False;
+ }
+ return ok;
+}
+
+int
+ExprResolveModMask(ExprDef * expr,
+ ExprResult * val_rtrn,
+ IdentLookupFunc lookup, XPointer lookupPriv)
+{
+ LookupPriv priv;
+
+ priv.priv = NULL;
+ priv.chain = lookup;
+ priv.chainPriv = lookupPriv;
+ return ExprResolveMask(expr, val_rtrn, LookupModMask, (XPointer) & priv);
+}
+
+int
+ExprResolveBoolean(ExprDef * expr,
+ ExprResult * val_rtrn,
+ IdentLookupFunc lookup, XPointer lookupPriv)
+{
+ int ok = 0;
+ char *bogus = NULL;
+
+ switch (expr->op)
+ {
+ case ExprValue:
+ if (expr->type != TypeBoolean)
+ {
+ ERROR1
+ ("Found constant of type %s where boolean was expected\n",
+ exprTypeText(expr->type));
+ return False;
+ }
+ val_rtrn->ival = expr->value.ival;
+ return True;
+ case ExprIdent:
+ bogus = XkbAtomGetString(NULL, expr->value.str);
+ if (bogus)
+ {
+ if ((uStrCaseCmp(bogus, "true") == 0) ||
+ (uStrCaseCmp(bogus, "yes") == 0) ||
+ (uStrCaseCmp(bogus, "on") == 0))
+ {
+ val_rtrn->uval = 1;
+ return True;
+ }
+ else if ((uStrCaseCmp(bogus, "false") == 0) ||
+ (uStrCaseCmp(bogus, "no") == 0) ||
+ (uStrCaseCmp(bogus, "off") == 0))
+ {
+ val_rtrn->uval = 0;
+ return True;
+ }
+ }
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ None, expr->value.str, TypeBoolean, val_rtrn);
+ }
+ if (!ok)
+ ERROR1("Identifier \"%s\" of type int is unknown\n",
+ XkbAtomText(NULL, expr->value.str, XkbMessage));
+ return ok;
+ case ExprFieldRef:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ expr->value.field.element,
+ expr->value.field.field, TypeBoolean, val_rtrn);
+ }
+ if (!ok)
+ ERROR2("Default \"%s.%s\" of type boolean is unknown\n",
+ XkbAtomText(NULL, expr->value.field.element, XkbMessage),
+ XkbAtomText(NULL, expr->value.field.field, XkbMessage));
+ return ok;
+ case OpInvert:
+ case OpNot:
+ ok = ExprResolveBoolean(expr, val_rtrn, lookup, lookupPriv);
+ if (ok)
+ val_rtrn->uval = !val_rtrn->uval;
+ return ok;
+ case OpAdd:
+ if (bogus == NULL)
+ bogus = "Addition";
+ case OpSubtract:
+ if (bogus == NULL)
+ bogus = "Subtraction";
+ case OpMultiply:
+ if (bogus == NULL)
+ bogus = "Multiplication";
+ case OpDivide:
+ if (bogus == NULL)
+ bogus = "Division";
+ case OpAssign:
+ if (bogus == NULL)
+ bogus = "Assignment";
+ case OpNegate:
+ if (bogus == NULL)
+ bogus = "Negation";
+ ERROR1("%s of boolean values not permitted\n", bogus);
+ break;
+ case OpUnaryPlus:
+ ERROR("Unary \"+\" operator not permitted for boolean values\n");
+ break;
+ default:
+ WSGO1("Unknown operator %d in ResolveBoolean\n", expr->op);
+ break;
+ }
+ return False;
+}
+
+int
+ExprResolveFloat(ExprDef * expr,
+ ExprResult * val_rtrn,
+ IdentLookupFunc lookup, XPointer lookupPriv)
+{
+ int ok = 0;
+ ExprResult leftRtrn, rightRtrn;
+ ExprDef *left, *right;
+
+ switch (expr->op)
+ {
+ case ExprValue:
+ if (expr->type == TypeString)
+ {
+ register char *str;
+ str = XkbAtomGetString(NULL, expr->value.str);
+ if ((str != NULL) && (strlen(str) == 1))
+ {
+ val_rtrn->uval = str[0] * XkbGeomPtsPerMM;
+ return True;
+ }
+ }
+ if ((expr->type != TypeInt) && (expr->type != TypeFloat))
+ {
+ ERROR1("Found constant of type %s, expected a number\n",
+ exprTypeText(expr->type));
+ return False;
+ }
+ val_rtrn->ival = expr->value.ival;
+ if (expr->type == TypeInt)
+ val_rtrn->ival *= XkbGeomPtsPerMM;
+ return True;
+ case ExprIdent:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ None, expr->value.str, TypeFloat, val_rtrn);
+ }
+ if (!ok)
+ ERROR1("Numeric identifier \"%s\" unknown\n",
+ XkbAtomText(NULL, expr->value.str, XkbMessage));
+ return ok;
+ case ExprFieldRef:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ expr->value.field.element,
+ expr->value.field.field, TypeFloat, val_rtrn);
+ }
+ if (!ok)
+ ERROR2("Numeric default \"%s.%s\" unknown\n",
+ XkbAtomText(NULL, expr->value.field.element, XkbMessage),
+ XkbAtomText(NULL, expr->value.field.field, XkbMessage));
+ return ok;
+ case OpAdd:
+ case OpSubtract:
+ case OpMultiply:
+ case OpDivide:
+ left = expr->value.binary.left;
+ right = expr->value.binary.right;
+ if (ExprResolveFloat(left, &leftRtrn, lookup, lookupPriv) &&
+ ExprResolveFloat(right, &rightRtrn, lookup, lookupPriv))
+ {
+ switch (expr->op)
+ {
+ case OpAdd:
+ val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
+ break;
+ case OpSubtract:
+ val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
+ break;
+ case OpMultiply:
+ val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
+ break;
+ case OpDivide:
+ val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
+ break;
+ }
+ return True;
+ }
+ return False;
+ case OpAssign:
+ WSGO("Assignment operator not implemented yet\n");
+ break;
+ case OpNot:
+ left = expr->value.child;
+ if (ExprResolveFloat(left, &leftRtrn, lookup, lookupPriv))
+ {
+ ERROR("The ! operator cannot be applied to a number\n");
+ }
+ return False;
+ case OpInvert:
+ case OpNegate:
+ left = expr->value.child;
+ if (ExprResolveFloat(left, &leftRtrn, lookup, lookupPriv))
+ {
+ if (expr->op == OpNegate)
+ val_rtrn->ival = -leftRtrn.ival;
+ else
+ val_rtrn->ival = ~leftRtrn.ival;
+ return True;
+ }
+ return False;
+ case OpUnaryPlus:
+ left = expr->value.child;
+ return ExprResolveFloat(left, val_rtrn, lookup, lookupPriv);
+ default:
+ WSGO1("Unknown operator %d in ResolveFloat\n", expr->op);
+ break;
+ }
+ return False;
+}
+
+int
+ExprResolveInteger(ExprDef * expr,
+ ExprResult * val_rtrn,
+ IdentLookupFunc lookup, XPointer lookupPriv)
+{
+ int ok = 0;
+ ExprResult leftRtrn, rightRtrn;
+ ExprDef *left, *right;
+
+ switch (expr->op)
+ {
+ case ExprValue:
+ if (expr->type == TypeString)
+ {
+ register char *str;
+ str = XkbAtomGetString(NULL, expr->value.str);
+ if (str != NULL)
+ switch (strlen(str))
+ {
+ case 0:
+ val_rtrn->uval = 0;
+ return True;
+ case 1:
+ val_rtrn->uval = str[0];
+ return True;
+ default:
+ break;
+ }
+ }
+ if ((expr->type != TypeInt) && (expr->type != TypeFloat))
+ {
+ ERROR1
+ ("Found constant of type %s where an int was expected\n",
+ exprTypeText(expr->type));
+ return False;
+ }
+ val_rtrn->ival = expr->value.ival;
+ if (expr->type == TypeFloat)
+ val_rtrn->ival /= XkbGeomPtsPerMM;
+ return True;
+ case ExprIdent:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ None, expr->value.str, TypeInt, val_rtrn);
+ }
+ if (!ok)
+ ERROR1("Identifier \"%s\" of type int is unknown\n",
+ XkbAtomText(NULL, expr->value.str, XkbMessage));
+ return ok;
+ case ExprFieldRef:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ expr->value.field.element,
+ expr->value.field.field, TypeInt, val_rtrn);
+ }
+ if (!ok)
+ ERROR2("Default \"%s.%s\" of type int is unknown\n",
+ XkbAtomText(NULL, expr->value.field.element, XkbMessage),
+ XkbAtomText(NULL, expr->value.field.field, XkbMessage));
+ return ok;
+ case OpAdd:
+ case OpSubtract:
+ case OpMultiply:
+ case OpDivide:
+ left = expr->value.binary.left;
+ right = expr->value.binary.right;
+ if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv) &&
+ ExprResolveInteger(right, &rightRtrn, lookup, lookupPriv))
+ {
+ switch (expr->op)
+ {
+ case OpAdd:
+ val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
+ break;
+ case OpSubtract:
+ val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
+ break;
+ case OpMultiply:
+ val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
+ break;
+ case OpDivide:
+ val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
+ break;
+ }
+ return True;
+ }
+ return False;
+ case OpAssign:
+ WSGO("Assignment operator not implemented yet\n");
+ break;
+ case OpNot:
+ left = expr->value.child;
+ if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
+ {
+ ERROR("The ! operator cannot be applied to an integer\n");
+ }
+ return False;
+ case OpInvert:
+ case OpNegate:
+ left = expr->value.child;
+ if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
+ {
+ if (expr->op == OpNegate)
+ val_rtrn->ival = -leftRtrn.ival;
+ else
+ val_rtrn->ival = ~leftRtrn.ival;
+ return True;
+ }
+ return False;
+ case OpUnaryPlus:
+ left = expr->value.child;
+ return ExprResolveInteger(left, val_rtrn, lookup, lookupPriv);
+ default:
+ WSGO1("Unknown operator %d in ResolveInteger\n", expr->op);
+ break;
+ }
+ return False;
+}
+
+int
+ExprResolveString(ExprDef * expr,
+ ExprResult * val_rtrn,
+ IdentLookupFunc lookup, XPointer lookupPriv)
+{
+ int ok = 0;
+ ExprResult leftRtrn, rightRtrn;
+ ExprDef *left;
+ ExprDef *right;
+ char *bogus = NULL;
+
+ switch (expr->op)
+ {
+ case ExprValue:
+ if (expr->type != TypeString)
+ {
+ ERROR1("Found constant of type %s, expected a string\n",
+ exprTypeText(expr->type));
+ return False;
+ }
+ val_rtrn->str = XkbAtomGetString(NULL, expr->value.str);
+ if (val_rtrn->str == NULL)
+ {
+ static char *empty = "";
+ val_rtrn->str = empty;
+ }
+ return True;
+ case ExprIdent:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ None, expr->value.str, TypeString, val_rtrn);
+ }
+ if (!ok)
+ ERROR1("Identifier \"%s\" of type string not found\n",
+ XkbAtomText(NULL, expr->value.str, XkbMessage));
+ return ok;
+ case ExprFieldRef:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ expr->value.field.element,
+ expr->value.field.field, TypeString, val_rtrn);
+ }
+ if (!ok)
+ ERROR2("Default \"%s.%s\" of type string not found\n",
+ XkbAtomText(NULL, expr->value.field.element, XkbMessage),
+ XkbAtomText(NULL, expr->value.field.field, XkbMessage));
+ return ok;
+ case OpAdd:
+ left = expr->value.binary.left;
+ right = expr->value.binary.right;
+ if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv) &&
+ ExprResolveString(right, &rightRtrn, lookup, lookupPriv))
+ {
+ int len;
+ char *new;
+ len = strlen(leftRtrn.str) + strlen(rightRtrn.str) + 1;
+ new = (char *) uAlloc(len);
+ if (new)
+ {
+ sprintf(new, "%s%s", leftRtrn.str, rightRtrn.str);
+ val_rtrn->str = new;
+ return True;
+ }
+ }
+ return False;
+ case OpSubtract:
+ if (bogus == NULL)
+ bogus = "Subtraction";
+ case OpMultiply:
+ if (bogus == NULL)
+ bogus = "Multiplication";
+ case OpDivide:
+ if (bogus == NULL)
+ bogus = "Division";
+ case OpAssign:
+ if (bogus == NULL)
+ bogus = "Assignment";
+ case OpNegate:
+ if (bogus == NULL)
+ bogus = "Negation";
+ case OpInvert:
+ if (bogus == NULL)
+ bogus = "Bitwise complement";
+ ERROR1("%s of string values not permitted\n", bogus);
+ return False;
+ case OpNot:
+ left = expr->value.child;
+ if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
+ {
+ ERROR("The ! operator cannot be applied to a string\n");
+ }
+ return False;
+ case OpUnaryPlus:
+ left = expr->value.child;
+ if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
+ {
+ ERROR("The + operator cannot be applied to a string\n");
+ }
+ return False;
+ default:
+ WSGO1("Unknown operator %d in ResolveString\n", expr->op);
+ break;
+ }
+ return False;
+}
+
+int
+ExprResolveKeyName(ExprDef * expr,
+ ExprResult * val_rtrn,
+ IdentLookupFunc lookup, XPointer lookupPriv)
+{
+ int ok = 0;
+ ExprDef *left;
+ ExprResult leftRtrn;
+ char *bogus = NULL;
+
+ switch (expr->op)
+ {
+ case ExprValue:
+ if (expr->type != TypeKeyName)
+ {
+ ERROR1("Found constant of type %s, expected a key name\n",
+ exprTypeText(expr->type));
+ return False;
+ }
+ memcpy(val_rtrn->keyName.name, expr->value.keyName, XkbKeyNameLength);
+ return True;
+ case ExprIdent:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ None, expr->value.str, TypeString, val_rtrn);
+ }
+ if (!ok)
+ ERROR1("Identifier \"%s\" of type string not found\n",
+ XkbAtomText(NULL, expr->value.str, XkbMessage));
+ return ok;
+ case ExprFieldRef:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ expr->value.field.element,
+ expr->value.field.field, TypeString, val_rtrn);
+ }
+ if (!ok)
+ ERROR2("Default \"%s.%s\" of type key name not found\n",
+ XkbAtomText(NULL, expr->value.field.element, XkbMessage),
+ XkbAtomText(NULL, expr->value.field.field, XkbMessage));
+ return ok;
+ case OpAdd:
+ if (bogus == NULL)
+ bogus = "Addition";
+ case OpSubtract:
+ if (bogus == NULL)
+ bogus = "Subtraction";
+ case OpMultiply:
+ if (bogus == NULL)
+ bogus = "Multiplication";
+ case OpDivide:
+ if (bogus == NULL)
+ bogus = "Division";
+ case OpAssign:
+ if (bogus == NULL)
+ bogus = "Assignment";
+ case OpNegate:
+ if (bogus == NULL)
+ bogus = "Negation";
+ case OpInvert:
+ if (bogus == NULL)
+ bogus = "Bitwise complement";
+ ERROR1("%s of key name values not permitted\n", bogus);
+ return False;
+ case OpNot:
+ left = expr->value.binary.left;
+ if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
+ {
+ ERROR("The ! operator cannot be applied to a key name\n");
+ }
+ return False;
+ case OpUnaryPlus:
+ left = expr->value.binary.left;
+ if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
+ {
+ ERROR("The + operator cannot be applied to a key name\n");
+ }
+ return False;
+ default:
+ WSGO1("Unknown operator %d in ResolveKeyName\n", expr->op);
+ break;
+ }
+ return False;
+}
+
+/***====================================================================***/
+
+int
+ExprResolveEnum(ExprDef * expr, ExprResult * val_rtrn, LookupEntry * values)
+{
+ if (expr->op != ExprIdent)
+ {
+ ERROR1("Found a %s where an enumerated value was expected\n",
+ exprOpText(expr->op));
+ return False;
+ }
+ if (!SimpleLookup((XPointer) values, (Atom) None, expr->value.str,
+ (unsigned) TypeInt, val_rtrn))
+ {
+ int nOut = 0;
+ ERROR1("Illegal identifier %s (expected one of: ",
+ XkbAtomText(NULL, expr->value.str, XkbMessage));
+ while (values && values->name)
+ {
+ if (nOut != 0)
+ INFO1(", %s", values->name);
+ else
+ INFO1("%s", values->name);
+ values++;
+ nOut++;
+ }
+ INFO(")\n");
+ return False;
+ }
+ return True;
+}
+
+int
+ExprResolveMask(ExprDef * expr,
+ ExprResult * val_rtrn,
+ IdentLookupFunc lookup, XPointer lookupPriv)
+{
+ int ok = 0;
+ ExprResult leftRtrn, rightRtrn;
+ ExprDef *left, *right;
+ char *bogus = NULL;
+
+ switch (expr->op)
+ {
+ case ExprValue:
+ if (expr->type != TypeInt)
+ {
+ ERROR1
+ ("Found constant of type %s where a mask was expected\n",
+ exprTypeText(expr->type));
+ return False;
+ }
+ val_rtrn->ival = expr->value.ival;
+ return True;
+ case ExprIdent:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ None, expr->value.str, TypeInt, val_rtrn);
+ }
+ if (!ok)
+ ERROR1("Identifier \"%s\" of type int is unknown\n",
+ XkbAtomText(NULL, expr->value.str, XkbMessage));
+ return ok;
+ case ExprFieldRef:
+ if (lookup)
+ {
+ ok = (*lookup) (lookupPriv,
+ expr->value.field.element,
+ expr->value.field.field, TypeInt, val_rtrn);
+ }
+ if (!ok)
+ ERROR2("Default \"%s.%s\" of type int is unknown\n",
+ XkbAtomText(NULL, expr->value.field.element, XkbMessage),
+ XkbAtomText(NULL, expr->value.field.field, XkbMessage));
+ return ok;
+ case ExprArrayRef:
+ bogus = "array reference";
+ case ExprActionDecl:
+ if (bogus == NULL)
+ bogus = "function use";
+ ERROR1("Unexpected %s in mask expression\n", bogus);
+ ACTION("Expression ignored\n");
+ return False;
+ case OpAdd:
+ case OpSubtract:
+ case OpMultiply:
+ case OpDivide:
+ left = expr->value.binary.left;
+ right = expr->value.binary.right;
+ if (ExprResolveMask(left, &leftRtrn, lookup, lookupPriv) &&
+ ExprResolveMask(right, &rightRtrn, lookup, lookupPriv))
+ {
+ switch (expr->op)
+ {
+ case OpAdd:
+ val_rtrn->ival = leftRtrn.ival | rightRtrn.ival;
+ break;
+ case OpSubtract:
+ val_rtrn->ival = leftRtrn.ival & (~rightRtrn.ival);
+ break;
+ case OpMultiply:
+ case OpDivide:
+ ERROR1("Cannot %s masks\n",
+ expr->op == OpDivide ? "divide" : "multiply");
+ ACTION("Illegal operation ignored\n");
+ return False;
+ }
+ return True;
+ }
+ return False;
+ case OpAssign:
+ WSGO("Assignment operator not implemented yet\n");
+ break;
+ case OpInvert:
+ left = expr->value.child;
+ if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
+ {
+ val_rtrn->ival = ~leftRtrn.ival;
+ return True;
+ }
+ return False;
+ case OpUnaryPlus:
+ case OpNegate:
+ case OpNot:
+ left = expr->value.child;
+ if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
+ {
+ ERROR1("The %s operator cannot be used with a mask\n",
+ (expr->op == OpNegate ? "-" : "!"));
+ }
+ return False;
+ default:
+ WSGO1("Unknown operator %d in ResolveMask\n", expr->op);
+ break;
+ }
+ return False;
+}
+
+int
+ExprResolveKeySym(ExprDef * expr,
+ ExprResult * val_rtrn,
+ IdentLookupFunc lookup, XPointer lookupPriv)
+{
+ int ok = 0;
+ KeySym sym;
+
+ if (expr->op == ExprIdent)
+ {
+ char *str;
+ str = XkbAtomGetString(NULL, expr->value.str);
+ if ((str != NULL) && ((sym = XStringToKeysym(str)) != NoSymbol))
+ {
+ val_rtrn->uval = sym;
+ return True;
+ }
+ }
+ ok = ExprResolveInteger(expr, val_rtrn, lookup, lookupPriv);
+ if ((ok) && (val_rtrn->uval < 10))
+ val_rtrn->uval += '0';
+ return ok;
+}
diff --git a/src/xkbcomp/expr.h b/src/xkbcomp/expr.h
new file mode 100644
index 0000000..02519f9
--- /dev/null
+++ b/src/xkbcomp/expr.h
@@ -0,0 +1,172 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifndef EXPR_H
+#define EXPR_H 1
+
+typedef union _ExprResult
+{
+ char *str;
+ int ival;
+ unsigned uval;
+ XkbKeyNameRec keyName;
+} ExprResult;
+
+typedef Bool(*IdentLookupFunc) (XPointer /* priv */ ,
+ Atom /* elem */ ,
+ Atom /* field */ ,
+ unsigned /* type */ ,
+ ExprResult * /* val_rtrn */
+ );
+
+extern char *exprTypeText(unsigned /* type */
+ );
+
+extern int ExprResolveLhs(ExprDef * /* expr */ ,
+ ExprResult * /* elem_rtrn */ ,
+ ExprResult * /* field_rtrn */ ,
+ ExprDef ** /* index_rtrn */
+ );
+
+typedef struct _LookupPriv
+{
+ XPointer priv;
+ IdentLookupFunc chain;
+ XPointer chainPriv;
+} LookupPriv;
+
+typedef struct _LookupEntry
+{
+ const char *name;
+ unsigned result;
+} LookupEntry;
+
+typedef struct _LookupTable
+{
+ char *element;
+ LookupEntry *entries;
+ struct _LookupTable *nextElement;
+} LookupTable;
+
+
+extern char *exprOpText(unsigned /* type */
+ );
+
+extern int RadioLookup(XPointer /* priv */ ,
+ Atom /* elem */ ,
+ Atom /* field */ ,
+ unsigned /* type */ ,
+ ExprResult * /* val_rtrn */
+ );
+
+extern int SimpleLookup(XPointer /* priv */ ,
+ Atom /* elem */ ,
+ Atom /* field */ ,
+ unsigned /* type */ ,
+ ExprResult * /* val_rtrn */
+ );
+
+extern int TableLookup(XPointer /* priv */ ,
+ Atom /* elem */ ,
+ Atom /* field */ ,
+ unsigned /* type */ ,
+ ExprResult * /* val_rtrn */
+ );
+
+extern int LookupModIndex(XPointer /* priv */ ,
+ Atom /* elem */ ,
+ Atom /* field */ ,
+ unsigned /* type */ ,
+ ExprResult * /* val_rtrn */
+ );
+
+extern int LookupModMask(XPointer /* priv */ ,
+ Atom /* elem */ ,
+ Atom /* field */ ,
+ unsigned /* type */ ,
+ ExprResult * /* val_rtrn */
+ );
+
+extern int ExprResolveModIndex(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ IdentLookupFunc /* lookup */ ,
+ XPointer /* lookupPriv */
+ );
+
+extern int ExprResolveModMask(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ IdentLookupFunc /* lookup */ ,
+ XPointer /* priv */
+ );
+
+extern int ExprResolveBoolean(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ IdentLookupFunc /* lookup */ ,
+ XPointer /* lookupPriv */
+ );
+
+extern int ExprResolveInteger(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ IdentLookupFunc /* lookup */ ,
+ XPointer /* lookupPriv */
+ );
+
+extern int ExprResolveFloat(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ IdentLookupFunc /* lookup */ ,
+ XPointer /* lookupPriv */
+ );
+
+extern int ExprResolveString(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ IdentLookupFunc /* lookup */ ,
+ XPointer /* lookupPriv */
+ );
+
+extern int ExprResolveKeyName(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ IdentLookupFunc /* lookup */ ,
+ XPointer /* lookupPriv */
+ );
+
+extern int ExprResolveEnum(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ LookupEntry * /* values */
+ );
+
+extern int ExprResolveMask(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ IdentLookupFunc /* lookup */ ,
+ XPointer /* lookupPriv */
+ );
+
+extern int ExprResolveKeySym(ExprDef * /* expr */ ,
+ ExprResult * /* val_rtrn */ ,
+ IdentLookupFunc /* lookup */ ,
+ XPointer /* lookupPriv */
+ );
+
+#endif /* EXPR_H */
diff --git a/src/xkbcomp/geometry.c b/src/xkbcomp/geometry.c
new file mode 100644
index 0000000..6eb3fb8
--- /dev/null
+++ b/src/xkbcomp/geometry.c
@@ -0,0 +1,3768 @@
+/************************************************************
+ Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
+
+ Permission to use, copy, modify, and distribute this
+ software and its documentation for any purpose and without
+ fee is hereby granted, provided that the above copyright
+ notice appear in all copies and that both that copyright
+ notice and this permission notice appear in supporting
+ documentation, and that the name of Silicon Graphics not be
+ used in advertising or publicity pertaining to distribution
+ of the software without specific prior written permission.
+ Silicon Graphics makes no representation about the suitability
+ of this software for any purpose. It is provided "as is"
+ without any express or implied warranty.
+
+ SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
+ THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ********************************************************/
+
+#include "xkbcomp.h"
+#include "tokens.h"
+#include "expr.h"
+#include "vmod.h"
+#include "misc.h"
+#include "indicators.h"
+#include "action.h"
+#include "keycodes.h"
+#include "alias.h"
+
+#include "X11/extensions/XKBgeom.h"
+
+#define DFLT_FONT "helvetica"
+#define DFLT_SLANT "r"
+#define DFLT_WEIGHT "medium"
+#define DFLT_SET_WIDTH "normal"
+#define DFLT_VARIANT ""
+#define DFLT_ENCODING "iso8859-1"
+#define DFLT_SIZE 120
+
+typedef struct _PropertyInfo
+{
+ CommonInfo defs;
+ char *name;
+ char *value;
+} PropertyInfo;
+
+#define _GSh_Outlines (1<<1)
+#define _GSh_Approx (1<<2)
+#define _GSh_Primary (1<<3)
+typedef struct _ShapeInfo
+{
+ CommonInfo defs;
+ Atom name;
+ short index;
+ unsigned short nOutlines;
+ unsigned short szOutlines;
+ XkbOutlinePtr outlines;
+ XkbOutlinePtr approx;
+ XkbOutlinePtr primary;
+ int dfltCornerRadius;
+} ShapeInfo;
+
+#define shText(d,s) \
+ ((s)?XkbAtomText((d),(s)->name,XkbMessage):"default shape")
+
+#define _GD_Priority (1<<0)
+#define _GD_Top (1<<1)
+#define _GD_Left (1<<2)
+#define _GD_Angle (1<<3)
+#define _GD_Shape (1<<4)
+#define _GD_FontVariant (1<<4) /* CHEATING */
+#define _GD_Corner (1<<5)
+#define _GD_Width (1<<5) /* CHEATING */
+#define _GD_Color (1<<6)
+#define _GD_OffColor (1<<7)
+#define _GD_Height (1<<7) /* CHEATING */
+#define _GD_Text (1<<8)
+#define _GD_Font (1<<9)
+#define _GD_FontSlant (1<<10)
+#define _GD_FontWeight (1<<11)
+#define _GD_FontSetWidth (1<<12)
+#define _GD_FontSize (1<<13)
+#define _GD_FontEncoding (1<<14)
+#define _GD_FontSpec (1<<15)
+
+
+#define _GD_FontParts (_GD_Font|_GD_FontSlant|_GD_FontWeight|_GD_FontSetWidth|_GD_FontSize|_GD_FontEncoding|_GD_FontVariant)
+
+typedef struct _DoodadInfo
+{
+ CommonInfo defs;
+ Atom name;
+ unsigned char type;
+ unsigned char priority;
+ short top;
+ short left;
+ short angle;
+ unsigned short corner;
+ unsigned short width;
+ unsigned short height;
+ Atom shape;
+ Atom color;
+ Atom offColor;
+ Atom text;
+ Atom font;
+ Atom fontSlant;
+ Atom fontWeight;
+ Atom fontSetWidth;
+ Atom fontVariant;
+ unsigned short fontSize;
+ Atom fontEncoding;
+ Atom fontSpec;
+ char *logoName;
+ struct _SectionInfo *section;
+} DoodadInfo;
+
+#define Yes 1
+#define No 0
+#define Undefined -1
+
+#define _GK_Default (1<<0)
+#define _GK_Name (1<<1)
+#define _GK_Gap (1<<2)
+#define _GK_Shape (1<<3)
+#define _GK_Color (1<<4)
+typedef struct _KeyInfo
+{
+ CommonInfo defs;
+ char name[8];
+ short gap;
+ short index;
+ Atom shape;
+ Atom color;
+ struct _RowInfo *row;
+} KeyInfo;
+#define keyText(k) ((k)&&(k)->name[0]?(k)->name:"default")
+
+#define _GR_Default (1<<0)
+#define _GR_Vertical (1<<1)
+#define _GR_Top (1<<2)
+#define _GR_Left (1<<3)
+typedef struct _RowInfo
+{
+ CommonInfo defs;
+ unsigned short top;
+ unsigned short left;
+ short index;
+ Bool vertical;
+ unsigned short nKeys;
+ KeyInfo *keys;
+ KeyInfo dfltKey;
+ struct _SectionInfo *section;
+} RowInfo;
+#define rowText(d,r) \
+ ((r)?XkbAtomText((d),(r)->section->name,XkbMessage):"default")
+
+#define _GOK_UnknownRow -1
+typedef struct _OverlayKeyInfo
+{
+ CommonInfo defs;
+ short sectionRow;
+ short overlayRow;
+ char over[XkbKeyNameLength + 1];
+ char under[XkbKeyNameLength + 1];
+} OverlayKeyInfo;
+
+typedef struct _OverlayInfo
+{
+ CommonInfo defs;
+ Atom name;
+ unsigned short nRows;
+ unsigned short nKeys;
+ OverlayKeyInfo *keys;
+} OverlayInfo;
+#define oiText(d,o) ((o)?XkbAtomText((d),(o)->name,XkbMessage):"default")
+
+
+#define _GS_Default (1<<0)
+#define _GS_Name (1<<1)
+#define _GS_Top (1<<2)
+#define _GS_Left (1<<3)
+#define _GS_Width (1<<4)
+#define _GS_Height (1<<5)
+#define _GS_Angle (1<<6)
+#define _GS_Priority (1<<7)
+typedef struct _SectionInfo
+{
+ CommonInfo defs;
+ Atom name;
+ unsigned short top;
+ unsigned short left;
+ unsigned short width;
+ unsigned short height;
+ unsigned short angle;
+ unsigned short nRows;
+ unsigned short nDoodads;
+ unsigned short nOverlays;
+ unsigned char priority;
+ unsigned char nextDoodadPriority;
+ RowInfo *rows;
+ DoodadInfo *doodads;
+ RowInfo dfltRow;
+ DoodadInfo *dfltDoodads;
+ OverlayInfo *overlays;
+ struct _GeometryInfo *geometry;
+} SectionInfo;
+#define scText(d,s) ((s)?XkbAtomText((d),(s)->name,XkbMessage):"default")
+
+typedef struct _GeometryInfo
+{
+ char *name;
+ Display *dpy;
+ unsigned fileID;
+ unsigned merge;
+ int errorCount;
+ unsigned nextPriority;
+ int nProps;
+ int nShapes;
+ int nSections;
+ int nDoodads;
+ PropertyInfo *props;
+ ShapeInfo *shapes;
+ SectionInfo *sections;
+ DoodadInfo *doodads;
+ int widthMM;
+ int heightMM;
+ Atom font;
+ Atom fontSlant;
+ Atom fontWeight;
+ Atom fontSetWidth;
+ Atom fontVariant;
+ unsigned fontSize;
+ Atom fontEncoding;
+ Atom fontSpec;
+ Atom baseColor;
+ Atom labelColor;
+ int dfltCornerRadius;
+ SectionInfo dfltSection;
+ DoodadInfo *dfltDoodads;
+ AliasInfo *aliases;
+} GeometryInfo;
+
+static char *
+ddText(Display * dpy, DoodadInfo * di)
+{
+ static char buf[64];
+
+ if (di == NULL)
+ {
+ strcpy(buf, "default");
+ return buf;
+ }
+ if (di->section)
+ {
+ sprintf(buf, "%s in section %s",
+ XkbAtomText(dpy, di->name, XkbMessage), scText(dpy,
+ di->section));
+ return buf;
+ }
+ return XkbAtomText(dpy, di->name, XkbMessage);
+}
+
+/***====================================================================***/
+
+static void
+InitPropertyInfo(PropertyInfo * pi, GeometryInfo * info)
+{
+ pi->defs.defined = 0;
+ pi->defs.fileID = info->fileID;
+ pi->defs.merge = info->merge;
+ pi->name = pi->value = NULL;
+ return;
+}
+
+static void
+FreeProperties(PropertyInfo * pi, GeometryInfo * info)
+{
+ PropertyInfo *tmp;
+ PropertyInfo *next;
+
+ if (info->props == pi)
+ {
+ info->props = NULL;
+ info->nProps = 0;
+ }
+ for (tmp = pi; tmp != NULL; tmp = next)
+ {
+ if (tmp->name)
+ uFree(tmp->name);
+ if (tmp->value)
+ uFree(tmp->value);
+ tmp->name = tmp->value = NULL;
+ next = (PropertyInfo *) tmp->defs.next;
+ uFree(tmp);
+ }
+ return;
+}
+
+static void
+InitKeyInfo(KeyInfo * key, RowInfo * row, GeometryInfo * info)
+{
+
+ if (key != &row->dfltKey)
+ {
+ *key = row->dfltKey;
+ strcpy(key->name, "unknown");
+ key->defs.defined &= ~_GK_Default;
+ }
+ else
+ {
+ bzero(key, sizeof(KeyInfo));
+ strcpy(key->name, "default");
+ key->defs.defined = _GK_Default;
+ key->defs.fileID = info->fileID;
+ key->defs.merge = info->merge;
+ key->defs.next = NULL;
+ key->row = row;
+ }
+ return;
+}
+
+static void
+ClearKeyInfo(KeyInfo * key)
+{
+ key->defs.defined &= ~_GK_Default;
+ strcpy(key->name, "default");
+ key->gap = 0;
+ key->shape = None;
+ key->color = None;
+ return;
+}
+
+static void
+FreeKeys(KeyInfo * key, RowInfo * row, GeometryInfo * info)
+{
+ KeyInfo *tmp;
+ KeyInfo *next;
+
+ if (row->keys == key)
+ {
+ row->nKeys = 0;
+ row->keys = NULL;
+ }
+ for (tmp = key; tmp != NULL; tmp = next)
+ {
+ ClearKeyInfo(tmp);
+ next = (KeyInfo *) tmp->defs.next;
+ uFree(tmp);
+ }
+ return;
+}
+
+static void
+InitRowInfo(RowInfo * row, SectionInfo * section, GeometryInfo * info)
+{
+ if (row != &section->dfltRow)
+ {
+ *row = section->dfltRow;
+ row->defs.defined &= ~_GR_Default;
+ }
+ else
+ {
+ bzero(row, sizeof(RowInfo *));
+ row->defs.defined = _GR_Default;
+ row->defs.fileID = info->fileID;
+ row->defs.merge = info->merge;
+ row->defs.next = NULL;
+ row->section = section;
+ row->nKeys = 0;
+ row->keys = NULL;
+ InitKeyInfo(&row->dfltKey, row, info);
+ }
+ return;
+}
+
+static void
+ClearRowInfo(RowInfo * row, GeometryInfo * info)
+{
+ row->defs.defined &= ~_GR_Default;
+ row->top = row->left = 0;
+ row->vertical = False;
+ row->nKeys = 0;
+ if (row->keys)
+ FreeKeys(row->keys, row, info);
+ ClearKeyInfo(&row->dfltKey);
+ row->dfltKey.defs.defined |= _GK_Default;
+ return;
+}
+
+static void
+FreeRows(RowInfo * row, SectionInfo * section, GeometryInfo * info)
+{
+ RowInfo *next;
+ RowInfo *tmp;
+
+ if (row == section->rows)
+ {
+ section->nRows = 0;
+ section->rows = NULL;
+ }
+ for (tmp = row; tmp != NULL; tmp = next)
+ {
+ ClearRowInfo(tmp, info);
+ next = (RowInfo *) tmp->defs.next;
+ uFree(tmp);
+ }
+ return;
+}
+
+static DoodadInfo *
+FindDoodadByType(DoodadInfo * di, unsigned type)
+{
+ while (di)
+ {
+ if (di->type == type)
+ return di;
+ di = (DoodadInfo *) di->defs.next;
+ }
+ return NULL;
+}
+
+static DoodadInfo *
+FindDoodadByName(DoodadInfo * di, Atom name)
+{
+ while (di)
+ {
+ if (di->name == name)
+ return di;
+ di = (DoodadInfo *) di->defs.next;
+ }
+ return NULL;
+}
+
+static void
+InitDoodadInfo(DoodadInfo * di, unsigned type, SectionInfo * si,
+ GeometryInfo * info)
+{
+ DoodadInfo *dflt;
+
+ dflt = NULL;
+ if (si && si->dfltDoodads)
+ dflt = FindDoodadByType(si->dfltDoodads, type);
+ if ((dflt == NULL) && (info->dfltDoodads))
+ dflt = FindDoodadByType(info->dfltDoodads, type);
+ if (dflt != NULL)
+ {
+ *di = *dflt;
+ di->defs.next = NULL;
+ }
+ else
+ {
+ bzero(di, sizeof(DoodadInfo));
+ di->defs.fileID = info->fileID;
+ di->type = type;
+ }
+ di->section = si;
+ if (si != NULL)
+ {
+ di->priority = si->nextDoodadPriority++;
+#if XkbGeomMaxPriority < 255
+ if (si->nextDoodadPriority > XkbGeomMaxPriority)
+ si->nextDoodadPriority = XkbGeomMaxPriority;
+#endif
+ }
+ else
+ {
+ di->priority = info->nextPriority++;
+ if (info->nextPriority > XkbGeomMaxPriority)
+ info->nextPriority = XkbGeomMaxPriority;
+ }
+ return;
+}
+
+static void
+ClearDoodadInfo(DoodadInfo * di)
+{
+ CommonInfo defs;
+
+ defs = di->defs;
+ bzero(di, sizeof(DoodadInfo));
+ di->defs = defs;
+ di->defs.defined = 0;
+ return;
+}
+
+static void
+ClearOverlayInfo(OverlayInfo * ol)
+{
+ if (ol && ol->keys)
+ {
+ ol->keys = (OverlayKeyInfo *) ClearCommonInfo(&ol->keys->defs);
+ ol->nKeys = 0;
+ }
+ return;
+}
+
+static void
+FreeDoodads(DoodadInfo * di, SectionInfo * si, GeometryInfo * info)
+{
+ DoodadInfo *tmp;
+ DoodadInfo *next;
+
+ if (si)
+ {
+ if (si->doodads == di)
+ {
+ si->doodads = NULL;
+ si->nDoodads = 0;
+ }
+ if (si->dfltDoodads == di)
+ si->dfltDoodads = NULL;
+ }
+ if (info->doodads == di)
+ {
+ info->doodads = NULL;
+ info->nDoodads = 0;
+ }
+ if (info->dfltDoodads == di)
+ info->dfltDoodads = NULL;
+ for (tmp = di; tmp != NULL; tmp = next)
+ {
+ next = (DoodadInfo *) tmp->defs.next;
+ ClearDoodadInfo(tmp);
+ uFree(tmp);
+ }
+ return;
+}
+
+static void
+InitSectionInfo(SectionInfo * si, GeometryInfo * info)
+{
+ if (si != &info->dfltSection)
+ {
+ *si = info->dfltSection;
+ si->defs.defined &= ~_GS_Default;
+ si->name = XkbInternAtom(info->dpy, "unknown", False);
+ si->priority = info->nextPriority++;
+ if (info->nextPriority > XkbGeomMaxPriority)
+ info->nextPriority = XkbGeomMaxPriority;
+ }
+ else
+ {
+ bzero(si, sizeof(SectionInfo));
+ si->defs.fileID = info->fileID;
+ si->defs.merge = info->merge;
+ si->defs.next = NULL;
+ si->geometry = info;
+ si->name = XkbInternAtom(info->dpy, "default", False);
+ InitRowInfo(&si->dfltRow, si, info);
+ }
+ return;
+}
+
+static void
+DupSectionInfo(SectionInfo * into, SectionInfo * from, GeometryInfo * info)
+{
+ CommonInfo defs;
+
+ defs = into->defs;
+ *into = *from;
+ into->defs.fileID = defs.fileID;
+ into->defs.merge = defs.merge;
+ into->defs.next = NULL;
+ into->dfltRow.defs.fileID = defs.fileID;
+ into->dfltRow.defs.merge = defs.merge;
+ into->dfltRow.defs.next = NULL;
+ into->dfltRow.section = into;
+ into->dfltRow.dfltKey.defs.fileID = defs.fileID;
+ into->dfltRow.dfltKey.defs.merge = defs.merge;
+ into->dfltRow.dfltKey.defs.next = NULL;
+ into->dfltRow.dfltKey.row = &into->dfltRow;
+ return;
+}
+
+static void
+ClearSectionInfo(SectionInfo * si, GeometryInfo * info)
+{
+
+ si->defs.defined &= ~_GS_Default;
+ si->name = XkbInternAtom(info->dpy, "default", False);
+ si->top = si->left = 0;
+ si->width = si->height = 0;
+ si->angle = 0;
+ if (si->rows)
+ {
+ FreeRows(si->rows, si, info);
+ si->rows = NULL;
+ }
+ ClearRowInfo(&si->dfltRow, info);
+ if (si->doodads)
+ {
+ FreeDoodads(si->doodads, si, info);
+ si->doodads = NULL;
+ }
+ si->dfltRow.defs.defined = _GR_Default;
+ return;
+}
+
+static void
+FreeSections(SectionInfo * si, GeometryInfo * info)
+{
+ SectionInfo *tmp;
+ SectionInfo *next;
+
+ if (si == info->sections)
+ {
+ info->nSections = 0;
+ info->sections = NULL;
+ }
+ for (tmp = si; tmp != NULL; tmp = next)
+ {
+ ClearSectionInfo(tmp, info);
+ next = (SectionInfo *) tmp->defs.next;
+ uFree(tmp);
+ }
+ return;
+}
+
+static void
+FreeShapes(ShapeInfo * si, GeometryInfo * info)
+{
+ ShapeInfo *tmp;
+ ShapeInfo *next;
+
+ if (si == info->shapes)
+ {
+ info->nShapes = 0;
+ info->shapes = NULL;
+ }
+ for (tmp = si; tmp != NULL; tmp = next)
+ {
+ if (tmp->outlines)
+ {
+ register int i;
+ for (i = 0; i < tmp->nOutlines; i++)
+ {
+ if (tmp->outlines[i].points != NULL)
+ {
+ uFree(tmp->outlines[i].points);
+ tmp->outlines[i].num_points = 0;
+ tmp->outlines[i].points = NULL;
+ }
+ }
+ uFree(tmp->outlines);
+ tmp->szOutlines = 0;
+ tmp->nOutlines = 0;
+ tmp->outlines = NULL;
+ tmp->primary = tmp->approx = NULL;
+ }
+ next = (ShapeInfo *) tmp->defs.next;
+ uFree(tmp);
+ }
+ return;
+}
+
+/***====================================================================***/
+
+static void
+InitGeometryInfo(GeometryInfo * info, unsigned fileID, unsigned merge)
+{
+ bzero(info, sizeof(GeometryInfo));
+ info->fileID = fileID;
+ info->merge = merge;
+ InitSectionInfo(&info->dfltSection, info);
+ info->dfltSection.defs.defined = _GS_Default;
+ return;
+}
+
+static void
+ClearGeometryInfo(GeometryInfo * info)
+{
+ if (info->name)
+ uFree(info->name);
+ info->name = NULL;
+ if (info->props)
+ FreeProperties(info->props, info);
+ if (info->shapes)
+ FreeShapes(info->shapes, info);
+ if (info->sections)
+ FreeSections(info->sections, info);
+ info->widthMM = 0;
+ info->heightMM = 0;
+ info->dfltCornerRadius = 0;
+ ClearSectionInfo(&info->dfltSection, info);
+ info->dfltSection.defs.defined = _GS_Default;
+ if (info->aliases)
+ ClearAliases(&info->aliases);
+ return;
+}
+
+/***====================================================================***/
+
+static PropertyInfo *
+NextProperty(GeometryInfo * info)
+{
+ PropertyInfo *pi;
+
+ pi = uTypedAlloc(PropertyInfo);
+ if (pi)
+ {
+ bzero((char *) pi, sizeof(PropertyInfo));
+ info->props = (PropertyInfo *) AddCommonInfo(&info->props->defs,
+ (CommonInfo *) pi);
+ info->nProps++;
+ }
+ return pi;
+}
+
+static PropertyInfo *
+FindProperty(GeometryInfo * info, char *name)
+{
+ PropertyInfo *old;
+
+ if (!name)
+ return NULL;
+ for (old = info->props; old != NULL;
+ old = (PropertyInfo *) old->defs.next)
+ {
+ if ((old->name) && (uStringEqual(name, old->name)))
+ return old;
+ }
+ return NULL;
+}
+
+static Bool
+AddProperty(GeometryInfo * info, PropertyInfo * new)
+{
+ PropertyInfo *old;
+
+ if ((!new) || (!new->value) || (!new->name))
+ return False;
+ old = FindProperty(info, new->name);
+ if (old != NULL)
+ {
+ if ((new->defs.merge == MergeReplace)
+ || (new->defs.merge == MergeOverride))
+ {
+ if (((old->defs.fileID == new->defs.fileID)
+ && (warningLevel > 0)) || (warningLevel > 9))
+ {
+ WARN1("Multiple definitions for the \"%s\" property\n",
+ new->name);
+ ACTION2("Ignoring \"%s\", using \"%s\"\n", old->value,
+ new->value);
+ }
+ if (old->value)
+ uFree(old->value);
+ old->value = uStringDup(new->value);
+ return True;
+ }
+ if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN1("Multiple definitions for \"%s\" property\n", new->name);
+ ACTION2("Using \"%s\", ignoring \"%s\" \n", old->value,
+ new->value);
+ }
+ return True;
+ }
+ old = new;
+ if ((new = NextProperty(info)) == NULL)
+ return False;
+ new->defs.next = NULL;
+ new->name = uStringDup(old->name);
+ new->value = uStringDup(old->value);
+ return True;
+}
+
+/***====================================================================***/
+
+static ShapeInfo *
+NextShape(GeometryInfo * info)
+{
+ ShapeInfo *si;
+
+ si = uTypedAlloc(ShapeInfo);
+ if (si)
+ {
+ bzero((char *) si, sizeof(ShapeInfo));
+ info->shapes = (ShapeInfo *) AddCommonInfo(&info->shapes->defs,
+ (CommonInfo *) si);
+ info->nShapes++;
+ si->dfltCornerRadius = info->dfltCornerRadius;
+ }
+ return si;
+}
+
+static ShapeInfo *
+FindShape(GeometryInfo * info, Atom name, const char *type, const char *which)
+{
+ ShapeInfo *old;
+
+ for (old = info->shapes; old != NULL; old = (ShapeInfo *) old->defs.next)
+ {
+ if (name == old->name)
+ return old;
+ }
+ if (type != NULL)
+ {
+ old = info->shapes;
+ WARN3("Unknown shape \"%s\" for %s %s\n",
+ XkbAtomText(info->dpy, name, XkbMessage), type, which);
+ if (old)
+ {
+ ACTION1("Using default shape %s instead\n",
+ shText(info->dpy, old));
+ return old;
+ }
+ ACTION("No default shape; definition ignored\n");
+ return NULL;
+ }
+ return NULL;
+}
+
+static Bool
+AddShape(GeometryInfo * info, ShapeInfo * new)
+{
+ ShapeInfo *old;
+
+ old = FindShape(info, new->name, NULL, NULL);
+ if (old != NULL)
+ {
+ if ((new->defs.merge == MergeReplace)
+ || (new->defs.merge == MergeOverride))
+ {
+ ShapeInfo *next = (ShapeInfo *) old->defs.next;
+ if (((old->defs.fileID == new->defs.fileID)
+ && (warningLevel > 0)) || (warningLevel > 9))
+ {
+ WARN1("Duplicate shape name \"%s\"\n",
+ shText(info->dpy, old));
+ ACTION("Using last definition\n");
+ }
+ *old = *new;
+ old->defs.next = &next->defs;
+ return True;
+ }
+ if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN1("Multiple shapes named \"%s\"\n", shText(info->dpy, old));
+ ACTION("Using first definition\n");
+ }
+ return True;
+ }
+ old = new;
+ if ((new = NextShape(info)) == NULL)
+ return False;
+ *new = *old;
+ new->defs.next = NULL;
+ old->szOutlines = old->nOutlines = 0;
+ old->outlines = NULL;
+ old->approx = NULL;
+ old->primary = NULL;
+ return True;
+}
+
+/***====================================================================***/
+
+static void
+ReplaceDoodad(DoodadInfo * into, DoodadInfo * from)
+{
+ CommonInfo *next;
+
+ next = into->defs.next;
+ ClearDoodadInfo(into);
+ *into = *from;
+ into->defs.next = next;
+ next = from->defs.next;
+ ClearDoodadInfo(from);
+ from->defs.next = next;
+ return;
+}
+
+static DoodadInfo *
+NextDfltDoodad(SectionInfo * si, GeometryInfo * info)
+{
+ DoodadInfo *di;
+
+ di = uTypedCalloc(1, DoodadInfo);
+ if (!di)
+ return NULL;
+ if (si)
+ {
+ si->dfltDoodads =
+ (DoodadInfo *) AddCommonInfo(&si->dfltDoodads->defs,
+ (CommonInfo *) di);
+ }
+ else
+ {
+ info->dfltDoodads =
+ (DoodadInfo *) AddCommonInfo(&info->dfltDoodads->defs,
+ (CommonInfo *) di);
+ }
+ return di;
+}
+
+static DoodadInfo *
+NextDoodad(SectionInfo * si, GeometryInfo * info)
+{
+ DoodadInfo *di;
+
+ di = uTypedCalloc(1, DoodadInfo);
+ if (di)
+ {
+ if (si)
+ {
+ si->doodads = (DoodadInfo *) AddCommonInfo(&si->doodads->defs,
+ (CommonInfo *) di);
+ si->nDoodads++;
+ }
+ else
+ {
+ info->doodads =
+ (DoodadInfo *) AddCommonInfo(&info->doodads->defs,
+ (CommonInfo *) di);
+ info->nDoodads++;
+ }
+ }
+ return di;
+}
+
+static Bool
+AddDoodad(SectionInfo * si, GeometryInfo * info, DoodadInfo * new)
+{
+ DoodadInfo *old;
+
+ old = FindDoodadByName((si ? si->doodads : info->doodads), new->name);
+ if (old != NULL)
+ {
+ if ((new->defs.merge == MergeReplace)
+ || (new->defs.merge == MergeOverride))
+ {
+ if (((old->defs.fileID == new->defs.fileID)
+ && (warningLevel > 0)) || (warningLevel > 9))
+ {
+ WARN1("Multiple doodads named \"%s\"\n",
+ XkbAtomText(info->dpy, old->name, XkbMessage));
+ ACTION("Using last definition\n");
+ }
+ ReplaceDoodad(old, new);
+ old->section = si;
+ return True;
+ }
+ if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN1("Multiple doodads named \"%s\"\n",
+ XkbAtomText(info->dpy, old->name, XkbMessage));
+ ACTION("Using first definition\n");
+ }
+ return True;
+ }
+ old = new;
+ if ((new = NextDoodad(si, info)) == NULL)
+ return False;
+ ReplaceDoodad(new, old);
+ new->section = si;
+ new->defs.next = NULL;
+ return True;
+}
+
+static DoodadInfo *
+FindDfltDoodadByTypeName(char *name, SectionInfo * si, GeometryInfo * info)
+{
+ DoodadInfo *dflt;
+ unsigned type;
+
+ if (uStrCaseCmp(name, "outline") == 0)
+ type = XkbOutlineDoodad;
+ else if (uStrCaseCmp(name, "solid") == 0)
+ type = XkbSolidDoodad;
+ else if (uStrCaseCmp(name, "text") == 0)
+ type = XkbTextDoodad;
+ else if (uStrCaseCmp(name, "indicator") == 0)
+ type = XkbIndicatorDoodad;
+ else if (uStrCaseCmp(name, "logo") == 0)
+ type = XkbLogoDoodad;
+ else
+ return NULL;
+ if ((si) && (si->dfltDoodads))
+ dflt = FindDoodadByType(si->dfltDoodads, type);
+ else
+ dflt = NULL;
+ if ((!dflt) && (info->dfltDoodads))
+ dflt = FindDoodadByType(info->dfltDoodads, type);
+ if (dflt == NULL)
+ {
+ dflt = NextDfltDoodad(si, info);
+ if (dflt != NULL)
+ {
+ dflt->name = None;
+ dflt->type = type;
+ }
+ }
+ return dflt;
+}
+
+/***====================================================================***/
+
+static Bool
+AddOverlay(SectionInfo * si, GeometryInfo * info, OverlayInfo * new)
+{
+ OverlayInfo *old;
+
+ for (old = si->overlays; old != NULL;
+ old = (OverlayInfo *) old->defs.next)
+ {
+ if (old->name == new->name)
+ break;
+ }
+ if (old != NULL)
+ {
+ if ((new->defs.merge == MergeReplace)
+ || (new->defs.merge == MergeOverride))
+ {
+ if (((old->defs.fileID == new->defs.fileID)
+ && (warningLevel > 0)) || (warningLevel > 9))
+ {
+ WARN2
+ ("Multiple overlays named \"%s\" for section \"%s\"\n",
+ XkbAtomText(info->dpy, old->name, XkbMessage),
+ XkbAtomText(info->dpy, si->name, XkbMessage));
+ ACTION("Using last definition\n");
+ }
+ ClearOverlayInfo(old);
+ old->nKeys = new->nKeys;
+ old->keys = new->keys;
+ new->nKeys = 0;
+ new->keys = NULL;
+ return True;
+ }
+ if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN2("Multiple doodads named \"%s\" in section \"%s\"\n",
+ XkbAtomText(info->dpy, old->name, XkbMessage),
+ XkbAtomText(info->dpy, si->name, XkbMessage));
+ ACTION("Using first definition\n");
+ }
+ return True;
+ }
+ old = new;
+ new = uTypedCalloc(1, OverlayInfo);
+ if (!new)
+ {
+ if (warningLevel > 0)
+ {
+ WSGO("Couldn't allocate a new OverlayInfo\n");
+ ACTION2
+ ("Overlay \"%s\" in section \"%s\" will be incomplete\n",
+ XkbAtomText(info->dpy, old->name, XkbMessage),
+ XkbAtomText(info->dpy, si->name, XkbMessage));
+ }
+ return False;
+ }
+ *new = *old;
+ old->nKeys = 0;
+ old->keys = NULL;
+ si->overlays = (OverlayInfo *) AddCommonInfo(&si->overlays->defs,
+ (CommonInfo *) new);
+ si->nOverlays++;
+ return True;
+}
+
+/***====================================================================***/
+
+static SectionInfo *
+NextSection(GeometryInfo * info)
+{
+ SectionInfo *si;
+
+ si = uTypedAlloc(SectionInfo);
+ if (si)
+ {
+ *si = info->dfltSection;
+ si->defs.defined &= ~_GS_Default;
+ si->defs.next = NULL;
+ si->nRows = 0;
+ si->rows = NULL;
+ info->sections =
+ (SectionInfo *) AddCommonInfo(&info->sections->defs,
+ (CommonInfo *) si);
+ info->nSections++;
+ }
+ return si;
+}
+
+static SectionInfo *
+FindMatchingSection(GeometryInfo * info, SectionInfo * new)
+{
+ SectionInfo *old;
+
+ for (old = info->sections; old != NULL;
+ old = (SectionInfo *) old->defs.next)
+ {
+ if (new->name == old->name)
+ return old;
+ }
+ return NULL;
+}
+
+static Bool
+AddSection(GeometryInfo * info, SectionInfo * new)
+{
+ SectionInfo *old;
+
+ old = FindMatchingSection(info, new);
+ if (old != NULL)
+ {
+#ifdef NOTDEF
+ if ((new->defs.merge == MergeReplace)
+ || (new->defs.merge == MergeOverride))
+ {
+ SectionInfo *next = (SectionInfo *) old->defs.next;
+ if (((old->defs.fileID == new->defs.fileID)
+ && (warningLevel > 0)) || (warningLevel > 9))
+ {
+ WARN1("Duplicate shape name \"%s\"\n",
+ shText(info->dpy, old));
+ ACTION("Using last definition\n");
+ }
+ *old = *new;
+ old->defs.next = &next->defs;
+ return True;
+ }
+ if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN1("Multiple shapes named \"%s\"\n", shText(info->dpy, old));
+ ACTION("Using first definition\n");
+ }
+ return True;
+#else
+ WARN("Don't know how to merge sections yet\n");
+#endif
+ }
+ old = new;
+ if ((new = NextSection(info)) == NULL)
+ return False;
+ *new = *old;
+ new->defs.next = NULL;
+ old->nRows = old->nDoodads = old->nOverlays = 0;
+ old->rows = NULL;
+ old->doodads = NULL;
+ old->overlays = NULL;
+ if (new->doodads)
+ {
+ DoodadInfo *di;
+ for (di = new->doodads; di; di = (DoodadInfo *) di->defs.next)
+ {
+ di->section = new;
+ }
+ }
+ return True;
+}
+
+/***====================================================================***/
+
+static RowInfo *
+NextRow(SectionInfo * si)
+{
+ RowInfo *row;
+
+ row = uTypedAlloc(RowInfo);
+ if (row)
+ {
+ *row = si->dfltRow;
+ row->defs.defined &= ~_GR_Default;
+ row->defs.next = NULL;
+ row->nKeys = 0;
+ row->keys = NULL;
+ si->rows =
+ (RowInfo *) AddCommonInfo(&si->rows->defs, (CommonInfo *) row);
+ row->index = si->nRows++;
+ }
+ return row;
+}
+
+static Bool
+AddRow(SectionInfo * si, RowInfo * new)
+{
+ RowInfo *old;
+
+ old = new;
+ if ((new = NextRow(si)) == NULL)
+ return False;
+ *new = *old;
+ new->defs.next = NULL;
+ old->nKeys = 0;
+ old->keys = NULL;
+ return True;
+}
+
+/***====================================================================***/
+
+static KeyInfo *
+NextKey(RowInfo * row)
+{
+ KeyInfo *key;
+
+ key = uTypedAlloc(KeyInfo);
+ if (key)
+ {
+ *key = row->dfltKey;
+ key->defs.defined &= ~_GK_Default;
+ key->defs.next = NULL;
+ key->index = row->nKeys++;
+ }
+ return key;
+}
+
+static Bool
+AddKey(RowInfo * row, KeyInfo * new)
+{
+ KeyInfo *old;
+
+ old = new;
+ if ((new = NextKey(row)) == NULL)
+ return False;
+ *new = *old;
+ new->defs.next = NULL;
+ row->keys =
+ (KeyInfo *) AddCommonInfo(&row->keys->defs, (CommonInfo *) new);
+ return True;
+}
+
+/***====================================================================***/
+
+static void
+MergeIncludedGeometry(GeometryInfo * into, GeometryInfo * from,
+ unsigned merge)
+{
+ Bool clobber;
+
+ if (from->errorCount > 0)
+ {
+ into->errorCount += from->errorCount;
+ return;
+ }
+ clobber = (merge == MergeOverride) || (merge == MergeReplace);
+ if (into->name == NULL)
+ {
+ into->name = from->name;
+ from->name = NULL;
+ }
+ if ((into->widthMM == 0) || ((from->widthMM != 0) && clobber))
+ into->widthMM = from->widthMM;
+ if ((into->heightMM == 0) || ((from->heightMM != 0) && clobber))
+ into->heightMM = from->heightMM;
+ if ((into->font == None) || ((from->font != None) && clobber))
+ into->font = from->font;
+ if ((into->fontSlant == None) || ((from->fontSlant != None) && clobber))
+ into->fontSlant = from->fontSlant;
+ if ((into->fontWeight == None) || ((from->fontWeight != None) && clobber))
+ into->fontWeight = from->fontWeight;
+ if ((into->fontSetWidth == None)
+ || ((from->fontSetWidth != None) && clobber))
+ into->fontSetWidth = from->fontSetWidth;
+ if ((into->fontVariant == None)
+ || ((from->fontVariant != None) && clobber))
+ into->fontVariant = from->fontVariant;
+ if ((into->fontSize == 0) || ((from->fontSize != 0) && clobber))
+ into->fontSize = from->fontSize;
+ if ((into->fontEncoding == None)
+ || ((from->fontEncoding != None) && clobber))
+ into->fontEncoding = from->fontEncoding;
+ if ((into->fontSpec == None) || ((from->fontSpec != None) && clobber))
+ into->fontSpec = from->fontSpec;
+ if ((into->baseColor == None) || ((from->baseColor != None) && clobber))
+ into->baseColor = from->baseColor;
+ if ((into->labelColor == None) || ((from->labelColor != None) && clobber))
+ into->labelColor = from->labelColor;
+ into->nextPriority = from->nextPriority;
+ if (from->props != NULL)
+ {
+ PropertyInfo *pi;
+ for (pi = from->props; pi; pi = (PropertyInfo *) pi->defs.next)
+ {
+ if (!AddProperty(into, pi))
+ into->errorCount++;
+ }
+ }
+ if (from->shapes != NULL)
+ {
+ ShapeInfo *si;
+
+ for (si = from->shapes; si; si = (ShapeInfo *) si->defs.next)
+ {
+ if (!AddShape(into, si))
+ into->errorCount++;
+ }
+ }
+ if (from->sections != NULL)
+ {
+ SectionInfo *si;
+
+ for (si = from->sections; si; si = (SectionInfo *) si->defs.next)
+ {
+ if (!AddSection(into, si))
+ into->errorCount++;
+ }
+ }
+ if (from->doodads != NULL)
+ {
+ DoodadInfo *di;
+
+ for (di = from->doodads; di; di = (DoodadInfo *) di->defs.next)
+ {
+ if (!AddDoodad(NULL, into, di))
+ into->errorCount++;
+ }
+ }
+ if (!MergeAliases(&into->aliases, &from->aliases, merge))
+ into->errorCount++;
+ return;
+}
+
+typedef void (*FileHandler) (XkbFile * /* file */ ,
+ XkbDescPtr /* xkb */ ,
+ unsigned /* merge */ ,
+ GeometryInfo * /* info */
+ );
+
+static Bool
+HandleIncludeGeometry(IncludeStmt * stmt, XkbDescPtr xkb, GeometryInfo * info,
+ FileHandler hndlr)
+{
+ unsigned newMerge;
+ XkbFile *rtrn;
+ GeometryInfo included;
+ Bool haveSelf;
+
+ haveSelf = False;
+ if ((stmt->file == NULL) && (stmt->map == NULL))
+ {
+ haveSelf = True;
+ included = *info;
+ bzero(info, sizeof(GeometryInfo));
+ }
+ else if (ProcessIncludeFile(stmt, XkmGeometryIndex, &rtrn, &newMerge))
+ {
+ InitGeometryInfo(&included, rtrn->id, newMerge);
+ included.nextPriority = info->nextPriority;
+ included.dfltCornerRadius = info->dfltCornerRadius;
+ DupSectionInfo(&included.dfltSection, &info->dfltSection, info);
+ (*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;
+ GeometryInfo next_incl;
+
+ for (next = stmt->next; next != NULL; next = next->next)
+ {
+ if ((next->file == NULL) && (next->map == NULL))
+ {
+ haveSelf = True;
+ MergeIncludedGeometry(&included, info, next->merge);
+ ClearGeometryInfo(info);
+ }
+ else if (ProcessIncludeFile(next, XkmGeometryIndex, &rtrn, &op))
+ {
+ InitGeometryInfo(&next_incl, rtrn->id, op);
+ next_incl.nextPriority = included.nextPriority;
+ next_incl.dfltCornerRadius = included.dfltCornerRadius;
+ DupSectionInfo(&next_incl.dfltSection,
+ &included.dfltSection, &included);
+ (*hndlr) (rtrn, xkb, MergeOverride, &next_incl);
+ MergeIncludedGeometry(&included, &next_incl, op);
+ ClearGeometryInfo(&next_incl);
+ }
+ else
+ {
+ info->errorCount += 10;
+ return False;
+ }
+ }
+ }
+ if (haveSelf)
+ *info = included;
+ else
+ {
+ MergeIncludedGeometry(info, &included, newMerge);
+ ClearGeometryInfo(&included);
+ }
+ return (info->errorCount == 0);
+}
+
+static int
+SetShapeField(ShapeInfo * si,
+ char *field,
+ ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
+{
+ ExprResult tmp;
+
+ if ((uStrCaseCmp(field, "radius") == 0)
+ || (uStrCaseCmp(field, "corner") == 0)
+ || (uStrCaseCmp(field, "cornerradius") == 0))
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("key shape", field, shText(info->dpy, si));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("key shape", field,
+ shText(info->dpy, si), "number");
+ }
+ if (si)
+ si->dfltCornerRadius = tmp.ival;
+ else
+ info->dfltCornerRadius = tmp.ival;
+ return True;
+ }
+ info->errorCount++;
+ return ReportBadField("key shape", field, shText(info->dpy, si));
+}
+
+static int
+SetShapeDoodadField(DoodadInfo * di,
+ char *field,
+ ExprDef * arrayNdx,
+ ExprDef * value, SectionInfo * si, GeometryInfo * info)
+{
+ ExprResult tmp;
+ const char *typeName;
+
+ typeName =
+ (di->type == XkbSolidDoodad ? "solid doodad" : "outline doodad");
+ if ((!uStrCaseCmp(field, "corner"))
+ || (!uStrCaseCmp(field, "cornerradius")))
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray(typeName, field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "number");
+ }
+ di->defs.defined |= _GD_Corner;
+ di->corner = tmp.ival;
+ return True;
+ }
+ else if (uStrCaseCmp(field, "angle") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray(typeName, field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "number");
+ }
+ di->defs.defined |= _GD_Angle;
+ di->angle = tmp.ival;
+ return True;
+ }
+ else if (uStrCaseCmp(field, "shape") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray(typeName, field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveString(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "string");
+ }
+ di->shape = XkbInternAtom(info->dpy, tmp.str, False);
+ di->defs.defined |= _GD_Shape;
+ return True;
+ }
+ return ReportBadField(typeName, field, ddText(info->dpy, di));
+}
+
+#define FIELD_STRING 0
+#define FIELD_SHORT 1
+#define FIELD_USHORT 2
+
+static int
+SetTextDoodadField(DoodadInfo * di,
+ char *field,
+ ExprDef * arrayNdx,
+ ExprDef * value, SectionInfo * si, GeometryInfo * info)
+{
+ ExprResult tmp;
+ unsigned def;
+ unsigned type;
+ char *typeName = "text doodad";
+ union
+ {
+ Atom *str;
+ short *ival;
+ unsigned short *uval;
+ } pField;
+
+ if (uStrCaseCmp(field, "angle") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray(typeName, field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "number");
+ }
+ di->defs.defined |= _GD_Angle;
+ di->angle = tmp.ival;
+ return True;
+ }
+ if (uStrCaseCmp(field, "width") == 0)
+ {
+ type = FIELD_USHORT;
+ pField.uval = &di->width;
+ def = _GD_Width;
+ }
+ else if (uStrCaseCmp(field, "height") == 0)
+ {
+ type = FIELD_USHORT;
+ pField.uval = &di->height;
+ def = _GD_Height;
+ }
+ else if (uStrCaseCmp(field, "text") == 0)
+ {
+ type = FIELD_STRING;
+ pField.str = &di->text;
+ def = _GD_Text;
+ }
+ else if (uStrCaseCmp(field, "font") == 0)
+ {
+ type = FIELD_STRING;
+ pField.str = &di->font;
+ def = _GD_Font;
+ }
+ else if ((uStrCaseCmp(field, "fontslant") == 0) ||
+ (uStrCaseCmp(field, "slant") == 0))
+ {
+ type = FIELD_STRING;
+ pField.str = &di->fontSlant;
+ def = _GD_FontSlant;
+ }
+ else if ((uStrCaseCmp(field, "fontweight") == 0) ||
+ (uStrCaseCmp(field, "weight") == 0))
+ {
+ type = FIELD_STRING;
+ pField.str = &di->fontWeight;
+ def = _GD_FontWeight;
+ }
+ else if ((uStrCaseCmp(field, "fontwidth") == 0) ||
+ (uStrCaseCmp(field, "setwidth") == 0))
+ {
+ type = FIELD_STRING;
+ pField.str = &di->fontSetWidth;
+ def = _GD_FontSetWidth;
+ }
+ else if ((uStrCaseCmp(field, "fontvariant") == 0) ||
+ (uStrCaseCmp(field, "variant") == 0))
+ {
+ type = FIELD_STRING;
+ pField.str = &di->fontVariant;
+ def = _GD_FontVariant;
+ }
+ else if ((uStrCaseCmp(field, "fontencoding") == 0) ||
+ (uStrCaseCmp(field, "encoding") == 0))
+ {
+ type = FIELD_STRING;
+ pField.str = &di->fontEncoding;
+ def = _GD_FontEncoding;
+ }
+ else if ((uStrCaseCmp(field, "xfont") == 0) ||
+ (uStrCaseCmp(field, "xfontname") == 0))
+ {
+ type = FIELD_STRING;
+ pField.str = &di->fontSpec;
+ def = _GD_FontSpec;
+ }
+ else if (uStrCaseCmp(field, "fontsize") == 0)
+ {
+ type = FIELD_USHORT;
+ pField.uval = &di->fontSize;
+ def = _GD_FontSize;
+ }
+ else
+ {
+ return ReportBadField(typeName, field, ddText(info->dpy, di));
+ }
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray(typeName, field, ddText(info->dpy, di));
+ }
+ if (type == FIELD_STRING)
+ {
+ if (!ExprResolveString(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "string");
+ }
+ di->defs.defined |= def;
+ *pField.str = XkbInternAtom(NULL, tmp.str, False);
+ }
+ else
+ {
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "number");
+ }
+ if ((type == FIELD_USHORT) && (tmp.ival < 0))
+ {
+ info->errorCount++;
+ return
+ ReportBadType(typeName, field, ddText(info->dpy, di),
+ "unsigned");
+ }
+ di->defs.defined |= def;
+ if (type == FIELD_USHORT)
+ *pField.uval = tmp.uval;
+ else
+ *pField.ival = tmp.ival;
+ }
+ return True;
+}
+
+static int
+SetIndicatorDoodadField(DoodadInfo * di,
+ char *field,
+ ExprDef * arrayNdx,
+ ExprDef * value,
+ SectionInfo * si, GeometryInfo * info)
+{
+ ExprResult tmp;
+
+ if ((uStrCaseCmp(field, "oncolor") == 0)
+ || (uStrCaseCmp(field, "offcolor") == 0)
+ || (uStrCaseCmp(field, "shape") == 0))
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("indicator doodad", field,
+ ddText(info->dpy, di));
+ }
+ if (!ExprResolveString(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("indicator doodad", field,
+ ddText(info->dpy, di), "string");
+ }
+ if (uStrCaseCmp(field, "oncolor") == 0)
+ {
+ di->defs.defined |= _GD_Color;
+ di->color = XkbInternAtom(NULL, tmp.str, False);
+ }
+ else if (uStrCaseCmp(field, "offcolor") == 0)
+ {
+ di->defs.defined |= _GD_OffColor;
+ di->offColor = XkbInternAtom(NULL, tmp.str, False);
+ }
+ else if (uStrCaseCmp(field, "shape") == 0)
+ {
+ di->defs.defined |= _GD_Shape;
+ di->shape = XkbInternAtom(info->dpy, tmp.str, False);
+ }
+ return True;
+ }
+ return ReportBadField("indicator doodad", field, ddText(info->dpy, di));
+}
+
+static int
+SetLogoDoodadField(DoodadInfo * di,
+ char *field,
+ ExprDef * arrayNdx,
+ ExprDef * value, SectionInfo * si, GeometryInfo * info)
+{
+ ExprResult tmp;
+ char *typeName = "logo doodad";
+
+ if ((!uStrCaseCmp(field, "corner"))
+ || (!uStrCaseCmp(field, "cornerradius")))
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray(typeName, field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "number");
+ }
+ di->defs.defined |= _GD_Corner;
+ di->corner = tmp.ival;
+ return True;
+ }
+ else if (uStrCaseCmp(field, "angle") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray(typeName, field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "number");
+ }
+ di->defs.defined |= _GD_Angle;
+ di->angle = tmp.ival;
+ return True;
+ }
+ else if (uStrCaseCmp(field, "shape") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray(typeName, field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveString(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "string");
+ }
+ di->shape = XkbInternAtom(info->dpy, tmp.str, False);
+ di->defs.defined |= _GD_Shape;
+ return True;
+ }
+ else if ((!uStrCaseCmp(field, "logoname"))
+ || (!uStrCaseCmp(field, "name")))
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray(typeName, field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveString(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType(typeName, field, ddText(info->dpy, di),
+ "string");
+ }
+ di->logoName = uStringDup(tmp.str);
+ return True;
+ }
+ return ReportBadField(typeName, field, ddText(info->dpy, di));
+}
+
+static int
+SetDoodadField(DoodadInfo * di,
+ char *field,
+ ExprDef * arrayNdx,
+ ExprDef * value, SectionInfo * si, GeometryInfo * info)
+{
+ ExprResult tmp;
+
+ if (uStrCaseCmp(field, "priority") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("doodad", field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveInteger(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("doodad", field, ddText(info->dpy, di),
+ "integer");
+ }
+ if ((tmp.ival < 0) || (tmp.ival > XkbGeomMaxPriority))
+ {
+ info->errorCount++;
+ ERROR2("Doodad priority %d out of range (must be 0..%d)\n",
+ tmp.ival, XkbGeomMaxPriority);
+ ACTION1("Priority for doodad %s not changed",
+ ddText(info->dpy, di));
+ return False;
+ }
+ di->defs.defined |= _GD_Priority;
+ di->priority = tmp.ival;
+ return True;
+ }
+ else if (uStrCaseCmp(field, "left") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("doodad", field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("doodad", field, ddText(info->dpy, di),
+ "number");
+ }
+ di->defs.defined |= _GD_Left;
+ di->left = tmp.ival;
+ return True;
+ }
+ else if (uStrCaseCmp(field, "top") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("doodad", field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("doodad", field, ddText(info->dpy, di),
+ "number");
+ }
+ di->defs.defined |= _GD_Top;
+ di->top = tmp.ival;
+ return True;
+ }
+ else if (uStrCaseCmp(field, "color") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("doodad", field, ddText(info->dpy, di));
+ }
+ if (!ExprResolveString(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("doodad", field, ddText(info->dpy, di),
+ "string");
+ }
+ di->defs.defined |= _GD_Color;
+ di->color = XkbInternAtom(NULL, tmp.str, False);
+ return True;
+ }
+ switch (di->type)
+ {
+ case XkbOutlineDoodad:
+ case XkbSolidDoodad:
+ return SetShapeDoodadField(di, field, arrayNdx, value, si, info);
+ case XkbTextDoodad:
+ return SetTextDoodadField(di, field, arrayNdx, value, si, info);
+ case XkbIndicatorDoodad:
+ return SetIndicatorDoodadField(di, field, arrayNdx, value, si, info);
+ case XkbLogoDoodad:
+ return SetLogoDoodadField(di, field, arrayNdx, value, si, info);
+ }
+ WSGO1("Unknown doodad type %d in SetDoodadField\n",
+ (unsigned int) di->type);
+ ACTION2("Definition of %s in %s ignored\n", field, ddText(info->dpy, di));
+ return False;
+}
+
+static int
+SetSectionField(SectionInfo * si,
+ char *field,
+ ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
+{
+ unsigned short *pField;
+ unsigned def;
+ ExprResult tmp;
+
+ pField = NULL;
+ def = 0;
+ if (uStrCaseCmp(field, "priority") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard section", field,
+ scText(info->dpy, si));
+ }
+ if (!ExprResolveInteger(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ ReportBadType("keyboard section", field,
+ scText(info->dpy, si), "integer");
+ return False;
+ }
+ if ((tmp.ival < 0) || (tmp.ival > XkbGeomMaxPriority))
+ {
+ info->errorCount++;
+ ERROR2("Section priority %d out of range (must be 0..%d)\n",
+ tmp.ival, XkbGeomMaxPriority);
+ ACTION1("Priority for section %s not changed",
+ scText(info->dpy, si));
+ return False;
+ }
+ si->priority = tmp.ival;
+ si->defs.defined |= _GS_Priority;
+ return True;
+ }
+ else if (uStrCaseCmp(field, "top") == 0)
+ {
+ pField = &si->top;
+ def = _GS_Top;
+ }
+ else if (uStrCaseCmp(field, "left") == 0)
+ {
+ pField = &si->left;
+ def = _GS_Left;
+ }
+ else if (uStrCaseCmp(field, "width") == 0)
+ {
+ pField = &si->width;
+ def = _GS_Width;
+ }
+ else if (uStrCaseCmp(field, "height") == 0)
+ {
+ pField = &si->height;
+ def = _GS_Height;
+ }
+ else if (uStrCaseCmp(field, "angle") == 0)
+ {
+ pField = &si->angle;
+ def = _GS_Angle;
+ }
+ else
+ {
+ info->errorCount++;
+ return ReportBadField("keyboard section", field,
+ scText(info->dpy, si));
+ }
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard section", field,
+ scText(info->dpy, si));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ ReportBadType("keyboard section", field, scText(info->dpy, si),
+ "number");
+ return False;
+ }
+ si->defs.defined |= def;
+ *pField = tmp.uval;
+ return True;
+}
+
+static int
+SetRowField(RowInfo * row,
+ char *field,
+ ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
+{
+ ExprResult tmp;
+
+ if (uStrCaseCmp(field, "top") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard row", field,
+ rowText(info->dpy, row));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("keyboard row", field,
+ rowText(info->dpy, row), "number");
+ }
+ row->defs.defined |= _GR_Top;
+ row->top = tmp.uval;
+ }
+ else if (uStrCaseCmp(field, "left") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard row", field,
+ rowText(info->dpy, row));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("keyboard row", field,
+ rowText(info->dpy, row), "number");
+ }
+ row->defs.defined |= _GR_Left;
+ row->left = tmp.uval;
+ }
+ else if (uStrCaseCmp(field, "vertical") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard row", field,
+ rowText(info->dpy, row));
+ }
+ if (!ExprResolveBoolean(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("keyboard row", field,
+ rowText(info->dpy, row), "boolean");
+ }
+ row->defs.defined |= _GR_Vertical;
+ row->vertical = tmp.uval;
+ }
+ else
+ {
+ info->errorCount++;
+ return ReportBadField("keyboard row", field, rowText(info->dpy, row));
+ }
+ return True;
+}
+
+static int
+SetKeyField(KeyInfo * key,
+ const char *field,
+ ExprDef * arrayNdx, ExprDef * value, GeometryInfo * info)
+{
+ ExprResult tmp;
+
+ if (uStrCaseCmp(field, "gap") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("key", field, keyText(key));
+ }
+ if (!ExprResolveFloat(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("key", field, keyText(key), "number");
+ }
+ key->defs.defined |= _GK_Gap;
+ key->gap = tmp.ival;
+ }
+ else if (uStrCaseCmp(field, "shape") == 0)
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("key", field, keyText(key));
+ }
+ if (!ExprResolveString(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("key", field, keyText(key), "string");
+ }
+ key->defs.defined |= _GK_Shape;
+ key->shape = XkbInternAtom(info->dpy, tmp.str, False);
+ }
+ else if ((uStrCaseCmp(field, "color") == 0) ||
+ (uStrCaseCmp(field, "keycolor") == 0))
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("key", field, keyText(key));
+ }
+ if (!ExprResolveString(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("key", field, keyText(key), "string");
+ }
+ key->defs.defined |= _GK_Color;
+ key->color = XkbInternAtom(NULL, tmp.str, False);
+ }
+ else if ((uStrCaseCmp(field, "name") == 0)
+ || (uStrCaseCmp(field, "keyname") == 0))
+ {
+ if (arrayNdx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("key", field, keyText(key));
+ }
+ if (!ExprResolveKeyName(value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("key", field, keyText(key), "key name");
+ }
+ key->defs.defined |= _GK_Name;
+ bzero(key->name, XkbKeyNameLength + 1);
+ strncpy(key->name, tmp.keyName.name, XkbKeyNameLength);
+ }
+ else
+ {
+ info->errorCount++;
+ return ReportBadField("key", field, keyText(key));
+ }
+ return True;
+}
+
+static int
+SetGeometryProperty(GeometryInfo * info, char *property, ExprDef * value)
+{
+ PropertyInfo pi;
+ ExprResult result;
+
+ InitPropertyInfo(&pi, info);
+ pi.name = property;
+ if (!ExprResolveString(value, &result, NULL, NULL))
+ {
+ info->errorCount++;
+ ERROR("Property values must be type string\n");
+ ACTION1("Ignoring illegal definition of \"%s\" property\n", property);
+ return False;
+ }
+ pi.value = result.str;
+ return AddProperty(info, &pi);
+}
+
+static int
+HandleGeometryVar(VarDef * stmt, XkbDescPtr xkb, GeometryInfo * info)
+{
+ ExprResult elem, field, tmp;
+ ExprDef *ndx;
+ DoodadInfo *di;
+ Atom *pField;
+
+ if (ExprResolveLhs(stmt->name, &elem, &field, &ndx) == 0)
+ return 0; /* internal error, already reported */
+ if (elem.str && (uStrCaseCmp(elem.str, "shape") == 0))
+ return SetShapeField(NULL, field.str, ndx, stmt->value, info);
+ if (elem.str && (uStrCaseCmp(elem.str, "key") == 0))
+ return SetKeyField(&info->dfltSection.dfltRow.dfltKey,
+ field.str, ndx, stmt->value, info);
+ if (elem.str && (uStrCaseCmp(elem.str, "row") == 0))
+ return SetRowField(&info->dfltSection.dfltRow, field.str, ndx,
+ stmt->value, info);
+ if (elem.str && (uStrCaseCmp(elem.str, "section") == 0))
+ {
+ return SetSectionField(&info->dfltSection, field.str, ndx,
+ stmt->value, info);
+ }
+ if (elem.str && (uStrCaseCmp(elem.str, "property") == 0))
+ {
+ if (ndx != NULL)
+ {
+ info->errorCount++;
+ ERROR1("The %s geometry property is not an array\n", field.str);
+ ACTION("Ignoring illegal property definition\n");
+ return False;
+ }
+ return SetGeometryProperty(info, field.str, stmt->value);
+ }
+ if (elem.str
+ && ((di = FindDfltDoodadByTypeName(elem.str, NULL, info)) != NULL))
+ {
+ return SetDoodadField(di, field.str, ndx, stmt->value, NULL, info);
+ }
+ if (elem.str && (uStrCaseCmp(elem.str, "solid") == 0))
+ {
+ DoodadInfo *dflt;
+ dflt = FindDoodadByType(info->dfltDoodads, XkbSolidDoodad);
+ if (dflt == NULL)
+ dflt = NextDfltDoodad(NULL, info);
+ return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
+ }
+ if (elem.str && (uStrCaseCmp(elem.str, "outline") == 0))
+ {
+ DoodadInfo *dflt;
+ dflt = FindDoodadByType(info->dfltDoodads, XkbOutlineDoodad);
+ if (dflt == NULL)
+ dflt = NextDfltDoodad(NULL, info);
+ return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
+ }
+ if (elem.str && (uStrCaseCmp(elem.str, "text") == 0))
+ {
+ DoodadInfo *dflt;
+ dflt = FindDoodadByType(info->dfltDoodads, XkbTextDoodad);
+ if (dflt == NULL)
+ dflt = NextDfltDoodad(NULL, info);
+ return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
+ }
+ if (elem.str && (uStrCaseCmp(elem.str, "indicator") == 0))
+ {
+ DoodadInfo *dflt;
+ dflt = FindDoodadByType(info->dfltDoodads, XkbIndicatorDoodad);
+ if (dflt == NULL)
+ dflt = NextDfltDoodad(NULL, info);
+ return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
+ }
+ if (elem.str && (uStrCaseCmp(elem.str, "logo") == 0))
+ {
+ DoodadInfo *dflt;
+ dflt = FindDoodadByType(info->dfltDoodads, XkbLogoDoodad);
+ if (dflt == NULL)
+ dflt = NextDfltDoodad(NULL, info);
+ return SetDoodadField(dflt, field.str, ndx, stmt->value, NULL, info);
+ }
+ if (elem.str)
+ {
+ WARN("Assignment to field of unknown element\n");
+ ACTION2("No value assigned to %s.%s\n", elem.str, field.str);
+ return False;
+ }
+
+ if ((uStrCaseCmp(field.str, "width") == 0) ||
+ (uStrCaseCmp(field.str, "widthmm") == 0))
+ {
+ if (ndx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard", field.str, "geometry");
+ }
+ if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("keyboard", field.str, "geometry", "number");
+ }
+ if (tmp.ival < 1)
+ {
+ WARN("Keyboard width must be positive\n");
+ ACTION1("Ignoring illegal keyboard width %s\n",
+ XkbGeomFPText(tmp.ival, XkbMessage));
+ return True;
+ }
+ if (info->widthMM != 0)
+ {
+ WARN("Keyboard width multiply defined\n");
+ ACTION1("Using last definition (%s),",
+ XkbGeomFPText(tmp.ival, XkbMessage));
+ INFO1(" ignoring first (%s)\n",
+ XkbGeomFPText(info->widthMM, XkbMessage));
+ }
+ info->widthMM = tmp.ival;
+ return True;
+ }
+ else if ((uStrCaseCmp(field.str, "height") == 0) ||
+ (uStrCaseCmp(field.str, "heightmm") == 0))
+ {
+ if (ndx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard", field.str, "geometry");
+ }
+ if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("keyboard", field.str, "geometry", "number");
+ }
+ if (tmp.ival < 1)
+ {
+ WARN("Keyboard height must be positive\n");
+ ACTION1("Ignoring illegal keyboard height %s\n",
+ XkbGeomFPText(tmp.ival, XkbMessage));
+ return True;
+ }
+ if (info->heightMM != 0)
+ {
+ WARN("Keyboard height multiply defined\n");
+ ACTION1("Using last definition (%s),",
+ XkbGeomFPText(tmp.ival, XkbMessage));
+ INFO1(" ignoring first (%s)\n",
+ XkbGeomFPText(info->heightMM, XkbMessage));
+ }
+ info->heightMM = tmp.ival;
+ return True;
+ }
+ else if (uStrCaseCmp(field.str, "font") == 0)
+ {
+ pField = &info->font;
+ }
+ else if ((uStrCaseCmp(field.str, "fontslant") == 0) ||
+ (uStrCaseCmp(field.str, "slant") == 0))
+ {
+ pField = &info->fontSlant;
+ }
+ else if ((uStrCaseCmp(field.str, "fontweight") == 0) ||
+ (uStrCaseCmp(field.str, "weight") == 0))
+ {
+ pField = &info->fontWeight;
+ }
+ else if ((uStrCaseCmp(field.str, "fontwidth") == 0) ||
+ (uStrCaseCmp(field.str, "setwidth") == 0))
+ {
+ pField = &info->fontWeight;
+ }
+ else if ((uStrCaseCmp(field.str, "fontencoding") == 0) ||
+ (uStrCaseCmp(field.str, "encoding") == 0))
+ {
+ pField = &info->fontEncoding;
+ }
+ else if ((uStrCaseCmp(field.str, "xfont") == 0) ||
+ (uStrCaseCmp(field.str, "xfontname") == 0))
+ {
+ pField = &info->fontSpec;
+ }
+ else if (uStrCaseCmp(field.str, "fontsize") == 0)
+ {
+ if (ndx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard", field.str, "geometry");
+ }
+ if (!ExprResolveFloat(stmt->value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("keyboard", field.str, "geometry", "number");
+ }
+ if ((tmp.ival < 40) || (tmp.ival > 2550))
+ {
+ info->errorCount++;
+ ERROR1("Illegal font size %d (must be 4..255)\n", tmp.ival);
+ ACTION("Ignoring font size in keyboard geometry\n");
+ return False;
+ }
+ info->fontSize = tmp.ival;
+ return True;
+ }
+ else if ((uStrCaseCmp(field.str, "color") == 0) ||
+ (uStrCaseCmp(field.str, "basecolor") == 0))
+ {
+ if (ndx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard", field.str, "geometry");
+ }
+ if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("keyboard", field.str, "geometry", "string");
+ }
+ info->baseColor = XkbInternAtom(NULL, tmp.str, False);
+ return True;
+ }
+ else if (uStrCaseCmp(field.str, "labelcolor") == 0)
+ {
+ if (ndx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard", field.str, "geometry");
+ }
+ if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("keyboard", field.str, "geometry", "string");
+ }
+ info->labelColor = XkbInternAtom(NULL, tmp.str, False);
+ return True;
+ }
+ else
+ {
+ return SetGeometryProperty(info, field.str, stmt->value);
+ }
+
+ if (ndx != NULL)
+ {
+ info->errorCount++;
+ return ReportNotArray("keyboard", field.str, "geometry");
+ }
+ if (!ExprResolveString(stmt->value, &tmp, NULL, NULL))
+ {
+ info->errorCount++;
+ return ReportBadType("keyboard", field.str, "geometry", "string");
+ }
+ *pField = XkbInternAtom(NULL, tmp.str, False);
+ return True;
+}
+
+/***====================================================================***/
+
+static Bool
+HandleShapeBody(ShapeDef * def, ShapeInfo * si, unsigned merge,
+ GeometryInfo * info)
+{
+ OutlineDef *ol;
+ int nOut, nPt;
+ XkbOutlinePtr outline;
+ ExprDef *pt;
+
+ if (def->nOutlines < 1)
+ {
+ WARN1("Shape \"%s\" has no outlines\n", shText(info->dpy, si));
+ ACTION("Definition ignored\n");
+ return True;
+ }
+ si->nOutlines = def->nOutlines;
+ si->outlines = uTypedCalloc(def->nOutlines, XkbOutlineRec);
+ if (!si->outlines)
+ {
+ ERROR1("Couldn't allocate outlines for \"%s\"\n",
+ shText(info->dpy, si));
+ ACTION("Definition ignored\n");
+ info->errorCount++;
+ return False;
+ }
+ for (nOut = 0, ol = def->outlines; ol != NULL;
+ ol = (OutlineDef *) ol->common.next)
+ {
+ if (ol->nPoints < 1)
+ {
+ SetShapeField(si, XkbAtomGetString(NULL, ol->field), NULL,
+ ol->points, info);
+ continue;
+ }
+ outline = NULL;
+ outline = &si->outlines[nOut++];
+ outline->num_points = ol->nPoints;
+ outline->corner_radius = si->dfltCornerRadius;
+ outline->points = uTypedCalloc(ol->nPoints, XkbPointRec);
+ if (!outline->points)
+ {
+ ERROR1("Can't allocate points for \"%s\"\n",
+ shText(info->dpy, si));
+ ACTION("Definition ignored\n");
+ info->errorCount++;
+ return False;
+ }
+ for (nPt = 0, pt = ol->points; pt != NULL;
+ pt = (ExprDef *) pt->common.next)
+ {
+ outline->points[nPt].x = pt->value.coord.x;
+ outline->points[nPt].y = pt->value.coord.y;
+ nPt++;
+ }
+ if (ol->field != None)
+ {
+ char *str = XkbAtomText(NULL, ol->field, XkbMessage);
+ if ((uStrCaseCmp(str, "approximation") == 0) ||
+ (uStrCaseCmp(str, "approx") == 0))
+ {
+ if (si->approx == NULL)
+ si->approx = outline;
+ else
+ {
+ WARN1("Multiple approximations for \"%s\"\n",
+ shText(info->dpy, si));
+ ACTION("Treating all but the first as normal outlines\n");
+ }
+ }
+ else if (uStrCaseCmp(str, "primary") == 0)
+ {
+ if (si->primary == NULL)
+ si->primary = outline;
+ else
+ {
+ WARN1("Multiple primary outlines for \"%s\"\n",
+ shText(info->dpy, si));
+ ACTION("Treating all but the first as normal outlines\n");
+ }
+ }
+ else
+ {
+ WARN2("Unknown outline type %s for \"%s\"\n", str,
+ shText(info->dpy, si));
+ ACTION("Treated as a normal outline\n");
+ }
+ }
+ }
+ if (nOut != si->nOutlines)
+ {
+ WSGO2("Expected %d outlines, got %d\n",
+ (unsigned int) si->nOutlines, nOut);
+ si->nOutlines = nOut;
+ }
+ return True;
+}
+
+static int
+HandleShapeDef(ShapeDef * def, XkbDescPtr xkb, unsigned merge,
+ GeometryInfo * info)
+{
+ ShapeInfo si;
+
+ if (def->merge != MergeDefault)
+ merge = def->merge;
+
+ bzero(&si, sizeof(ShapeInfo));
+ si.defs.merge = merge;
+ si.name =
+ XkbInternAtom(info->dpy, XkbAtomGetString(NULL, def->name), False);
+ si.dfltCornerRadius = info->dfltCornerRadius;
+ if (!HandleShapeBody(def, &si, merge, info))
+ return False;
+ if (!AddShape(info, &si))
+ return False;
+ return True;
+}
+
+/***====================================================================***/
+
+static int
+HandleDoodadDef(DoodadDef * def,
+ unsigned merge, SectionInfo * si, GeometryInfo * info)
+{
+ ExprResult elem, field;
+ ExprDef *ndx;
+ DoodadInfo new;
+ VarDef *var;
+
+ if (def->common.stmtType == StmtIndicatorMapDef)
+ {
+ def->common.stmtType = StmtDoodadDef;
+ def->type = XkbIndicatorDoodad;
+ }
+ InitDoodadInfo(&new, def->type, si, info);
+ new.name =
+ XkbInternAtom(info->dpy, XkbAtomGetString(NULL, def->name), False);
+ for (var = def->body; var != NULL; var = (VarDef *) var->common.next)
+ {
+ if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
+ return 0; /* internal error, already reported */
+ if (elem.str != NULL)
+ {
+ WARN1("Assignment to field of unknown element in doodad %s\n",
+ ddText(info->dpy, &new));
+ ACTION2("No value assigned to %s.%s\n", elem.str, field.str);
+ }
+ else if (!SetDoodadField(&new, field.str, ndx, var->value, si, info))
+ return False;
+ }
+ if (!AddDoodad(si, info, &new))
+ return False;
+ ClearDoodadInfo(&new);
+ return True;
+}
+
+/***====================================================================***/
+
+static int
+HandleOverlayDef(OverlayDef * def,
+ unsigned merge, SectionInfo * si, GeometryInfo * info)
+{
+ OverlayKeyDef *keyDef;
+ OverlayKeyInfo *key;
+ OverlayInfo ol;
+
+ if ((def->nKeys < 1) && (warningLevel > 3))
+ {
+ WARN2("Overlay \"%s\" in section \"%s\" has no keys\n",
+ XkbAtomText(NULL, def->name, XkbMessage), scText(info->dpy,
+ si));
+ ACTION("Overlay ignored\n");
+ return True;
+ }
+ bzero(&ol, sizeof(OverlayInfo));
+ ol.name =
+ XkbInternAtom(info->dpy, XkbAtomGetString(NULL, def->name), False);
+ for (keyDef = def->keys; keyDef;
+ keyDef = (OverlayKeyDef *) keyDef->common.next)
+ {
+ key = uTypedCalloc(1, OverlayKeyInfo);
+ if ((!key) && warningLevel > 0)
+ {
+ WSGO("Couldn't allocate OverlayKeyInfo\n");
+ ACTION2("Overlay %s for section %s will be incomplete\n",
+ oiText(info->dpy, &ol), scText(info->dpy, si));
+ return False;
+ }
+ strncpy(key->over, keyDef->over, XkbKeyNameLength);
+ strncpy(key->under, keyDef->under, XkbKeyNameLength);
+ key->sectionRow = _GOK_UnknownRow;
+ key->overlayRow = _GOK_UnknownRow;
+ ol.keys = (OverlayKeyInfo *) AddCommonInfo(&ol.keys->defs,
+ (CommonInfo *) key);
+ ol.nKeys++;
+ }
+ if (!AddOverlay(si, info, &ol))
+ return False;
+ ClearOverlayInfo(&ol);
+ return True;
+}
+
+/***====================================================================***/
+
+static Bool
+HandleComplexKey(KeyDef * def, KeyInfo * key, GeometryInfo * info)
+{
+ RowInfo *row;
+ ExprDef *expr;
+
+ row = key->row;
+ for (expr = def->expr; expr != NULL; expr = (ExprDef *) expr->common.next)
+ {
+ if (expr->op == OpAssign)
+ {
+ ExprResult elem, f;
+ ExprDef *ndx;
+ if (ExprResolveLhs(expr->value.binary.left, &elem, &f, &ndx) == 0)
+ return False; /* internal error, already reported */
+ if ((elem.str == NULL) || (uStrCaseCmp(elem.str, "key") == 0))
+ {
+ if (!SetKeyField
+ (key, f.str, ndx, expr->value.binary.right, info))
+ return False;
+ }
+ else
+ {
+ ERROR("Illegal element used in a key definition\n");
+ ACTION2("Assignment to %s.%s ignored\n", elem.str, f.str);
+ return False;
+ }
+ }
+ else
+ {
+ switch (expr->type)
+ {
+ case TypeInt:
+ case TypeFloat:
+ if (!SetKeyField(key, "gap", NULL, expr, info))
+ return False;
+ break;
+ case TypeString:
+ if (!SetKeyField(key, "shape", NULL, expr, info))
+ return False;
+ break;
+ case TypeKeyName:
+ if (!SetKeyField(key, "name", NULL, expr, info))
+ return False;
+ break;
+ default:
+ ERROR("Cannot determine field for unnamed expression\n");
+ ACTION3("Ignoring key %d in row %d of section %s\n",
+ row->nKeys + 1, row->section->nRows + 1,
+ rowText(info->dpy, row));
+ return False;
+ }
+ }
+ }
+ return True;
+}
+
+static Bool
+HandleRowBody(RowDef * def, RowInfo * row, unsigned merge,
+ GeometryInfo * info)
+{
+ KeyDef *keyDef;
+
+ if ((def->nKeys < 1) && (warningLevel > 3))
+ {
+ ERROR1("Row in section %s has no keys\n", rowText(info->dpy, row));
+ ACTION("Section ignored\n");
+ return True;
+ }
+ for (keyDef = def->keys; keyDef != NULL;
+ keyDef = (KeyDef *) keyDef->common.next)
+ {
+ if (keyDef->common.stmtType == StmtVarDef)
+ {
+ VarDef *var = (VarDef *) keyDef;
+ ExprResult elem, field;
+ ExprDef *ndx;
+ if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
+ return 0; /* internal error, already reported */
+ if ((elem.str == NULL) || (uStrCaseCmp(elem.str, "row") == 0))
+ {
+ if (!SetRowField(row, field.str, ndx, var->value, info))
+ return False;
+ }
+ else if (uStrCaseCmp(elem.str, "key") == 0)
+ {
+ if (!SetKeyField
+ (&row->dfltKey, field.str, ndx, var->value, info))
+ return False;
+ }
+ else
+ {
+ WARN("Assignment to field of unknown element in row\n");
+ ACTION2("No value assigned to %s.%s\n", elem.str, field.str);
+ }
+ }
+ else if (keyDef->common.stmtType == StmtKeyDef)
+ {
+ KeyInfo key;
+ InitKeyInfo(&key, row, info);
+ if (keyDef->name != NULL)
+ {
+ int len = strlen(keyDef->name);
+ if ((len < 1) || (len > XkbKeyNameLength))
+ {
+ ERROR2("Illegal name %s for key in section %s\n",
+ keyDef->name, rowText(info->dpy, row));
+ ACTION("Section not compiled\n");
+ return False;
+ }
+ bzero(key.name, XkbKeyNameLength + 1);
+ strncpy(key.name, keyDef->name, XkbKeyNameLength);
+ key.defs.defined |= _GK_Name;
+ }
+ else if (!HandleComplexKey(keyDef, &key, info))
+ return False;
+ if (!AddKey(row, &key))
+ return False;
+ }
+ else
+ {
+ WSGO1("Unexpected statement (type %d) in row body\n",
+ keyDef->common.stmtType);
+ return False;
+ }
+ }
+ return True;
+}
+
+static Bool
+HandleSectionBody(SectionDef * def,
+ SectionInfo * si, unsigned merge, GeometryInfo * info)
+{
+ RowDef *rowDef;
+ DoodadInfo *di;
+
+ for (rowDef = def->rows; rowDef != NULL;
+ rowDef = (RowDef *) rowDef->common.next)
+ {
+ if (rowDef->common.stmtType == StmtVarDef)
+ {
+ VarDef *var = (VarDef *) rowDef;
+ ExprResult elem, field;
+ ExprDef *ndx;
+ if (ExprResolveLhs(var->name, &elem, &field, &ndx) == 0)
+ return 0; /* internal error, already reported */
+ if ((elem.str == NULL) || (uStrCaseCmp(elem.str, "section") == 0))
+ {
+ if (!SetSectionField(si, field.str, ndx, var->value, info))
+ return False;
+ }
+ else if (uStrCaseCmp(elem.str, "row") == 0)
+ {
+ if (!SetRowField
+ (&si->dfltRow, field.str, ndx, var->value, info))
+ return False;
+ }
+ else if (uStrCaseCmp(elem.str, "key") == 0)
+ {
+ if (!SetKeyField(&si->dfltRow.dfltKey, field.str, ndx,
+ var->value, info))
+ return False;
+ }
+ else if ((di =
+ FindDfltDoodadByTypeName(elem.str, si, info)) != NULL)
+ {
+ if (!SetDoodadField(di, field.str, ndx, var->value, si, info))
+ return False;
+ }
+ else
+ {
+ WARN("Assignment to field of unknown element in section\n");
+ ACTION2("No value assigned to %s.%s\n", elem.str, field.str);
+ }
+ }
+ else if (rowDef->common.stmtType == StmtRowDef)
+ {
+ RowInfo row;
+ InitRowInfo(&row, si, info);
+ if (!HandleRowBody(rowDef, &row, merge, info))
+ return False;
+ if (!AddRow(si, &row))
+ return False;
+/* ClearRowInfo(&row,info);*/
+ }
+ else if ((rowDef->common.stmtType == StmtDoodadDef) ||
+ (rowDef->common.stmtType == StmtIndicatorMapDef))
+ {
+ if (!HandleDoodadDef((DoodadDef *) rowDef, merge, si, info))
+ return False;
+ }
+ else if (rowDef->common.stmtType == StmtOverlayDef)
+ {
+ if (!HandleOverlayDef((OverlayDef *) rowDef, merge, si, info))
+ return False;
+ }
+ else
+ {
+ WSGO1("Unexpected statement (type %d) in section body\n",
+ rowDef->common.stmtType);
+ return False;
+ }
+ }
+ if (si->nRows != def->nRows)
+ {
+ WSGO2("Expected %d rows, found %d\n", (unsigned int) def->nRows,
+ (unsigned int) si->nRows);
+ ACTION1("Definition of section %s might be incorrect\n",
+ scText(info->dpy, si));
+ }
+ return True;
+}
+
+static int
+HandleSectionDef(SectionDef * def,
+ XkbDescPtr xkb, unsigned merge, GeometryInfo * info)
+{
+ SectionInfo si;
+ char *str;
+
+ if (def->merge != MergeDefault)
+ merge = def->merge;
+ InitSectionInfo(&si, info);
+ si.defs.merge = merge;
+ str = XkbAtomGetString(NULL, def->name);
+ if ((str == NULL) || (strlen(str) < 1))
+ {
+ ERROR("Section defined without a name\n");
+ ACTION("Definition ignored\n");
+ return False;
+ }
+ si.name =
+ XkbInternAtom(info->dpy, XkbAtomGetString(NULL, def->name), False);
+ if (!HandleSectionBody(def, &si, merge, info))
+ return False;
+ if (!AddSection(info, &si))
+ return False;
+ return True;
+}
+
+/***====================================================================***/
+
+static void
+HandleGeometryFile(XkbFile * file,
+ XkbDescPtr xkb, unsigned merge, GeometryInfo * info)
+{
+ ParseCommon *stmt;
+ char *failWhat;
+
+ if (merge == MergeDefault)
+ merge = MergeAugment;
+ info->name = uStringDup(file->name);
+ stmt = file->defs;
+ while (stmt)
+ {
+ failWhat = NULL;
+ switch (stmt->stmtType)
+ {
+ case StmtInclude:
+ if (!HandleIncludeGeometry((IncludeStmt *) stmt, xkb, info,
+ HandleGeometryFile))
+ info->errorCount++;
+ break;
+ case StmtKeyAliasDef:
+ if (!HandleAliasDef((KeyAliasDef *) stmt,
+ merge, info->fileID, &info->aliases))
+ {
+ info->errorCount++;
+ }
+ break;
+ case StmtVarDef:
+ if (!HandleGeometryVar((VarDef *) stmt, xkb, info))
+ info->errorCount++;
+ break;
+ case StmtShapeDef:
+ if (!HandleShapeDef((ShapeDef *) stmt, xkb, merge, info))
+ info->errorCount++;
+ break;
+ case StmtSectionDef:
+ if (!HandleSectionDef((SectionDef *) stmt, xkb, merge, info))
+ info->errorCount++;
+ break;
+ case StmtIndicatorMapDef:
+ case StmtDoodadDef:
+ if (!HandleDoodadDef((DoodadDef *) stmt, merge, NULL, info))
+ info->errorCount++;
+ break;
+ case StmtVModDef:
+ if (!failWhat)
+ failWhat = "virtual modfier";
+ case StmtInterpDef:
+ if (!failWhat)
+ failWhat = "symbol interpretation";
+ case StmtGroupCompatDef:
+ if (!failWhat)
+ failWhat = "group compatibility map";
+ case StmtKeycodeDef:
+ if (!failWhat)
+ failWhat = "key name";
+ ERROR("Interpretation files may not include other types\n");
+ ACTION1("Ignoring %s definition.\n", failWhat);
+ info->errorCount++;
+ break;
+ default:
+ WSGO1("Unexpected statement type %d in HandleGeometryFile\n",
+ stmt->stmtType);
+ break;
+ }
+ stmt = stmt->next;
+ if (info->errorCount > 10)
+ {
+#ifdef NOISY
+ ERROR("Too many errors\n");
+#endif
+ ACTION1("Abandoning geometry file \"%s\"\n", file->topName);
+ break;
+ }
+ }
+ return;
+}
+
+/***====================================================================***/
+
+static Bool
+CopyShapeDef(Display * dpy, XkbGeometryPtr geom, ShapeInfo * si)
+{
+ register int i, n;
+ XkbShapePtr shape;
+ XkbOutlinePtr old_outline, outline;
+ Atom name;
+
+ si->index = geom->num_shapes;
+ name = XkbInternAtom(dpy, XkbAtomGetString(NULL, si->name), False);
+ shape = XkbAddGeomShape(geom, name, si->nOutlines);
+ if (!shape)
+ {
+ WSGO("Couldn't allocate shape in geometry\n");
+ ACTION1("Shape %s not compiled\n", shText(dpy, si));
+ return False;
+ }
+ old_outline = si->outlines;
+ for (i = 0; i < si->nOutlines; i++, old_outline++)
+ {
+ outline = XkbAddGeomOutline(shape, old_outline->num_points);
+ if (!outline)
+ {
+ WSGO("Couldn't allocate outline in shape\n");
+ ACTION1("Shape %s is incomplete\n", shText(dpy, si));
+ return False;
+ }
+ n = old_outline->num_points;
+ memcpy(outline->points, old_outline->points, n * sizeof(XkbPointRec));
+ outline->num_points = old_outline->num_points;
+ outline->corner_radius = old_outline->corner_radius;
+ }
+ if (si->approx)
+ {
+ n = (si->approx - si->outlines);
+ shape->approx = &shape->outlines[n];
+ }
+ if (si->primary)
+ {
+ n = (si->primary - si->outlines);
+ shape->primary = &shape->outlines[n];
+ }
+ XkbComputeShapeBounds(shape);
+ return True;
+}
+
+static Bool
+VerifyDoodadInfo(DoodadInfo * di, GeometryInfo * info)
+{
+ if ((di->defs.defined & (_GD_Top | _GD_Left)) != (_GD_Top | _GD_Left))
+ {
+ if (warningLevel < 9)
+ {
+ ERROR1("No position defined for doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION("Illegal doodad ignored\n");
+ return False;
+ }
+ }
+ if ((di->defs.defined & _GD_Priority) == 0)
+ {
+ /* calculate priority -- should be just above previous doodad/row */
+ }
+ switch (di->type)
+ {
+ case XkbOutlineDoodad:
+ case XkbSolidDoodad:
+ if ((di->defs.defined & _GD_Shape) == 0)
+ {
+ ERROR2("No shape defined for %s doodad %s\n",
+ (di->type == XkbOutlineDoodad ? "outline" : "filled"),
+ ddText(info->dpy, di));
+ ACTION("Incomplete definition ignored\n");
+ return False;
+ }
+ else
+ {
+ ShapeInfo *si;
+ si = FindShape(info, di->shape,
+ (di->type ==
+ XkbOutlineDoodad ? "outline doodad" :
+ "solid doodad"), ddText(info->dpy, di));
+ if (si)
+ di->shape = si->name;
+ else
+ {
+ ERROR1("No legal shape for %s\n", ddText(info->dpy, di));
+ ACTION("Incomplete definition ignored\n");
+ return False;
+ }
+ }
+ if ((di->defs.defined & _GD_Color) == 0)
+ {
+ if (warningLevel > 5)
+ {
+ WARN1("No color for doodad %s\n", ddText(info->dpy, di));
+ ACTION("Using black\n");
+ }
+ di->color = XkbInternAtom(NULL, "black", False);
+ }
+ break;
+ case XkbTextDoodad:
+ if ((di->defs.defined & _GD_Text) == 0)
+ {
+ ERROR1("No text specified for text doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION("Illegal doodad definition ignored\n");
+ return False;
+ }
+ if ((di->defs.defined & _GD_Angle) == 0)
+ di->angle = 0;
+ if ((di->defs.defined & _GD_Color) == 0)
+ {
+ if (warningLevel > 5)
+ {
+ WARN1("No color specified for doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION("Using black\n");
+ }
+ di->color = XkbInternAtom(NULL, "black", False);
+ }
+ if ((di->defs.defined & _GD_FontSpec) != 0)
+ {
+ if ((di->defs.defined & _GD_FontParts) == 0)
+ return True;
+ if (warningLevel < 9)
+ {
+ WARN1
+ ("Text doodad %s has full and partial font definition\n",
+ ddText(info->dpy, di));
+ ACTION("Full specification ignored\n");
+ }
+ di->defs.defined &= ~_GD_FontSpec;
+ di->fontSpec = None;
+ }
+ if ((di->defs.defined & _GD_Font) == 0)
+ {
+ if (warningLevel > 5)
+ {
+ WARN1("No font specified for doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION1("Using \"%s\"\n", DFLT_FONT);
+ }
+ di->font = XkbInternAtom(NULL, DFLT_FONT, False);
+ }
+ if ((di->defs.defined & _GD_FontSlant) == 0)
+ {
+ if (warningLevel > 7)
+ {
+ WARN1("No font slant for text doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION1("Using \"%s\"\n", DFLT_SLANT);
+ }
+ di->fontSlant = XkbInternAtom(NULL, DFLT_SLANT, False);
+ }
+ if ((di->defs.defined & _GD_FontWeight) == 0)
+ {
+ if (warningLevel > 7)
+ {
+ WARN1("No font weight for text doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION1("Using \"%s\"\n", DFLT_WEIGHT);
+ }
+ di->fontWeight = XkbInternAtom(NULL, DFLT_WEIGHT, False);
+ }
+ if ((di->defs.defined & _GD_FontSetWidth) == 0)
+ {
+ if (warningLevel > 9)
+ {
+ WARN1("No font set width for text doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION1("Using \"%s\"\n", DFLT_SET_WIDTH);
+ }
+ di->fontSetWidth = XkbInternAtom(NULL, DFLT_SET_WIDTH, False);
+ }
+ if ((di->defs.defined & _GD_FontVariant) == 0)
+ {
+ if (warningLevel > 9)
+ {
+ WARN1("No font variant for text doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION1("Using \"%s\"\n", DFLT_VARIANT);
+ }
+ di->fontVariant = XkbInternAtom(NULL, DFLT_VARIANT, False);
+ }
+ if ((di->defs.defined & _GD_FontEncoding) == 0)
+ {
+ if (warningLevel > 7)
+ {
+ WARN1("No font encoding for doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION1("Using \"%s\"\n", DFLT_ENCODING);
+ }
+ di->fontEncoding = XkbInternAtom(NULL, DFLT_ENCODING, False);
+ }
+ if ((di->defs.defined & _GD_FontSize) == 0)
+ {
+ if (warningLevel > 7)
+ {
+ WARN1("No font size for text doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION1("Using %s point text\n",
+ XkbGeomFPText(DFLT_SIZE, XkbMessage));
+ }
+ di->fontSize = DFLT_SIZE;
+ }
+ if ((di->defs.defined & _GD_Height) == 0)
+ {
+ unsigned size, nLines;
+ char *tmp;
+ size = (di->fontSize * 120) / 100;
+ size = (size * 254) / 720; /* convert to mm/10 */
+ for (nLines = 1, tmp = XkbAtomGetString(NULL, di->text); *tmp;
+ tmp++)
+ {
+ if (*tmp == '\n')
+ nLines++;
+ }
+ size *= nLines;
+ if (warningLevel > 5)
+ {
+ WARN1("No height for text doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION1("Using calculated height %s millimeters\n",
+ XkbGeomFPText(size, XkbMessage));
+ }
+ di->height = size;
+ }
+ if ((di->defs.defined & _GD_Width) == 0)
+ {
+ unsigned width, tmp;
+ char *str;
+ width = tmp = 0;
+ for (str = XkbAtomGetString(NULL, di->text); *str; str++)
+ {
+ if (*str != '\n')
+ tmp++;
+ else
+ {
+ if (tmp > width)
+ width = tmp;
+ tmp = 1;
+ }
+ }
+ if (width == 0)
+ width = tmp;
+ width *= (di->height * 2) / 3;
+ if (warningLevel > 5)
+ {
+ WARN1("No width for text doodad %s\n", ddText(info->dpy, di));
+ ACTION1("Using calculated width %s millimeters\n",
+ XkbGeomFPText(width, XkbMessage));
+ }
+ di->width = width;
+ }
+ break;
+ case XkbIndicatorDoodad:
+ if ((di->defs.defined & _GD_Shape) == 0)
+ {
+ ERROR1("No shape defined for indicator doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION("Incomplete definition ignored\n");
+ return False;
+ }
+ else
+ {
+ ShapeInfo *si;
+ si = FindShape(info, di->shape, "indicator doodad",
+ ddText(info->dpy, di));
+ if (si)
+ di->shape = si->name;
+ else
+ {
+ ERROR1("No legal shape for doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION("Incomplete definition ignored\n");
+ return False;
+ }
+ }
+ if ((di->defs.defined & _GD_Color) == 0)
+ {
+ if (warningLevel > 5)
+ {
+ WARN1("No \"on\" color for indicator doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION("Using green\n");
+ }
+ di->color = XkbInternAtom(NULL, "green", False);
+ }
+ if ((di->defs.defined & _GD_OffColor) == 0)
+ {
+ if (warningLevel > 5)
+ {
+ WARN1("No \"off\" color for indicator doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION("Using black\n");
+ }
+ di->offColor = XkbInternAtom(NULL, "black", False);
+ }
+ break;
+ case XkbLogoDoodad:
+ if (di->logoName == NULL)
+ {
+ ERROR1("No logo name defined for logo doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION("Incomplete definition ignored\n");
+ return False;
+ }
+ if ((di->defs.defined & _GD_Shape) == 0)
+ {
+ ERROR1("No shape defined for logo doodad %s\n",
+ ddText(info->dpy, di));
+ ACTION("Incomplete definition ignored\n");
+ return False;
+ }
+ else
+ {
+ ShapeInfo *si;
+ si = FindShape(info, di->shape, "logo doodad",
+ ddText(info->dpy, di));
+ if (si)
+ di->shape = si->name;
+ else
+ {
+ ERROR1("No legal shape for %s\n", ddText(info->dpy, di));
+ ACTION("Incomplete definition ignored\n");
+ return False;
+ }
+ }
+ if ((di->defs.defined & _GD_Color) == 0)
+ {
+ if (warningLevel > 5)
+ {
+ WARN1("No color for doodad %s\n", ddText(info->dpy, di));
+ ACTION("Using black\n");
+ }
+ di->color = XkbInternAtom(NULL, "black", False);
+ }
+ break;
+ default:
+ WSGO1("Uknown doodad type %d in VerifyDoodad\n",
+ (unsigned int) di->type);
+ return False;
+ }
+ return True;
+}
+
+#define FONT_TEMPLATE "-*-%s-%s-%s-%s-%s-*-%d-*-*-*-*-%s"
+
+static char *
+FontFromParts(Atom fontTok,
+ Atom weightTok,
+ Atom slantTok,
+ Atom setWidthTok, Atom varTok, int size, Atom encodingTok)
+{
+ int totalSize;
+ char *font, *weight, *slant, *setWidth, *variant, *encoding;
+ char *rtrn;
+
+ font = (fontTok != None ? XkbAtomGetString(NULL, fontTok) : DFLT_FONT);
+ weight =
+ (weightTok != None ? XkbAtomGetString(NULL, weightTok) : DFLT_WEIGHT);
+ slant =
+ (slantTok != None ? XkbAtomGetString(NULL, slantTok) : DFLT_SLANT);
+ setWidth =
+ (setWidthTok !=
+ None ? XkbAtomGetString(NULL, setWidthTok) : DFLT_SET_WIDTH);
+ variant =
+ (varTok != None ? XkbAtomGetString(NULL, varTok) : DFLT_VARIANT);
+ encoding =
+ (encodingTok !=
+ None ? XkbAtomGetString(NULL, encodingTok) : DFLT_ENCODING);
+ if (size == 0)
+ size = DFLT_SIZE;
+ totalSize =
+ strlen(FONT_TEMPLATE) + strlen(font) + strlen(weight) + strlen(slant);
+ totalSize += strlen(setWidth) + strlen(variant) + strlen(encoding);
+ rtrn = uCalloc(totalSize, 1);
+ if (rtrn)
+ {
+ sprintf(rtrn, FONT_TEMPLATE, font, weight, slant, setWidth, variant,
+ size, encoding);
+ }
+ return rtrn;
+}
+
+static Bool
+CopyDoodadDef(XkbGeometryPtr geom,
+ XkbSectionPtr section, DoodadInfo * di, GeometryInfo * info)
+{
+ Atom name;
+ XkbDoodadPtr doodad;
+ XkbColorPtr color;
+ XkbShapePtr shape;
+ ShapeInfo *si;
+
+ if (!VerifyDoodadInfo(di, info))
+ return False;
+ name = XkbInternAtom(NULL, XkbAtomGetString(NULL, di->name), False);
+ doodad = XkbAddGeomDoodad(geom, section, name);
+ if (!doodad)
+ {
+ WSGO1("Couldn't allocate doodad in %s\n",
+ (section ? "section" : "geometry"));
+ ACTION1("Cannot copy doodad %s\n", ddText(info->dpy, di));
+ return False;
+ }
+ doodad->any.type = di->type;
+ doodad->any.priority = di->priority;
+ doodad->any.top = di->top;
+ doodad->any.left = di->left;
+ switch (di->type)
+ {
+ case XkbOutlineDoodad:
+ case XkbSolidDoodad:
+ si = FindShape(info, di->shape, NULL, NULL);
+ if (!si)
+ return False;
+ doodad->shape.angle = di->angle;
+ color =
+ XkbAddGeomColor(geom, XkbAtomGetString(NULL, di->color),
+ geom->num_colors);
+ shape = &geom->shapes[si->index];
+ XkbSetShapeDoodadColor(geom, &doodad->shape, color);
+ XkbSetShapeDoodadShape(geom, &doodad->shape, shape);
+ break;
+ case XkbTextDoodad:
+ doodad->text.angle = di->angle;
+ doodad->text.width = di->width;
+ doodad->text.height = di->height;
+ if (di->fontSpec == None)
+ doodad->text.font = FontFromParts(di->font, di->fontWeight,
+ di->fontSlant,
+ di->fontSetWidth,
+ di->fontVariant, di->fontSize,
+ di->fontEncoding);
+ else
+ doodad->text.font = XkbAtomGetString(NULL, di->fontSpec);
+ doodad->text.text = XkbAtomGetString(NULL, di->text);
+ color =
+ XkbAddGeomColor(geom, XkbAtomGetString(NULL, di->color),
+ geom->num_colors);
+ XkbSetTextDoodadColor(geom, &doodad->text, color);
+ break;
+ case XkbIndicatorDoodad:
+ si = FindShape(info, di->shape, NULL, NULL);
+ if (!si)
+ return False;
+ shape = &geom->shapes[si->index];
+ color =
+ XkbAddGeomColor(geom, XkbAtomGetString(NULL, di->color),
+ geom->num_colors);
+ XkbSetIndicatorDoodadShape(geom, &doodad->indicator, shape);
+ XkbSetIndicatorDoodadOnColor(geom, &doodad->indicator, color);
+ color =
+ XkbAddGeomColor(geom, XkbAtomGetString(NULL, di->offColor),
+ geom->num_colors);
+ XkbSetIndicatorDoodadOffColor(geom, &doodad->indicator, color);
+ break;
+ case XkbLogoDoodad:
+ si = FindShape(info, di->shape, NULL, NULL);
+ if (!si)
+ return False;
+ doodad->logo.angle = di->angle;
+ color =
+ XkbAddGeomColor(geom, XkbAtomGetString(NULL, di->color),
+ geom->num_colors);
+ shape = &geom->shapes[si->index];
+ XkbSetLogoDoodadColor(geom, &doodad->logo, color);
+ XkbSetLogoDoodadShape(geom, &doodad->logo, shape);
+ doodad->logo.logo_name = di->logoName;
+ di->logoName = NULL;
+ break;
+ }
+ return True;
+}
+
+/***====================================================================***/
+
+static Bool
+VerifyOverlayInfo(XkbGeometryPtr geom,
+ XkbSectionPtr section,
+ OverlayInfo * oi,
+ GeometryInfo * info, short rowMap[256], short rowSize[256])
+{
+ register OverlayKeyInfo *ki, *next;
+ unsigned long oKey, uKey, sKey;
+ XkbRowPtr row;
+ XkbKeyPtr key;
+ int r, k;
+
+ /* find out which row each key is in */
+ for (ki = oi->keys; ki != NULL; ki = (OverlayKeyInfo *) ki->defs.next)
+ {
+ oKey = KeyNameToLong(ki->over);
+ uKey = KeyNameToLong(ki->under);
+ for (r = 0, row = section->rows; (r < section->num_rows) && oKey;
+ r++, row++)
+ {
+ for (k = 0, key = row->keys; (k < row->num_keys) && oKey;
+ k++, key++)
+ {
+ sKey = KeyNameToLong(key->name.name);
+ if (sKey == oKey)
+ {
+ if (warningLevel > 0)
+ {
+ WARN3
+ ("Key %s in section \"%s\" and overlay \"%s\"\n",
+ XkbKeyNameText(key->name.name,
+ XkbMessage),
+ XkbAtomText(info->dpy, section->name,
+ XkbMessage),
+ XkbAtomText(info->dpy, oi->name, XkbMessage));
+ ACTION("Overlay definition ignored\n");
+ }
+ oKey = 0;
+ }
+ else if (sKey == uKey)
+ {
+ ki->sectionRow = r;
+ oKey = 0;
+ }
+ }
+ }
+ if ((ki->sectionRow == _GOK_UnknownRow) && (warningLevel > 0))
+ {
+ WARN3
+ ("Key %s not in \"%s\", but has an overlay key in \"%s\"\n",
+ XkbKeyNameText(ki->under, XkbMessage),
+ XkbAtomText(info->dpy, section->name, XkbMessage),
+ XkbAtomText(info->dpy, oi->name, XkbMessage));
+ ACTION("Definition ignored\n");
+ }
+ }
+ /* now prune out keys that aren't in the section */
+ while ((oi->keys != NULL) && (oi->keys->sectionRow == _GOK_UnknownRow))
+ {
+ next = (OverlayKeyInfo *) oi->keys->defs.next;
+ uFree(oi->keys);
+ oi->keys = next;
+ oi->nKeys--;
+ }
+ for (ki = oi->keys; (ki != NULL) && (ki->defs.next != NULL); ki = next)
+ {
+ next = (OverlayKeyInfo *) ki->defs.next;
+ if (next->sectionRow == _GOK_UnknownRow)
+ {
+ ki->defs.next = next->defs.next;
+ oi->nKeys--;
+ uFree(next);
+ next = (OverlayKeyInfo *) ki->defs.next;
+ }
+ }
+ if (oi->nKeys < 1)
+ {
+ ERROR2("Overlay \"%s\" for section \"%s\" has no legal keys\n",
+ XkbAtomText(info->dpy, oi->name, XkbMessage),
+ XkbAtomText(info->dpy, section->name, XkbMessage));
+ ACTION("Overlay definition ignored\n");
+ return False;
+ }
+ /* now figure out how many rows are defined for the overlay */
+ bzero(rowSize, sizeof(short) * 256);
+ for (k = 0; k < 256; k++)
+ {
+ rowMap[k] = -1;
+ }
+ oi->nRows = 0;
+ for (ki = oi->keys; ki != NULL; ki = (OverlayKeyInfo *) ki->defs.next)
+ {
+ if (rowMap[ki->sectionRow] == -1)
+ rowMap[ki->sectionRow] = oi->nRows++;
+ ki->overlayRow = rowMap[ki->sectionRow];
+ rowSize[ki->overlayRow]++;
+ }
+ return True;
+}
+
+static Bool
+CopyOverlayDef(XkbGeometryPtr geom,
+ XkbSectionPtr section, OverlayInfo * oi, GeometryInfo * info)
+{
+ Atom name;
+ XkbOverlayPtr ol;
+ XkbOverlayRowPtr row;
+ XkbOverlayKeyPtr key;
+ OverlayKeyInfo *ki;
+ short rowMap[256], rowSize[256];
+ int i;
+
+ if (!VerifyOverlayInfo(geom, section, oi, info, rowMap, rowSize))
+ return False;
+ name = XkbInternAtom(NULL, XkbAtomGetString(NULL, oi->name), False);
+ ol = XkbAddGeomOverlay(section, name, oi->nRows);
+ if (!ol)
+ {
+ WSGO2("Couldn't add overlay \"%s\" to section \"%s\"\n",
+ XkbAtomText(info->dpy, name, XkbMessage),
+ XkbAtomText(info->dpy, section->name, XkbMessage));
+ return False;
+ }
+ for (i = 0; i < oi->nRows; i++)
+ {
+ int tmp, row_under;
+ for (tmp = 0, row_under = -1;
+ (tmp < section->num_rows) && (row_under < 0); tmp++)
+ {
+ if (rowMap[tmp] == i)
+ row_under = tmp;
+ }
+ if (!XkbAddGeomOverlayRow(ol, row_under, rowSize[i]))
+ {
+ WSGO3
+ ("Can't add row %d to overlay \"%s\" of section \"%s\"\n",
+ i, XkbAtomText(info->dpy, name, XkbMessage),
+ XkbAtomText(info->dpy, section->name, XkbMessage));
+ return False;
+ }
+ }
+ for (ki = oi->keys; ki != NULL; ki = (OverlayKeyInfo *) ki->defs.next)
+ {
+ row = &ol->rows[ki->overlayRow];
+ key = &row->keys[row->num_keys++];
+ bzero(key, sizeof(XkbOverlayKeyRec));
+ strncpy(key->over.name, ki->over, XkbKeyNameLength);
+ strncpy(key->under.name, ki->under, XkbKeyNameLength);
+ }
+ return True;
+}
+
+/***====================================================================***/
+
+static Bool
+CopySectionDef(XkbGeometryPtr geom, SectionInfo * si, GeometryInfo * info)
+{
+ XkbSectionPtr section;
+ XkbRowPtr row;
+ XkbKeyPtr key;
+ KeyInfo *ki;
+ RowInfo *ri;
+ Atom name;
+
+ name = XkbInternAtom(NULL, XkbAtomGetString(NULL, si->name), False);
+ section =
+ XkbAddGeomSection(geom, name, si->nRows, si->nDoodads, si->nOverlays);
+ if (section == NULL)
+ {
+ WSGO("Couldn't allocate section in geometry\n");
+ ACTION1("Section %s not compiled\n", scText(info->dpy, si));
+ return False;
+ }
+ section->top = si->top;
+ section->left = si->left;
+ section->width = si->width;
+ section->height = si->height;
+ section->angle = si->angle;
+ section->priority = si->priority;
+ for (ri = si->rows; ri != NULL; ri = (RowInfo *) ri->defs.next)
+ {
+ row = XkbAddGeomRow(section, ri->nKeys);
+ if (row == NULL)
+ {
+ WSGO("Couldn't allocate row in section\n");
+ ACTION1("Section %s is incomplete\n", scText(info->dpy, si));
+ return False;
+ }
+ row->top = ri->top;
+ row->left = ri->left;
+ row->vertical = ri->vertical;
+ for (ki = ri->keys; ki != NULL; ki = (KeyInfo *) ki->defs.next)
+ {
+ XkbColorPtr color;
+ if ((ki->defs.defined & _GK_Name) == 0)
+ {
+ ERROR3("Key %d of row %d in section %s has no name\n",
+ (int) ki->index, (int) ri->index,
+ scText(info->dpy, si));
+ ACTION1("Section %s ignored\n", scText(info->dpy, si));
+ return False;
+ }
+ key = XkbAddGeomKey(row);
+ if (key == NULL)
+ {
+ WSGO("Couldn't allocate key in row\n");
+ ACTION1("Section %s is incomplete\n", scText(info->dpy, si));
+ return False;
+ }
+ memcpy(key->name.name, ki->name, XkbKeyNameLength);
+ key->gap = ki->gap;
+ if (ki->shape == None)
+ key->shape_ndx = 0;
+ else
+ {
+ ShapeInfo *si;
+ si = FindShape(info, ki->shape, "key", keyText(ki));
+ if (!si)
+ return False;
+ key->shape_ndx = si->index;
+ }
+ if (ki->color != None)
+ color =
+ XkbAddGeomColor(geom,
+ XkbAtomGetString(NULL, ki->color),
+ geom->num_colors);
+ else
+ color = XkbAddGeomColor(geom, "white", geom->num_colors);
+ XkbSetKeyColor(geom, key, color);
+ }
+ }
+ if (si->doodads != NULL)
+ {
+ DoodadInfo *di;
+ for (di = si->doodads; di != NULL; di = (DoodadInfo *) di->defs.next)
+ {
+ CopyDoodadDef(geom, section, di, info);
+ }
+ }
+ if (si->overlays != NULL)
+ {
+ OverlayInfo *oi;
+ for (oi = si->overlays; oi != NULL;
+ oi = (OverlayInfo *) oi->defs.next)
+ {
+ CopyOverlayDef(geom, section, oi, info);
+ }
+ }
+ if (XkbComputeSectionBounds(geom, section))
+ {
+ /* 7/6/94 (ef) -- check for negative origin and translate */
+ if ((si->defs.defined & _GS_Width) == 0)
+ section->width = section->bounds.x2;
+ if ((si->defs.defined & _GS_Height) == 0)
+ section->height = section->bounds.y2;
+ }
+ return True;
+}
+
+/***====================================================================***/
+
+Bool
+CompileGeometry(XkbFile * file, XkbFileInfo * result, unsigned merge)
+{
+ GeometryInfo info;
+ XkbDescPtr xkb;
+
+ xkb = result->xkb;
+ InitGeometryInfo(&info, file->id, merge);
+ info.dpy = xkb->dpy;
+ HandleGeometryFile(file, xkb, merge, &info);
+
+ if (info.errorCount == 0)
+ {
+ XkbGeometryPtr geom;
+ XkbGeometrySizesRec sizes;
+ bzero(&sizes, sizeof(sizes));
+ sizes.which = XkbGeomAllMask;
+ sizes.num_properties = info.nProps;
+ sizes.num_colors = 8;
+ sizes.num_shapes = info.nShapes;
+ sizes.num_sections = info.nSections;
+ sizes.num_doodads = info.nDoodads;
+ if (XkbAllocGeometry(xkb, &sizes) != Success)
+ {
+ WSGO("Couldn't allocate GeometryRec\n");
+ ACTION("Geometry not compiled\n");
+ return False;
+ }
+ geom = xkb->geom;
+
+ geom->width_mm = info.widthMM;
+ geom->height_mm = info.heightMM;
+ if (info.name != NULL)
+ {
+ geom->name = XkbInternAtom(xkb->dpy, info.name, False);
+ if (XkbAllocNames(xkb, XkbGeometryNameMask, 0, 0) == Success)
+ xkb->names->geometry = geom->name;
+ }
+ if (info.fontSpec != None)
+ geom->label_font =
+ uStringDup(XkbAtomGetString(NULL, info.fontSpec));
+ else
+ geom->label_font = FontFromParts(info.font, info.fontWeight,
+ info.fontSlant,
+ info.fontSetWidth,
+ info.fontVariant,
+ info.fontSize,
+ info.fontEncoding);
+ XkbAddGeomColor(geom, "black", geom->num_colors);
+ XkbAddGeomColor(geom, "white", geom->num_colors);
+
+ if (info.baseColor == None)
+ info.baseColor = XkbInternAtom(NULL, "white", False);
+ if (info.labelColor == None)
+ info.labelColor = XkbInternAtom(NULL, "black", False);
+ geom->base_color =
+ XkbAddGeomColor(geom, XkbAtomGetString(NULL, info.baseColor),
+ geom->num_colors);
+ geom->label_color =
+ XkbAddGeomColor(geom, XkbAtomGetString(NULL, info.labelColor),
+ geom->num_colors);
+
+ if (info.props)
+ {
+ PropertyInfo *pi;
+ for (pi = info.props; pi != NULL;
+ pi = (PropertyInfo *) pi->defs.next)
+ {
+ if (!XkbAddGeomProperty(geom, pi->name, pi->value))
+ return False;
+ }
+ }
+ if (info.shapes)
+ {
+ ShapeInfo *si;
+ for (si = info.shapes; si != NULL;
+ si = (ShapeInfo *) si->defs.next)
+ {
+ if (!CopyShapeDef(xkb->dpy, geom, si))
+ return False;
+ }
+ }
+ if (info.sections)
+ {
+ SectionInfo *si;
+ for (si = info.sections; si != NULL;
+ si = (SectionInfo *) si->defs.next)
+ {
+ if (!CopySectionDef(geom, si, &info))
+ return False;
+ }
+ }
+ if (info.doodads)
+ {
+ DoodadInfo *di;
+ for (di = info.doodads; di != NULL;
+ di = (DoodadInfo *) di->defs.next)
+ {
+ if (!CopyDoodadDef(geom, NULL, di, &info))
+ return False;
+ }
+ }
+ if (info.aliases)
+ ApplyAliases(xkb, True, &info.aliases);
+ ClearGeometryInfo(&info);
+ return True;
+ }
+ return False;
+}
diff --git a/src/xkbcomp/indicators.c b/src/xkbcomp/indicators.c
new file mode 100644
index 0000000..d4a362f
--- /dev/null
+++ b/src/xkbcomp/indicators.c
@@ -0,0 +1,575 @@
+/************************************************************
+ 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 "misc.h"
+#include "tokens.h"
+#include "expr.h"
+#include "vmod.h"
+#include "indicators.h"
+#include "action.h"
+#include "compat.h"
+
+/***====================================================================***/
+
+#define ReportIndicatorBadType(d,l,f,w) \
+ ReportBadType("indicator map",(f),\
+ XkbAtomText((d),(l)->name,XkbMessage),(w))
+#define ReportIndicatorNotArray(d,l,f) \
+ ReportNotArray("indicator map",(f),\
+ XkbAtomText((d),(l)->name,XkbMessage))
+
+/***====================================================================***/
+
+void
+ClearIndicatorMapInfo(Display * dpy, LEDInfo * info)
+{
+ info->name = XkbInternAtom(dpy, "default", False);
+ info->indicator = _LED_NotBound;
+ info->flags = info->which_mods = info->real_mods = 0;
+ info->vmods = 0;
+ info->which_groups = info->groups = 0;
+ info->ctrls = 0;
+ return;
+}
+
+LEDInfo *
+AddIndicatorMap(LEDInfo * oldLEDs, LEDInfo * new)
+{
+ LEDInfo *old, *last;
+ unsigned collide;
+
+ last = NULL;
+ for (old = oldLEDs; old != NULL; old = (LEDInfo *) old->defs.next)
+ {
+ if (old->name == new->name)
+ {
+ if ((old->real_mods == new->real_mods) &&
+ (old->vmods == new->vmods) &&
+ (old->groups == new->groups) &&
+ (old->ctrls == new->ctrls) &&
+ (old->which_mods == new->which_mods) &&
+ (old->which_groups == new->which_groups))
+ {
+ old->defs.defined |= new->defs.defined;
+ return oldLEDs;
+ }
+ if (new->defs.merge == MergeReplace)
+ {
+ CommonInfo *next = old->defs.next;
+ if (((old->defs.fileID == new->defs.fileID)
+ && (warningLevel > 0)) || (warningLevel > 9))
+ {
+ WARN1("Map for indicator %s redefined\n",
+ XkbAtomText(NULL, old->name, XkbMessage));
+ ACTION("Earlier definition ignored\n");
+ }
+ *old = *new;
+ old->defs.next = next;
+ return oldLEDs;
+ }
+ collide = 0;
+ if (UseNewField(_LED_Index, &old->defs, &new->defs, &collide))
+ {
+ old->indicator = new->indicator;
+ old->defs.defined |= _LED_Index;
+ }
+ if (UseNewField(_LED_Mods, &old->defs, &new->defs, &collide))
+ {
+ old->which_mods = new->which_mods;
+ old->real_mods = new->real_mods;
+ old->vmods = new->vmods;
+ old->defs.defined |= _LED_Mods;
+ }
+ if (UseNewField(_LED_Groups, &old->defs, &new->defs, &collide))
+ {
+ old->which_groups = new->which_groups;
+ old->groups = new->groups;
+ old->defs.defined |= _LED_Groups;
+ }
+ if (UseNewField(_LED_Ctrls, &old->defs, &new->defs, &collide))
+ {
+ old->ctrls = new->ctrls;
+ old->defs.defined |= _LED_Ctrls;
+ }
+ if (UseNewField(_LED_Explicit, &old->defs, &new->defs, &collide))
+ {
+ old->flags &= ~XkbIM_NoExplicit;
+ old->flags |= (new->flags & XkbIM_NoExplicit);
+ old->defs.defined |= _LED_Explicit;
+ }
+ if (UseNewField(_LED_Automatic, &old->defs, &new->defs, &collide))
+ {
+ old->flags &= ~XkbIM_NoAutomatic;
+ old->flags |= (new->flags & XkbIM_NoAutomatic);
+ old->defs.defined |= _LED_Automatic;
+ }
+ if (UseNewField(_LED_DrivesKbd, &old->defs, &new->defs, &collide))
+ {
+ old->flags &= ~XkbIM_LEDDrivesKB;
+ old->flags |= (new->flags & XkbIM_LEDDrivesKB);
+ old->defs.defined |= _LED_DrivesKbd;
+ }
+ if (collide)
+ {
+ WARN1("Map for indicator %s redefined\n",
+ XkbAtomText(NULL, old->name, XkbMessage));
+ ACTION1("Using %s definition for duplicate fields\n",
+ (new->defs.merge == MergeAugment ? "first" : "last"));
+ }
+ return oldLEDs;
+ }
+ if (old->defs.next == NULL)
+ last = old;
+ }
+ /* new definition */
+ old = uTypedAlloc(LEDInfo);
+ if (!old)
+ {
+ WSGO("Couldn't allocate indicator map\n");
+ ACTION1("Map for indicator %s not compiled\n",
+ XkbAtomText(NULL, new->name, XkbMessage));
+ return NULL;
+ }
+ *old = *new;
+ old->defs.next = NULL;
+ if (last)
+ {
+ last->defs.next = &old->defs;
+ return oldLEDs;
+ }
+ return old;
+}
+
+static LookupEntry modComponentNames[] = {
+ {"base", XkbIM_UseBase}
+ ,
+ {"latched", XkbIM_UseLatched}
+ ,
+ {"locked", XkbIM_UseLocked}
+ ,
+ {"effective", XkbIM_UseEffective}
+ ,
+ {"compat", XkbIM_UseCompat}
+ ,
+ {"any", XkbIM_UseAnyMods}
+ ,
+ {"none", 0}
+ ,
+ {NULL, 0}
+};
+static LookupEntry groupComponentNames[] = {
+ {"base", XkbIM_UseBase}
+ ,
+ {"latched", XkbIM_UseLatched}
+ ,
+ {"locked", XkbIM_UseLocked}
+ ,
+ {"effective", XkbIM_UseEffective}
+ ,
+ {"any", XkbIM_UseAnyGroup}
+ ,
+ {"none", 0}
+ ,
+ {NULL, 0}
+};
+
+int
+SetIndicatorMapField(LEDInfo * led,
+ XkbDescPtr xkb,
+ char *field, ExprDef * arrayNdx, ExprDef * value)
+{
+ ExprResult rtrn;
+ Bool ok;
+
+ ok = True;
+ if ((uStrCaseCmp(field, "modifiers") == 0)
+ || (uStrCaseCmp(field, "mods") == 0))
+ {
+ if (arrayNdx != NULL)
+ return ReportIndicatorNotArray(xkb->dpy, led, field);
+ if (!ExprResolveModMask(value, &rtrn, LookupVModMask, (XPointer) xkb))
+ return ReportIndicatorBadType(xkb->dpy, led, field,
+ "modifier mask");
+ led->real_mods = rtrn.uval & 0xff;
+ led->vmods = (rtrn.uval >> 8) & 0xff;
+ led->defs.defined |= _LED_Mods;
+ }
+ else if (uStrCaseCmp(field, "groups") == 0)
+ {
+ if (arrayNdx != NULL)
+ return ReportIndicatorNotArray(xkb->dpy, led, field);
+ if (!ExprResolveMask
+ (value, &rtrn, SimpleLookup, (XPointer) groupNames))
+ return ReportIndicatorBadType(xkb->dpy, led, field, "group mask");
+ led->groups = rtrn.uval;
+ led->defs.defined |= _LED_Groups;
+ }
+ else if ((uStrCaseCmp(field, "controls") == 0) ||
+ (uStrCaseCmp(field, "ctrls") == 0))
+ {
+ if (arrayNdx != NULL)
+ return ReportIndicatorNotArray(xkb->dpy, led, field);
+ if (!ExprResolveMask
+ (value, &rtrn, SimpleLookup, (XPointer) ctrlNames))
+ return ReportIndicatorBadType(xkb->dpy, led, field,
+ "controls mask");
+ led->ctrls = rtrn.uval;
+ led->defs.defined |= _LED_Ctrls;
+ }
+ else if (uStrCaseCmp(field, "allowexplicit") == 0)
+ {
+ if (arrayNdx != NULL)
+ return ReportIndicatorNotArray(xkb->dpy, led, field);
+ if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
+ return ReportIndicatorBadType(xkb->dpy, led, field, "boolean");
+ if (rtrn.uval)
+ led->flags &= ~XkbIM_NoExplicit;
+ else
+ led->flags |= XkbIM_NoExplicit;
+ led->defs.defined |= _LED_Explicit;
+ }
+ else if ((uStrCaseCmp(field, "whichmodstate") == 0) ||
+ (uStrCaseCmp(field, "whichmodifierstate") == 0))
+ {
+ if (arrayNdx != NULL)
+ return ReportIndicatorNotArray(xkb->dpy, led, field);
+ if (!ExprResolveMask(value, &rtrn, SimpleLookup,
+ (XPointer) modComponentNames))
+ {
+ return ReportIndicatorBadType(xkb->dpy, led, field,
+ "mask of modifier state components");
+ }
+ led->which_mods = rtrn.uval;
+ }
+ else if (uStrCaseCmp(field, "whichgroupstate") == 0)
+ {
+ if (arrayNdx != NULL)
+ return ReportIndicatorNotArray(xkb->dpy, led, field);
+ if (!ExprResolveMask(value, &rtrn, SimpleLookup,
+ (XPointer) groupComponentNames))
+ {
+ return ReportIndicatorBadType(xkb->dpy, led, field,
+ "mask of group state components");
+ }
+ led->which_groups = rtrn.uval;
+ }
+ else if ((uStrCaseCmp(field, "driveskbd") == 0) ||
+ (uStrCaseCmp(field, "driveskeyboard") == 0) ||
+ (uStrCaseCmp(field, "leddriveskbd") == 0) ||
+ (uStrCaseCmp(field, "leddriveskeyboard") == 0) ||
+ (uStrCaseCmp(field, "indicatordriveskbd") == 0) ||
+ (uStrCaseCmp(field, "indicatordriveskeyboard") == 0))
+ {
+ if (arrayNdx != NULL)
+ return ReportIndicatorNotArray(xkb->dpy, led, field);
+ if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
+ return ReportIndicatorBadType(xkb->dpy, led, field, "boolean");
+ if (rtrn.uval)
+ led->flags |= XkbIM_LEDDrivesKB;
+ else
+ led->flags &= ~XkbIM_LEDDrivesKB;
+ led->defs.defined |= _LED_DrivesKbd;
+ }
+ else if (uStrCaseCmp(field, "index") == 0)
+ {
+ if (arrayNdx != NULL)
+ return ReportIndicatorNotArray(xkb->dpy, led, field);
+ if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
+ return ReportIndicatorBadType(xkb->dpy, led, field,
+ "indicator index");
+ if ((rtrn.uval < 1) || (rtrn.uval > 32))
+ {
+ ERROR2("Illegal indicator index %d (range 1..%d)\n",
+ rtrn.uval, XkbNumIndicators);
+ ACTION1("Index definition for %s indicator ignored\n",
+ XkbAtomText(NULL, led->name, XkbMessage));
+ return False;
+ }
+ led->indicator = rtrn.uval;
+ led->defs.defined |= _LED_Index;
+ }
+ else
+ {
+ ERROR2("Unknown field %s in map for %s indicator\n", field,
+ XkbAtomText(NULL, led->name, XkbMessage));
+ ACTION("Definition ignored\n");
+ ok = False;
+ }
+ return ok;
+}
+
+LEDInfo *
+HandleIndicatorMapDef(IndicatorMapDef * def,
+ XkbDescPtr xkb,
+ LEDInfo * dflt, LEDInfo * oldLEDs, unsigned merge)
+{
+ LEDInfo led, *rtrn;
+ VarDef *var;
+ Bool ok;
+
+ if (def->merge != MergeDefault)
+ merge = def->merge;
+
+ led = *dflt;
+ led.defs.merge = merge;
+ led.name = def->name;
+
+ ok = True;
+ for (var = def->body; var != NULL; var = (VarDef *) var->common.next)
+ {
+ ExprResult elem, field;
+ ExprDef *arrayNdx;
+ if (!ExprResolveLhs(var->name, &elem, &field, &arrayNdx))
+ {
+ ok = False;
+ continue;
+ }
+ if (elem.str != NULL)
+ {
+ ERROR1
+ ("Cannot set defaults for \"%s\" element in indicator map\n",
+ elem.str);
+ ACTION2("Assignment to %s.%s ignored\n", elem.str, field.str);
+ ok = False;
+ }
+ else
+ {
+ ok = SetIndicatorMapField(&led, xkb, field.str, arrayNdx,
+ var->value) && ok;
+ }
+ }
+ if (ok)
+ {
+ rtrn = AddIndicatorMap(oldLEDs, &led);
+ return rtrn;
+ }
+ return NULL;
+}
+
+Bool
+CopyIndicatorMapDefs(XkbFileInfo * result, LEDInfo * leds,
+ LEDInfo ** unboundRtrn)
+{
+ LEDInfo *led, *next;
+ LEDInfo *unbound, *last;
+ XkbDescPtr xkb;
+
+ xkb = result->xkb;
+ if (XkbAllocNames(xkb, XkbIndicatorNamesMask, 0, 0) != Success)
+ {
+ WSGO("Couldn't allocate names\n");
+ ACTION("Indicator names may be incorrect\n");
+ }
+ if (XkbAllocIndicatorMaps(xkb) != Success)
+ {
+ WSGO("Can't allocate indicator maps\n");
+ ACTION("Indicator map definitions may be lost\n");
+ return False;
+ }
+ last = unbound = (unboundRtrn ? *unboundRtrn : NULL);
+ while ((last != NULL) && (last->defs.next != NULL))
+ {
+ last = (LEDInfo *) last->defs.next;
+ }
+ for (led = leds; led != NULL; led = next)
+ {
+ next = (LEDInfo *) led->defs.next;
+ if ((led->groups != 0) && (led->which_groups == 0))
+ led->which_groups = XkbIM_UseEffective;
+ if ((led->which_mods == 0) && ((led->real_mods) || (led->vmods)))
+ led->which_mods = XkbIM_UseEffective;
+ if ((led->indicator == _LED_NotBound) || (!xkb->indicators))
+ {
+ if (unboundRtrn != NULL)
+ {
+ led->defs.next = NULL;
+ if (last != NULL)
+ last->defs.next = (CommonInfo *) led;
+ else
+ unbound = led;
+ last = led;
+ }
+ else
+ uFree(led);
+ }
+ else
+ {
+ register XkbIndicatorMapPtr im;
+ im = &xkb->indicators->maps[led->indicator - 1];
+ im->flags = led->flags;
+ im->which_groups = led->which_groups;
+ im->groups = led->groups;
+ im->which_mods = led->which_mods;
+ im->mods.mask = led->real_mods;
+ im->mods.real_mods = led->real_mods;
+ im->mods.vmods = led->vmods;
+ im->ctrls = led->ctrls;
+ if (xkb->names != NULL)
+ xkb->names->indicators[led->indicator - 1] = led->name;
+ uFree(led);
+ }
+ }
+ if (unboundRtrn != NULL)
+ {
+ *unboundRtrn = unbound;
+ }
+ return True;
+}
+
+Bool
+BindIndicators(XkbFileInfo * result,
+ Bool force, LEDInfo * unbound, LEDInfo ** unboundRtrn)
+{
+ XkbDescPtr xkb;
+ register int i;
+ register LEDInfo *led, *next, *last;
+
+ xkb = result->xkb;
+ if (xkb->names != NULL)
+ {
+ for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next)
+ {
+ if (led->indicator == _LED_NotBound)
+ {
+ for (i = 0; i < XkbNumIndicators; i++)
+ {
+ if (xkb->names->indicators[i] == led->name)
+ {
+ led->indicator = i + 1;
+ break;
+ }
+ }
+ }
+ }
+ if (force)
+ {
+ for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next)
+ {
+ if (led->indicator == _LED_NotBound)
+ {
+ for (i = 0; i < XkbNumIndicators; i++)
+ {
+ if (xkb->names->indicators[i] == None)
+ {
+ xkb->names->indicators[i] = led->name;
+ led->indicator = i + 1;
+ xkb->indicators->phys_indicators &= ~(1 << i);
+ break;
+ }
+ }
+ if (led->indicator == _LED_NotBound)
+ {
+ ERROR("No unnamed indicators found\n");
+ ACTION1
+ ("Virtual indicator map \"%s\" not bound\n",
+ XkbAtomGetString(xkb->dpy, led->name));
+ continue;
+ }
+ }
+ }
+ }
+ }
+ for (last = NULL, led = unbound; led != NULL; led = next)
+ {
+ next = (LEDInfo *) led->defs.next;
+ if (led->indicator == _LED_NotBound)
+ {
+ if (force)
+ {
+ unbound = next;
+ uFree(led);
+ }
+ else
+ {
+ if (last)
+ last->defs.next = &led->defs;
+ else
+ unbound = led;
+ last = led;
+ }
+ }
+ else
+ {
+ if ((xkb->names != NULL) &&
+ (xkb->names->indicators[led->indicator - 1] != led->name))
+ {
+ Atom old = xkb->names->indicators[led->indicator - 1];
+ ERROR1("Multiple names bound to indicator %d\n",
+ (unsigned int) led->indicator);
+ ACTION2("Using %s, ignoring %s\n",
+ XkbAtomGetString(xkb->dpy, old),
+ XkbAtomGetString(xkb->dpy, led->name));
+ led->indicator = _LED_NotBound;
+ if (force)
+ {
+ uFree(led);
+ unbound = next;
+ }
+ else
+ {
+ if (last)
+ last->defs.next = &led->defs;
+ else
+ unbound = led;
+ last = led;
+ }
+ }
+ else
+ {
+ XkbIndicatorMapPtr map;
+ map = &xkb->indicators->maps[led->indicator - 1];
+ map->flags = led->flags;
+ map->which_groups = led->which_groups;
+ map->groups = led->groups;
+ map->which_mods = led->which_mods;
+ map->mods.mask = led->real_mods;
+ map->mods.real_mods = led->real_mods;
+ map->mods.vmods = led->vmods;
+ map->ctrls = led->ctrls;
+ if (last)
+ last->defs.next = &next->defs;
+ else
+ unbound = next;
+ led->defs.next = NULL;
+ uFree(led);
+ }
+ }
+ }
+ if (unboundRtrn)
+ {
+ *unboundRtrn = unbound;
+ }
+ else if (unbound)
+ {
+ for (led = unbound; led != NULL; led = next)
+ {
+ next = (LEDInfo *) led->defs.next;
+ uFree(led);
+ }
+ }
+ return True;
+}
diff --git a/src/xkbcomp/indicators.h b/src/xkbcomp/indicators.h
new file mode 100644
index 0000000..35ae38a
--- /dev/null
+++ b/src/xkbcomp/indicators.h
@@ -0,0 +1,88 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifndef INDICATORS_H
+#define INDICATORS_H 1
+
+#define _LED_Index (1<<0)
+#define _LED_Mods (1<<1)
+#define _LED_Groups (1<<2)
+#define _LED_Ctrls (1<<3)
+#define _LED_Explicit (1<<4)
+#define _LED_Automatic (1<<5)
+#define _LED_DrivesKbd (1<<6)
+
+#define _LED_NotBound 255
+
+typedef struct _LEDInfo
+{
+ CommonInfo defs;
+ Atom name;
+ unsigned char indicator;
+ unsigned char flags;
+ unsigned char which_mods;
+ unsigned char real_mods;
+ unsigned short vmods;
+ unsigned char which_groups;
+ unsigned char groups;
+ unsigned int ctrls;
+} LEDInfo;
+
+extern void ClearIndicatorMapInfo(Display * /* dpy */ ,
+ LEDInfo * /* info */
+ );
+
+
+extern LEDInfo *AddIndicatorMap(LEDInfo * /* oldLEDs */ ,
+ LEDInfo * /* newLED */
+ );
+
+extern int SetIndicatorMapField(LEDInfo * /* led */ ,
+ XkbDescPtr /* xkb */ ,
+ char * /* field */ ,
+ ExprDef * /* arrayNdx */ ,
+ ExprDef * /* value */
+ );
+
+extern LEDInfo *HandleIndicatorMapDef(IndicatorMapDef * /* stmt */ ,
+ XkbDescPtr /* xkb */ ,
+ LEDInfo * /* dflt */ ,
+ LEDInfo * /* oldLEDs */ ,
+ unsigned /* mergeMode */
+ );
+
+extern Bool CopyIndicatorMapDefs(XkbFileInfo * /* result */ ,
+ LEDInfo * /* leds */ ,
+ LEDInfo ** /* unboundRtrn */
+ );
+
+extern Bool BindIndicators(XkbFileInfo * /* result */ ,
+ Bool /* force */ ,
+ LEDInfo * /* unbound */ ,
+ LEDInfo ** /* unboundRtrn */
+ );
+
+#endif /* INDICATORS_H */
diff --git a/src/xkbcomp/keycodes.c b/src/xkbcomp/keycodes.c
new file mode 100644
index 0000000..1bff7fa
--- /dev/null
+++ b/src/xkbcomp/keycodes.c
@@ -0,0 +1,896 @@
+/************************************************************
+ 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 "keycodes.h"
+#include "misc.h"
+#include "alias.h"
+
+char *
+longText(unsigned long val, unsigned format)
+{
+ char buf[4];
+
+ LongToKeyName(val, buf);
+ return XkbKeyNameText(buf, format);
+}
+
+/***====================================================================***/
+
+void
+LongToKeyName(unsigned long val, char *name)
+{
+ name[0] = ((val >> 24) & 0xff);
+ name[1] = ((val >> 16) & 0xff);
+ name[2] = ((val >> 8) & 0xff);
+ name[3] = (val & 0xff);
+ return;
+}
+
+/***====================================================================***/
+
+typedef struct _IndicatorNameInfo
+{
+ CommonInfo defs;
+ int ndx;
+ Atom name;
+ Bool virtual;
+} IndicatorNameInfo;
+
+typedef struct _KeyNamesInfo
+{
+ char *name; /* e.g. evdev+aliases(qwerty) */
+ int errorCount;
+ unsigned fileID;
+ unsigned merge;
+ int computedMin; /* lowest keycode stored */
+ int computedMax; /* highest keycode stored */
+ int explicitMin;
+ int explicitMax;
+ int effectiveMin;
+ int effectiveMax;
+ unsigned long names[XkbMaxLegalKeyCode + 1]; /* 4-letter name of key, keycode is the index */
+ unsigned files[XkbMaxLegalKeyCode + 1];
+ unsigned char has_alt_forms[XkbMaxLegalKeyCode + 1];
+ IndicatorNameInfo *leds;
+ AliasInfo *aliases;
+} KeyNamesInfo;
+
+static void HandleKeycodesFile(XkbFile * file,
+ XkbDescPtr xkb,
+ unsigned merge,
+ KeyNamesInfo * info);
+
+static void
+InitIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info)
+{
+ ii->defs.defined = 0;
+ ii->defs.merge = info->merge;
+ ii->defs.fileID = info->fileID;
+ ii->defs.next = NULL;
+ ii->ndx = 0;
+ ii->name = None;
+ ii->virtual = False;
+ return;
+}
+
+static void
+ClearIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info)
+{
+ if (ii == info->leds)
+ {
+ ClearCommonInfo(&ii->defs);
+ info->leds = NULL;
+ }
+ return;
+}
+
+static IndicatorNameInfo *
+NextIndicatorName(KeyNamesInfo * info)
+{
+ IndicatorNameInfo *ii;
+
+ ii = uTypedAlloc(IndicatorNameInfo);
+ if (ii)
+ {
+ InitIndicatorNameInfo(ii, info);
+ info->leds = (IndicatorNameInfo *) AddCommonInfo(&info->leds->defs,
+ (CommonInfo *) ii);
+ }
+ return ii;
+}
+
+static IndicatorNameInfo *
+FindIndicatorByIndex(KeyNamesInfo * info, int ndx)
+{
+ IndicatorNameInfo *old;
+
+ for (old = info->leds; old != NULL;
+ old = (IndicatorNameInfo *) old->defs.next)
+ {
+ if (old->ndx == ndx)
+ return old;
+ }
+ return NULL;
+}
+
+static IndicatorNameInfo *
+FindIndicatorByName(KeyNamesInfo * info, Atom name)
+{
+ IndicatorNameInfo *old;
+
+ for (old = info->leds; old != NULL;
+ old = (IndicatorNameInfo *) old->defs.next)
+ {
+ if (old->name == name)
+ return old;
+ }
+ return NULL;
+}
+
+static Bool
+AddIndicatorName(KeyNamesInfo * info, IndicatorNameInfo * new)
+{
+ IndicatorNameInfo *old;
+ Bool replace;
+ const char *action;
+
+ replace = (new->defs.merge == MergeReplace) ||
+ (new->defs.merge == MergeOverride);
+ old = FindIndicatorByName(info, new->name);
+ if (old)
+ {
+ if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN1("Multiple indicators named %s\n",
+ XkbAtomText(NULL, new->name, XkbMessage));
+ if (old->ndx == new->ndx)
+ {
+ if (old->virtual != new->virtual)
+ {
+ if (replace)
+ old->virtual = new->virtual;
+ action = "Using %s instead of %s\n";
+ }
+ else
+ {
+ action = "Identical definitions ignored\n";
+ }
+ ACTION2(action, (old->virtual ? "virtual" : "real"),
+ (old->virtual ? "real" : "virtual"));
+ return True;
+ }
+ else
+ {
+ if (replace)
+ action = "Ignoring %d, using %d\n";
+ else
+ action = "Using %d, ignoring %d\n";
+ ACTION2(action, old->ndx, new->ndx);
+ }
+ if (replace)
+ {
+ if (info->leds == old)
+ info->leds = (IndicatorNameInfo *) old->defs.next;
+ else
+ {
+ IndicatorNameInfo *tmp;
+ tmp = info->leds;
+ for (; tmp != NULL;
+ tmp = (IndicatorNameInfo *) tmp->defs.next)
+ {
+ if (tmp->defs.next == (CommonInfo *) old)
+ {
+ tmp->defs.next = old->defs.next;
+ break;
+ }
+ }
+ }
+ uFree(old);
+ }
+ }
+ }
+ old = FindIndicatorByIndex(info, new->ndx);
+ if (old)
+ {
+ if (((old->defs.fileID == new->defs.fileID) && (warningLevel > 0))
+ || (warningLevel > 9))
+ {
+ WARN1("Multiple names for indicator %d\n", new->ndx);
+ if ((old->name == new->name) && (old->virtual == new->virtual))
+ action = "Identical definitions ignored\n";
+ else
+ {
+ const char *oldType, *newType;
+ Atom using, ignoring;
+ if (old->virtual)
+ oldType = "virtual indicator";
+ else
+ oldType = "real indicator";
+ if (new->virtual)
+ newType = "virtual indicator";
+ else
+ newType = "real indicator";
+ if (replace)
+ {
+ using = new->name;
+ ignoring = old->name;
+ }
+ else
+ {
+ using = old->name;
+ ignoring = new->name;
+ }
+ ACTION4("Using %s %s, ignoring %s %s\n",
+ oldType, XkbAtomText(NULL, using, XkbMessage),
+ newType, XkbAtomText(NULL, ignoring, XkbMessage));
+ }
+ }
+ if (replace)
+ {
+ old->name = new->name;
+ old->virtual = new->virtual;
+ }
+ return True;
+ }
+ old = new;
+ new = NextIndicatorName(info);
+ if (!new)
+ {
+ WSGO1("Couldn't allocate name for indicator %d\n", new->ndx);
+ ACTION("Ignored\n");
+ return False;
+ }
+ new->name = old->name;
+ new->ndx = old->ndx;
+ new->virtual = old->virtual;
+ return True;
+}
+
+static void
+ClearKeyNamesInfo(KeyNamesInfo * info)
+{
+ if (info->name != NULL)
+ uFree(info->name);
+ info->name = NULL;
+ info->computedMax = info->explicitMax = info->explicitMin = -1;
+ info->computedMin = 256;
+ info->effectiveMin = 8;
+ info->effectiveMax = 255;
+ bzero((char *) info->names, sizeof(info->names));
+ bzero((char *) info->files, sizeof(info->files));
+ bzero((char *) info->has_alt_forms, sizeof(info->has_alt_forms));
+ if (info->leds)
+ ClearIndicatorNameInfo(info->leds, info);
+ if (info->aliases)
+ ClearAliases(&info->aliases);
+ return;
+}
+
+static void
+InitKeyNamesInfo(KeyNamesInfo * info)
+{
+ info->name = NULL;
+ info->leds = NULL;
+ info->aliases = NULL;
+ ClearKeyNamesInfo(info);
+ info->errorCount = 0;
+ return;
+}
+
+static int
+FindKeyByLong(KeyNamesInfo * info, unsigned long name)
+{
+ register int i;
+
+ for (i = info->effectiveMin; i <= info->effectiveMax; i++)
+ {
+ if (info->names[i] == name)
+ return i;
+ }
+ return 0;
+}
+
+/**
+ * Store the name of the key as a long in the info struct under the given
+ * keycode. If the same keys is referred to twice, print a warning.
+ * Note that the key's name is stored as a long, the keycode is the index.
+ */
+static Bool
+AddKeyName(KeyNamesInfo * info,
+ int kc,
+ char *name, unsigned merge, unsigned fileID, Bool reportCollisions)
+{
+ int old;
+ unsigned long lval;
+
+ if ((kc < info->effectiveMin) || (kc > info->effectiveMax))
+ {
+ ERROR2("Illegal keycode %d for name <%s>\n", kc, name);
+ ACTION2("Must be in the range %d-%d inclusive\n",
+ info->effectiveMin, info->effectiveMax);
+ return False;
+ }
+ if (kc < info->computedMin)
+ info->computedMin = kc;
+ if (kc > info->computedMax)
+ info->computedMax = kc;
+ lval = KeyNameToLong(name);
+
+ if (reportCollisions)
+ {
+ reportCollisions = ((warningLevel > 7) ||
+ ((warningLevel > 0)
+ && (fileID == info->files[kc])));
+ }
+
+ if (info->names[kc] != 0)
+ {
+ char buf[6];
+
+ LongToKeyName(info->names[kc], buf);
+ buf[4] = '\0';
+ if (info->names[kc] == lval)
+ {
+ if (info->has_alt_forms[kc] || (merge == MergeAltForm))
+ {
+ info->has_alt_forms[kc] = True;
+ }
+ else if (reportCollisions)
+ {
+ WARN("Multiple identical key name definitions\n");
+ ACTION2("Later occurences of \"<%s> = %d\" ignored\n",
+ buf, kc);
+ }
+ return True;
+ }
+ if (merge == MergeAugment)
+ {
+ if (reportCollisions)
+ {
+ WARN1("Multiple names for keycode %d\n", kc);
+ ACTION2("Using <%s>, ignoring <%s>\n", buf, name);
+ }
+ return True;
+ }
+ else
+ {
+ if (reportCollisions)
+ {
+ WARN1("Multiple names for keycode %d\n", kc);
+ ACTION2("Using <%s>, ignoring <%s>\n", name, buf);
+ }
+ info->names[kc] = 0;
+ info->files[kc] = 0;
+ }
+ }
+ old = FindKeyByLong(info, lval);
+ if ((old != 0) && (old != kc))
+ {
+ if (merge == MergeOverride)
+ {
+ info->names[old] = 0;
+ info->files[old] = 0;
+ info->has_alt_forms[old] = True;
+ if (reportCollisions)
+ {
+ WARN1("Key name <%s> assigned to multiple keys\n", name);
+ ACTION2("Using %d, ignoring %d\n", kc, old);
+ }
+ }
+ else if (merge != MergeAltForm)
+ {
+ if ((reportCollisions) && (warningLevel > 3))
+ {
+ WARN1("Key name <%s> assigned to multiple keys\n", name);
+ ACTION2("Using %d, ignoring %d\n", old, kc);
+ ACTION
+ ("Use 'alternate' keyword to assign the same name to multiple keys\n");
+ }
+ return True;
+ }
+ else
+ {
+ info->has_alt_forms[old] = True;
+ }
+ }
+ info->names[kc] = lval;
+ info->files[kc] = fileID;
+ info->has_alt_forms[kc] = (merge == MergeAltForm);
+ return True;
+}
+
+/***====================================================================***/
+
+static void
+MergeIncludedKeycodes(KeyNamesInfo * into, KeyNamesInfo * from,
+ unsigned merge)
+{
+ register int i;
+ char buf[5];
+
+ if (from->errorCount > 0)
+ {
+ into->errorCount += from->errorCount;
+ return;
+ }
+ if (into->name == NULL)
+ {
+ into->name = from->name;
+ from->name = NULL;
+ }
+ for (i = from->computedMin; i <= from->computedMax; i++)
+ {
+ unsigned thisMerge;
+ if (from->names[i] == 0)
+ continue;
+ LongToKeyName(from->names[i], buf);
+ buf[4] = '\0';
+ if (from->has_alt_forms[i])
+ thisMerge = MergeAltForm;
+ else
+ thisMerge = merge;
+ if (!AddKeyName(into, i, buf, thisMerge, from->fileID, False))
+ into->errorCount++;
+ }
+ if (from->leds)
+ {
+ IndicatorNameInfo *led, *next;
+ for (led = from->leds; led != NULL; led = next)
+ {
+ if (merge != MergeDefault)
+ led->defs.merge = merge;
+ if (!AddIndicatorName(into, led))
+ into->errorCount++;
+ next = (IndicatorNameInfo *) led->defs.next;
+ }
+ }
+ if (!MergeAliases(&into->aliases, &from->aliases, merge))
+ into->errorCount++;
+ if (from->explicitMin > 0)
+ {
+ if ((into->explicitMin < 0)
+ || (into->explicitMin > from->explicitMin))
+ into->effectiveMin = into->explicitMin = from->explicitMin;
+ }
+ if (from->explicitMax > 0)
+ {
+ if ((into->explicitMax < 0)
+ || (into->explicitMax < from->explicitMax))
+ into->effectiveMax = into->explicitMax = from->explicitMax;
+ }
+ return;
+}
+
+/**
+ * Handle the given include statement (e.g. "include "evdev+aliases(qwerty)").
+ *
+ * @param stmt The include statement from the keymap file.
+ * @param xkb Unused for all but the xkb->flags.
+ * @param info Struct to store the key info in.
+ */
+static Bool
+HandleIncludeKeycodes(IncludeStmt * stmt, XkbDescPtr xkb, KeyNamesInfo * info)
+{
+ unsigned newMerge;
+ XkbFile *rtrn;
+ KeyNamesInfo included = {NULL};
+ Bool haveSelf;
+
+ haveSelf = False;
+ if ((stmt->file == NULL) && (stmt->map == NULL))
+ {
+ haveSelf = True;
+ included = *info;
+ bzero(info, sizeof(KeyNamesInfo));
+ }
+ else if (strcmp(stmt->file, "computed") == 0)
+ {
+ xkb->flags |= AutoKeyNames;
+ info->explicitMin = XkbMinLegalKeyCode;
+ info->explicitMax = XkbMaxLegalKeyCode;
+ return (info->errorCount == 0);
+ } /* parse file, store returned info in the xkb struct */
+ else if (ProcessIncludeFile(stmt, XkmKeyNamesIndex, &rtrn, &newMerge))
+ {
+ InitKeyNamesInfo(&included);
+ HandleKeycodesFile(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; /* XXX: why 10?? */
+ return False;
+ }
+ /* Do we have more than one include statement? */
+ if ((stmt->next != NULL) && (included.errorCount < 1))
+ {
+ IncludeStmt *next;
+ unsigned op;
+ KeyNamesInfo next_incl;
+
+ for (next = stmt->next; next != NULL; next = next->next)
+ {
+ if ((next->file == NULL) && (next->map == NULL))
+ {
+ haveSelf = True;
+ MergeIncludedKeycodes(&included, info, next->merge);
+ ClearKeyNamesInfo(info);
+ }
+ else if (ProcessIncludeFile(next, XkmKeyNamesIndex, &rtrn, &op))
+ {
+ InitKeyNamesInfo(&next_incl);
+ HandleKeycodesFile(rtrn, xkb, MergeOverride, &next_incl);
+ MergeIncludedKeycodes(&included, &next_incl, op);
+ ClearKeyNamesInfo(&next_incl);
+ }
+ else
+ {
+ info->errorCount += 10; /* XXX: Why 10?? */
+ return False;
+ }
+ }
+ }
+ if (haveSelf)
+ *info = included;
+ else
+ {
+ MergeIncludedKeycodes(info, &included, newMerge);
+ ClearKeyNamesInfo(&included);
+ }
+ return (info->errorCount == 0);
+}
+
+/**
+ * Parse the given statement and store the output in the info struct.
+ * e.g. <ESC> = 9
+ */
+static int
+HandleKeycodeDef(KeycodeDef * stmt, unsigned merge, KeyNamesInfo * info)
+{
+ int code;
+ ExprResult result;
+
+ if (!ExprResolveInteger(stmt->value, &result, NULL, NULL))
+ {
+ ACTION1("No value keycode assigned to name <%s>\n", stmt->name);
+ return 0;
+ }
+ code = result.ival;
+ if ((code < info->effectiveMin) || (code > info->effectiveMax))
+ {
+ ERROR2("Illegal keycode %d for name <%s>\n", code, stmt->name);
+ ACTION2("Must be in the range %d-%d inclusive\n",
+ info->effectiveMin, info->effectiveMax);
+ return 0;
+ }
+ if (stmt->merge != MergeDefault)
+ {
+ if (stmt->merge == MergeReplace)
+ merge = MergeOverride;
+ else
+ merge = stmt->merge;
+ }
+ return AddKeyName(info, code, stmt->name, merge, info->fileID, True);
+}
+
+#define MIN_KEYCODE_DEF 0
+#define MAX_KEYCODE_DEF 1
+
+/**
+ * Handle the minimum/maximum statement of the xkb file.
+ * Sets explicitMin/Max and effectiveMin/Max of the info struct.
+ *
+ * @return 1 on success, 0 otherwise.
+ */
+static int
+HandleKeyNameVar(VarDef * stmt, KeyNamesInfo * info)
+{
+ ExprResult tmp, field;
+ ExprDef *arrayNdx;
+ int which;
+
+ if (ExprResolveLhs(stmt->name, &tmp, &field, &arrayNdx) == 0)
+ return 0; /* internal error, already reported */
+
+ if (tmp.str != NULL)
+ {
+ ERROR1("Unknown element %s encountered\n", tmp.str);
+ ACTION1("Default for field %s ignored\n", field.str);
+ return 0;
+ }
+ if (uStrCaseCmp(field.str, "minimum") == 0)
+ which = MIN_KEYCODE_DEF;
+ else if (uStrCaseCmp(field.str, "maximum") == 0)
+ which = MAX_KEYCODE_DEF;
+ else
+ {
+ ERROR("Unknown field encountered\n");
+ ACTION1("Assigment to field %s ignored\n", field.str);
+ return 0;
+ }
+ if (arrayNdx != NULL)
+ {
+ ERROR1("The %s setting is not an array\n", field.str);
+ ACTION("Illegal array reference ignored\n");
+ return 0;
+ }
+
+ if (ExprResolveInteger(stmt->value, &tmp, NULL, NULL) == 0)
+ {
+ ACTION1("Assignment to field %s ignored\n", field.str);
+ return 0;
+ }
+ if ((tmp.ival < XkbMinLegalKeyCode) || (tmp.ival > XkbMaxLegalKeyCode))
+ {
+ ERROR3
+ ("Illegal keycode %d (must be in the range %d-%d inclusive)\n",
+ tmp.ival, XkbMinLegalKeyCode, XkbMaxLegalKeyCode);
+ ACTION1("Value of \"%s\" not changed\n", field.str);
+ return 0;
+ }
+ if (which == MIN_KEYCODE_DEF)
+ {
+ if ((info->explicitMax > 0) && (info->explicitMax < tmp.ival))
+ {
+ ERROR2
+ ("Minimum key code (%d) must be <= maximum key code (%d)\n",
+ tmp.ival, info->explicitMax);
+ ACTION("Minimum key code value not changed\n");
+ return 0;
+ }
+ if ((info->computedMax > 0) && (info->computedMin < tmp.ival))
+ {
+ ERROR2
+ ("Minimum key code (%d) must be <= lowest defined key (%d)\n",
+ tmp.ival, info->computedMin);
+ ACTION("Minimum key code value not changed\n");
+ return 0;
+ }
+ info->explicitMin = tmp.ival;
+ info->effectiveMin = tmp.ival;
+ }
+ if (which == MAX_KEYCODE_DEF)
+ {
+ if ((info->explicitMin > 0) && (info->explicitMin > tmp.ival))
+ {
+ ERROR2("Maximum code (%d) must be >= minimum key code (%d)\n",
+ tmp.ival, info->explicitMin);
+ ACTION("Maximum code value not changed\n");
+ return 0;
+ }
+ if ((info->computedMax > 0) && (info->computedMax > tmp.ival))
+ {
+ ERROR2
+ ("Maximum code (%d) must be >= highest defined key (%d)\n",
+ tmp.ival, info->computedMax);
+ ACTION("Maximum code value not changed\n");
+ return 0;
+ }
+ info->explicitMax = tmp.ival;
+ info->effectiveMax = tmp.ival;
+ }
+ return 1;
+}
+
+static int
+HandleIndicatorNameDef(IndicatorNameDef * def,
+ unsigned merge, KeyNamesInfo * info)
+{
+ IndicatorNameInfo ii;
+ ExprResult tmp;
+
+ if ((def->ndx < 1) || (def->ndx > XkbNumIndicators))
+ {
+ info->errorCount++;
+ ERROR1("Name specified for illegal indicator index %d\n", def->ndx);
+ ACTION("Ignored\n");
+ return False;
+ }
+ InitIndicatorNameInfo(&ii, info);
+ ii.ndx = def->ndx;
+ if (!ExprResolveString(def->name, &tmp, NULL, NULL))
+ {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", def->ndx);
+ info->errorCount++;
+ return ReportBadType("indicator", "name", buf, "string");
+ }
+ ii.name = XkbInternAtom(NULL, tmp.str, False);
+ ii.virtual = def->virtual;
+ if (!AddIndicatorName(info, &ii))
+ return False;
+ return True;
+}
+
+/**
+ * Handle the xkb_keycodes section of a xkb file.
+ * All information about parsed keys is stored in the info struct.
+ *
+ * Such a section may have include statements, in which case this function is
+ * semi-recursive (it calls HandleIncludeKeycodes, which may call
+ * HandleKeycodesFile again).
+ *
+ * @param file The input file (parsed xkb_keycodes section)
+ * @param xkb Necessary to pass down, may have flags changed.
+ * @param merge Merge strategy (MergeOverride, etc.)
+ * @param info Struct to contain the fully parsed key information.
+ */
+static void
+HandleKeycodesFile(XkbFile * file,
+ XkbDescPtr xkb, unsigned merge, KeyNamesInfo * info)
+{
+ ParseCommon *stmt;
+
+ info->name = uStringDup(file->name);
+ stmt = file->defs;
+ while (stmt)
+ {
+ switch (stmt->stmtType)
+ {
+ case StmtInclude: /* e.g. include "evdev+aliases(qwerty)" */
+ if (!HandleIncludeKeycodes((IncludeStmt *) stmt, xkb, info))
+ info->errorCount++;
+ break;
+ case StmtKeycodeDef: /* e.g. <ESC> = 9; */
+ if (!HandleKeycodeDef((KeycodeDef *) stmt, merge, info))
+ info->errorCount++;
+ break;
+ case StmtKeyAliasDef: /* e.g. alias <MENU> = <COMP>; */
+ if (!HandleAliasDef((KeyAliasDef *) stmt,
+ merge, info->fileID, &info->aliases))
+ info->errorCount++;
+ break;
+ case StmtVarDef: /* e.g. minimum, maximum */
+ if (!HandleKeyNameVar((VarDef *) stmt, info))
+ info->errorCount++;
+ break;
+ case StmtIndicatorNameDef: /* e.g. indicator 1 = "Caps Lock"; */
+ if (!HandleIndicatorNameDef((IndicatorNameDef *) stmt,
+ merge, info))
+ {
+ info->errorCount++;
+ }
+ break;
+ case StmtInterpDef:
+ case StmtVModDef:
+ ERROR("Keycode files may define key and indicator names only\n");
+ ACTION1("Ignoring definition of %s\n",
+ ((stmt->stmtType ==
+ StmtInterpDef) ? "a symbol interpretation" :
+ "virtual modifiers"));
+ info->errorCount++;
+ break;
+ default:
+ WSGO1("Unexpected statement type %d in HandleKeycodesFile\n",
+ stmt->stmtType);
+ break;
+ }
+ stmt = stmt->next;
+ if (info->errorCount > 10)
+ {
+#ifdef NOISY
+ ERROR("Too many errors\n");
+#endif
+ ACTION1("Abandoning keycodes file \"%s\"\n", file->topName);
+ break;
+ }
+ }
+ return;
+}
+
+/**
+ * Compile the xkb_keycodes section, parse it's output, return the results.
+ *
+ * @param file The parsed XKB file (may have include statements requiring
+ * further parsing)
+ * @param result The effective keycodes, as gathered from the file.
+ * @param merge Merge strategy.
+ *
+ * @return True on success, False otherwise.
+ */
+Bool
+CompileKeycodes(XkbFile * file, XkbFileInfo * result, unsigned merge)
+{
+ KeyNamesInfo info; /* contains all the info after parsing */
+ XkbDescPtr xkb;
+
+ xkb = result->xkb;
+ InitKeyNamesInfo(&info);
+ HandleKeycodesFile(file, xkb, merge, &info);
+
+ /* all the keys are now stored in info */
+
+ if (info.errorCount == 0)
+ {
+ if (info.explicitMin > 0) /* if "minimum" statement was present */
+ xkb->min_key_code = info.effectiveMin;
+ else
+ xkb->min_key_code = info.computedMin;
+ if (info.explicitMax > 0) /* if "maximum" statement was present */
+ xkb->max_key_code = info.effectiveMax;
+ else
+ xkb->max_key_code = info.computedMax;
+ if (XkbAllocNames(xkb, XkbKeyNamesMask | XkbIndicatorNamesMask, 0, 0)
+ == Success)
+ {
+ register int i;
+ xkb->names->keycodes = XkbInternAtom(xkb->dpy, info.name, False);
+ uDEBUG2(1, "key range: %d..%d\n", xkb->min_key_code,
+ xkb->max_key_code);
+ for (i = info.computedMin; i <= info.computedMax; i++)
+ {
+ LongToKeyName(info.names[i], xkb->names->keys[i].name);
+ uDEBUG2(2, "key %d = %s\n", i,
+ XkbKeyNameText(xkb->names->keys[i].name, XkbMessage));
+ }
+ }
+ else
+ {
+ WSGO("Cannot create XkbNamesRec in CompileKeycodes\n");
+ return False;
+ }
+ if (info.leds)
+ {
+ IndicatorNameInfo *ii;
+ if (XkbAllocIndicatorMaps(xkb) != Success)
+ {
+ WSGO("Couldn't allocate IndicatorRec in CompileKeycodes\n");
+ ACTION("Physical indicators not set\n");
+ }
+ for (ii = info.leds; ii != NULL;
+ ii = (IndicatorNameInfo *) ii->defs.next)
+ {
+ xkb->names->indicators[ii->ndx - 1] =
+ XkbInternAtom(xkb->dpy,
+ XkbAtomGetString(NULL, ii->name), False);
+ if (xkb->indicators != NULL)
+ {
+ register unsigned bit;
+ bit = 1 << (ii->ndx - 1);
+ if (ii->virtual)
+ xkb->indicators->phys_indicators &= ~bit;
+ else
+ xkb->indicators->phys_indicators |= bit;
+ }
+ }
+ }
+ if (info.aliases)
+ ApplyAliases(xkb, False, &info.aliases);
+ return True;
+ }
+ ClearKeyNamesInfo(&info);
+ return False;
+}
diff --git a/src/xkbcomp/keycodes.h b/src/xkbcomp/keycodes.h
new file mode 100644
index 0000000..11f4460
--- /dev/null
+++ b/src/xkbcomp/keycodes.h
@@ -0,0 +1,40 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifndef KEYCODES_H
+#define KEYCODES_H 1
+
+#define KeyNameToLong(n) ((((unsigned long)n[0])<<24)|(((unsigned long)n[1])<<16)|(((unsigned long)n[2])<<8)|n[3])
+
+extern char *longText(unsigned long /* val */ ,
+ unsigned /* format */
+ );
+
+extern void LongToKeyName(unsigned long /* val */ ,
+ char * /* name_rtrn */
+ );
+
+#endif /* KEYCODES_H */
diff --git a/src/xkbcomp/keymap.c b/src/xkbcomp/keymap.c
new file mode 100644
index 0000000..a419d8c
--- /dev/null
+++ b/src/xkbcomp/keymap.c
@@ -0,0 +1,183 @@
+/************************************************************
+ Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
+
+ Permission to use, copy, modify, and distribute this
+ software and its documentation for any purpose and without
+ fee is hereby granted, provided that the above copyright
+ notice appear in all copies and that both that copyright
+ notice and this permission notice appear in supporting
+ documentation, and that the name of Silicon Graphics not be
+ used in advertising or publicity pertaining to distribution
+ of the software without specific prior written permission.
+ Silicon Graphics makes no representation about the suitability
+ of this software for any purpose. It is provided "as is"
+ without any express or implied warranty.
+
+ SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
+ THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ********************************************************/
+
+#include "xkbcomp.h"
+#include "tokens.h"
+#include "expr.h"
+#include "vmod.h"
+#include "action.h"
+#include "misc.h"
+#include "indicators.h"
+
+#define KEYCODES 0
+#define GEOMETRY 1
+#define TYPES 2
+#define COMPAT 3
+#define SYMBOLS 4
+#define MAX_SECTIONS 5
+
+static XkbFile *sections[MAX_SECTIONS];
+
+/**
+ * Compile the given file and store the output in result.
+ * @param file A list of XkbFiles, each denoting one type (e.g.
+ * XkmKeyNamesIdx, etc.)
+ */
+Bool
+CompileKeymap(XkbFile * file, XkbFileInfo * result, unsigned merge)
+{
+ unsigned have;
+ Bool ok;
+ unsigned required, legal;
+ unsigned mainType;
+ char *mainName;
+ LEDInfo *unbound = NULL;
+
+ bzero(sections, MAX_SECTIONS * sizeof(XkbFile *));
+ mainType = file->type;
+ mainName = file->name;
+ switch (mainType)
+ {
+ case XkmSemanticsFile:
+ required = XkmSemanticsRequired;
+ legal = XkmSemanticsLegal;
+ break;
+ case XkmLayoutFile: /* standard type if setxkbmap -print */
+ required = XkmLayoutRequired;
+ legal = XkmKeymapLegal;
+ break;
+ case XkmKeymapFile:
+ required = XkmKeymapRequired;
+ legal = XkmKeymapLegal;
+ break;
+ default:
+ ERROR1("Cannot compile %s alone into an XKM file\n",
+ XkbConfigText(mainType, XkbMessage));
+ return False;
+ }
+ have = 0;
+ ok = 1;
+ file = (XkbFile *) file->defs;
+ /* Check for duplicate entries in the input file */
+ while ((file) && (ok))
+ {
+ file->topName = mainName;
+ if ((have & (1 << file->type)) != 0)
+ {
+ ERROR2("More than one %s section in a %s file\n",
+ XkbConfigText(file->type, XkbMessage),
+ XkbConfigText(mainType, XkbMessage));
+ ACTION("All sections after the first ignored\n");
+ ok = False;
+ }
+ else if ((1 << file->type) & (~legal))
+ {
+ ERROR2("Cannot define %s in a %s file\n",
+ XkbConfigText(file->type, XkbMessage),
+ XkbConfigText(mainType, XkbMessage));
+ ok = False;
+ }
+ else
+ switch (file->type)
+ {
+ case XkmSemanticsFile:
+ case XkmLayoutFile:
+ case XkmKeymapFile:
+ WSGO2("Illegal %s configuration in a %s file\n",
+ XkbConfigText(file->type, XkbMessage),
+ XkbConfigText(mainType, XkbMessage));
+ ACTION("Ignored\n");
+ ok = False;
+ break;
+ case XkmKeyNamesIndex:
+ sections[KEYCODES] = file;
+ break;
+ case XkmTypesIndex:
+ sections[TYPES] = file;
+ break;
+ case XkmSymbolsIndex:
+ sections[SYMBOLS] = file;
+ break;
+ case XkmCompatMapIndex:
+ sections[COMPAT] = file;
+ break;
+ case XkmGeometryIndex:
+ case XkmGeometryFile:
+ sections[GEOMETRY] = file;
+ break;
+ case XkmVirtualModsIndex:
+ case XkmIndicatorsIndex:
+ WSGO1("Found an isolated %s section\n",
+ XkbConfigText(file->type, XkbMessage));
+ break;
+ default:
+ WSGO1("Unknown file type %d\n", file->type);
+ break;
+ }
+ if (ok)
+ have |= (1 << file->type);
+ file = (XkbFile *) file->common.next;
+ }
+ /* compile the sections we have in the file one-by-one, or fail. */
+ if (ok)
+ {
+ if (ok && (sections[KEYCODES] != NULL))
+ ok = CompileKeycodes(sections[KEYCODES], result, MergeOverride);
+ if (ok && (sections[GEOMETRY] != NULL))
+ ok = CompileGeometry(sections[GEOMETRY], result, MergeOverride);
+ if (ok && (sections[TYPES] != NULL))
+ ok = CompileKeyTypes(sections[TYPES], result, MergeOverride);
+ if (ok && (sections[COMPAT] != NULL))
+ ok = CompileCompatMap(sections[COMPAT], result, MergeOverride,
+ &unbound);
+ if (ok && (sections[SYMBOLS] != NULL))
+ ok = CompileSymbols(sections[SYMBOLS], result, MergeOverride);
+ }
+ if (!ok)
+ return False;
+ result->defined = have;
+ if (required & (~have))
+ {
+ register int i, bit;
+ unsigned missing;
+ missing = required & (~have);
+ for (i = 0, bit = 1; missing != 0; i++, bit <<= 1)
+ {
+ if (missing & bit)
+ {
+ ERROR2("Missing %s section in a %s file\n",
+ XkbConfigText(i, XkbMessage),
+ XkbConfigText(mainType, XkbMessage));
+ missing &= ~bit;
+ }
+ }
+ ACTION1("Description of %s not compiled\n",
+ XkbConfigText(mainType, XkbMessage));
+ ok = False;
+ }
+ ok = BindIndicators(result, True, unbound, NULL);
+ return ok;
+}
diff --git a/src/xkbcomp/keytypes.c b/src/xkbcomp/keytypes.c
new file mode 100644
index 0000000..da55d75
--- /dev/null
+++ b/src/xkbcomp/keytypes.c
@@ -0,0 +1,1293 @@
+/************************************************************
+ Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
+
+ Permission to use, copy, modify, and distribute this
+ software and its documentation for any purpose and without
+ fee is hereby granted, provided that the above copyright
+ notice appear in all copies and that both that copyright
+ notice and this permission notice appear in supporting
+ documentation, and that the name of Silicon Graphics not be
+ used in advertising or publicity pertaining to distribution
+ of the software without specific prior written permission.
+ Silicon Graphics makes no representation about the suitability
+ of this software for any purpose. It is provided "as is"
+ without any express or implied warranty.
+
+ SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
+ THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ********************************************************/
+
+#include "xkbcomp.h"
+#include "tokens.h"
+#include "expr.h"
+#include "vmod.h"
+#include "action.h"
+#include "misc.h"
+
+typedef struct _PreserveInfo
+{
+ CommonInfo defs;
+ short matchingMapIndex;
+ unsigned char indexMods;
+ unsigned char preMods;
+ unsigned short indexVMods;
+ unsigned short preVMods;
+} PreserveInfo;
+
+#define _KT_Name (1<<0)
+#define _KT_Mask (1<<1)
+#define _KT_Map (1<<2)
+#define _KT_Preserve (1<<3)
+#define _KT_LevelNames (1<<4)
+
+typedef struct _KeyTypeInfo
+{
+ CommonInfo defs;
+ Display *dpy;
+ Atom name;
+ int fileID;
+ unsigned mask;
+ unsigned vmask;
+ Bool groupInfo;
+ int numLevels;
+ int nEntries;
+ int szEntries;
+ XkbKTMapEntryPtr entries;
+ PreserveInfo *preserve;
+ int szNames;
+ Atom *lvlNames;
+} KeyTypeInfo;
+
+typedef struct _KeyTypesInfo
+{
+ Display *dpy;
+ char *name;
+ int errorCount;
+ int fileID;
+ unsigned stdPresent;
+ int nTypes;
+ KeyTypeInfo *types;
+ KeyTypeInfo dflt;
+ VModInfo vmods;
+} KeyTypesInfo;
+
+Atom tok_ONE_LEVEL;
+Atom tok_TWO_LEVEL;
+Atom tok_ALPHABETIC;
+Atom tok_KEYPAD;
+
+/***====================================================================***/
+
+#define ReportTypeShouldBeArray(t,f) \
+ ReportShouldBeArray("key type",(f),TypeTxt(t))
+#define ReportTypeBadType(t,f,w) \
+ ReportBadType("key type",(f),TypeTxt(t),(w))
+
+/***====================================================================***/
+
+extern Bool AddMapEntry(XkbDescPtr /* xkb */ ,
+ KeyTypeInfo * /* type */ ,
+ XkbKTMapEntryPtr /* new */ ,
+ Bool /* clobber */ ,
+ Bool /* report */
+ );
+
+extern Bool AddPreserve(XkbDescPtr /* xkb */ ,
+ KeyTypeInfo * /* type */ ,
+ PreserveInfo * /* new */ ,
+ Bool /* clobber */ ,
+ Bool /* report */
+ );
+
+extern Bool AddLevelName(KeyTypeInfo * /* type */ ,
+ unsigned /* level */ ,
+ Atom /* name */ ,
+ Bool /* clobber */ ,
+ Bool /* report */
+ );
+
+#define MapEntryTxt(t,x,e) \
+ XkbVModMaskText((t)->dpy,(x),(e)->mods.real_mods,(e)->mods.vmods,XkbMessage)
+#define PreserveIndexTxt(t,x,p) \
+ XkbVModMaskText((t)->dpy,(x),(p)->indexMods,(p)->indexVMods,XkbMessage)
+#define PreserveTxt(t,x,p) \
+ XkbVModMaskText((t)->dpy,(x),(p)->preMods,(p)->preVMods,XkbMessage)
+#define TypeTxt(t) XkbAtomText((t)->dpy,(t)->name,XkbMessage)
+#define TypeMaskTxt(t,x) \
+ XkbVModMaskText((t)->dpy,(x),(t)->mask,(t)->vmask,XkbMessage)
+
+/***====================================================================***/
+
+static void
+InitKeyTypesInfo(KeyTypesInfo * info, XkbDescPtr xkb, KeyTypesInfo * from)
+{
+ tok_ONE_LEVEL = XkbInternAtom(NULL, "ONE_LEVEL", False);
+ tok_TWO_LEVEL = XkbInternAtom(NULL, "TWO_LEVEL", False);
+ tok_ALPHABETIC = XkbInternAtom(NULL, "ALPHABETIC", False);
+ tok_KEYPAD = XkbInternAtom(NULL, "KEYPAD", False);
+ info->dpy = NULL;
+ info->name = uStringDup("default");
+ info->errorCount = 0;
+ info->stdPresent = 0;
+ info->nTypes = 0;
+ info->types = NULL;
+ info->dflt.defs.defined = 0;
+ info->dflt.defs.fileID = 0;
+ info->dflt.defs.merge = MergeOverride;
+ info->dflt.defs.next = NULL;
+ info->dflt.name = None;
+ info->dflt.mask = 0;
+ info->dflt.vmask = 0;
+ info->dflt.groupInfo = False;
+ info->dflt.numLevels = 1;
+ info->dflt.nEntries = info->dflt.szEntries = 0;
+ info->dflt.entries = NULL;
+ info->dflt.szNames = 0;
+ info->dflt.lvlNames = NULL;
+ info->dflt.preserve = NULL;
+ InitVModInfo(&info->vmods, xkb);
+ if (from != NULL)
+ {
+ info->dpy = from->dpy;
+ info->dflt = from->dflt;
+ if (from->dflt.entries)
+ {
+ info->dflt.entries = uTypedCalloc(from->dflt.szEntries,
+ XkbKTMapEntryRec);
+ if (info->dflt.entries)
+ {
+ unsigned sz = from->dflt.nEntries * sizeof(XkbKTMapEntryRec);
+ memcpy(info->dflt.entries, from->dflt.entries, sz);
+ }
+ }
+ if (from->dflt.lvlNames)
+ {
+ info->dflt.lvlNames = uTypedCalloc(from->dflt.szNames, Atom);
+ if (info->dflt.lvlNames)
+ {
+ register unsigned sz = from->dflt.szNames * sizeof(Atom);
+ memcpy(info->dflt.lvlNames, from->dflt.lvlNames, sz);
+ }
+ }
+ if (from->dflt.preserve)
+ {
+ PreserveInfo *old, *new, *last;
+ last = NULL;
+ old = from->dflt.preserve;
+ for (; old; old = (PreserveInfo *) old->defs.next)
+ {
+ new = uTypedAlloc(PreserveInfo);
+ if (!new)
+ return;
+ *new = *old;
+ new->defs.next = NULL;
+ if (last)
+ last->defs.next = (CommonInfo *) new;
+ else
+ info->dflt.preserve = new;
+ last = new;
+ }
+ }
+ }
+ return;
+}
+
+static void
+FreeKeyTypeInfo(KeyTypeInfo * type)
+{
+ if (type->entries != NULL)
+ {
+ uFree(type->entries);
+ type->entries = NULL;
+ }
+ if (type->lvlNames != NULL)
+ {
+ uFree(type->lvlNames);
+ type->lvlNames = NULL;
+ }
+ if (type->preserve != NULL)
+ {
+ ClearCommonInfo(&type->preserve->defs);
+ type->preserve = NULL;
+ }
+ return;
+}
+
+static void
+FreeKeyTypesInfo(KeyTypesInfo * info)
+{
+ info->dpy = NULL;
+ if (info->name)
+ uFree(info->name);
+ info->name = NULL;
+ if (info->types)
+ {
+ register KeyTypeInfo *type;
+ for (type = info->types; type; type = (KeyTypeInfo *) type->defs.next)
+ {
+ FreeKeyTypeInfo(type);
+ }
+ info->types = (KeyTypeInfo *) ClearCommonInfo(&info->types->defs);
+ }
+ FreeKeyTypeInfo(&info->dflt);
+ return;
+}
+
+static KeyTypeInfo *
+NextKeyType(KeyTypesInfo * info)
+{
+ KeyTypeInfo *type;
+
+ type = uTypedAlloc(KeyTypeInfo);
+ if (type != NULL)
+ {
+ bzero(type, sizeof(KeyTypeInfo));
+ type->defs.fileID = info->fileID;
+ type->dpy = info->dpy;
+ info->types = (KeyTypeInfo *) AddCommonInfo(&info->types->defs,
+ (CommonInfo *) type);
+ info->nTypes++;
+ }
+ return type;
+}
+
+static KeyTypeInfo *
+FindMatchingKeyType(KeyTypesInfo * info, KeyTypeInfo * new)
+{
+ KeyTypeInfo *old;
+
+ for (old = info->types; old; old = (KeyTypeInfo *) old->defs.next)
+ {
+ if (old->name == new->name)
+ return old;
+ }
+ return NULL;
+}
+
+static Bool
+ReportTypeBadWidth(const char *type, int has, int needs)
+{
+ ERROR3("Key type \"%s\" has %d levels, must have %d\n", type, has, needs);
+ ACTION("Illegal type definition ignored\n");
+ return False;
+}
+
+static Bool
+AddKeyType(XkbDescPtr xkb, KeyTypesInfo * info, KeyTypeInfo * new)
+{
+ KeyTypeInfo *old;
+
+ if (new->name == tok_ONE_LEVEL)
+ {
+ if (new->numLevels > 1)
+ return ReportTypeBadWidth("ONE_LEVEL", new->numLevels, 1);
+ info->stdPresent |= XkbOneLevelMask;
+ }
+ else if (new->name == tok_TWO_LEVEL)
+ {
+ if (new->numLevels > 2)
+ return ReportTypeBadWidth("TWO_LEVEL", new->numLevels, 2);
+ else if (new->numLevels < 2)
+ new->numLevels = 2;
+ info->stdPresent |= XkbTwoLevelMask;
+ }
+ else if (new->name == tok_ALPHABETIC)
+ {
+ if (new->numLevels > 2)
+ return ReportTypeBadWidth("ALPHABETIC", new->numLevels, 2);
+ else if (new->numLevels < 2)
+ new->numLevels = 2;
+ info->stdPresent |= XkbAlphabeticMask;
+ }
+ else if (new->name == tok_KEYPAD)
+ {
+ if (new->numLevels > 2)
+ return ReportTypeBadWidth("KEYPAD", new->numLevels, 2);
+ else if (new->numLevels < 2)
+ new->numLevels = 2;
+ info->stdPresent |= XkbKeypadMask;
+ }
+
+ old = FindMatchingKeyType(info, new);
+ if (old != NULL)
+ {
+ Bool report;
+ if ((new->defs.merge == MergeReplace)
+ || (new->defs.merge == MergeOverride))
+ {
+ KeyTypeInfo *next = (KeyTypeInfo *) old->defs.next;
+ if (((old->defs.fileID == new->defs.fileID)
+ && (warningLevel > 0)) || (warningLevel > 9))
+ {
+ WARN1("Multiple definitions of the %s key type\n",
+ XkbAtomGetString(NULL, new->name));
+ ACTION("Earlier definition ignored\n");
+ }
+ FreeKeyTypeInfo(old);
+ *old = *new;
+ new->szEntries = new->nEntries = 0;
+ new->entries = NULL;
+ new->preserve = NULL;
+ new->lvlNames = NULL;
+ old->defs.next = &next->defs;
+ return True;
+ }
+ report = (old->defs.fileID == new->defs.fileID) && (warningLevel > 0);
+ if (report)
+ {
+ WARN1("Multiple definitions of the %s key type\n",
+ XkbAtomGetString(NULL, new->name));
+ ACTION("Later definition ignored\n");
+ }
+ FreeKeyTypeInfo(new);
+ return True;
+ }
+ old = NextKeyType(info);
+ if (old == NULL)
+ return False;
+ *old = *new;
+ old->defs.next = NULL;
+ new->nEntries = new->szEntries = 0;
+ new->entries = NULL;
+ new->szNames = 0;
+ new->lvlNames = NULL;
+ new->preserve = NULL;
+ return True;
+}
+
+/***====================================================================***/
+
+static void
+MergeIncludedKeyTypes(KeyTypesInfo * into,
+ KeyTypesInfo * from, unsigned merge, XkbDescPtr xkb)
+{
+ KeyTypeInfo *type;
+
+ if (from->errorCount > 0)
+ {
+ into->errorCount += from->errorCount;
+ return;
+ }
+ if (into->name == NULL)
+ {
+ into->name = from->name;
+ from->name = NULL;
+ }
+ for (type = from->types; type; type = (KeyTypeInfo *) type->defs.next)
+ {
+ if (merge != MergeDefault)
+ type->defs.merge = merge;
+ if (!AddKeyType(xkb, into, type))
+ into->errorCount++;
+ }
+ into->stdPresent |= from->stdPresent;
+ return;
+}
+
+typedef void (*FileHandler) (XkbFile * /* file */ ,
+ XkbDescPtr /* xkb */ ,
+ unsigned /* merge */ ,
+ KeyTypesInfo * /* included */
+ );
+
+static Bool
+HandleIncludeKeyTypes(IncludeStmt * stmt,
+ XkbDescPtr xkb, KeyTypesInfo * info, FileHandler hndlr)
+{
+ unsigned newMerge;
+ XkbFile *rtrn;
+ KeyTypesInfo included;
+ Bool haveSelf;
+
+ haveSelf = False;
+ if ((stmt->file == NULL) && (stmt->map == NULL))
+ {
+ haveSelf = True;
+ included = *info;
+ bzero(info, sizeof(KeyTypesInfo));
+ }
+ else if (ProcessIncludeFile(stmt, XkmTypesIndex, &rtrn, &newMerge))
+ {
+ InitKeyTypesInfo(&included, xkb, info);
+ included.fileID = included.dflt.defs.fileID = rtrn->id;
+ included.dflt.defs.merge = newMerge;
+
+ (*hndlr) (rtrn, xkb, newMerge, &included);
+ if (stmt->stmt != NULL)
+ {
+ if (included.name != NULL)
+ uFree(included.name);
+ included.name = stmt->stmt;
+ stmt->stmt = NULL;
+ }
+ }
+ else
+ {
+ info->errorCount += 10;
+ return False;
+ }
+ if ((stmt->next != NULL) && (included.errorCount < 1))
+ {
+ IncludeStmt *next;
+ unsigned op;
+ KeyTypesInfo next_incl;
+
+ for (next = stmt->next; next != NULL; next = next->next)
+ {
+ if ((next->file == NULL) && (next->map == NULL))
+ {
+ haveSelf = True;
+ MergeIncludedKeyTypes(&included, info, next->merge, xkb);
+ FreeKeyTypesInfo(info);
+ }
+ else if (ProcessIncludeFile(next, XkmTypesIndex, &rtrn, &op))
+ {
+ InitKeyTypesInfo(&next_incl, xkb, &included);
+ next_incl.fileID = next_incl.dflt.defs.fileID = rtrn->id;
+ next_incl.dflt.defs.merge = op;
+ (*hndlr) (rtrn, xkb, op, &next_incl);
+ MergeIncludedKeyTypes(&included, &next_incl, op, xkb);
+ FreeKeyTypesInfo(&next_incl);
+ }
+ else
+ {
+ info->errorCount += 10;
+ return False;
+ }
+ }
+ }
+ if (haveSelf)
+ *info = included;
+ else
+ {
+ MergeIncludedKeyTypes(info, &included, newMerge, xkb);
+ FreeKeyTypesInfo(&included);
+ }
+ return (info->errorCount == 0);
+}
+
+/***====================================================================***/
+
+static XkbKTMapEntryPtr
+FindMatchingMapEntry(KeyTypeInfo * type, unsigned mask, unsigned vmask)
+{
+ register int i;
+ XkbKTMapEntryPtr entry;
+
+ for (i = 0, entry = type->entries; i < type->nEntries; i++, entry++)
+ {
+ if ((entry->mods.real_mods == mask) && (entry->mods.vmods == vmask))
+ return entry;
+ }
+ return NULL;
+}
+
+static void
+DeleteLevel1MapEntries(KeyTypeInfo * type)
+{
+ register int i, n;
+
+ for (i = 0; i < type->nEntries; i++)
+ {
+ if (type->entries[i].level == 0)
+ {
+ for (n = i; n < type->nEntries - 1; n++)
+ {
+ type->entries[n] = type->entries[n + 1];
+ }
+ type->nEntries--;
+ }
+ }
+ return;
+}
+
+/**
+ * Return a pointer to the next free XkbKTMapEntry, reallocating space if
+ * necessary.
+ */
+static XkbKTMapEntryPtr
+NextMapEntry(KeyTypeInfo * type)
+{
+ if (type->entries == NULL)
+ {
+ type->entries = uTypedCalloc(2, XkbKTMapEntryRec);
+ if (type->entries == NULL)
+ {
+ ERROR1("Couldn't allocate map entries for %s\n", TypeTxt(type));
+ ACTION("Map entries lost\n");
+ return NULL;
+ }
+ type->szEntries = 2;
+ type->nEntries = 0;
+ }
+ else if (type->nEntries >= type->szEntries)
+ {
+ type->szEntries *= 2;
+ type->entries = uTypedRecalloc(type->entries,
+ type->nEntries, type->szEntries,
+ XkbKTMapEntryRec);
+ if (type->entries == NULL)
+ {
+ ERROR1("Couldn't reallocate map entries for %s\n", TypeTxt(type));
+ ACTION("Map entries lost\n");
+ return NULL;
+ }
+ }
+ return &type->entries[type->nEntries++];
+}
+
+Bool
+AddPreserve(XkbDescPtr xkb,
+ KeyTypeInfo * type, PreserveInfo * new, Bool clobber, Bool report)
+{
+ PreserveInfo *old;
+
+ old = type->preserve;
+ while (old != NULL)
+ {
+ if ((old->indexMods != new->indexMods) ||
+ (old->indexVMods != new->indexVMods))
+ {
+ old = (PreserveInfo *) old->defs.next;
+ continue;
+ }
+ if ((old->preMods == new->preMods)
+ && (old->preVMods == new->preVMods))
+ {
+ if (warningLevel > 9)
+ {
+ WARN2("Identical definitions for preserve[%s] in %s\n",
+ PreserveIndexTxt(type, xkb, old), TypeTxt(type));
+ ACTION("Ignored\n");
+ }
+ return True;
+ }
+ if (report && (warningLevel > 0))
+ {
+ char *str;
+ WARN2("Multiple definitions for preserve[%s] in %s\n",
+ PreserveIndexTxt(type, xkb, old), TypeTxt(type));
+
+ if (clobber)
+ str = PreserveTxt(type, xkb, new);
+ else
+ str = PreserveTxt(type, xkb, old);
+ ACTION1("Using %s, ", str);
+ if (clobber)
+ str = PreserveTxt(type, xkb, old);
+ else
+ str = PreserveTxt(type, xkb, new);
+ INFO1("ignoring %s\n", str);
+ }
+ if (clobber)
+ {
+ old->preMods = new->preMods;
+ old->preVMods = new->preVMods;
+ }
+ return True;
+ }
+ old = uTypedAlloc(PreserveInfo);
+ if (!old)
+ {
+ WSGO1("Couldn't allocate preserve in %s\n", TypeTxt(type));
+ ACTION1("Preserve[%s] lost\n", PreserveIndexTxt(type, xkb, old));
+ return False;
+ }
+ *old = *new;
+ old->matchingMapIndex = -1;
+ type->preserve =
+ (PreserveInfo *) AddCommonInfo(&type->preserve->defs, &old->defs);
+ return True;
+}
+
+/**
+ * Add a new KTMapEntry to the given key type. If an entry with the same mods
+ * already exists, the level is updated (if clobber is TRUE). Otherwise, a new
+ * entry is created.
+ *
+ * @param clobber Overwrite existing entry.
+ * @param report True if a warning is to be printed on.
+ */
+Bool
+AddMapEntry(XkbDescPtr xkb,
+ KeyTypeInfo * type,
+ XkbKTMapEntryPtr new, Bool clobber, Bool report)
+{
+ XkbKTMapEntryPtr old;
+
+ if ((old =
+ FindMatchingMapEntry(type, new->mods.real_mods, new->mods.vmods)))
+ {
+ if (report && (old->level != new->level))
+ {
+ unsigned use, ignore;
+ if (clobber)
+ {
+ use = new->level + 1;
+ ignore = old->level + 1;
+ }
+ else
+ {
+ use = old->level + 1;
+ ignore = new->level + 1;
+ }
+ WARN2("Multiple map entries for %s in %s\n",
+ MapEntryTxt(type, xkb, new), TypeTxt(type));
+ ACTION2("Using %d, ignoring %d\n", use, ignore);
+ }
+ else if (warningLevel > 9)
+ {
+ WARN3("Multiple occurences of map[%s]= %d in %s\n",
+ MapEntryTxt(type, xkb, new), new->level + 1, TypeTxt(type));
+ ACTION("Ignored\n");
+ return True;
+ }
+ if (clobber)
+ old->level = new->level;
+ return True;
+ }
+ if ((old = NextMapEntry(type)) == NULL)
+ return False; /* allocation failure, already reported */
+ if (new->level >= type->numLevels)
+ type->numLevels = new->level + 1;
+ if (new->mods.vmods == 0)
+ old->active = True;
+ else
+ old->active = False;
+ old->mods.mask = new->mods.real_mods;
+ old->mods.real_mods = new->mods.real_mods;
+ old->mods.vmods = new->mods.vmods;
+ old->level = new->level;
+ return True;
+}
+
+static LookupEntry lnames[] = {
+ {"level1", 1},
+ {"level2", 2},
+ {"level3", 3},
+ {"level4", 4},
+ {"level5", 5},
+ {"level6", 6},
+ {"level7", 7},
+ {"level8", 8},
+ {NULL, 0}
+};
+
+static Bool
+SetMapEntry(KeyTypeInfo * type,
+ XkbDescPtr xkb, ExprDef * arrayNdx, ExprDef * value)
+{
+ ExprResult rtrn;
+ XkbKTMapEntryRec entry;
+
+ if (arrayNdx == NULL)
+ return ReportTypeShouldBeArray(type, "map entry");
+ if (!ExprResolveModMask(arrayNdx, &rtrn, LookupVModMask, (XPointer) xkb))
+ return ReportTypeBadType(type, "map entry", "modifier mask");
+ entry.mods.real_mods = rtrn.uval & 0xff; /* modifiers < 512 */
+ entry.mods.vmods = (rtrn.uval >> 8) & 0xffff; /* modifiers > 512 */
+ if ((entry.mods.real_mods & (~type->mask)) ||
+ ((entry.mods.vmods & (~type->vmask)) != 0))
+ {
+ if (warningLevel > 0)
+ {
+ WARN1("Map entry for unused modifiers in %s\n", TypeTxt(type));
+ ACTION1("Using %s instead of ",
+ XkbVModMaskText(type->dpy, xkb,
+ entry.mods.real_mods & type->mask,
+ entry.mods.vmods & type->vmask,
+ XkbMessage));
+ INFO1("%s\n", MapEntryTxt(type, xkb, &entry));
+ }
+ entry.mods.real_mods &= type->mask;
+ entry.mods.vmods &= type->vmask;
+ }
+ if (!ExprResolveInteger(value, &rtrn, SimpleLookup, (XPointer) lnames))
+ {
+ ERROR("Level specifications in a key type must be integer\n");
+ ACTION("Ignoring malformed level specification\n");
+ return False;
+ }
+ if ((rtrn.ival < 1) || (rtrn.ival > XkbMaxShiftLevel + 1))
+ {
+ ERROR3("Shift level %d out of range (1..%d) in key type %s\n",
+ XkbMaxShiftLevel + 1, rtrn.ival, TypeTxt(type));
+ ACTION1("Ignoring illegal definition of map[%s]\n",
+ MapEntryTxt(type, xkb, &entry));
+ return False;
+ }
+ entry.level = rtrn.ival - 1;
+ return AddMapEntry(xkb, type, &entry, True, True);
+}
+
+static Bool
+SetPreserve(KeyTypeInfo * type,
+ XkbDescPtr xkb, ExprDef * arrayNdx, ExprDef * value)
+{
+ ExprResult rtrn;
+ PreserveInfo new;
+
+ if (arrayNdx == NULL)
+ return ReportTypeShouldBeArray(type, "preserve entry");
+ if (!ExprResolveModMask(arrayNdx, &rtrn, LookupVModMask, (XPointer) xkb))
+ return ReportTypeBadType(type, "preserve entry", "modifier mask");
+ new.defs = type->defs;
+ new.defs.next = NULL;
+ new.indexMods = rtrn.uval & 0xff;
+ new.indexVMods = (rtrn.uval >> 8) & 0xffff;
+ if ((new.indexMods & (~type->mask)) || (new.indexVMods & (~type->vmask)))
+ {
+ if (warningLevel > 0)
+ {
+ WARN1("Preserve for modifiers not used by the %s type\n",
+ TypeTxt(type));
+ ACTION1("Index %s converted to ",
+ PreserveIndexTxt(type, xkb, &new));
+ }
+ new.indexMods &= type->mask;
+ new.indexVMods &= type->vmask;
+ if (warningLevel > 0)
+ INFO1("%s\n", PreserveIndexTxt(type, xkb, &new));
+ }
+ if (!ExprResolveModMask(value, &rtrn, LookupVModMask, (XPointer) xkb))
+ {
+ ERROR("Preserve value in a key type is not a modifier mask\n");
+ ACTION2("Ignoring preserve[%s] in type %s\n",
+ PreserveIndexTxt(type, xkb, &new), TypeTxt(type));
+ return False;
+ }
+ new.preMods = rtrn.uval & 0xff;
+ new.preVMods = (rtrn.uval >> 16) & 0xffff;
+ if ((new.preMods & (~new.indexMods))
+ || (new.preVMods && (~new.indexVMods)))
+ {
+ if (warningLevel > 0)
+ {
+ WARN2("Illegal value for preserve[%s] in type %s\n",
+ PreserveTxt(type, xkb, &new), TypeTxt(type));
+ ACTION1("Converted %s to ", PreserveIndexTxt(type, xkb, &new));
+ }
+ new.preMods &= new.indexMods;
+ new.preVMods &= new.indexVMods;
+ if (warningLevel > 0)
+ {
+ INFO1("%s\n", PreserveIndexTxt(type, xkb, &new));
+ }
+ }
+ return AddPreserve(xkb, type, &new, True, True);
+}
+
+/***====================================================================***/
+
+Bool
+AddLevelName(KeyTypeInfo * type,
+ unsigned level, Atom name, Bool clobber, Bool report)
+{
+ if ((type->lvlNames == NULL) || (type->szNames <= level))
+ {
+ type->lvlNames =
+ uTypedRecalloc(type->lvlNames, type->szNames, level + 1, Atom);
+ if (type->lvlNames == NULL)
+ {
+ ERROR1("Couldn't allocate level names for type %s\n",
+ TypeTxt(type));
+ ACTION("Level names lost\n");
+ type->szNames = 0;
+ return False;
+ }
+ type->szNames = level + 1;
+ }
+ else if (type->lvlNames[level] == name)
+ {
+ if (warningLevel > 9)
+ {
+ WARN2("Duplicate names for level %d of key type %s\n",
+ level + 1, TypeTxt(type));
+ ACTION("Ignored\n");
+ }
+ return True;
+ }
+ else if (type->lvlNames[level] != None)
+ {
+ if (warningLevel > 0)
+ {
+ char *old, *new;
+ old = XkbAtomText(type->dpy, type->lvlNames[level], XkbMessage);
+ new = XkbAtomText(type->dpy, name, XkbMessage);
+ WARN2("Multiple names for level %d of key type %s\n",
+ level + 1, TypeTxt(type));
+ if (clobber)
+ ACTION2("Using %s, ignoring %s\n", new, old);
+ else
+ ACTION2("Using %s, ignoring %s\n", old, new);
+ }
+ if (!clobber)
+ return True;
+ }
+ if (level >= type->numLevels)
+ type->numLevels = level + 1;
+ type->lvlNames[level] = name;
+ return True;
+}
+
+static Bool
+SetLevelName(KeyTypeInfo * type, ExprDef * arrayNdx, ExprDef * value)
+{
+ ExprResult rtrn;
+ unsigned level;
+
+ if (arrayNdx == NULL)
+ return ReportTypeShouldBeArray(type, "level name");
+ if (!ExprResolveInteger(arrayNdx, &rtrn, SimpleLookup, (XPointer) lnames))
+ return ReportTypeBadType(type, "level name", "integer");
+ if ((rtrn.ival < 1) || (rtrn.ival > XkbMaxShiftLevel + 1))
+ {
+ ERROR3("Level name %d out of range (1..%d) in key type %s\n",
+ rtrn.ival,
+ XkbMaxShiftLevel + 1,
+ XkbAtomText(type->dpy, type->name, XkbMessage));
+ ACTION("Ignoring illegal level name definition\n");
+ return False;
+ }
+ level = rtrn.ival - 1;
+ if (!ExprResolveString(value, &rtrn, NULL, NULL))
+ {
+ ERROR2("Non-string name for level %d in key type %s\n", level + 1,
+ XkbAtomText(type->dpy, type->name, XkbMessage));
+ ACTION("Ignoring illegal level name definition\n");
+ return False;
+ }
+ return
+ AddLevelName(type, level, XkbInternAtom(NULL, rtrn.str, False), True,
+ True);
+}
+
+/***====================================================================***/
+
+/**
+ * Parses the fields in a type "..." { } description.
+ *
+ * @param field The field to parse (e.g. modifiers, map, level_name)
+ */
+static Bool
+SetKeyTypeField(KeyTypeInfo * type,
+ XkbDescPtr xkb,
+ char *field,
+ ExprDef * arrayNdx, ExprDef * value, KeyTypesInfo * info)
+{
+ ExprResult tmp;
+
+ if (uStrCaseCmp(field, "modifiers") == 0)
+ {
+ unsigned mods, vmods;
+ if (arrayNdx != NULL)
+ {
+ WARN("The modifiers field of a key type is not an array\n");
+ ACTION("Illegal array subscript ignored\n");
+ }
+ /* get modifier mask for current type */
+ if (!ExprResolveModMask(value, &tmp, LookupVModMask, (XPointer) xkb))
+ {
+ ERROR("Key type mask field must be a modifier mask\n");
+ ACTION("Key type definition ignored\n");
+ return False;
+ }
+ mods = tmp.uval & 0xff; /* core mods */
+ vmods = (tmp.uval >> 8) & 0xffff; /* xkb virtual mods */
+ if (type->defs.defined & _KT_Mask)
+ {
+ WARN1("Multiple modifier mask definitions for key type %s\n",
+ XkbAtomText(type->dpy, type->name, XkbMessage));
+ ACTION1("Using %s, ", TypeMaskTxt(type, xkb));
+ INFO1("ignoring %s\n", XkbVModMaskText(type->dpy, xkb, mods,
+ vmods, XkbMessage));
+ return False;
+ }
+ type->mask = mods;
+ type->vmask = vmods;
+ type->defs.defined |= _KT_Mask;
+ return True;
+ }
+ else if (uStrCaseCmp(field, "map") == 0)
+ {
+ type->defs.defined |= _KT_Map;
+ return SetMapEntry(type, xkb, arrayNdx, value);
+ }
+ else if (uStrCaseCmp(field, "preserve") == 0)
+ {
+ type->defs.defined |= _KT_Preserve;
+ return SetPreserve(type, xkb, arrayNdx, value);
+ }
+ else if ((uStrCaseCmp(field, "levelname") == 0) ||
+ (uStrCaseCmp(field, "level_name") == 0))
+ {
+ type->defs.defined |= _KT_LevelNames;
+ return SetLevelName(type, arrayNdx, value);
+ }
+ ERROR2("Unknown field %s in key type %s\n", field, TypeTxt(type));
+ ACTION("Definition ignored\n");
+ return False;
+}
+
+static Bool
+HandleKeyTypeVar(VarDef * stmt, XkbDescPtr xkb, KeyTypesInfo * info)
+{
+ ExprResult elem, field;
+ ExprDef *arrayNdx;
+
+ if (!ExprResolveLhs(stmt->name, &elem, &field, &arrayNdx))
+ return False; /* internal error, already reported */
+ if (elem.str && (uStrCaseCmp(elem.str, "type") == 0))
+ return SetKeyTypeField(&info->dflt, xkb, field.str, arrayNdx,
+ stmt->value, info);
+ if (elem.str != NULL)
+ {
+ ERROR1("Default for unknown element %s\n", uStringText(elem.str));
+ ACTION1("Value for field %s ignored\n", uStringText(field.str));
+ }
+ else if (field.str != NULL)
+ {
+ ERROR1("Default defined for unknown field %s\n",
+ uStringText(field.str));
+ ACTION("Ignored\n");
+ }
+ return False;
+}
+
+static int
+HandleKeyTypeBody(VarDef * def,
+ XkbDescPtr xkb, KeyTypeInfo * type, KeyTypesInfo * info)
+{
+ int ok = 1;
+ ExprResult tmp, field;
+ ExprDef *arrayNdx;
+
+ for (; def != NULL; def = (VarDef *) def->common.next)
+ {
+ if ((def->name) && (def->name->type == ExprFieldRef))
+ {
+ ok = HandleKeyTypeVar(def, xkb, info);
+ continue;
+ }
+ ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
+ if (ok)
+ ok = SetKeyTypeField(type, xkb, field.str, arrayNdx, def->value,
+ info);
+ }
+ return ok;
+}
+
+/**
+ * Process a type "XYZ" { } specification in the xkb_types section.
+ *
+ */
+static int
+HandleKeyTypeDef(KeyTypeDef * def,
+ XkbDescPtr xkb, unsigned merge, KeyTypesInfo * info)
+{
+ register int i;
+ KeyTypeInfo type;
+
+ if (def->merge != MergeDefault)
+ merge = def->merge;
+
+ type.defs.defined = 0;
+ type.defs.fileID = info->fileID;
+ type.defs.merge = merge;
+ type.defs.next = NULL;
+ type.dpy = info->dpy;
+ type.name = def->name;
+ type.mask = info->dflt.mask;
+ type.vmask = info->dflt.vmask;
+ type.groupInfo = info->dflt.groupInfo;
+ type.numLevels = 1;
+ type.nEntries = type.szEntries = 0;
+ type.entries = NULL;
+ type.szNames = 0;
+ type.lvlNames = NULL;
+ type.preserve = NULL;
+
+ /* Parse the actual content. */
+ if (!HandleKeyTypeBody(def->body, xkb, &type, info))
+ {
+ info->errorCount++;
+ return False;
+ }
+
+ /* now copy any appropriate map, preserve or level names from the */
+ /* default type */
+ for (i = 0; i < info->dflt.nEntries; i++)
+ {
+ XkbKTMapEntryPtr dflt;
+ dflt = &info->dflt.entries[i];
+ if (((dflt->mods.real_mods & type.mask) == dflt->mods.real_mods) &&
+ ((dflt->mods.vmods & type.vmask) == dflt->mods.vmods))
+ {
+ AddMapEntry(xkb, &type, dflt, False, False);
+ }
+ }
+ if (info->dflt.preserve)
+ {
+ PreserveInfo *dflt = info->dflt.preserve;
+ while (dflt)
+ {
+ if (((dflt->indexMods & type.mask) == dflt->indexMods) &&
+ ((dflt->indexVMods & type.vmask) == dflt->indexVMods))
+ {
+ AddPreserve(xkb, &type, dflt, False, False);
+ }
+ dflt = (PreserveInfo *) dflt->defs.next;
+ }
+ }
+ for (i = 0; i < info->dflt.szNames; i++)
+ {
+ if ((i < type.numLevels) && (info->dflt.lvlNames[i] != None))
+ {
+ AddLevelName(&type, i, info->dflt.lvlNames[i], False, False);
+ }
+ }
+ /* Now add the new keytype to the info struct */
+ if (!AddKeyType(xkb, info, &type))
+ {
+ info->errorCount++;
+ return False;
+ }
+ return True;
+}
+
+/**
+ * Process an xkb_types section.
+ *
+ * @param file The parsed xkb_types section.
+ * @param merge Merge Strategy (e.g. MergeOverride)
+ * @param info Pointer to memory where the outcome will be stored.
+ */
+static void
+HandleKeyTypesFile(XkbFile * file,
+ XkbDescPtr xkb, unsigned merge, KeyTypesInfo * info)
+{
+ ParseCommon *stmt;
+
+ info->name = uStringDup(file->name);
+ stmt = file->defs;
+ while (stmt)
+ {
+ switch (stmt->stmtType)
+ {
+ case StmtInclude:
+ if (!HandleIncludeKeyTypes((IncludeStmt *) stmt, xkb, info,
+ HandleKeyTypesFile))
+ info->errorCount++;
+ break;
+ case StmtKeyTypeDef: /* e.g. type "ONE_LEVEL" */
+ if (!HandleKeyTypeDef((KeyTypeDef *) stmt, xkb, merge, info))
+ info->errorCount++;
+ break;
+ case StmtVarDef:
+ if (!HandleKeyTypeVar((VarDef *) stmt, xkb, info))
+ info->errorCount++;
+ break;
+ case StmtVModDef: /* virtual_modifiers NumLock, ... */
+ if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
+ info->errorCount++;
+ break;
+ case StmtKeyAliasDef:
+ ERROR("Key type files may not include other declarations\n");
+ ACTION("Ignoring definition of key alias\n");
+ info->errorCount++;
+ break;
+ case StmtKeycodeDef:
+ ERROR("Key type files may not include other declarations\n");
+ ACTION("Ignoring definition of key name\n");
+ info->errorCount++;
+ break;
+ case StmtInterpDef:
+ ERROR("Key type files may not include other declarations\n");
+ ACTION("Ignoring definition of symbol interpretation\n");
+ info->errorCount++;
+ break;
+ default:
+ WSGO1("Unexpected statement type %d in HandleKeyTypesFile\n",
+ stmt->stmtType);
+ break;
+ }
+ stmt = stmt->next;
+ if (info->errorCount > 10)
+ {
+#ifdef NOISY
+ ERROR("Too many errors\n");
+#endif
+ ACTION1("Abandoning keytypes file \"%s\"\n", file->topName);
+ break;
+ }
+ }
+ return;
+}
+
+static Bool
+CopyDefToKeyType(XkbDescPtr xkb, XkbKeyTypePtr type, KeyTypeInfo * def)
+{
+ register int i;
+ PreserveInfo *pre;
+
+ for (pre = def->preserve; pre != NULL;
+ pre = (PreserveInfo *) pre->defs.next)
+ {
+ XkbKTMapEntryPtr match;
+ XkbKTMapEntryRec tmp;
+ tmp.mods.real_mods = pre->indexMods;
+ tmp.mods.vmods = pre->indexVMods;
+ tmp.level = 0;
+ AddMapEntry(xkb, def, &tmp, False, False);
+ match = FindMatchingMapEntry(def, pre->indexMods, pre->indexVMods);
+ if (!match)
+ {
+ WSGO("Couldn't find matching entry for preserve\n");
+ ACTION("Aborting\n");
+ return False;
+ }
+ pre->matchingMapIndex = match - def->entries;
+ }
+ type->mods.real_mods = def->mask;
+ type->mods.vmods = def->vmask;
+ type->num_levels = def->numLevels;
+ type->map_count = def->nEntries;
+ type->map = def->entries;
+ if (def->preserve)
+ {
+ type->preserve = uTypedCalloc(type->map_count, XkbModsRec);
+ if (!type->preserve)
+ {
+ WARN("Couldn't allocate preserve array in CopyDefToKeyType\n");
+ ACTION1("Preserve setting for type %s lost\n",
+ XkbAtomText(def->dpy, def->name, XkbMessage));
+ }
+ else
+ {
+ pre = def->preserve;
+ for (; pre != NULL; pre = (PreserveInfo *) pre->defs.next)
+ {
+ int ndx = pre->matchingMapIndex;
+ type->preserve[ndx].mask = pre->preMods;
+ type->preserve[ndx].real_mods = pre->preMods;
+ type->preserve[ndx].vmods = pre->preVMods;
+ }
+ }
+ }
+ else
+ type->preserve = NULL;
+ type->name = (Atom) def->name;
+ if (def->szNames > 0)
+ {
+ type->level_names = uTypedCalloc(def->numLevels, Atom);
+
+ /* assert def->szNames<=def->numLevels */
+ for (i = 0; i < def->szNames; i++)
+ {
+ type->level_names[i] = (Atom) def->lvlNames[i];
+ }
+ }
+ else
+ {
+ type->level_names = NULL;
+ }
+
+ def->nEntries = def->szEntries = 0;
+ def->entries = NULL;
+ return XkbComputeEffectiveMap(xkb, type, NULL);
+}
+
+Bool
+CompileKeyTypes(XkbFile * file, XkbFileInfo * result, unsigned merge)
+{
+ KeyTypesInfo info;
+ XkbDescPtr xkb;
+
+ xkb = result->xkb;
+ InitKeyTypesInfo(&info, xkb, NULL);
+ info.fileID = file->id;
+ HandleKeyTypesFile(file, xkb, merge, &info);
+
+ if (info.errorCount == 0)
+ {
+ register int i;
+ register KeyTypeInfo *def;
+ register XkbKeyTypePtr type, next;
+
+ if (info.name != NULL)
+ {
+ if (XkbAllocNames(xkb, XkbTypesNameMask, 0, 0) == Success)
+ xkb->names->types = XkbInternAtom(xkb->dpy, info.name, False);
+ else
+ {
+ WSGO("Couldn't allocate space for types name\n");
+ ACTION2("Name \"%s\" (from %s) NOT assigned\n",
+ scanFile, info.name);
+ }
+ }
+ i = info.nTypes;
+ if ((info.stdPresent & XkbOneLevelMask) == 0)
+ i++;
+ if ((info.stdPresent & XkbTwoLevelMask) == 0)
+ i++;
+ if ((info.stdPresent & XkbKeypadMask) == 0)
+ i++;
+ if ((info.stdPresent & XkbAlphabeticMask) == 0)
+ i++;
+ if (XkbAllocClientMap(xkb, XkbKeyTypesMask, i) != Success)
+ {
+ WSGO("Couldn't allocate client map\n");
+ ACTION("Exiting\n");
+ return False;
+ }
+ xkb->map->num_types = i;
+ if (XkbAllRequiredTypes & (~info.stdPresent))
+ {
+ unsigned missing, keypadVMod;
+
+ missing = XkbAllRequiredTypes & (~info.stdPresent);
+ keypadVMod = FindKeypadVMod(xkb);
+ if (XkbInitCanonicalKeyTypes(xkb, missing, keypadVMod) != Success)
+ {
+ WSGO("Couldn't initialize canonical key types\n");
+ ACTION("Exiting\n");
+ return False;
+ }
+ if (missing & XkbOneLevelMask)
+ xkb->map->types[XkbOneLevelIndex].name = tok_ONE_LEVEL;
+ if (missing & XkbTwoLevelMask)
+ xkb->map->types[XkbTwoLevelIndex].name = tok_TWO_LEVEL;
+ if (missing & XkbAlphabeticMask)
+ xkb->map->types[XkbAlphabeticIndex].name = tok_ALPHABETIC;
+ if (missing & XkbKeypadMask)
+ xkb->map->types[XkbKeypadIndex].name = tok_KEYPAD;
+ }
+ next = &xkb->map->types[XkbLastRequiredType + 1];
+ for (i = 0, def = info.types; i < info.nTypes; i++)
+ {
+ if (def->name == tok_ONE_LEVEL)
+ type = &xkb->map->types[XkbOneLevelIndex];
+ else if (def->name == tok_TWO_LEVEL)
+ type = &xkb->map->types[XkbTwoLevelIndex];
+ else if (def->name == tok_ALPHABETIC)
+ type = &xkb->map->types[XkbAlphabeticIndex];
+ else if (def->name == tok_KEYPAD)
+ type = &xkb->map->types[XkbKeypadIndex];
+ else
+ type = next++;
+ DeleteLevel1MapEntries(def);
+ if (!CopyDefToKeyType(xkb, type, def))
+ return False;
+ def = (KeyTypeInfo *) def->defs.next;
+ }
+ return True;
+ }
+ return False;
+}
diff --git a/src/xkbcomp/listing.c b/src/xkbcomp/listing.c
new file mode 100644
index 0000000..146ecba
--- /dev/null
+++ b/src/xkbcomp/listing.c
@@ -0,0 +1,495 @@
+/************************************************************
+ Copyright 1996 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.
+
+ ********************************************************/
+/***********************************************************
+
+Copyright 1988, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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 <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <X11/keysym.h>
+
+#if defined(sgi)
+#include <malloc.h>
+#endif
+
+#define DEBUG_VAR listingDebug
+#include "xkbcomp.h"
+#include <stdlib.h>
+
+#ifdef _POSIX_SOURCE
+# include <limits.h>
+#else
+# define _POSIX_SOURCE
+# include <limits.h>
+# undef _POSIX_SOURCE
+#endif
+
+#ifndef PATH_MAX
+#ifdef WIN32
+#define PATH_MAX 512
+#else
+#include <sys/param.h>
+#endif
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+#endif
+
+#ifdef WIN32
+# include <windows.h>
+# define FileName(file) file.cFileName
+# undef TEXT
+# undef ALTERNATE
+#else
+# include <dirent.h>
+# define FileName(file) file->d_name
+#endif
+
+#include "xkbpath.h"
+#include "parseutils.h"
+#include "misc.h"
+#include "tokens.h"
+#include <X11/extensions/XKBgeom.h>
+
+#define lowbit(x) ((x) & (-(x)))
+
+unsigned int listingDebug;
+
+static int szListing = 0;
+static int nListed = 0;
+static int nFilesListed = 0;
+
+typedef struct _Listing
+{
+ char *file;
+ char *map;
+} Listing;
+
+static int szMapOnly;
+static int nMapOnly;
+static char **mapOnly;
+
+static Listing *list = NULL;
+
+/***====================================================================***/
+
+int
+AddMapOnly(char *map)
+{
+ if (nMapOnly >= szMapOnly)
+ {
+ if (szMapOnly < 1)
+ szMapOnly = 5;
+ else
+ szMapOnly *= 2;
+ mapOnly = uTypedRealloc(list, szMapOnly, char *);
+ if (!mapOnly)
+ {
+ WSGO("Couldn't allocate list of maps\n");
+ return 0;
+ }
+ }
+ mapOnly[nMapOnly++] = map;
+ return 1;
+}
+
+int
+AddListing(char *file, char *map)
+{
+ if (nListed >= szListing)
+ {
+ if (szListing < 1)
+ szListing = 10;
+ else
+ szListing *= 2;
+ list = uTypedRealloc(list, szListing, Listing);
+ if (!list)
+ {
+ WSGO("Couldn't allocate list of files and maps\n");
+ ACTION("Exiting\n");
+ exit(1);
+ }
+ }
+
+ list[nListed].file = file;
+ list[nListed].map = map;
+ nListed++;
+ if (file != NULL)
+ nFilesListed++;
+ return 1;
+}
+
+/***====================================================================***/
+
+static void
+ListFile(FILE * outFile, char *fileName, XkbFile * map)
+{
+ register unsigned flags;
+ char *mapName;
+
+ flags = map->flags;
+ if ((flags & XkbLC_Hidden) && (!(verboseLevel & WantHiddenMaps)))
+ return;
+ if ((flags & XkbLC_Partial) && (!(verboseLevel & WantPartialMaps)))
+ return;
+ if (verboseLevel & WantLongListing)
+ {
+ fprintf(outFile, (flags & XkbLC_Hidden) ? "h" : "-");
+ fprintf(outFile, (flags & XkbLC_Default) ? "d" : "-");
+ fprintf(outFile, (flags & XkbLC_Partial) ? "p" : "-");
+ fprintf(outFile, "----- ");
+ if (map->type == XkmSymbolsIndex)
+ {
+ fprintf(outFile, (flags & XkbLC_AlphanumericKeys) ? "a" : "-");
+ fprintf(outFile, (flags & XkbLC_ModifierKeys) ? "m" : "-");
+ fprintf(outFile, (flags & XkbLC_KeypadKeys) ? "k" : "-");
+ fprintf(outFile, (flags & XkbLC_FunctionKeys) ? "f" : "-");
+ fprintf(outFile, (flags & XkbLC_AlternateGroup) ? "g" : "-");
+ fprintf(outFile, "--- ");
+ }
+ else
+ fprintf(outFile, "-------- ");
+ }
+ mapName = map->name;
+ if ((!(verboseLevel & WantFullNames)) && ((flags & XkbLC_Default) != 0))
+ mapName = NULL;
+ if (dirsToStrip > 0)
+ {
+ char *tmp, *last;
+ int i;
+ for (i = 0, tmp = last = fileName; (i < dirsToStrip) && tmp; i++)
+ {
+ last = tmp;
+ tmp = strchr(tmp, '/');
+ if (tmp != NULL)
+ tmp++;
+ }
+ fileName = (tmp ? tmp : last);
+ }
+ if (mapName)
+ fprintf(outFile, "%s(%s)\n", fileName, mapName);
+ else
+ fprintf(outFile, "%s\n", fileName);
+ return;
+}
+
+/***====================================================================***/
+
+static int
+AddDirectory(char *head, char *ptrn, char *rest, char *map)
+{
+#ifdef WIN32
+ HANDLE dirh;
+ WIN32_FIND_DATA file;
+#else
+ DIR *dirp;
+ struct dirent *file;
+#endif
+ int nMatch;
+
+ if (map == NULL)
+ {
+ char *tmp = ptrn;
+ if ((rest == NULL) && (ptrn != NULL) && (strchr(ptrn, '/') == NULL))
+ {
+ tmp = ptrn;
+ map = strchr(ptrn, '(');
+ }
+ else if ((rest == NULL) && (ptrn == NULL) &&
+ (head != NULL) && (strchr(head, '/') == NULL))
+ {
+ tmp = head;
+ map = strchr(head, '(');
+ }
+ if (map != NULL)
+ {
+ tmp = strchr(tmp, ')');
+ if ((tmp == NULL) || (tmp[1] != '\0'))
+ {
+ ERROR1("File and map must have the format file(map)\n");
+ return 0;
+ }
+ *map = '\0';
+ map++;
+ *tmp = '\0';
+ }
+ }
+#ifdef WIN32
+ if ((dirh = FindFirstFile("*.*", &file)) == INVALID_HANDLE_VALUE)
+ return 0;
+#else
+ if ((dirp = opendir((head ? head : "."))) == NULL)
+ return 0;
+ nMatch = 0;
+#endif
+#ifdef WIN32
+ do
+#else
+ while ((file = readdir(dirp)) != NULL)
+#endif
+ {
+ char *tmp, *filename;
+ struct stat sbuf;
+
+ filename = FileName(file);
+ if (!filename || filename[0] == '.')
+ continue;
+ if (ptrn && (!XkbNameMatchesPattern(filename, ptrn)))
+ continue;
+ tmp =
+ (char *) uAlloc((head ? strlen(head) : 0) + strlen(filename) + 2);
+ if (!tmp)
+ continue;
+ sprintf(tmp, "%s%s%s", (head ? head : ""), (head ? "/" : ""),
+ filename);
+ if (stat(tmp, &sbuf) < 0)
+ {
+ uFree(tmp);
+ continue;
+ }
+ if (((rest != NULL) && (!S_ISDIR(sbuf.st_mode))) ||
+ ((map != NULL) && (S_ISDIR(sbuf.st_mode))))
+ {
+ uFree(tmp);
+ continue;
+ }
+ if (S_ISDIR(sbuf.st_mode))
+ {
+ if ((rest != NULL) || (verboseLevel & ListRecursive))
+ nMatch += AddDirectory(tmp, rest, NULL, map);
+ }
+ else
+ nMatch += AddListing(tmp, map);
+ }
+#ifdef WIN32
+ while (FindNextFile(dirh, &file));
+#endif
+ return nMatch;
+}
+
+/***====================================================================***/
+
+Bool
+AddMatchingFiles(char *head_in)
+{
+ char *str, *head, *ptrn, *rest = NULL;
+
+ if (head_in == NULL)
+ return 0;
+ ptrn = NULL;
+ for (str = head_in; (*str != '\0') && (*str != '?') && (*str != '*');
+ str++)
+ {
+ if ((str != head_in) && (*str == '/'))
+ ptrn = str;
+ }
+ if (*str == '\0')
+ { /* no wildcards */
+ head = head_in;
+ ptrn = NULL;
+ rest = NULL;
+ }
+ else if (ptrn == NULL)
+ { /* no slash before the first wildcard */
+ head = NULL;
+ ptrn = head_in;
+ }
+ else
+ { /* slash followed by wildcard */
+ head = head_in;
+ *ptrn = '\0';
+ ptrn++;
+ }
+ if (ptrn)
+ {
+ rest = strchr(ptrn, '/');
+ if (rest != NULL)
+ {
+ *rest = '\0';
+ rest++;
+ }
+ }
+ if (((rest && ptrn)
+ && ((strchr(ptrn, '(') != NULL) || (strchr(ptrn, ')') != NULL)))
+ || (head
+ && ((strchr(head, '(') != NULL) || (strchr(head, ')') != NULL))))
+ {
+ ERROR1("Files/maps to list must have the form file(map)\n");
+ ACTION("Illegal specifier ignored\n");
+ return 0;
+ }
+ return AddDirectory(head, ptrn, rest, NULL);
+}
+
+/***====================================================================***/
+
+static Bool
+MapMatches(char *mapToConsider, char *ptrn)
+{
+ int i;
+
+ if (ptrn != NULL)
+ return XkbNameMatchesPattern(mapToConsider, ptrn);
+ if (nMapOnly < 1)
+ return True;
+ for (i = 0; i < nMapOnly; i++)
+ {
+ if (XkbNameMatchesPattern(mapToConsider, mapOnly[i]))
+ return True;
+ }
+ return False;
+}
+
+int
+GenerateListing(char *out_name)
+{
+ int i;
+ FILE *inputFile, *outFile;
+ XkbFile *rtrn, *mapToUse;
+ unsigned oldWarningLevel;
+ char *mapName;
+
+ if (nFilesListed < 1)
+ {
+ ERROR1("Must specify at least one file or pattern to list\n");
+ return 0;
+ }
+ if ((!out_name) || ((out_name[0] == '-') && (out_name[1] == '\0')))
+ outFile = stdout;
+ else if ((outFile = fopen(out_name, "w")) == NULL)
+ {
+ ERROR1("Cannot open \"%s\" to write keyboard description\n",
+ out_name);
+ ACTION("Exiting\n");
+ return 0;
+ }
+#ifdef DEBUG
+ if (warningLevel > 9)
+ fprintf(stderr, "should list:\n");
+#endif
+ for (i = 0; i < nListed; i++)
+ {
+#ifdef DEBUG
+ if (warningLevel > 9)
+ {
+ fprintf(stderr, "%s(%s)\n",
+ (list[i].file ? list[i].file : "*"),
+ (list[i].map ? list[i].map : "*"));
+ }
+#endif
+ oldWarningLevel = warningLevel;
+ warningLevel = 0;
+ if (list[i].file)
+ {
+ struct stat sbuf;
+
+ if (stat(list[i].file, &sbuf) < 0)
+ {
+ if (oldWarningLevel > 5)
+ WARN1("Couldn't open \"%s\"\n", list[i].file);
+ continue;
+ }
+ if (S_ISDIR(sbuf.st_mode))
+ {
+ if (verboseLevel & ListRecursive)
+ AddDirectory(list[i].file, NULL, NULL, NULL);
+ continue;
+ }
+
+ inputFile = fopen(list[i].file, "r");
+ if (!inputFile)
+ {
+ if (oldWarningLevel > 5)
+ WARN1("Couldn't open \"%s\"\n", list[i].file);
+ continue;
+ }
+ setScanState(list[i].file, 1);
+ if (XKBParseFile(inputFile, &rtrn) && (rtrn != NULL))
+ {
+ mapName = list[i].map;
+ mapToUse = rtrn;
+ for (; mapToUse; mapToUse = (XkbFile *) mapToUse->common.next)
+ {
+ if (!MapMatches(mapToUse->name, mapName))
+ continue;
+ ListFile(outFile, list[i].file, mapToUse);
+ }
+ }
+ fclose(inputFile);
+ }
+ warningLevel = oldWarningLevel;
+ }
+ return 1;
+}
diff --git a/src/xkbcomp/misc.c b/src/xkbcomp/misc.c
new file mode 100644
index 0000000..0e4f61d
--- /dev/null
+++ b/src/xkbcomp/misc.c
@@ -0,0 +1,576 @@
+/************************************************************
+ 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 "xkbpath.h"
+#include "tokens.h"
+#include "keycodes.h"
+#include "misc.h"
+#include <X11/keysym.h>
+#include "parseutils.h"
+
+#include <X11/extensions/XKBgeom.h>
+
+/***====================================================================***/
+
+/**
+ * Open the file given in the include statement and parse it's content.
+ * If the statement defines a specific map to use, this map is returned in
+ * file_rtrn. Otherwise, the default map is returned.
+ *
+ * @param stmt The include statement, specifying the file name to look for.
+ * @param file_type Type of file (XkmKeyNamesIdx, etc.)
+ * @param file_rtrn Returns the key map to be used.
+ * @param merge_rtrn Always returns stmt->merge.
+ *
+ * @return True on success or False otherwise.
+ */
+Bool
+ProcessIncludeFile(IncludeStmt * stmt,
+ unsigned file_type,
+ XkbFile ** file_rtrn, unsigned *merge_rtrn)
+{
+ FILE *file;
+ XkbFile *rtrn, *mapToUse;
+ char oldFile[1024] = {0};
+ int oldLine = lineNum;
+
+ rtrn = XkbFindFileInCache(stmt->file, file_type, &stmt->path);
+ if (rtrn == NULL)
+ {
+ /* file not in cache, open it, parse it and store it in cache for next
+ time. */
+ file = XkbFindFileInPath(stmt->file, file_type, &stmt->path);
+ if (file == NULL)
+ {
+ ERROR2("Can't find file \"%s\" for %s include\n", stmt->file,
+ XkbDirectoryForInclude(file_type));
+ ACTION("Exiting\n");
+ return False;
+ }
+ strcpy(oldFile, scanFile);
+ oldLine = lineNum;
+ setScanState(stmt->file, 1);
+ if (debugFlags & 2)
+ INFO1("About to parse include file %s\n", stmt->file);
+ /* parse the file */
+ if ((XKBParseFile(file, &rtrn) == 0) || (rtrn == NULL))
+ {
+ setScanState(oldFile, oldLine);
+ ERROR1("Error interpreting include file \"%s\"\n", stmt->file);
+ ACTION("Exiting\n");
+ fclose(file);
+ return False;
+ }
+ fclose(file);
+ XkbAddFileToCache(stmt->file, file_type, stmt->path, rtrn);
+ }
+ mapToUse = rtrn;
+ if (stmt->map != NULL)
+ {
+ while ((mapToUse) && ((!uStringEqual(mapToUse->name, stmt->map)) ||
+ (mapToUse->type != file_type)))
+ {
+ mapToUse = (XkbFile *) mapToUse->common.next;
+ }
+ if (!mapToUse)
+ {
+ ERROR3("No %s named \"%s\" in the include file \"%s\"\n",
+ XkbConfigText(file_type, XkbMessage), stmt->map,
+ stmt->file);
+ ACTION("Exiting\n");
+ return False;
+ }
+ }
+ else if ((rtrn->common.next != NULL) && (warningLevel > 5))
+ {
+ WARN1("No map in include statement, but \"%s\" contains several\n",
+ stmt->file);
+ ACTION1("Using first defined map, \"%s\"\n", rtrn->name);
+ }
+ setScanState(oldFile, oldLine);
+ if (mapToUse->type != file_type)
+ {
+ ERROR2("Include file wrong type (expected %s, got %s)\n",
+ XkbConfigText(file_type, XkbMessage),
+ XkbConfigText(mapToUse->type, XkbMessage));
+ ACTION1("Include file \"%s\" ignored\n", stmt->file);
+ return False;
+ }
+ /* FIXME: we have to check recursive includes here (or somewhere) */
+
+ mapToUse->compiled = True;
+ *file_rtrn = mapToUse;
+ *merge_rtrn = stmt->merge;
+ return True;
+}
+
+/***====================================================================***/
+
+int
+ReportNotArray(const char *type, const char *field, const char *name)
+{
+ ERROR2("The %s %s field is not an array\n", type, field);
+ ACTION1("Ignoring illegal assignment in %s\n", name);
+ return False;
+}
+
+int
+ReportShouldBeArray(const char *type, const char *field, char *name)
+{
+ ERROR2("Missing subscript for %s %s\n", type, field);
+ ACTION1("Ignoring illegal assignment in %s\n", name);
+ return False;
+}
+
+int
+ReportBadType(const char *type, const char *field,
+ const char *name, const char *wanted)
+{
+ ERROR3("The %s %s field must be a %s\n", type, field, wanted);
+ ACTION1("Ignoring illegal assignment in %s\n", name);
+ return False;
+}
+
+int
+ReportBadIndexType(char *type, char *field, char *name, char *wanted)
+{
+ ERROR3("Index for the %s %s field must be a %s\n", type, field, wanted);
+ ACTION1("Ignoring assignment to illegal field in %s\n", name);
+ return False;
+}
+
+int
+ReportBadField(const char *type, const char *field, const char *name)
+{
+ ERROR3("Unknown %s field %s in %s\n", type, field, name);
+ ACTION1("Ignoring assignment to unknown field in %s\n", name);
+ return False;
+}
+
+int
+ReportMultipleDefs(char *type, char *field, char *name)
+{
+ WARN3("Multiple definitions of %s in %s \"%s\"\n", field, type, name);
+ ACTION("Using last definition\n");
+ return False;
+}
+
+/***====================================================================***/
+
+Bool
+UseNewField(unsigned field,
+ CommonInfo * oldDefs, CommonInfo * newDefs, unsigned *pCollide)
+{
+ Bool useNew;
+
+ useNew = False;
+ if (oldDefs->defined & field)
+ {
+ if (newDefs->defined & field)
+ {
+ if (((oldDefs->fileID == newDefs->fileID)
+ && (warningLevel > 0)) || (warningLevel > 9))
+ {
+ *pCollide |= field;
+ }
+ if (newDefs->merge != MergeAugment)
+ useNew = True;
+ }
+ }
+ else if (newDefs->defined & field)
+ useNew = True;
+ return useNew;
+}
+
+Bool
+MergeNewField(unsigned field,
+ CommonInfo * oldDefs, CommonInfo * newDefs, unsigned *pCollide)
+{
+ if ((oldDefs->defined & field) && (newDefs->defined & field))
+ {
+ if (((oldDefs->fileID == newDefs->fileID) && (warningLevel > 0)) ||
+ (warningLevel > 9))
+ {
+ *pCollide |= field;
+ }
+ if (newDefs->merge == MergeAugment)
+ return True;
+ }
+ return False;
+}
+
+XPointer
+ClearCommonInfo(CommonInfo * cmn)
+{
+ if (cmn != NULL)
+ {
+ CommonInfo *this, *next;
+ for (this = cmn; this != NULL; this = next)
+ {
+ next = this->next;
+ uFree(this);
+ }
+ }
+ return NULL;
+}
+
+XPointer
+AddCommonInfo(CommonInfo * old, CommonInfo * new)
+{
+ CommonInfo *first;
+
+ first = old;
+ while (old && old->next)
+ {
+ old = old->next;
+ }
+ new->next = NULL;
+ if (old)
+ {
+ old->next = new;
+ return (XPointer) first;
+ }
+ return (XPointer) new;
+}
+
+/***====================================================================***/
+
+typedef struct _KeyNameDesc
+{
+ KeySym level1;
+ KeySym level2;
+ char name[5];
+ Bool used;
+} KeyNameDesc;
+
+static KeyNameDesc dfltKeys[] = {
+ {XK_Escape, NoSymbol, "ESC\0"},
+ {XK_quoteleft, XK_asciitilde, "TLDE"},
+ {XK_1, XK_exclam, "AE01"},
+ {XK_2, XK_at, "AE02"},
+ {XK_3, XK_numbersign, "AE03"},
+ {XK_4, XK_dollar, "AE04"},
+ {XK_5, XK_percent, "AE05"},
+ {XK_6, XK_asciicircum, "AE06"},
+ {XK_7, XK_ampersand, "AE07"},
+ {XK_8, XK_asterisk, "AE08"},
+ {XK_9, XK_parenleft, "AE09"},
+ {XK_0, XK_parenright, "AE10"},
+ {XK_minus, XK_underscore, "AE11"},
+ {XK_equal, XK_plus, "AE12"},
+ {XK_BackSpace, NoSymbol, "BKSP"},
+ {XK_Tab, NoSymbol, "TAB\0"},
+ {XK_q, XK_Q, "AD01"},
+ {XK_w, XK_W, "AD02"},
+ {XK_e, XK_E, "AD03"},
+ {XK_r, XK_R, "AD04"},
+ {XK_t, XK_T, "AD05"},
+ {XK_y, XK_Y, "AD06"},
+ {XK_u, XK_U, "AD07"},
+ {XK_i, XK_I, "AD08"},
+ {XK_o, XK_O, "AD09"},
+ {XK_p, XK_P, "AD10"},
+ {XK_bracketleft, XK_braceleft, "AD11"},
+ {XK_bracketright, XK_braceright, "AD12"},
+ {XK_Return, NoSymbol, "RTRN"},
+ {XK_Caps_Lock, NoSymbol, "CAPS"},
+ {XK_a, XK_A, "AC01"},
+ {XK_s, XK_S, "AC02"},
+ {XK_d, XK_D, "AC03"},
+ {XK_f, XK_F, "AC04"},
+ {XK_g, XK_G, "AC05"},
+ {XK_h, XK_H, "AC06"},
+ {XK_j, XK_J, "AC07"},
+ {XK_k, XK_K, "AC08"},
+ {XK_l, XK_L, "AC09"},
+ {XK_semicolon, XK_colon, "AC10"},
+ {XK_quoteright, XK_quotedbl, "AC11"},
+ {XK_Shift_L, NoSymbol, "LFSH"},
+ {XK_z, XK_Z, "AB01"},
+ {XK_x, XK_X, "AB02"},
+ {XK_c, XK_C, "AB03"},
+ {XK_v, XK_V, "AB04"},
+ {XK_b, XK_B, "AB05"},
+ {XK_n, XK_N, "AB06"},
+ {XK_m, XK_M, "AB07"},
+ {XK_comma, XK_less, "AB08"},
+ {XK_period, XK_greater, "AB09"},
+ {XK_slash, XK_question, "AB10"},
+ {XK_backslash, XK_bar, "BKSL"},
+ {XK_Control_L, NoSymbol, "LCTL"},
+ {XK_space, NoSymbol, "SPCE"},
+ {XK_Shift_R, NoSymbol, "RTSH"},
+ {XK_Alt_L, NoSymbol, "LALT"},
+ {XK_space, NoSymbol, "SPCE"},
+ {XK_Control_R, NoSymbol, "RCTL"},
+ {XK_Alt_R, NoSymbol, "RALT"},
+ {XK_F1, NoSymbol, "FK01"},
+ {XK_F2, NoSymbol, "FK02"},
+ {XK_F3, NoSymbol, "FK03"},
+ {XK_F4, NoSymbol, "FK04"},
+ {XK_F5, NoSymbol, "FK05"},
+ {XK_F6, NoSymbol, "FK06"},
+ {XK_F7, NoSymbol, "FK07"},
+ {XK_F8, NoSymbol, "FK08"},
+ {XK_F9, NoSymbol, "FK09"},
+ {XK_F10, NoSymbol, "FK10"},
+ {XK_F11, NoSymbol, "FK11"},
+ {XK_F12, NoSymbol, "FK12"},
+ {XK_Print, NoSymbol, "PRSC"},
+ {XK_Scroll_Lock, NoSymbol, "SCLK"},
+ {XK_Pause, NoSymbol, "PAUS"},
+ {XK_Insert, NoSymbol, "INS\0"},
+ {XK_Home, NoSymbol, "HOME"},
+ {XK_Prior, NoSymbol, "PGUP"},
+ {XK_Delete, NoSymbol, "DELE"},
+ {XK_End, NoSymbol, "END"},
+ {XK_Next, NoSymbol, "PGDN"},
+ {XK_Up, NoSymbol, "UP\0\0"},
+ {XK_Left, NoSymbol, "LEFT"},
+ {XK_Down, NoSymbol, "DOWN"},
+ {XK_Right, NoSymbol, "RGHT"},
+ {XK_Num_Lock, NoSymbol, "NMLK"},
+ {XK_KP_Divide, NoSymbol, "KPDV"},
+ {XK_KP_Multiply, NoSymbol, "KPMU"},
+ {XK_KP_Subtract, NoSymbol, "KPSU"},
+ {NoSymbol, XK_KP_7, "KP7\0"},
+ {NoSymbol, XK_KP_8, "KP8\0"},
+ {NoSymbol, XK_KP_9, "KP9\0"},
+ {XK_KP_Add, NoSymbol, "KPAD"},
+ {NoSymbol, XK_KP_4, "KP4\0"},
+ {NoSymbol, XK_KP_5, "KP5\0"},
+ {NoSymbol, XK_KP_6, "KP6\0"},
+ {NoSymbol, XK_KP_1, "KP1\0"},
+ {NoSymbol, XK_KP_2, "KP2\0"},
+ {NoSymbol, XK_KP_3, "KP3\0"},
+ {XK_KP_Enter, NoSymbol, "KPEN"},
+ {NoSymbol, XK_KP_0, "KP0\0"},
+ {XK_KP_Delete, NoSymbol, "KPDL"},
+ {XK_less, XK_greater, "LSGT"},
+ {XK_KP_Separator, NoSymbol, "KPCO"},
+ {XK_Find, NoSymbol, "FIND"},
+ {NoSymbol, NoSymbol, "\0\0\0\0"}
+};
+
+Status
+ComputeKbdDefaults(XkbDescPtr xkb)
+{
+ Status rtrn;
+ register int i, tmp, nUnknown;
+ KeyNameDesc *name;
+ KeySym *syms;
+
+ if ((xkb->names == NULL) || (xkb->names->keys == NULL))
+ {
+ if ((rtrn = XkbAllocNames(xkb, XkbKeyNamesMask, 0, 0)) != Success)
+ return rtrn;
+ }
+ for (name = dfltKeys; (name->name[0] != '\0'); name++)
+ {
+ name->used = False;
+ }
+ nUnknown = 0;
+ for (i = xkb->min_key_code; i <= xkb->max_key_code; i++)
+ {
+ tmp = XkbKeyNumSyms(xkb, i);
+ if ((xkb->names->keys[i].name[0] == '\0') && (tmp > 0))
+ {
+ tmp = XkbKeyGroupsWidth(xkb, i);
+ syms = XkbKeySymsPtr(xkb, i);
+ for (name = dfltKeys; (name->name[0] != '\0'); name++)
+ {
+ Bool match = True;
+ if (((name->level1 != syms[0])
+ && (name->level1 != NoSymbol))
+ || ((name->level2 != NoSymbol) && (tmp < 2))
+ || ((name->level2 != syms[1])
+ && (name->level2 != NoSymbol)))
+ {
+ match = False;
+ }
+ if (match)
+ {
+ if (!name->used)
+ {
+ memcpy(xkb->names->keys[i].name, name->name,
+ XkbKeyNameLength);
+ name->used = True;
+ }
+ else
+ {
+ if (warningLevel > 2)
+ {
+ WARN1
+ ("Several keys match pattern for %s\n",
+ XkbKeyNameText(name->name, XkbMessage));
+ ACTION2("Using <U%03d> for key %d\n",
+ nUnknown, i);
+ }
+ sprintf(xkb->names->keys[i].name, "U%03d",
+ nUnknown++);
+ }
+ break;
+ }
+ }
+ if (xkb->names->keys[i].name[0] == '\0')
+ {
+ if (warningLevel > 2)
+ {
+ WARN1("Key %d does not match any defaults\n", i);
+ ACTION1("Using name <U%03d>\n", nUnknown);
+ sprintf(xkb->names->keys[i].name, "U%03d", nUnknown++);
+ }
+ }
+ }
+ }
+ return Success;
+}
+
+/**
+ * Find the key with the given name and return its keycode in kc_rtrn.
+ *
+ * @param name The 4-letter name of the key as a long.
+ * @param kc_rtrn Set to the keycode if the key was found, otherwise 0.
+ * @param use_aliases True if the key aliases should be searched too.
+ * @param create If True and the key is not found, it is added to the
+ * xkb->names at the first free keycode.
+ * @param start_from Keycode to start searching from.
+ *
+ * @return True if found, False otherwise.
+ */
+Bool
+FindNamedKey(XkbDescPtr xkb,
+ unsigned long name,
+ unsigned int *kc_rtrn,
+ Bool use_aliases, Bool create, int start_from)
+{
+ register unsigned n;
+
+ if (start_from < xkb->min_key_code)
+ {
+ start_from = xkb->min_key_code;
+ }
+ else if (start_from > xkb->max_key_code)
+ {
+ return False;
+ }
+
+ *kc_rtrn = 0; /* some callers rely on this */
+ if (xkb && xkb->names && xkb->names->keys)
+ {
+ for (n = start_from; n <= xkb->max_key_code; n++)
+ {
+ unsigned long tmp;
+ tmp = KeyNameToLong(xkb->names->keys[n].name);
+ if (tmp == name)
+ {
+ *kc_rtrn = n;
+ return True;
+ }
+ }
+ if (use_aliases)
+ {
+ unsigned long new_name;
+ if (FindKeyNameForAlias(xkb, name, &new_name))
+ return FindNamedKey(xkb, new_name, kc_rtrn, False, create, 0);
+ }
+ }
+ if (create)
+ {
+ if ((!xkb->names) || (!xkb->names->keys))
+ {
+ if (xkb->min_key_code < XkbMinLegalKeyCode)
+ {
+ xkb->min_key_code = XkbMinLegalKeyCode;
+ xkb->max_key_code = XkbMaxLegalKeyCode;
+ }
+ if (XkbAllocNames(xkb, XkbKeyNamesMask, 0, 0) != Success)
+ {
+ if (warningLevel > 0)
+ {
+ WARN("Couldn't allocate key names in FindNamedKey\n");
+ ACTION1("Key \"%s\" not automatically created\n",
+ longText(name, XkbMessage));
+ }
+ return False;
+ }
+ }
+ /* Find first unused keycode and store our key here */
+ for (n = xkb->min_key_code; n <= xkb->max_key_code; n++)
+ {
+ if (xkb->names->keys[n].name[0] == '\0')
+ {
+ char buf[XkbKeyNameLength + 1];
+ LongToKeyName(name, buf);
+ memcpy(xkb->names->keys[n].name, buf, XkbKeyNameLength);
+ *kc_rtrn = n;
+ return True;
+ }
+ }
+ }
+ return False;
+}
+
+Bool
+FindKeyNameForAlias(XkbDescPtr xkb, unsigned long lname,
+ unsigned long *real_name)
+{
+ register int i;
+ char name[XkbKeyNameLength + 1];
+
+ if (xkb && xkb->geom && xkb->geom->key_aliases)
+ {
+ XkbKeyAliasPtr a;
+ a = xkb->geom->key_aliases;
+ LongToKeyName(lname, name);
+ name[XkbKeyNameLength] = '\0';
+ for (i = 0; i < xkb->geom->num_key_aliases; i++, a++)
+ {
+ if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
+ {
+ *real_name = KeyNameToLong(a->real);
+ return True;
+ }
+ }
+ }
+ if (xkb && xkb->names && xkb->names->key_aliases)
+ {
+ XkbKeyAliasPtr a;
+ a = xkb->names->key_aliases;
+ LongToKeyName(lname, name);
+ name[XkbKeyNameLength] = '\0';
+ for (i = 0; i < xkb->names->num_key_aliases; i++, a++)
+ {
+ if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
+ {
+ *real_name = KeyNameToLong(a->real);
+ return True;
+ }
+ }
+ }
+ return False;
+}
diff --git a/src/xkbcomp/misc.h b/src/xkbcomp/misc.h
new file mode 100644
index 0000000..4fa4b6d
--- /dev/null
+++ b/src/xkbcomp/misc.h
@@ -0,0 +1,111 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifndef MISC_H
+#define MISC_H 1
+
+typedef struct _CommonInfo
+{
+ unsigned short defined;
+ unsigned char fileID;
+ unsigned char merge;
+ struct _CommonInfo *next;
+} CommonInfo;
+
+extern Bool UseNewField(unsigned /* field */ ,
+ CommonInfo * /* oldDefs */ ,
+ CommonInfo * /* newDefs */ ,
+ unsigned * /* pCollide */
+ );
+
+extern Bool MergeNewField(unsigned /* field */ ,
+ CommonInfo * /* oldDefs */ ,
+ CommonInfo * /* newDefs */ ,
+ unsigned * /* pCollide */
+ );
+
+extern XPointer ClearCommonInfo(CommonInfo * /* cmn */
+ );
+
+extern XPointer AddCommonInfo(CommonInfo * /* old */ ,
+ CommonInfo * /* new */
+ );
+
+extern int ReportNotArray(const char * /* type */ ,
+ const char * /* field */ ,
+ const char * /* name */
+ );
+
+extern int ReportShouldBeArray(const char * /* type */ ,
+ const char * /* field */ ,
+ char * /* name */
+ );
+
+extern int ReportBadType(const char * /* type */ ,
+ const char * /* field */ ,
+ const char * /* name */ ,
+ const char * /* wanted */
+ );
+
+extern int ReportBadIndexType(char * /* type */ ,
+ char * /* field */ ,
+ char * /* name */ ,
+ char * /* wanted */
+ );
+
+extern int ReportBadField(const char * /* type */ ,
+ const char * /* field */ ,
+ const char * /* name */
+ );
+
+extern int ReportMultipleDefs(char * /* type */ ,
+ char * /* field */ ,
+ char * /* which */
+ );
+
+extern Bool ProcessIncludeFile(IncludeStmt * /* stmt */ ,
+ unsigned /* file_type */ ,
+ XkbFile ** /* file_rtrn */ ,
+ unsigned * /* merge_rtrn */
+ );
+
+extern Status ComputeKbdDefaults(XkbDescPtr /* xkb */
+ );
+
+extern Bool FindNamedKey(XkbDescPtr /* xkb */ ,
+ unsigned long /* name */ ,
+ unsigned int * /* kc_rtrn */ ,
+ Bool /* use_aliases */ ,
+ Bool /* create */ ,
+ int /* start_from */
+ );
+
+extern Bool FindKeyNameForAlias(XkbDescPtr /* xkb */ ,
+ unsigned long /* lname */ ,
+ unsigned long * /* real_name */
+ );
+
+#endif /* MISC_H */
diff --git a/src/xkbcomp/parseutils.c b/src/xkbcomp/parseutils.c
new file mode 100644
index 0000000..ad1b0d1
--- /dev/null
+++ b/src/xkbcomp/parseutils.c
@@ -0,0 +1,834 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#define DEBUG_VAR parseDebug
+#include "parseutils.h"
+#include "xkbpath.h"
+#include <X11/keysym.h>
+#include <X11/extensions/XKBgeom.h>
+#include <X11/Xalloca.h>
+
+XkbFile *rtrnValue;
+
+ParseCommon *
+AppendStmt(ParseCommon * to, ParseCommon * append)
+{
+ ParseCommon *start = to;
+
+ if (append == NULL)
+ return to;
+ while ((to != NULL) && (to->next != NULL))
+ {
+ to = to->next;
+ }
+ if (to)
+ {
+ to->next = append;
+ return start;
+ }
+ return append;
+}
+
+ExprDef *
+ExprCreate(unsigned op, unsigned type)
+{
+ ExprDef *expr;
+ expr = uTypedAlloc(ExprDef);
+ if (expr)
+ {
+ expr->common.stmtType = StmtExpr;
+ expr->common.next = NULL;
+ expr->op = op;
+ expr->type = type;
+ }
+ else
+ {
+ FATAL("Couldn't allocate expression in parser\n");
+ /* NOTREACHED */
+ }
+ return expr;
+}
+
+ExprDef *
+ExprCreateUnary(unsigned op, unsigned type, ExprDef * child)
+{
+ ExprDef *expr;
+ expr = uTypedAlloc(ExprDef);
+ if (expr)
+ {
+ expr->common.stmtType = StmtExpr;
+ expr->common.next = NULL;
+ expr->op = op;
+ expr->type = type;
+ expr->value.child = child;
+ }
+ else
+ {
+ FATAL("Couldn't allocate expression in parser\n");
+ /* NOTREACHED */
+ }
+ return expr;
+}
+
+ExprDef *
+ExprCreateBinary(unsigned op, ExprDef * left, ExprDef * right)
+{
+ ExprDef *expr;
+ expr = uTypedAlloc(ExprDef);
+ if (expr)
+ {
+ expr->common.stmtType = StmtExpr;
+ expr->common.next = NULL;
+ expr->op = op;
+ if ((op == OpAssign) || (left->type == TypeUnknown))
+ expr->type = right->type;
+ else if ((left->type == right->type) || (right->type == TypeUnknown))
+ expr->type = left->type;
+ else
+ expr->type = TypeUnknown;
+ expr->value.binary.left = left;
+ expr->value.binary.right = right;
+ }
+ else
+ {
+ FATAL("Couldn't allocate expression in parser\n");
+ /* NOTREACHED */
+ }
+ return expr;
+}
+
+KeycodeDef *
+KeycodeCreate(char *name, ExprDef * value)
+{
+ KeycodeDef *def;
+
+ def = uTypedAlloc(KeycodeDef);
+ if (def)
+ {
+ def->common.stmtType = StmtKeycodeDef;
+ def->common.next = NULL;
+ strncpy(def->name, name, XkbKeyNameLength);
+ def->name[XkbKeyNameLength] = '\0';
+ def->value = value;
+ }
+ else
+ {
+ FATAL("Couldn't allocate key name definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+KeyAliasDef *
+KeyAliasCreate(char *alias, char *real)
+{
+ KeyAliasDef *def;
+
+ def = uTypedAlloc(KeyAliasDef);
+ if (def)
+ {
+ def->common.stmtType = StmtKeyAliasDef;
+ def->common.next = NULL;
+ strncpy(def->alias, alias, XkbKeyNameLength);
+ def->alias[XkbKeyNameLength] = '\0';
+ strncpy(def->real, real, XkbKeyNameLength);
+ def->real[XkbKeyNameLength] = '\0';
+ }
+ else
+ {
+ FATAL("Couldn't allocate key alias definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+VModDef *
+VModCreate(Atom name, ExprDef * value)
+{
+ VModDef *def;
+ def = uTypedAlloc(VModDef);
+ if (def)
+ {
+ def->common.stmtType = StmtVModDef;
+ def->common.next = NULL;
+ def->name = name;
+ def->value = value;
+ }
+ else
+ {
+ FATAL("Couldn't allocate variable definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+VarDef *
+VarCreate(ExprDef * name, ExprDef * value)
+{
+ VarDef *def;
+ def = uTypedAlloc(VarDef);
+ if (def)
+ {
+ def->common.stmtType = StmtVarDef;
+ def->common.next = NULL;
+ def->name = name;
+ def->value = value;
+ }
+ else
+ {
+ FATAL("Couldn't allocate variable definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+VarDef *
+BoolVarCreate(Atom nameToken, unsigned set)
+{
+ ExprDef *name, *value;
+
+ name = ExprCreate(ExprIdent, TypeUnknown);
+ name->value.str = nameToken;
+ value = ExprCreate(ExprValue, TypeBoolean);
+ value->value.uval = set;
+ return VarCreate(name, value);
+}
+
+InterpDef *
+InterpCreate(KeySym sym, ExprDef * match)
+{
+ InterpDef *def;
+
+ def = uTypedAlloc(InterpDef);
+ if (def)
+ {
+ def->common.stmtType = StmtInterpDef;
+ def->common.next = NULL;
+ def->sym = sym;
+ def->match = match;
+ }
+ else
+ {
+ FATAL("Couldn't allocate interp definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+KeyTypeDef *
+KeyTypeCreate(Atom name, VarDef * body)
+{
+ KeyTypeDef *def;
+
+ def = uTypedAlloc(KeyTypeDef);
+ if (def)
+ {
+ def->common.stmtType = StmtKeyTypeDef;
+ def->common.next = NULL;
+ def->merge = MergeDefault;
+ def->name = name;
+ def->body = body;
+ }
+ else
+ {
+ FATAL("Couldn't allocate key type definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+SymbolsDef *
+SymbolsCreate(char *keyName, ExprDef * symbols)
+{
+ SymbolsDef *def;
+
+ def = uTypedAlloc(SymbolsDef);
+ if (def)
+ {
+ def->common.stmtType = StmtSymbolsDef;
+ def->common.next = NULL;
+ def->merge = MergeDefault;
+ bzero(def->keyName, 5);
+ strncpy(def->keyName, keyName, 4);
+ def->symbols = symbols;
+ }
+ else
+ {
+ FATAL("Couldn't allocate symbols definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+GroupCompatDef *
+GroupCompatCreate(int group, ExprDef * val)
+{
+ GroupCompatDef *def;
+
+ def = uTypedAlloc(GroupCompatDef);
+ if (def)
+ {
+ def->common.stmtType = StmtGroupCompatDef;
+ def->common.next = NULL;
+ def->merge = MergeDefault;
+ def->group = group;
+ def->def = val;
+ }
+ else
+ {
+ FATAL("Couldn't allocate group compat definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+ModMapDef *
+ModMapCreate(Atom modifier, ExprDef * keys)
+{
+ ModMapDef *def;
+
+ def = uTypedAlloc(ModMapDef);
+ if (def)
+ {
+ def->common.stmtType = StmtModMapDef;
+ def->common.next = NULL;
+ def->merge = MergeDefault;
+ def->modifier = modifier;
+ def->keys = keys;
+ }
+ else
+ {
+ FATAL("Couldn't allocate mod mask definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+IndicatorMapDef *
+IndicatorMapCreate(Atom name, VarDef * body)
+{
+ IndicatorMapDef *def;
+
+ def = uTypedAlloc(IndicatorMapDef);
+ if (def)
+ {
+ def->common.stmtType = StmtIndicatorMapDef;
+ def->common.next = NULL;
+ def->merge = MergeDefault;
+ def->name = name;
+ def->body = body;
+ }
+ else
+ {
+ FATAL("Couldn't allocate indicator map definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+IndicatorNameDef *
+IndicatorNameCreate(int ndx, ExprDef * name, Bool virtual)
+{
+ IndicatorNameDef *def;
+
+ def = uTypedAlloc(IndicatorNameDef);
+ if (def)
+ {
+ def->common.stmtType = StmtIndicatorNameDef;
+ def->common.next = NULL;
+ def->merge = MergeDefault;
+ def->ndx = ndx;
+ def->name = name;
+ def->virtual = virtual;
+ }
+ else
+ {
+ FATAL("Couldn't allocate indicator index definition in parser\n");
+ /* NOTREACHED */
+ }
+ return def;
+}
+
+ExprDef *
+ActionCreate(Atom name, ExprDef * args)
+{
+ ExprDef *act;
+
+ act = uTypedAlloc(ExprDef);
+ if (act)
+ {
+ act->common.stmtType = StmtExpr;
+ act->common.next = NULL;
+ act->op = ExprActionDecl;
+ act->value.action.name = name;
+ act->value.action.args = args;
+ return act;
+ }
+ FATAL("Couldn't allocate ActionDef in parser\n");
+ return NULL;
+}
+
+ExprDef *
+CreateKeysymList(KeySym sym)
+{
+ ExprDef *def;
+
+ def = ExprCreate(ExprKeysymList, TypeSymbols);
+ if (def)
+ {
+ def->value.list.nSyms = 1;
+ def->value.list.szSyms = 2;
+ def->value.list.syms = uTypedCalloc(2, KeySym);
+ if (def->value.list.syms != NULL)
+ {
+ def->value.list.syms[0] = sym;
+ return def;
+ }
+ }
+ FATAL("Couldn't allocate expression for keysym list in parser\n");
+ return NULL;
+}
+
+ShapeDef *
+ShapeDeclCreate(Atom name, OutlineDef * outlines)
+{
+ ShapeDef *shape;
+ OutlineDef *ol;
+
+ shape = uTypedAlloc(ShapeDef);
+ if (shape != NULL)
+ {
+ bzero(shape, sizeof(ShapeDef));
+ shape->common.stmtType = StmtShapeDef;
+ shape->common.next = NULL;
+ shape->merge = MergeDefault;
+ shape->name = name;
+ shape->nOutlines = 0;
+ shape->outlines = outlines;
+ for (ol = outlines; ol != NULL; ol = (OutlineDef *) ol->common.next)
+ {
+ if (ol->nPoints > 0)
+ shape->nOutlines++;
+ }
+ }
+ return shape;
+}
+
+OutlineDef *
+OutlineCreate(Atom field, ExprDef * points)
+{
+ OutlineDef *outline;
+ ExprDef *pt;
+
+ outline = uTypedAlloc(OutlineDef);
+ if (outline != NULL)
+ {
+ bzero(outline, sizeof(OutlineDef));
+ outline->common.stmtType = StmtOutlineDef;
+ outline->common.next = NULL;
+ outline->field = field;
+ outline->nPoints = 0;
+ if (points->op == ExprCoord)
+ {
+ for (pt = points; pt != NULL; pt = (ExprDef *) pt->common.next)
+ {
+ outline->nPoints++;
+ }
+ }
+ outline->points = points;
+ }
+ return outline;
+}
+
+KeyDef *
+KeyDeclCreate(char *name, ExprDef * expr)
+{
+ KeyDef *key;
+
+ key = uTypedAlloc(KeyDef);
+ if (key != NULL)
+ {
+ bzero(key, sizeof(KeyDef));
+ key->common.stmtType = StmtKeyDef;
+ key->common.next = NULL;
+ if (name)
+ key->name = name;
+ else
+ key->expr = expr;
+ }
+ return key;
+}
+
+KeyDef *
+KeyDeclMerge(KeyDef * into, KeyDef * from)
+{
+ into->expr =
+ (ExprDef *) AppendStmt(&into->expr->common, &from->expr->common);
+ from->expr = NULL;
+ uFree(from);
+ return into;
+}
+
+RowDef *
+RowDeclCreate(KeyDef * keys)
+{
+ RowDef *row;
+ KeyDef *key;
+
+ row = uTypedAlloc(RowDef);
+ if (row != NULL)
+ {
+ bzero(row, sizeof(RowDef));
+ row->common.stmtType = StmtRowDef;
+ row->common.next = NULL;
+ row->nKeys = 0;
+ row->keys = keys;
+ for (key = keys; key != NULL; key = (KeyDef *) key->common.next)
+ {
+ if (key->common.stmtType == StmtKeyDef)
+ row->nKeys++;
+ }
+ }
+ return row;
+}
+
+SectionDef *
+SectionDeclCreate(Atom name, RowDef * rows)
+{
+ SectionDef *section;
+ RowDef *row;
+
+ section = uTypedAlloc(SectionDef);
+ if (section != NULL)
+ {
+ bzero(section, sizeof(SectionDef));
+ section->common.stmtType = StmtSectionDef;
+ section->common.next = NULL;
+ section->name = name;
+ section->nRows = 0;
+ section->rows = rows;
+ for (row = rows; row != NULL; row = (RowDef *) row->common.next)
+ {
+ if (row->common.stmtType == StmtRowDef)
+ section->nRows++;
+ }
+ }
+ return section;
+}
+
+OverlayKeyDef *
+OverlayKeyCreate(char *under, char *over)
+{
+ OverlayKeyDef *key;
+
+ key = uTypedAlloc(OverlayKeyDef);
+ if (key != NULL)
+ {
+ bzero(key, sizeof(OverlayKeyDef));
+ key->common.stmtType = StmtOverlayKeyDef;
+ strncpy(key->over, over, XkbKeyNameLength);
+ strncpy(key->under, under, XkbKeyNameLength);
+ if (over)
+ uFree(over);
+ if (under)
+ uFree(under);
+ }
+ return key;
+}
+
+OverlayDef *
+OverlayDeclCreate(Atom name, OverlayKeyDef * keys)
+{
+ OverlayDef *ol;
+ OverlayKeyDef *key;
+
+ ol = uTypedAlloc(OverlayDef);
+ if (ol != NULL)
+ {
+ bzero(ol, sizeof(OverlayDef));
+ ol->common.stmtType = StmtOverlayDef;
+ ol->name = name;
+ ol->keys = keys;
+ for (key = keys; key != NULL;
+ key = (OverlayKeyDef *) key->common.next)
+ {
+ ol->nKeys++;
+ }
+ }
+ return ol;
+}
+
+DoodadDef *
+DoodadCreate(unsigned type, Atom name, VarDef * body)
+{
+ DoodadDef *doodad;
+
+ doodad = uTypedAlloc(DoodadDef);
+ if (doodad != NULL)
+ {
+ bzero(doodad, sizeof(DoodadDef));
+ doodad->common.stmtType = StmtDoodadDef;
+ doodad->common.next = NULL;
+ doodad->type = type;
+ doodad->name = name;
+ doodad->body = body;
+ }
+ return doodad;
+}
+
+ExprDef *
+AppendKeysymList(ExprDef * list, KeySym sym)
+{
+ if (list->value.list.nSyms >= list->value.list.szSyms)
+ {
+ list->value.list.szSyms *= 2;
+ list->value.list.syms = uTypedRecalloc(list->value.list.syms,
+ list->value.list.nSyms,
+ list->value.list.szSyms,
+ KeySym);
+ if (list->value.list.syms == NULL)
+ {
+ FATAL("Couldn't resize list of symbols for append\n");
+ return NULL;
+ }
+ }
+ list->value.list.syms[list->value.list.nSyms++] = sym;
+ return list;
+}
+
+int
+LookupKeysym(char *str, KeySym * sym_rtrn)
+{
+ KeySym sym;
+
+ if ((!str) || (uStrCaseCmp(str, "any") == 0)
+ || (uStrCaseCmp(str, "nosymbol") == 0))
+ {
+ *sym_rtrn = NoSymbol;
+ return 1;
+ }
+ else if ((uStrCaseCmp(str, "none") == 0)
+ || (uStrCaseCmp(str, "voidsymbol") == 0))
+ {
+ *sym_rtrn = XK_VoidSymbol;
+ return 1;
+ }
+ sym = XStringToKeysym(str);
+ if (sym != NoSymbol)
+ {
+ *sym_rtrn = sym;
+ return 1;
+ }
+ return 0;
+}
+
+IncludeStmt *
+IncludeCreate(char *str, unsigned merge)
+{
+ IncludeStmt *incl, *first;
+ char *file, *map, *stmt, *tmp, *extra_data;
+ char nextop;
+ Bool haveSelf;
+
+ haveSelf = False;
+ incl = first = NULL;
+ file = map = NULL;
+ tmp = str;
+ stmt = uStringDup(str);
+ while ((tmp) && (*tmp))
+ {
+ if (XkbParseIncludeMap(&tmp, &file, &map, &nextop, &extra_data))
+ {
+ if ((file == NULL) && (map == NULL))
+ {
+ if (haveSelf)
+ goto BAIL;
+ haveSelf = True;
+ }
+ if (first == NULL)
+ first = incl = uTypedAlloc(IncludeStmt);
+ else
+ {
+ incl->next = uTypedAlloc(IncludeStmt);
+ incl = incl->next;
+ }
+ if (incl)
+ {
+ incl->common.stmtType = StmtInclude;
+ incl->common.next = NULL;
+ incl->merge = merge;
+ incl->stmt = NULL;
+ incl->file = file;
+ incl->map = map;
+ incl->modifier = extra_data;
+ incl->path = NULL;
+ incl->next = NULL;
+ }
+ else
+ {
+ WSGO("Allocation failure in IncludeCreate\n");
+ ACTION("Using only part of the include\n");
+ break;
+ }
+ if (nextop == '|')
+ merge = MergeAugment;
+ else
+ merge = MergeOverride;
+ }
+ else
+ {
+ goto BAIL;
+ }
+ }
+ if (first)
+ first->stmt = stmt;
+ else if (stmt)
+ uFree(stmt);
+ return first;
+ BAIL:
+ ERROR1("Illegal include statement \"%s\"\n", stmt);
+ ACTION("Ignored\n");
+ while (first)
+ {
+ incl = first->next;
+ if (first->file)
+ uFree(first->file);
+ if (first->map)
+ uFree(first->map);
+ if (first->modifier)
+ uFree(first->modifier);
+ if (first->path)
+ uFree(first->path);
+ first->file = first->map = first->path = NULL;
+ uFree(first);
+ first = incl;
+ }
+ if (stmt)
+ uFree(stmt);
+ return NULL;
+}
+
+#ifdef DEBUG
+void
+PrintStmtAddrs(ParseCommon * stmt)
+{
+ fprintf(stderr, "0x%x", stmt);
+ if (stmt)
+ {
+ do
+ {
+ fprintf(stderr, "->0x%x", stmt->next);
+ stmt = stmt->next;
+ }
+ while (stmt);
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+static void
+CheckDefaultMap(XkbFile * maps)
+{
+ XkbFile *dflt, *tmp;
+
+ dflt = NULL;
+ for (tmp = maps, dflt = NULL; tmp != NULL;
+ tmp = (XkbFile *) tmp->common.next)
+ {
+ if (tmp->flags & XkbLC_Default)
+ {
+ if (dflt == NULL)
+ dflt = tmp;
+ else
+ {
+ if (warningLevel > 2)
+ {
+ WARN1("Multiple default components in %s\n",
+ (scanFile ? scanFile : "(unknown)"));
+ ACTION2("Using %s, ignoring %s\n",
+ (dflt->name ? dflt->name : "(first)"),
+ (tmp->name ? tmp->name : "(subsequent)"));
+ }
+ tmp->flags &= (~XkbLC_Default);
+ }
+ }
+ }
+ return;
+}
+
+int
+XKBParseFile(FILE * file, XkbFile ** pRtrn)
+{
+ if (file)
+ {
+ yyin = file;
+ rtrnValue = NULL;
+ if (yyparse() == 0)
+ {
+ *pRtrn = rtrnValue;
+ CheckDefaultMap(rtrnValue);
+ rtrnValue = NULL;
+ return 1;
+ }
+ *pRtrn = NULL;
+ return 0;
+ }
+ *pRtrn = NULL;
+ return 1;
+}
+
+XkbFile *
+CreateXKBFile(int type, char *name, ParseCommon * defs, unsigned flags)
+{
+ XkbFile *file;
+ static int fileID;
+
+ file = uTypedAlloc(XkbFile);
+ if (file)
+ {
+ XkbEnsureSafeMapName(name);
+ bzero(file, sizeof(XkbFile));
+ file->type = type;
+ file->topName = uStringDup(name);
+ file->name = name;
+ file->defs = defs;
+ file->id = fileID++;
+ file->compiled = False;
+ file->flags = flags;
+ }
+ return file;
+}
+
+unsigned
+StmtSetMerge(ParseCommon * stmt, unsigned merge)
+{
+ if ((merge == MergeAltForm) && (stmt->stmtType != StmtKeycodeDef))
+ {
+ yyerror("illegal use of 'alternate' merge mode");
+ merge = MergeDefault;
+ }
+ return merge;
+}
diff --git a/src/xkbcomp/parseutils.h b/src/xkbcomp/parseutils.h
new file mode 100644
index 0000000..73a0ec8
--- /dev/null
+++ b/src/xkbcomp/parseutils.h
@@ -0,0 +1,208 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifndef XKBPARSE_H
+#define XKBPARSE_H 1
+
+#ifndef DEBUG_VAR
+#define DEBUG_VAR parseDebug
+#endif
+
+#include "xkbcomp.h"
+
+extern char *scanStr;
+extern int scanInt;
+extern int lineNum;
+
+extern XkbFile *rtrnValue;
+
+#ifdef DEBUG
+#define d(str) fprintf(stderr,"%s\n",str);
+#define d1(str,a) fprintf(stderr,str,a);
+#define d2(str,a,b) fprintf(stderr,str,a,b);
+#else
+#define d(str)
+#define d1(str,a)
+#define d2(str,a,b)
+#endif
+
+
+extern ParseCommon *AppendStmt(ParseCommon * /* to */ ,
+ ParseCommon * /* append */
+ );
+
+extern ExprDef *ExprCreate(unsigned /* op */ ,
+ unsigned /* type */
+ );
+
+extern ExprDef *ExprCreateUnary(unsigned /* op */ ,
+ unsigned /* type */ ,
+ ExprDef * /* child */
+ );
+
+extern ExprDef *ExprCreateBinary(unsigned /* op */ ,
+ ExprDef * /* left */ ,
+ ExprDef * /* right */
+ );
+
+extern KeycodeDef *KeycodeCreate(char * /* name */ ,
+ ExprDef * /* value */
+ );
+
+extern KeyAliasDef *KeyAliasCreate(char * /* alias */ ,
+ char * /* real */
+ );
+
+extern VModDef *VModCreate(Atom /* name */ ,
+ ExprDef * /* value */
+ );
+
+extern VarDef *VarCreate(ExprDef * /* name */ ,
+ ExprDef * /* value */
+ );
+
+extern VarDef *BoolVarCreate(Atom /* nameToken */ ,
+ unsigned /* set */
+ );
+
+extern InterpDef *InterpCreate(KeySym /* sym */ ,
+ ExprDef * /* match */
+ );
+
+extern KeyTypeDef *KeyTypeCreate(Atom /* name */ ,
+ VarDef * /* body */
+ );
+
+extern SymbolsDef *SymbolsCreate(char * /* keyName */ ,
+ ExprDef * /* symbols */
+ );
+
+extern GroupCompatDef *GroupCompatCreate(int /* group */ ,
+ ExprDef * /* def */
+ );
+
+extern ModMapDef *ModMapCreate(Atom /* modifier */ ,
+ ExprDef * /* keys */
+ );
+
+extern IndicatorMapDef *IndicatorMapCreate(Atom /* name */ ,
+ VarDef * /* body */
+ );
+
+extern IndicatorNameDef *IndicatorNameCreate(int /* ndx */ ,
+ ExprDef * /* name */ ,
+ Bool /* virtual */
+ );
+
+extern ExprDef *ActionCreate(Atom /* name */ ,
+ ExprDef * /* args */
+ );
+
+extern ExprDef *CreateKeysymList(KeySym /* sym */
+ );
+
+extern ShapeDef *ShapeDeclCreate(Atom /* name */ ,
+ OutlineDef * /* outlines */
+ );
+
+extern OutlineDef *OutlineCreate(Atom /* field */ ,
+ ExprDef * /* points */
+ );
+
+extern KeyDef *KeyDeclCreate(char * /* name */ ,
+ ExprDef * /* expr */
+ );
+
+extern KeyDef *KeyDeclMerge(KeyDef * /* into */ ,
+ KeyDef * /* from */
+ );
+
+extern RowDef *RowDeclCreate(KeyDef * /* keys */
+ );
+
+extern SectionDef *SectionDeclCreate(Atom /* name */ ,
+ RowDef * /* rows */
+ );
+
+extern OverlayKeyDef *OverlayKeyCreate(char * /* under */ ,
+ char * /* over */
+ );
+
+extern OverlayDef *OverlayDeclCreate(Atom /* name */ ,
+ OverlayKeyDef * /* rows */
+ );
+
+extern DoodadDef *DoodadCreate(unsigned /* type */ ,
+ Atom /* name */ ,
+ VarDef * /* body */
+ );
+
+extern ExprDef *AppendKeysymList(ExprDef * /* list */ ,
+ KeySym /* sym */
+ );
+
+extern int LookupKeysym(char * /* str */ ,
+ KeySym * /* sym_rtrn */
+ );
+
+extern IncludeStmt *IncludeCreate(char * /* str */ ,
+ unsigned /* merge */
+ );
+
+extern unsigned StmtSetMerge(ParseCommon * /* stmt */ ,
+ unsigned /* merge */
+ );
+
+#ifdef DEBUG
+extern void PrintStmtAddrs(ParseCommon * /* stmt */
+ );
+#endif
+
+extern int XKBParseFile(FILE * /* file */ ,
+ XkbFile ** /* pRtrn */
+ );
+
+extern XkbFile *CreateXKBFile(int /* type */ ,
+ char * /* name */ ,
+ ParseCommon * /* defs */ ,
+ unsigned /* flags */
+ );
+
+extern void yyerror(const char * /* s */
+ );
+
+extern int yywrap(void);
+
+extern int yylex(void);
+extern int yyparse(void);
+
+extern int setScanState(char * /* file */ ,
+ int /* line */
+ );
+
+extern FILE *yyin;
+
+#endif /* XKBPARSE_H */
diff --git a/src/xkbcomp/symbols.c b/src/xkbcomp/symbols.c
new file mode 100644
index 0000000..47ad67b
--- /dev/null
+++ b/src/xkbcomp/symbols.c
@@ -0,0 +1,2301 @@
+/************************************************************
+ 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 <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);
+ memcpy((char *) key->syms[ndx], (char *) value->value.list.syms,
+ nSyms * sizeof(KeySym));
+ for (i = key->numLevels[ndx] - 1;
+ (i >= 0) && (key->syms[ndx][i] == NoSymbol); i--)
+ {
+ key->numLevels[ndx]--;
+ }
+ return True;
+}
+
+static Bool
+AddActionsToKey(KeyInfo * key,
+ XkbDescPtr xkb,
+ char *field,
+ ExprDef * arrayNdx, ExprDef * value, SymbolsInfo * info)
+{
+ register int i;
+ unsigned ndx, nActs;
+ ExprDef *act;
+ XkbAnyAction *toAct;
+
+ if (!GetGroupIndex(key, arrayNdx, ACTIONS, &ndx))
+ return False;
+
+ if (value == NULL)
+ {
+ key->actsDefined |= (1 << ndx);
+ return True;
+ }
+ if (value->op != ExprActionList)
+ {
+ WSGO1("Bad expression type (%d) for action list value\n", value->op);
+ ACTION2("Ignoring actions for group %d of %s\n", ndx,
+ longText(key->name, XkbMessage));
+ return False;
+ }
+ if (key->acts[ndx] != NULL)
+ {
+ WSGO2("Actions for key %s, group %d already defined\n",
+ longText(key->name, XkbMessage), ndx);
+ return False;
+ }
+ for (nActs = 0, act = value->value.child; act != NULL; nActs++)
+ {
+ act = (ExprDef *) act->common.next;
+ }
+ if (nActs < 1)
+ {
+ WSGO("Action list but not actions in AddActionsToKey\n");
+ return False;
+ }
+ if (((key->numLevels[ndx] < nActs) || (key->acts[ndx] == NULL)) &&
+ (!ResizeKeyGroup(key, ndx, nActs, True)))
+ {
+ WSGO2("Could not resize group %d of key %s\n", ndx,
+ longText(key->name, XkbMessage));
+ ACTION("Actions lost\n");
+ return False;
+ }
+ key->actsDefined |= (1 << ndx);
+
+ toAct = (XkbAnyAction *) key->acts[ndx];
+ act = value->value.child;
+ for (i = 0; i < nActs; i++, toAct++)
+ {
+ if (!HandleActionDef(act, xkb, toAct, MergeOverride, info->action))
+ {
+ ERROR1("Illegal action definition for %s\n",
+ longText(key->name, XkbMessage));
+ ACTION2("Action for group %d/level %d ignored\n", ndx + 1, i + 1);
+ }
+ act = (ExprDef *) act->common.next;
+ }
+ return True;
+}
+
+static int
+SetAllowNone(KeyInfo * key, ExprDef * arrayNdx, ExprDef * value)
+{
+ ExprResult tmp;
+ unsigned radio_groups = 0;
+
+ if (arrayNdx == NULL)
+ {
+ radio_groups = XkbAllRadioGroupsMask;
+ }
+ else
+ {
+ if (!ExprResolveInteger(arrayNdx, &tmp, RadioLookup, NULL))
+ {
+ ERROR("Illegal index in group name definition\n");
+ ACTION("Definition with non-integer array index ignored\n");
+ return False;
+ }
+ if ((tmp.uval < 1) || (tmp.uval > XkbMaxRadioGroups))
+ {
+ ERROR1("Illegal radio group specified (must be 1..%d)\n",
+ XkbMaxRadioGroups + 1);
+ ACTION1("Value of \"allow none\" for group %d ignored\n",
+ tmp.uval);
+ return False;
+ }
+ radio_groups |= (1 << (tmp.uval - 1));
+ }
+ if (!ExprResolveBoolean(value, &tmp, NULL, NULL))
+ {
+ ERROR1("Illegal \"allow none\" value for %s\n",
+ longText(key->name, XkbMessage));
+ ACTION("Non-boolean value ignored\n");
+ return False;
+ }
+ if (tmp.uval)
+ key->allowNone |= radio_groups;
+ else
+ key->allowNone &= ~radio_groups;
+ return True;
+}
+
+
+static LookupEntry lockingEntries[] = {
+ {"true", XkbKB_Lock},
+ {"yes", XkbKB_Lock},
+ {"on", XkbKB_Lock},
+ {"false", XkbKB_Default},
+ {"no", XkbKB_Default},
+ {"off", XkbKB_Default},
+ {"permanent", XkbKB_Lock | XkbKB_Permanent},
+ {NULL, 0}
+};
+
+static LookupEntry repeatEntries[] = {
+ {"true", RepeatYes},
+ {"yes", RepeatYes},
+ {"on", RepeatYes},
+ {"false", RepeatNo},
+ {"no", RepeatNo},
+ {"off", RepeatNo},
+ {"default", RepeatUndefined},
+ {NULL, 0}
+};
+
+static LookupEntry rgEntries[] = {
+ {"none", 0},
+ {NULL, 0}
+};
+
+static Bool
+SetSymbolsField(KeyInfo * key,
+ XkbDescPtr xkb,
+ char *field,
+ ExprDef * arrayNdx, ExprDef * value, SymbolsInfo * info)
+{
+ Bool ok = True;
+ ExprResult tmp;
+
+ if (uStrCaseCmp(field, "type") == 0)
+ {
+ ExprResult ndx;
+ if ((!ExprResolveString(value, &tmp, NULL, NULL))
+ && (warningLevel > 0))
+ {
+ WARN("The type field of a key symbol map must be a string\n");
+ ACTION("Ignoring illegal type definition\n");
+ }
+ if (arrayNdx == NULL)
+ {
+ key->dfltType = XkbInternAtom(NULL, tmp.str, False);
+ key->defs.defined |= _Key_Type_Dflt;
+ }
+ else if (!ExprResolveInteger(arrayNdx, &ndx, SimpleLookup,
+ (XPointer) groupNames))
+ {
+ ERROR1("Illegal group index for type of key %s\n",
+ longText(key->name, XkbMessage));
+ ACTION("Definition with non-integer array index ignored\n");
+ return False;
+ }
+ else if ((ndx.uval < 1) || (ndx.uval > XkbNumKbdGroups))
+ {
+ ERROR2
+ ("Group index for type of key %s is out of range (1..%d)\n",
+ longText(key->name, XkbMessage), XkbNumKbdGroups + 1);
+ ACTION1("Ignoring type for group %d\n", ndx.uval);
+ return False;
+ }
+ else
+ {
+ key->types[ndx.uval - 1] = XkbInternAtom(NULL, tmp.str, False);
+ key->typesDefined |= (1 << (ndx.uval - 1));
+ }
+ }
+ else if (uStrCaseCmp(field, "symbols") == 0)
+ return AddSymbolsToKey(key, xkb, field, arrayNdx, value, info);
+ else if (uStrCaseCmp(field, "actions") == 0)
+ return AddActionsToKey(key, xkb, field, arrayNdx, value, info);
+ else if ((uStrCaseCmp(field, "vmods") == 0) ||
+ (uStrCaseCmp(field, "virtualmods") == 0) ||
+ (uStrCaseCmp(field, "virtualmodifiers") == 0))
+ {
+ ok = ExprResolveModMask(value, &tmp, LookupVModMask, (XPointer) xkb);
+ if (ok)
+ {
+ key->vmodmap = (tmp.uval >> 8);
+ key->defs.defined |= _Key_VModMap;
+ }
+ else
+ {
+ ERROR1("Expected a virtual modifier mask, found %s\n",
+ exprOpText(value->op));
+ ACTION1("Ignoring virtual modifiers definition for key %s\n",
+ longText(key->name, XkbMessage));
+ }
+ }
+ else if ((uStrCaseCmp(field, "locking") == 0)
+ || (uStrCaseCmp(field, "lock") == 0)
+ || (uStrCaseCmp(field, "locks") == 0))
+ {
+ ok = ExprResolveEnum(value, &tmp, lockingEntries);
+ if (ok)
+ key->behavior.type = tmp.uval;
+ key->defs.defined |= _Key_Behavior;
+ }
+ else if ((uStrCaseCmp(field, "radiogroup") == 0) ||
+ (uStrCaseCmp(field, "permanentradiogroup") == 0))
+ {
+ Bool permanent = False;
+ if (uStrCaseCmp(field, "permanentradiogroup") == 0)
+ permanent = True;
+ ok = ExprResolveInteger(value, &tmp, SimpleLookup,
+ (XPointer) rgEntries);
+ if (!ok)
+ {
+ ERROR1("Illegal radio group specification for %s\n",
+ longText(key->name, XkbMessage));
+ ACTION("Non-integer radio group ignored\n");
+ return False;
+ }
+ if (tmp.uval == 0)
+ {
+ key->behavior.type = XkbKB_Default;
+ key->behavior.data = 0;
+ return ok;
+ }
+ if ((tmp.uval < 1) || (tmp.uval > XkbMaxRadioGroups))
+ {
+ ERROR1
+ ("Radio group specification for %s out of range (1..32)\n",
+ longText(key->name, XkbMessage));
+ ACTION1("Illegal radio group %d ignored\n", tmp.uval);
+ return False;
+ }
+ key->behavior.type =
+ XkbKB_RadioGroup | (permanent ? XkbKB_Permanent : 0);
+ key->behavior.data = tmp.uval - 1;
+ if (key->allowNone & (1 << (tmp.uval - 1)))
+ key->behavior.data |= XkbKB_RGAllowNone;
+ key->defs.defined |= _Key_Behavior;
+ }
+ else if (uStrCaseEqual(field, "allownone"))
+ {
+ ok = SetAllowNone(key, arrayNdx, value);
+ }
+ else if (uStrCasePrefix("overlay", field) ||
+ uStrCasePrefix("permanentoverlay", field))
+ {
+ Bool permanent = False;
+ char *which;
+ int overlayNdx;
+ if (uStrCasePrefix("permanent", field))
+ {
+ permanent = True;
+ which = &field[sizeof("permanentoverlay") - 1];
+ }
+ else
+ {
+ which = &field[sizeof("overlay") - 1];
+ }
+ if (sscanf(which, "%d", &overlayNdx) == 1)
+ {
+ if (((overlayNdx < 1) || (overlayNdx > 2)) && (warningLevel > 0))
+ {
+ ERROR2("Illegal overlay %d specified for %s\n",
+ overlayNdx, longText(key->name, XkbMessage));
+ ACTION("Ignored\n");
+ return False;
+ }
+ }
+ else if (*which == '\0')
+ overlayNdx = 1;
+ else if (warningLevel > 0)
+ {
+ ERROR2("Illegal overlay \"%s\" specified for %s\n",
+ which, longText(key->name, XkbMessage));
+ ACTION("Ignored\n");
+ return False;
+ }
+ ok = ExprResolveKeyName(value, &tmp, NULL, NULL);
+ if (!ok)
+ {
+ ERROR1("Illegal overlay key specification for %s\n",
+ longText(key->name, XkbMessage));
+ ACTION("Overlay key must be specified by name\n");
+ return False;
+ }
+ if (overlayNdx == 1)
+ key->behavior.type = XkbKB_Overlay1;
+ else
+ key->behavior.type = XkbKB_Overlay2;
+ if (permanent)
+ key->behavior.type |= XkbKB_Permanent;
+
+ key->behavior.data = 0;
+ key->nameForOverlayKey = KeyNameToLong(tmp.keyName.name);
+ key->defs.defined |= _Key_Behavior;
+ }
+ else if ((uStrCaseCmp(field, "repeating") == 0) ||
+ (uStrCaseCmp(field, "repeats") == 0) ||
+ (uStrCaseCmp(field, "repeat") == 0))
+ {
+ ok = ExprResolveEnum(value, &tmp, repeatEntries);
+ if (!ok)
+ {
+ ERROR1("Illegal repeat setting for %s\n",
+ longText(key->name, XkbMessage));
+ ACTION("Non-boolean repeat setting ignored\n");
+ return False;
+ }
+ key->repeat = tmp.uval;
+ key->defs.defined |= _Key_Repeat;
+ }
+ else if ((uStrCaseCmp(field, "groupswrap") == 0) ||
+ (uStrCaseCmp(field, "wrapgroups") == 0))
+ {
+ ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
+ if (!ok)
+ {
+ ERROR1("Illegal groupsWrap setting for %s\n",
+ longText(key->name, XkbMessage));
+ ACTION("Non-boolean value ignored\n");
+ return False;
+ }
+ if (tmp.uval)
+ key->groupInfo = XkbWrapIntoRange;
+ else
+ key->groupInfo = XkbClampIntoRange;
+ key->defs.defined |= _Key_GroupInfo;
+ }
+ else if ((uStrCaseCmp(field, "groupsclamp") == 0) ||
+ (uStrCaseCmp(field, "clampgroups") == 0))
+ {
+ ok = ExprResolveBoolean(value, &tmp, NULL, NULL);
+ if (!ok)
+ {
+ ERROR1("Illegal groupsClamp setting for %s\n",
+ longText(key->name, XkbMessage));
+ ACTION("Non-boolean value ignored\n");
+ return False;
+ }
+ if (tmp.uval)
+ key->groupInfo = XkbClampIntoRange;
+ else
+ key->groupInfo = XkbWrapIntoRange;
+ key->defs.defined |= _Key_GroupInfo;
+ }
+ else if ((uStrCaseCmp(field, "groupsredirect") == 0) ||
+ (uStrCaseCmp(field, "redirectgroups") == 0))
+ {
+ if (!ExprResolveInteger
+ (value, &tmp, SimpleLookup, (XPointer) groupNames))
+ {
+ ERROR1("Illegal group index for redirect of key %s\n",
+ longText(key->name, XkbMessage));
+ ACTION("Definition with non-integer group ignored\n");
+ return False;
+ }
+ if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
+ {
+ ERROR2("Out-of-range (1..%d) group for redirect of key %s\n",
+ XkbNumKbdGroups, longText(key->name, XkbMessage));
+ ERROR1("Ignoring illegal group %d\n", tmp.uval);
+ return False;
+ }
+ key->groupInfo =
+ XkbSetGroupInfo(0, XkbRedirectIntoRange, tmp.uval - 1);
+ key->defs.defined |= _Key_GroupInfo;
+ }
+ else
+ {
+ ERROR1("Unknown field %s in a symbol interpretation\n", field);
+ ACTION("Definition ignored\n");
+ ok = False;
+ }
+ return ok;
+}
+
+static int
+SetGroupName(SymbolsInfo * info, ExprDef * arrayNdx, ExprDef * value)
+{
+ ExprResult tmp, name;
+
+ if ((arrayNdx == NULL) && (warningLevel > 0))
+ {
+ WARN("You must specify an index when specifying a group name\n");
+ ACTION("Group name definition without array subscript ignored\n");
+ return False;
+ }
+ if (!ExprResolveInteger
+ (arrayNdx, &tmp, SimpleLookup, (XPointer) groupNames))
+ {
+ ERROR("Illegal index in group name definition\n");
+ ACTION("Definition with non-integer array index ignored\n");
+ return False;
+ }
+ if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
+ {
+ ERROR1
+ ("Attempt to specify name for illegal group (must be 1..%d)\n",
+ XkbNumKbdGroups + 1);
+ ACTION1("Name for group %d ignored\n", tmp.uval);
+ return False;
+ }
+ if (!ExprResolveString(value, &name, NULL, NULL))
+ {
+ ERROR("Group name must be a string\n");
+ ACTION1("Illegal name for group %d ignored\n", tmp.uval);
+ return False;
+ }
+ info->groupNames[tmp.uval - 1 + info->explicit_group] =
+ XkbInternAtom(NULL, name.str, False);
+
+ return True;
+}
+
+static int
+HandleSymbolsVar(VarDef * stmt, XkbDescPtr xkb, SymbolsInfo * info)
+{
+ ExprResult elem, field, tmp;
+ ExprDef *arrayNdx;
+
+ if (ExprResolveLhs(stmt->name, &elem, &field, &arrayNdx) == 0)
+ return 0; /* internal error, already reported */
+ if (elem.str && (uStrCaseCmp(elem.str, "key") == 0))
+ {
+ return SetSymbolsField(&info->dflt, xkb, field.str, arrayNdx,
+ stmt->value, info);
+ }
+ else if ((elem.str == NULL) && ((uStrCaseCmp(field.str, "name") == 0) ||
+ (uStrCaseCmp(field.str, "groupname") ==
+ 0)))
+ {
+ return SetGroupName(info, arrayNdx, stmt->value);
+ }
+ else if ((elem.str == NULL)
+ && ((uStrCaseCmp(field.str, "groupswrap") == 0)
+ || (uStrCaseCmp(field.str, "wrapgroups") == 0)))
+ {
+ if (!ExprResolveBoolean(stmt->value, &tmp, NULL, NULL))
+ {
+ ERROR("Illegal setting for global groupsWrap\n");
+ ACTION("Non-boolean value ignored\n");
+ return False;
+ }
+ if (tmp.uval)
+ info->groupInfo = XkbWrapIntoRange;
+ else
+ info->groupInfo = XkbClampIntoRange;
+ return True;
+ }
+ else if ((elem.str == NULL)
+ && ((uStrCaseCmp(field.str, "groupsclamp") == 0)
+ || (uStrCaseCmp(field.str, "clampgroups") == 0)))
+ {
+ if (!ExprResolveBoolean(stmt->value, &tmp, NULL, NULL))
+ {
+ ERROR("Illegal setting for global groupsClamp\n");
+ ACTION("Non-boolean value ignored\n");
+ return False;
+ }
+ if (tmp.uval)
+ info->groupInfo = XkbClampIntoRange;
+ else
+ info->groupInfo = XkbWrapIntoRange;
+ return True;
+ }
+ else if ((elem.str == NULL)
+ && ((uStrCaseCmp(field.str, "groupsredirect") == 0)
+ || (uStrCaseCmp(field.str, "redirectgroups") == 0)))
+ {
+ if (!ExprResolveInteger(stmt->value, &tmp,
+ SimpleLookup, (XPointer) groupNames))
+ {
+ ERROR("Illegal group index for global groupsRedirect\n");
+ ACTION("Definition with non-integer group ignored\n");
+ return False;
+ }
+ if ((tmp.uval < 1) || (tmp.uval > XkbNumKbdGroups))
+ {
+ ERROR1
+ ("Out-of-range (1..%d) group for global groupsRedirect\n",
+ XkbNumKbdGroups);
+ ACTION1("Ignoring illegal group %d\n", tmp.uval);
+ return False;
+ }
+ info->groupInfo = XkbSetGroupInfo(0, XkbRedirectIntoRange, tmp.uval);
+ return True;
+ }
+ else if ((elem.str == NULL) && (uStrCaseCmp(field.str, "allownone") == 0))
+ {
+ return SetAllowNone(&info->dflt, arrayNdx, stmt->value);
+ }
+ return SetActionField(xkb, elem.str, field.str, arrayNdx, stmt->value,
+ &info->action);
+}
+
+static Bool
+HandleSymbolsBody(VarDef * def,
+ XkbDescPtr xkb, KeyInfo * key, SymbolsInfo * info)
+{
+ Bool ok = True;
+ ExprResult tmp, field;
+ ExprDef *arrayNdx;
+
+ for (; def != NULL; def = (VarDef *) def->common.next)
+ {
+ if ((def->name) && (def->name->type == ExprFieldRef))
+ {
+ ok = HandleSymbolsVar(def, xkb, info);
+ continue;
+ }
+ else
+ {
+ if (def->name == NULL)
+ {
+ if ((def->value == NULL)
+ || (def->value->op == ExprKeysymList))
+ field.str = "symbols";
+ else
+ field.str = "actions";
+ arrayNdx = NULL;
+ }
+ else
+ {
+ ok = ExprResolveLhs(def->name, &tmp, &field, &arrayNdx);
+ }
+ if (ok)
+ ok = SetSymbolsField(key, xkb, field.str, arrayNdx,
+ def->value, info);
+ }
+ }
+ return ok;
+}
+
+static Bool
+SetExplicitGroup(SymbolsInfo * info, KeyInfo * key)
+{
+ unsigned group = info->explicit_group;
+
+ if (group == 0)
+ return True;
+
+ if ((key->typesDefined | key->symsDefined | key->actsDefined) & ~1)
+ {
+ int i;
+ WARN1("For the map %s an explicit group specified\n", info->name);
+ WARN1("but key %s has more than one group defined\n",
+ longText(key->name, XkbMessage));
+ ACTION("All groups except first one will be ignored\n");
+ for (i = 1; i < XkbNumKbdGroups; i++)
+ {
+ key->numLevels[i] = 0;
+ if (key->syms[i] != NULL)
+ uFree(key->syms[i]);
+ key->syms[i] = (KeySym *) NULL;
+ if (key->acts[i] != NULL)
+ uFree(key->acts[i]);
+ key->acts[i] = (XkbAction *) NULL;
+ key->types[i] = (Atom) 0;
+ }
+ }
+ key->typesDefined = key->symsDefined = key->actsDefined = 1 << group;
+
+ key->numLevels[group] = key->numLevels[0];
+ key->numLevels[0] = 0;
+ key->syms[group] = key->syms[0];
+ key->syms[0] = (KeySym *) NULL;
+ key->acts[group] = key->acts[0];
+ key->acts[0] = (XkbAction *) NULL;
+ key->types[group] = key->types[0];
+ key->types[0] = (Atom) 0;
+ return True;
+}
+
+static int
+HandleSymbolsDef(SymbolsDef * stmt,
+ XkbDescPtr xkb, unsigned merge, SymbolsInfo * info)
+{
+ KeyInfo key;
+
+ InitKeyInfo(&key);
+ CopyKeyInfo(&info->dflt, &key, False);
+ key.defs.merge = stmt->merge;
+ key.name = KeyNameToLong(stmt->keyName);
+ if (!HandleSymbolsBody((VarDef *) stmt->symbols, xkb, &key, info))
+ {
+ info->errorCount++;
+ return False;
+ }
+
+ if (!SetExplicitGroup(info, &key))
+ {
+ info->errorCount++;
+ return False;
+ }
+
+ if (!AddKeySymbols(info, &key, xkb))
+ {
+ info->errorCount++;
+ return False;
+ }
+ return True;
+}
+
+static Bool
+HandleModMapDef(ModMapDef * def,
+ XkbDescPtr xkb, unsigned merge, SymbolsInfo * info)
+{
+ ExprDef *key;
+ ModMapEntry tmp;
+ ExprResult rtrn;
+ Bool ok;
+
+ if (!LookupModIndex(NULL, None, def->modifier, TypeInt, &rtrn))
+ {
+ ERROR("Illegal modifier map definition\n");
+ ACTION1("Ignoring map for non-modifier \"%s\"\n",
+ XkbAtomText(NULL, def->modifier, XkbMessage));
+ return False;
+ }
+ ok = True;
+ tmp.modifier = rtrn.uval;
+ for (key = def->keys; key != NULL; key = (ExprDef *) key->common.next)
+ {
+ if ((key->op == ExprValue) && (key->type == TypeKeyName))
+ {
+ tmp.haveSymbol = False;
+ tmp.u.keyName = KeyNameToLong(key->value.keyName);
+ }
+ else if (ExprResolveKeySym(key, &rtrn, NULL, NULL))
+ {
+ tmp.haveSymbol = True;
+ tmp.u.keySym = rtrn.uval;
+ }
+ else
+ {
+ ERROR("Modmap entries may contain only key names or keysyms\n");
+ ACTION1("Illegal definition for %s modifier ignored\n",
+ XkbModIndexText(tmp.modifier, XkbMessage));
+ continue;
+ }
+
+ ok = AddModMapEntry(info, &tmp) && ok;
+ }
+ return ok;
+}
+
+static void
+HandleSymbolsFile(XkbFile * file,
+ XkbDescPtr xkb, unsigned merge, SymbolsInfo * info)
+{
+ ParseCommon *stmt;
+
+ info->name = uStringDup(file->name);
+ stmt = file->defs;
+ while (stmt)
+ {
+ switch (stmt->stmtType)
+ {
+ case StmtInclude:
+ if (!HandleIncludeSymbols((IncludeStmt *) stmt, xkb, info,
+ HandleSymbolsFile))
+ info->errorCount++;
+ break;
+ case StmtSymbolsDef:
+ if (!HandleSymbolsDef((SymbolsDef *) stmt, xkb, merge, info))
+ info->errorCount++;
+ break;
+ case StmtVarDef:
+ if (!HandleSymbolsVar((VarDef *) stmt, xkb, info))
+ info->errorCount++;
+ break;
+ case StmtVModDef:
+ if (!HandleVModDef((VModDef *) stmt, merge, &info->vmods))
+ info->errorCount++;
+ break;
+ case StmtInterpDef:
+ ERROR("Interpretation files may not include other types\n");
+ ACTION("Ignoring definition of symbol interpretation\n");
+ info->errorCount++;
+ break;
+ case StmtKeycodeDef:
+ ERROR("Interpretation files may not include other types\n");
+ ACTION("Ignoring definition of key name\n");
+ info->errorCount++;
+ break;
+ case StmtModMapDef:
+ if (!HandleModMapDef((ModMapDef *) stmt, xkb, merge, info))
+ info->errorCount++;
+ break;
+ default:
+ WSGO1("Unexpected statement type %d in HandleSymbolsFile\n",
+ stmt->stmtType);
+ break;
+ }
+ stmt = stmt->next;
+ if (info->errorCount > 10)
+ {
+#ifdef NOISY
+ ERROR("Too many errors\n");
+#endif
+ ACTION1("Abandoning symbols file \"%s\"\n", file->topName);
+ break;
+ }
+ }
+ return;
+}
+
+static Bool
+FindKeyForSymbol(XkbDescPtr xkb, KeySym sym, unsigned int *kc_rtrn)
+{
+ register int i, j;
+ register Bool gotOne;
+
+ j = 0;
+ do
+ {
+ gotOne = False;
+ for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++)
+ {
+ if (j < (int) XkbKeyNumSyms(xkb, i))
+ {
+ gotOne = True;
+ if ((XkbKeySym(xkb, i, j) == sym))
+ {
+ *kc_rtrn = i;
+ return True;
+ }
+ }
+ }
+ j++;
+ }
+ while (gotOne);
+ return False;
+}
+
+/**
+ * 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;
+}
diff --git a/src/xkbcomp/tokens.h b/src/xkbcomp/tokens.h
new file mode 100644
index 0000000..970f3d4
--- /dev/null
+++ b/src/xkbcomp/tokens.h
@@ -0,0 +1,104 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+#ifndef TOKENS_H
+#define TOKENS_H 1
+
+#define END_OF_FILE 0
+#define ERROR_TOK 255
+
+#define XKB_KEYMAP 1
+#define XKB_KEYCODES 2
+#define XKB_TYPES 3
+#define XKB_SYMBOLS 4
+#define XKB_COMPATMAP 5
+#define XKB_GEOMETRY 6
+#define XKB_SEMANTICS 7
+#define XKB_LAYOUT 8
+
+#define INCLUDE 10
+#define OVERRIDE 11
+#define AUGMENT 12
+#define REPLACE 13
+#define ALTERNATE 14
+
+#define VIRTUAL_MODS 20
+#define TYPE 21
+#define INTERPRET 22
+#define ACTION_TOK 23
+#define KEY 24
+#define ALIAS 25
+#define GROUP 26
+#define MODIFIER_MAP 27
+#define INDICATOR 28
+#define SHAPE 29
+#define KEYS 30
+#define ROW 31
+#define SECTION 32
+#define OVERLAY 33
+#define TEXT 34
+#define OUTLINE 35
+#define SOLID 36
+#define LOGO 37
+#define VIRTUAL 38
+
+#define EQUALS 40
+#define PLUS 41
+#define MINUS 42
+#define DIVIDE 43
+#define TIMES 44
+#define OBRACE 45
+#define CBRACE 46
+#define OPAREN 47
+#define CPAREN 48
+#define OBRACKET 49
+#define CBRACKET 50
+#define DOT 51
+#define COMMA 52
+#define SEMI 53
+#define EXCLAM 54
+#define INVERT 55
+
+#define STRING 60
+#define INTEGER 61
+#define FLOAT 62
+#define IDENT 63
+#define KEYNAME 64
+
+#define PARTIAL 70
+#define DEFAULT 71
+#define HIDDEN 72
+#define ALPHANUMERIC_KEYS 73
+#define MODIFIER_KEYS 74
+#define KEYPAD_KEYS 75
+#define FUNCTION_KEYS 76
+#define ALTERNATE_GROUP 77
+
+extern Atom tok_ONE_LEVEL;
+extern Atom tok_TWO_LEVEL;
+extern Atom tok_ALPHABETIC;
+extern Atom tok_KEYPAD;
+
+#endif
diff --git a/src/xkbcomp/utils.c b/src/xkbcomp/utils.c
new file mode 100644
index 0000000..55efbe1
--- /dev/null
+++ b/src/xkbcomp/utils.c
@@ -0,0 +1,434 @@
+
+ /*\
+ *
+ * COPYRIGHT 1990
+ * DIGITAL EQUIPMENT CORPORATION
+ * MAYNARD, MASSACHUSETTS
+ * ALL RIGHTS RESERVED.
+ *
+ * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
+ * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
+ * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE
+ * FOR ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED
+ * WARRANTY.
+ *
+ * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
+ * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
+ * ADDITION TO THAT SET FORTH ABOVE.
+ *
+ * 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 Digital Equipment Corporation not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ \*/
+
+#include "utils.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+/***====================================================================***/
+
+Opaque
+uAlloc(unsigned size)
+{
+ return ((Opaque) malloc(size));
+}
+
+/***====================================================================***/
+
+Opaque
+uCalloc(unsigned n, unsigned size)
+{
+ return ((Opaque) calloc(n, size));
+}
+
+/***====================================================================***/
+
+Opaque
+uRealloc(Opaque old, unsigned newSize)
+{
+ if (old == NULL)
+ return ((Opaque) malloc(newSize));
+ else
+ return ((Opaque) realloc((char *) old, newSize));
+}
+
+/***====================================================================***/
+
+Opaque
+uRecalloc(Opaque old, unsigned nOld, unsigned nNew, unsigned itemSize)
+{
+ char *rtrn;
+
+ if (old == NULL)
+ rtrn = (char *) calloc(nNew, itemSize);
+ else
+ {
+ rtrn = (char *) realloc((char *) old, nNew * itemSize);
+ if ((rtrn) && (nNew > nOld))
+ {
+ bzero(&rtrn[nOld * itemSize], (nNew - nOld) * itemSize);
+ }
+ }
+ return (Opaque) rtrn;
+}
+
+/***====================================================================***/
+
+void
+uFree(Opaque ptr)
+{
+ if (ptr != (Opaque) NULL)
+ free((char *) ptr);
+ return;
+}
+
+/***====================================================================***/
+/*** FUNCTION ENTRY TRACKING ***/
+/***====================================================================***/
+
+static FILE *entryFile = NULL;
+int uEntryLevel;
+
+Boolean
+uSetEntryFile(char *name)
+{
+ if ((entryFile != NULL) && (entryFile != stderr))
+ {
+ fprintf(entryFile, "switching to %s\n", name ? name : "stderr");
+ fclose(entryFile);
+ }
+ if (name != NullString)
+ entryFile = fopen(name, "w");
+ else
+ entryFile = stderr;
+ if (entryFile == NULL)
+ {
+ entryFile = stderr;
+ return (False);
+ }
+ return (True);
+}
+
+void
+uEntry(int l, char *s, ...)
+{
+ int i;
+ va_list args;
+
+ for (i = 0; i < uEntryLevel; i++)
+ {
+ putc(' ', entryFile);
+ }
+ va_start(args, s);
+ vfprintf(entryFile, s, args);
+ va_end(args);
+ uEntryLevel += l;
+}
+
+void
+uExit(int l, char *rtVal)
+{
+ int i;
+
+ uEntryLevel -= l;
+ if (uEntryLevel < 0)
+ uEntryLevel = 0;
+ for (i = 0; i < uEntryLevel; i++)
+ {
+ putc(' ', entryFile);
+ }
+ fprintf(entryFile, "---> %p\n", rtVal);
+ return;
+}
+
+/***====================================================================***/
+/*** PRINT FUNCTIONS ***/
+/***====================================================================***/
+
+FILE *uDebugFile = NULL;
+int uDebugIndentLevel = 0;
+int uDebugIndentSize = 4;
+
+Boolean
+uSetDebugFile(char *name)
+{
+ if ((uDebugFile != NULL) && (uDebugFile != stderr))
+ {
+ fprintf(uDebugFile, "switching to %s\n", name ? name : "stderr");
+ fclose(uDebugFile);
+ }
+ if (name != NullString)
+ uDebugFile = fopen(name, "w");
+ else
+ uDebugFile = stderr;
+ if (uDebugFile == NULL)
+ {
+ uDebugFile = stderr;
+ return (False);
+ }
+ return (True);
+}
+
+void
+uDebug(char *s, ...)
+{
+ int i;
+ va_list args;
+
+ for (i = (uDebugIndentLevel * uDebugIndentSize); i > 0; i--)
+ {
+ putc(' ', uDebugFile);
+ }
+ va_start(args, s);
+ vfprintf(uDebugFile, s, args);
+ va_end(args);
+ fflush(uDebugFile);
+}
+
+void
+uDebugNOI(char *s, ...)
+{
+ va_list args;
+
+ va_start(args, s);
+ vfprintf(uDebugFile, s, args);
+ va_end(args);
+ fflush(uDebugFile);
+}
+
+/***====================================================================***/
+
+static FILE *errorFile = NULL;
+static int outCount = 0;
+static char *preMsg = NULL;
+static char *postMsg = NULL;
+static char *prefix = NULL;
+
+Boolean
+uSetErrorFile(char *name)
+{
+ if ((errorFile != NULL) && (errorFile != stderr))
+ {
+ fprintf(errorFile, "switching to %s\n", name ? name : "stderr");
+ fclose(errorFile);
+ }
+ if (name != NullString)
+ errorFile = fopen(name, "w");
+ else
+ errorFile = stderr;
+ if (errorFile == NULL)
+ {
+ errorFile = stderr;
+ return (False);
+ }
+ return (True);
+}
+
+void
+uInformation(const char *s, ...)
+{
+ va_list args;
+
+ va_start(args, s);
+ vfprintf(errorFile, s, args);
+ va_end(args);
+ fflush(errorFile);
+}
+
+/***====================================================================***/
+
+void
+uAction(const char *s, ...)
+{
+ va_list args;
+
+ if (prefix != NULL)
+ fprintf(errorFile, "%s", prefix);
+ fprintf(errorFile, " ");
+ va_start(args, s);
+ vfprintf(errorFile, s, args);
+ va_end(args);
+ fflush(errorFile);
+}
+
+/***====================================================================***/
+
+void
+uWarning(const char *s, ...)
+{
+ va_list args;
+
+ if ((outCount == 0) && (preMsg != NULL))
+ fprintf(errorFile, "%s\n", preMsg);
+ if (prefix != NULL)
+ fprintf(errorFile, "%s", prefix);
+ fprintf(errorFile, "Warning: ");
+ va_start(args, s);
+ vfprintf(errorFile, s, args);
+ va_end(args);
+ fflush(errorFile);
+ outCount++;
+}
+
+/***====================================================================***/
+
+void
+uError(const char *s, ...)
+{
+ va_list args;
+
+ if ((outCount == 0) && (preMsg != NULL))
+ fprintf(errorFile, "%s\n", preMsg);
+ if (prefix != NULL)
+ fprintf(errorFile, "%s", prefix);
+ fprintf(errorFile, "Error: ");
+ va_start(args, s);
+ vfprintf(errorFile, s, args);
+ va_end(args);
+ fflush(errorFile);
+ outCount++;
+}
+
+/***====================================================================***/
+
+void
+uFatalError(const char *s, ...)
+{
+ va_list args;
+
+ if ((outCount == 0) && (preMsg != NULL))
+ fprintf(errorFile, "%s\n", preMsg);
+ if (prefix != NULL)
+ fprintf(errorFile, "%s", prefix);
+ fprintf(errorFile, "Fatal Error: ");
+ va_start(args, s);
+ vfprintf(errorFile, s, args);
+ va_end(args);
+ fprintf(errorFile, " Exiting\n");
+ fflush(errorFile);
+ outCount++;
+ exit(1);
+ /* NOTREACHED */
+}
+
+/***====================================================================***/
+
+void
+uInternalError(const char *s, ...)
+{
+ va_list args;
+
+ if ((outCount == 0) && (preMsg != NULL))
+ fprintf(errorFile, "%s\n", preMsg);
+ if (prefix != NULL)
+ fprintf(errorFile, "%s", prefix);
+ fprintf(errorFile, "Internal error: ");
+ va_start(args, s);
+ vfprintf(errorFile, s, args);
+ va_end(args);
+ fflush(errorFile);
+ outCount++;
+}
+
+void
+uSetPreErrorMessage(char *msg)
+{
+ outCount = 0;
+ preMsg = msg;
+ return;
+}
+
+void
+uSetPostErrorMessage(char *msg)
+{
+ postMsg = msg;
+ return;
+}
+
+void
+uSetErrorPrefix(char *pre)
+{
+ prefix = pre;
+ return;
+}
+
+void
+uFinishUp(void)
+{
+ if ((outCount > 0) && (postMsg != NULL))
+ fprintf(errorFile, "%s\n", postMsg);
+ return;
+}
+
+/***====================================================================***/
+
+#ifndef HAVE_STRDUP
+char *
+uStringDup(const char *str)
+{
+ char *rtrn;
+
+ if (str == NULL)
+ return NULL;
+ rtrn = (char *) uAlloc(strlen(str) + 1);
+ strcpy(rtrn, str);
+ return rtrn;
+}
+#endif
+
+#ifndef HAVE_STRCASECMP
+int
+uStrCaseCmp(const char *str1, const char *str2)
+{
+ char buf1[512], buf2[512];
+ char c, *s;
+ register int n;
+
+ for (n = 0, s = buf1; (c = *str1++); n++)
+ {
+ if (isupper(c))
+ c = tolower(c);
+ if (n > 510)
+ break;
+ *s++ = c;
+ }
+ *s = '\0';
+ for (n = 0, s = buf2; (c = *str2++); n++)
+ {
+ if (isupper(c))
+ c = tolower(c);
+ if (n > 510)
+ break;
+ *s++ = c;
+ }
+ *s = '\0';
+ return (strcmp(buf1, buf2));
+}
+
+int
+uStrCasePrefix(const char *my_prefix, char *str)
+{
+ char c1;
+ char c2;
+ while (((c1 = *my_prefix) != '\0') && ((c2 = *str) != '\0'))
+ {
+ if (isupper(c1))
+ c1 = tolower(c1);
+ if (isupper(c2))
+ c2 = tolower(c2);
+ if (c1 != c2)
+ return 0;
+ my_prefix++;
+ str++;
+ }
+ if (c1 != '\0')
+ return 0;
+ return 1;
+}
+
+#endif
diff --git a/src/xkbcomp/utils.h b/src/xkbcomp/utils.h
new file mode 100644
index 0000000..65e37c8
--- /dev/null
+++ b/src/xkbcomp/utils.h
@@ -0,0 +1,381 @@
+#ifndef UTILS_H
+#define UTILS_H 1
+
+ /*\
+ *
+ * COPYRIGHT 1990
+ * DIGITAL EQUIPMENT CORPORATION
+ * MAYNARD, MASSACHUSETTS
+ * ALL RIGHTS RESERVED.
+ *
+ * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
+ * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
+ * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE
+ * FOR ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED
+ * WARRANTY.
+ *
+ * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
+ * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
+ * ADDITION TO THAT SET FORTH ABOVE.
+ *
+ * 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 Digital Equipment Corporation not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ \*/
+
+/***====================================================================***/
+
+#include <stdio.h>
+#include <X11/Xos.h>
+#include <X11/Xfuncproto.h>
+#include <X11/Xfuncs.h>
+
+#include <stddef.h>
+#include "config.h"
+
+#ifndef NUL
+#define NUL '\0'
+#endif
+
+/***====================================================================***/
+
+#ifndef OPAQUE_DEFINED
+typedef void *Opaque;
+#endif
+#ifndef NullOpaque
+#define NullOpaque ((Opaque)NULL)
+#endif
+
+#ifndef BOOLEAN_DEFINED
+typedef char Boolean;
+#endif
+
+#ifndef True
+#define True ((Boolean)1)
+#define False ((Boolean)0)
+#endif /* ndef True */
+#define booleanText(b) ((b)?"True":"False")
+
+#ifndef COMPARISON_DEFINED
+typedef int Comparison;
+
+#define Greater ((Comparison)1)
+#define Equal ((Comparison)0)
+#define Less ((Comparison)-1)
+#define CannotCompare ((Comparison)-37)
+#define comparisonText(c) ((c)?((c)<0?"Less":"Greater"):"Equal")
+#endif
+
+/***====================================================================***/
+
+extern Opaque uAlloc(unsigned /* size */
+ );
+extern Opaque uCalloc(unsigned /* n */ ,
+ unsigned /* size */
+ );
+extern Opaque uRealloc(Opaque /* old */ ,
+ unsigned /* newSize */
+ );
+extern Opaque uRecalloc(Opaque /* old */ ,
+ unsigned /* nOld */ ,
+ unsigned /* nNew */ ,
+ unsigned /* newSize */
+ );
+extern void uFree(Opaque /* ptr */
+ );
+
+#define uTypedAlloc(t) ((t *)uAlloc((unsigned)sizeof(t)))
+#define uTypedCalloc(n,t) ((t *)uCalloc((unsigned)n,(unsigned)sizeof(t)))
+#define uTypedRealloc(pO,n,t) ((t *)uRealloc((Opaque)pO,((unsigned)n)*sizeof(t)))
+#define uTypedRecalloc(pO,o,n,t) ((t *)uRecalloc((Opaque)pO,((unsigned)o),((unsigned)n),sizeof(t)))
+#if (defined mdHasAlloca) && (mdHasAlloca)
+#define uTmpAlloc(n) ((Opaque)alloca((unsigned)n))
+#define uTmpFree(p)
+#else
+#define uTmpAlloc(n) uAlloc(n)
+#define uTmpFree(p) uFree(p)
+#endif
+
+/***====================================================================***/
+
+extern Boolean uSetErrorFile(char * /* name */
+ );
+
+#define INFO6 uInformation
+#define INFO5 uInformation
+#define INFO4 uInformation
+#define INFO3 uInformation
+#define INFO2 uInformation
+#define INFO1 uInformation
+#define INFO uInformation
+
+extern void
+uInformation(const char * /* s */ , ...
+ )
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 6)))
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ ;
+
+#define ACTION6 uAction
+#define ACTION5 uAction
+#define ACTION4 uAction
+#define ACTION3 uAction
+#define ACTION2 uAction
+#define ACTION1 uAction
+#define ACTION uAction
+
+ extern void uAction(const char * /* s */ , ...
+ )
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 6)))
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ ;
+
+#define WARN6 uWarning
+#define WARN5 uWarning
+#define WARN4 uWarning
+#define WARN3 uWarning
+#define WARN2 uWarning
+#define WARN1 uWarning
+#define WARN uWarning
+
+ extern void uWarning(const char * /* s */ , ...
+ )
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 6)))
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ ;
+
+#define ERROR6 uError
+#define ERROR5 uError
+#define ERROR4 uError
+#define ERROR3 uError
+#define ERROR2 uError
+#define ERROR1 uError
+#define ERROR uError
+
+ extern void uError(const char * /* s */ , ...
+ )
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 6)))
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ ;
+
+#define FATAL6 uFatalError
+#define FATAL5 uFatalError
+#define FATAL4 uFatalError
+#define FATAL3 uFatalError
+#define FATAL2 uFatalError
+#define FATAL1 uFatalError
+#define FATAL uFatalError
+
+ extern void uFatalError(const char * /* s */ , ...
+ )
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 6)))
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ ;
+
+/* WSGO stands for "Weird Stuff Going On" */
+#define WSGO6 uInternalError
+#define WSGO5 uInternalError
+#define WSGO4 uInternalError
+#define WSGO3 uInternalError
+#define WSGO2 uInternalError
+#define WSGO1 uInternalError
+#define WSGO uInternalError
+
+ extern void uInternalError(const char * /* s */ , ...
+ )
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 6)))
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ ;
+
+ extern void uSetPreErrorMessage(char * /* msg */
+ );
+
+ extern void uSetPostErrorMessage(char * /* msg */
+ );
+
+ extern void uSetErrorPrefix(char * /* void */
+ );
+
+ extern void uFinishUp(void);
+
+
+/***====================================================================***/
+
+#define NullString ((char *)NULL)
+
+#define uStringText(s) ((s)==NullString?"<NullString>":(s))
+#define uStringEqual(s1,s2) (uStringCompare(s1,s2)==Equal)
+#define uStringPrefix(p,s) (strncmp(p,s,strlen(p))==0)
+#define uStringCompare(s1,s2) (((s1)==NullString||(s2)==NullString)?\
+ (s1)!=(s2):strcmp(s1,s2))
+#define uStrCaseEqual(s1,s2) (uStrCaseCmp(s1,s2)==0)
+#ifdef HAVE_STRCASECMP
+#define uStrCaseCmp(s1,s2) (strcasecmp(s1,s2))
+#define uStrCasePrefix(p,s) (strncasecmp(p,s,strlen(p))==0)
+#else
+ extern int uStrCaseCmp(const char * /* s1 */ ,
+ const char * /* s2 */
+ );
+ extern int uStrCasePrefix(const char * /* p */ ,
+ char * /* str */
+ );
+#endif
+#ifdef HAVE_STRDUP
+#define uStringDup(s1) ((s1) ? strdup(s1) : NULL)
+#else
+ extern char *uStringDup(const char * /* s1 */
+ );
+#endif
+
+/***====================================================================***/
+
+#ifdef ASSERTIONS_ON
+#define uASSERT(where,why) \
+ {if (!(why)) uFatalError("assertion botched in %s ( why )\n",where);}
+#else
+#define uASSERT(where,why)
+#endif
+
+/***====================================================================***/
+
+#ifndef DEBUG_VAR
+#define DEBUG_VAR debugFlags
+#endif
+
+extern
+ unsigned int DEBUG_VAR;
+
+ extern void uDebug(char * /* s */ , ...
+ )
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 6)))
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ ;
+
+ extern void uDebugNOI( /* no indent */
+ char * /* s */ , ...
+ )
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 6)))
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ ;
+
+ extern Boolean uSetDebugFile(char *name);
+
+ extern FILE *uDebugFile;
+ extern int uDebugIndentLevel;
+ extern int uDebugIndentSize;
+#define uDebugIndent(l) (uDebugIndentLevel+=(l))
+#define uDebugOutdent(l) (uDebugIndentLevel-=(l))
+#ifdef DEBUG_ON
+#define uDEBUG(f,s) { if (DEBUG_VAR&(f)) uDebug(s);}
+#define uDEBUG1(f,s,a) { if (DEBUG_VAR&(f)) uDebug(s,a);}
+#define uDEBUG2(f,s,a,b) { if (DEBUG_VAR&(f)) uDebug(s,a,b);}
+#define uDEBUG3(f,s,a,b,c) { if (DEBUG_VAR&(f)) uDebug(s,a,b,c);}
+#define uDEBUG4(f,s,a,b,c,d) { if (DEBUG_VAR&(f)) uDebug(s,a,b,c,d);}
+#define uDEBUG5(f,s,a,b,c,d,e) { if (DEBUG_VAR&(f)) uDebug(s,a,b,c,d,e);}
+#define uDEBUG_NOI(f,s) { if (DEBUG_VAR&(f)) uDebug(s);}
+#define uDEBUG_NOI1(f,s,a) { if (DEBUG_VAR&(f)) uDebugNOI(s,a);}
+#define uDEBUG_NOI2(f,s,a,b) { if (DEBUG_VAR&(f)) uDebugNOI(s,a,b);}
+#define uDEBUG_NOI3(f,s,a,b,c) { if (DEBUG_VAR&(f)) uDebugNOI(s,a,b,c);}
+#define uDEBUG_NOI4(f,s,a,b,c,d) { if (DEBUG_VAR&(f)) uDebugNOI(s,a,b,c,d);}
+#define uDEBUG_NOI5(f,s,a,b,c,d,e) { if (DEBUG_VAR&(f)) uDebugNOI(s,a,b,c,d,e);}
+#else
+#define uDEBUG(f,s)
+#define uDEBUG1(f,s,a)
+#define uDEBUG2(f,s,a,b)
+#define uDEBUG3(f,s,a,b,c)
+#define uDEBUG4(f,s,a,b,c,d)
+#define uDEBUG5(f,s,a,b,c,d,e)
+#define uDEBUG_NOI(f,s)
+#define uDEBUG_NOI1(f,s,a)
+#define uDEBUG_NOI2(f,s,a,b)
+#define uDEBUG_NOI3(f,s,a,b,c)
+#define uDEBUG_NOI4(f,s,a,b,c,d)
+#define uDEBUG_NOI5(f,s,a,b,c,d,e)
+#endif
+
+ extern Boolean uSetEntryFile(char *name);
+ extern void uEntry(int /* l */ ,
+ char * /* s */ , ...
+ )
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 6)))
+ __attribute__ ((format(printf, 2, 3)))
+#endif
+ ;
+
+ extern void uExit(int l, char *rtVal);
+#ifdef ENTRY_TRACKING_ON
+#define ENTRY_BIT 0x10
+#define LOW_ENTRY_BIT 0x1000
+#define ENTER (DEBUG_VAR&ENTRY_BIT)
+#define FLAG(fLag) (DEBUG_VAR&(fLag))
+
+ extern int uEntryLevel;
+
+#define uENTRY(s) { if (ENTER) uEntry(1,s);}
+#define uENTRY1(s,a) { if (ENTER) uEntry(1,s,a);}
+#define uENTRY2(s,a,b) { if (ENTER) uEntry(1,s,a,b);}
+#define uENTRY3(s,a,b,c) { if (ENTER) uEntry(1,s,a,b,c);}
+#define uENTRY4(s,a,b,c,d) { if (ENTER) uEntry(1,s,a,b,c,d);}
+#define uENTRY5(s,a,b,c,d,e) { if (ENTER) uEntry(1,s,a,b,c,d,e);}
+#define uENTRY6(s,a,b,c,d,e,f) { if (ENTER) uEntry(1,s,a,b,c,d,e,f);}
+#define uENTRY7(s,a,b,c,d,e,f,g) { if (ENTER) uEntry(1,s,a,b,c,d,e,f,g);}
+#define uRETURN(v) { if (ENTER) uEntryLevel--; return(v); }
+#define uVOIDRETURN { if (ENTER) uEntryLevel--; return; }
+
+#define uFLAG_ENTRY(w,s) { if (FLAG(w)) uEntry(0,s);}
+#define uFLAG_ENTRY1(w,s,a) { if (FLAG(w)) uEntry(0,s,a);}
+#define uFLAG_ENTRY2(w,s,a,b) { if (FLAG(w)) uEntry(0,s,a,b);}
+#define uFLAG_ENTRY3(w,s,a,b,c) { if (FLAG(w)) uEntry(0,s,a,b,c);}
+#define uFLAG_ENTRY4(w,s,a,b,c,d) { if (FLAG(w)) uEntry(0,s,a,b,c,d);}
+#define uFLAG_ENTRY5(w,s,a,b,c,d,e) { if (FLAG(w)) uEntry(0,s,a,b,c,d,e);}
+#define uFLAG_ENTRY6(w,s,a,b,c,d,e,f) { if (FLAG(w)) uEntry(0,s,a,b,c,d,e,f);}
+#define uFLAG_ENTRY7(w,s,a,b,c,d,e,f,g) { if(FLAG(w))uEntry(0,s,a,b,c,d,e,f,g);}
+#define uFLAG_RETURN(v) { return(v);}
+#define uFLAG_VOIDRETURN { return; }
+#else
+#define uENTRY(s)
+#define uENTRY1(s,a)
+#define uENTRY2(s,a1,a2)
+#define uENTRY3(s,a1,a2,a3)
+#define uENTRY4(s,a1,a2,a3,a4)
+#define uENTRY5(s,a1,a2,a3,a4,a5)
+#define uENTRY6(s,a1,a2,a3,a4,a5,a6)
+#define uENTRY7(s,a1,a2,a3,a4,a5,a6,a7)
+#define uRETURN(v) { return(v); }
+#define uVOIDRETURN { return; }
+
+#define uFLAG_ENTRY(f,s)
+#define uFLAG_ENTRY1(f,s,a)
+#define uFLAG_ENTRY2(f,s,a,b)
+#define uFLAG_ENTRY3(f,s,a,b,c)
+#define uFLAG_ENTRY4(f,s,a,b,c,d)
+#define uFLAG_ENTRY5(f,s,a,b,c,d,e)
+#define uFLAG_ENTRY6(f,s,a,b,c,d,e,g)
+#define uFLAG_ENTRY7(f,s,a,b,c,d,e,g,h)
+#define uFLAG_RETURN(v) { return(v);}
+#define uFLAG_VOIDRETURN { return; }
+#endif
+
+
+#endif /* UTILS_H */
diff --git a/src/xkbcomp/vmod.c b/src/xkbcomp/vmod.c
new file mode 100644
index 0000000..5578fd0
--- /dev/null
+++ b/src/xkbcomp/vmod.c
@@ -0,0 +1,271 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#define DEBUG_VAR debugFlags
+#include <stdio.h>
+#include "xkbcomp.h"
+#include "tokens.h"
+#include "expr.h"
+#include "misc.h"
+
+#include <X11/extensions/XKB.h>
+#include <X11/extensions/XKBstr.h>
+
+#include "vmod.h"
+
+void
+InitVModInfo(VModInfo * info, XkbDescPtr xkb)
+{
+ ClearVModInfo(info, xkb);
+ info->errorCount = 0;
+ return;
+}
+
+void
+ClearVModInfo(VModInfo * info, XkbDescPtr xkb)
+{
+ register int i;
+
+ if (XkbAllocNames(xkb, XkbVirtualModNamesMask, 0, 0) != Success)
+ return;
+ if (XkbAllocServerMap(xkb, XkbVirtualModsMask, 0) != Success)
+ return;
+ info->xkb = xkb;
+ info->newlyDefined = info->defined = info->available = 0;
+ if (xkb && xkb->names)
+ {
+ register int bit;
+ for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1)
+ {
+ if (xkb->names->vmods[i] != None)
+ info->defined |= bit;
+ }
+ }
+ return;
+}
+
+/***====================================================================***/
+
+/**
+ * Handle one entry in the virtualModifiers line (e.g. NumLock).
+ * If the entry is e.g. NumLock=Mod1, stmt->value is not NULL, and the
+ * XkbServerMap's vmod is set to the given modifier. Otherwise, the vmod is 0.
+ *
+ * @param stmt The statement specifying the name and (if any the value).
+ * @param mergeMode Merge strategy (e.g. MergeOverride)
+ */
+Bool
+HandleVModDef(VModDef * stmt, unsigned mergeMode, VModInfo * info)
+{
+ register int i, bit, nextFree;
+ ExprResult mod;
+ XkbServerMapPtr srv;
+ XkbNamesPtr names;
+ Atom stmtName;
+
+ srv = info->xkb->server;
+ names = info->xkb->names;
+ stmtName =
+ XkbInternAtom(info->xkb->dpy, XkbAtomGetString(NULL, stmt->name),
+ False);
+ for (i = 0, bit = 1, nextFree = -1; i < XkbNumVirtualMods; i++, bit <<= 1)
+ {
+ if (info->defined & bit)
+ {
+ if (names->vmods[i] == stmtName)
+ { /* already defined */
+ info->available |= bit;
+ if (stmt->value == NULL)
+ return True;
+ else
+ {
+ char *str1;
+ const char *str2 = "";
+ if (!ExprResolveModMask(stmt->value, &mod, NULL, NULL))
+ {
+ str1 = XkbAtomText(NULL, stmt->name, XkbMessage);
+ ACTION1("Declaration of %s ignored\n", str1);
+ return False;
+ }
+ if (mod.uval == srv->vmods[i])
+ return True;
+
+ str1 = XkbAtomText(NULL, stmt->name, XkbMessage);
+ WARN1("Virtual modifier %s multiply defined\n", str1);
+ str1 = XkbModMaskText(srv->vmods[i], XkbCFile);
+ if (mergeMode == MergeOverride)
+ {
+ str2 = str1;
+ str1 = XkbModMaskText(mod.uval, XkbCFile);
+ }
+ ACTION2("Using %s, ignoring %s\n", str1, str2);
+ if (mergeMode == MergeOverride)
+ srv->vmods[i] = mod.uval;
+ return True;
+ }
+ }
+ }
+ else if (nextFree < 0)
+ nextFree = i;
+ }
+ if (nextFree < 0)
+ {
+ ERROR1("Too many virtual modifiers defined (maximum %d)\n",
+ XkbNumVirtualMods);
+ ACTION("Exiting\n");
+ return False;
+ }
+ info->defined |= (1 << nextFree);
+ info->newlyDefined |= (1 << nextFree);
+ info->available |= (1 << nextFree);
+ names->vmods[nextFree] = stmtName;
+ if (stmt->value == NULL)
+ return True;
+ if (ExprResolveModMask(stmt->value, &mod, NULL, NULL))
+ {
+ srv->vmods[nextFree] = mod.uval;
+ return True;
+ }
+ ACTION1("Declaration of %s ignored\n",
+ XkbAtomText(NULL, stmt->name, XkbMessage));
+ return False;
+}
+
+/**
+ * Returns the index of the given modifier in the xkb->names->vmods array.
+ *
+ * @param priv Pointer to the xkb data structure.
+ * @param elem Must be None, otherwise return False.
+ * @param field The Atom of the modifier's name (e.g. Atom for LAlt)
+ * @param type Must be TypeInt, otherwise return False.
+ * @param val_rtrn Set to the index of the modifier that matches.
+ *
+ * @return True on success, False otherwise. If False is returned, val_rtrn is
+ * undefined.
+ */
+int
+LookupVModIndex(XPointer priv,
+ Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
+{
+ register int i;
+ register char *fieldStr;
+ register char *modStr;
+ XkbDescPtr xkb;
+
+ xkb = (XkbDescPtr) priv;
+ if ((xkb == NULL) || (xkb->names == NULL) || (elem != None)
+ || (type != TypeInt))
+ {
+ return False;
+ }
+ /* get the actual name */
+ fieldStr = XkbAtomGetString(xkb->dpy, field);
+ if (fieldStr == NULL)
+ return False;
+ /* For each named modifier, get the name and compare it to the one passed
+ * in. If we get a match, return the index of the modifier.
+ * The order of modifiers is the same as in the virtual_modifiers line in
+ * the xkb_types section.
+ */
+ for (i = 0; i < XkbNumVirtualMods; i++)
+ {
+ modStr = XkbAtomGetString(xkb->dpy, xkb->names->vmods[i]);
+ if ((modStr != NULL) && (uStrCaseCmp(fieldStr, modStr) == 0))
+ {
+ val_rtrn->uval = i;
+ return True;
+ }
+ }
+ return False;
+}
+
+/**
+ * Get the mask for the given modifier and set val_rtrn.uval to the mask.
+ * Note that the mask returned is always > 512.
+ *
+ * @param priv Pointer to xkb data structure.
+ * @param val_rtrn Set to the mask returned.
+ *
+ * @return True on success, False otherwise. If False is returned, val_rtrn is
+ * undefined.
+ */
+int
+LookupVModMask(XPointer priv,
+ Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
+{
+ if (LookupVModIndex(priv, elem, field, type, val_rtrn))
+ {
+ register unsigned ndx = val_rtrn->uval;
+ val_rtrn->uval = (1 << (XkbNumModifiers + ndx));
+ return True;
+ }
+ return False;
+}
+
+int
+FindKeypadVMod(XkbDescPtr xkb)
+{
+ Atom name;
+ ExprResult rtrn;
+
+ name = XkbInternAtom(xkb->dpy, "NumLock", False);
+ if ((xkb) && LookupVModIndex((XPointer) xkb, None, name, TypeInt, &rtrn))
+ {
+ return rtrn.ival;
+ }
+ return -1;
+}
+
+Bool
+ResolveVirtualModifier(ExprDef * def, ExprResult * val_rtrn, VModInfo * info)
+{
+ XkbNamesPtr names;
+
+ names = info->xkb->names;
+ if (def->op == ExprIdent)
+ {
+ register int i, bit;
+ for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1)
+ {
+ char *str1, *str2;
+ str1 = XkbAtomGetString(info->xkb->dpy, names->vmods[i]);
+ str2 = XkbAtomGetString(NULL, def->value.str);
+ if ((info->available & bit) && (uStrCaseCmp(str1, str2) == Equal))
+ {
+ val_rtrn->uval = i;
+ return True;
+ }
+ }
+ }
+ if (ExprResolveInteger(def, val_rtrn, NULL, NULL))
+ {
+ if (val_rtrn->uval < XkbNumVirtualMods)
+ return True;
+ ERROR2("Illegal virtual modifier %d (must be 0..%d inclusive)\n",
+ val_rtrn->uval, XkbNumVirtualMods - 1);
+ }
+ return False;
+}
diff --git a/src/xkbcomp/vmod.h b/src/xkbcomp/vmod.h
new file mode 100644
index 0000000..559b9d5
--- /dev/null
+++ b/src/xkbcomp/vmod.h
@@ -0,0 +1,78 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifndef VMOD_H
+#define VMOD_H 1
+
+typedef struct _VModInfo
+{
+ XkbDescPtr xkb;
+ unsigned defined;
+ unsigned available;
+ unsigned newlyDefined;
+ int errorCount;
+} VModInfo;
+
+extern void InitVModInfo(VModInfo * /* info */ ,
+ XkbDescPtr /* xkb */
+ );
+
+extern void ClearVModInfo(VModInfo * /* info */ ,
+ XkbDescPtr /* xkb */
+ );
+
+extern Bool HandleVModDef(VModDef * /* stmt */ ,
+ unsigned /* mergeMode */ ,
+ VModInfo * /* info */
+ );
+
+extern Bool ApplyVModDefs(VModInfo * /* info */ ,
+ XkbDescPtr /* xkb */
+ );
+
+extern int LookupVModIndex(XPointer /* priv */ ,
+ Atom /* elem */ ,
+ Atom /* field */ ,
+ unsigned /* type */ ,
+ ExprResult * /* val_rtrn */
+ );
+
+extern int LookupVModMask(XPointer /* priv */ ,
+ Atom /* elem */ ,
+ Atom /* field */ ,
+ unsigned /* type */ ,
+ ExprResult * /* val_rtrn */
+ );
+
+extern int FindKeypadVMod(XkbDescPtr /* xkb */
+ );
+
+extern Bool ResolveVirtualModifier(ExprDef * /* def */ ,
+ ExprResult * /* value_rtrn */ ,
+ VModInfo * /* info */
+ );
+
+#endif /* VMOD_H */
diff --git a/src/xkbcomp/xkbcomp.h b/src/xkbcomp/xkbcomp.h
new file mode 100644
index 0000000..6e02ed5
--- /dev/null
+++ b/src/xkbcomp/xkbcomp.h
@@ -0,0 +1,396 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifndef XKBCOMP_H
+#define XKBCOMP_H 1
+
+#ifndef DEBUG_VAR
+#define DEBUG_VAR debugFlags
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+
+#include "utils.h"
+
+#include <X11/extensions/XKM.h>
+#include <X11/extensions/XKBfile.h>
+
+extern char *scanFile;
+
+#define TypeUnknown 0
+#define TypeBoolean 1
+#define TypeInt 2
+#define TypeFloat 3
+#define TypeString 4
+#define TypeAction 5
+#define TypeKeyName 6
+#define TypeSymbols 7
+
+#define StmtUnknown 0
+#define StmtInclude 1
+#define StmtKeycodeDef 2
+#define StmtKeyAliasDef 3
+#define StmtExpr 4
+#define StmtVarDef 5
+#define StmtKeyTypeDef 6
+#define StmtInterpDef 7
+#define StmtVModDef 8
+#define StmtSymbolsDef 9
+#define StmtModMapDef 10
+#define StmtGroupCompatDef 11
+#define StmtIndicatorMapDef 12
+#define StmtIndicatorNameDef 13
+#define StmtOutlineDef 14
+#define StmtShapeDef 15
+#define StmtKeyDef 16
+#define StmtRowDef 17
+#define StmtSectionDef 18
+#define StmtOverlayKeyDef 19
+#define StmtOverlayDef 20
+#define StmtDoodadDef 21
+
+#define FileSymInterp 100
+
+typedef struct _ParseCommon
+{
+ unsigned stmtType;
+ struct _ParseCommon *next;
+} ParseCommon;
+
+#define ExprValue 0
+#define ExprIdent 1
+#define ExprActionDecl 2
+#define ExprFieldRef 3
+#define ExprArrayRef 4
+#define ExprKeysymList 5
+#define ExprActionList 6
+#define ExprCoord 7
+
+#define OpAdd 20
+#define OpSubtract 21
+#define OpMultiply 22
+#define OpDivide 23
+#define OpAssign 24
+#define OpNot 25
+#define OpNegate 26
+#define OpInvert 27
+#define OpUnaryPlus 28
+
+#define MergeDefault 0
+#define MergeAugment 1
+#define MergeOverride 2
+#define MergeReplace 3
+#define MergeAltForm 4
+
+#define AutoKeyNames (1L << 0)
+#define CreateKeyNames(x) ((x)->flags&AutoKeyNames)
+
+extern unsigned warningLevel;
+extern unsigned optionalParts;
+
+typedef struct _IncludeStmt
+{
+ ParseCommon common;
+ unsigned merge;
+ char *stmt;
+ char *file;
+ char *map;
+ char *modifier;
+ char *path;
+ struct _IncludeStmt *next;
+} IncludeStmt;
+
+typedef struct _Expr
+{
+ ParseCommon common;
+ unsigned op;
+ unsigned type;
+ union
+ {
+ struct
+ {
+ struct _Expr *left;
+ struct _Expr *right;
+ } binary;
+ struct
+ {
+ Atom element;
+ Atom field;
+ } field;
+ struct
+ {
+ Atom element;
+ Atom field;
+ struct _Expr *entry;
+ } array;
+ struct
+ {
+ Atom name;
+ struct _Expr *args;
+ } action;
+ struct
+ {
+ int nSyms;
+ int szSyms;
+ KeySym *syms;
+ } list;
+ struct
+ {
+ int x;
+ int y;
+ } coord;
+ struct _Expr *child;
+ Atom str;
+ unsigned uval;
+ int ival;
+ char keyName[5];
+ Opaque ptr;
+ } value;
+} ExprDef;
+
+typedef struct _VarDef
+{
+ ParseCommon common;
+ unsigned merge;
+ ExprDef *name;
+ ExprDef *value;
+} VarDef;
+
+typedef struct _VModDef
+{
+ ParseCommon common;
+ unsigned merge;
+ Atom name;
+ ExprDef *value;
+} VModDef;
+
+typedef struct _KeycodeDef
+{
+ ParseCommon common;
+ unsigned merge;
+ char name[5];
+ ExprDef *value;
+} KeycodeDef;
+
+typedef struct _KeyAliasDef
+{
+ ParseCommon common;
+ unsigned merge;
+ char alias[5];
+ char real[5];
+} KeyAliasDef;
+
+typedef struct _KeyTypeDef
+{
+ ParseCommon common;
+ unsigned merge;
+ Atom name;
+ VarDef *body;
+} KeyTypeDef;
+
+typedef struct _SymbolsDef
+{
+ ParseCommon common;
+ unsigned merge;
+ char keyName[5];
+ ExprDef *symbols;
+} SymbolsDef;
+
+typedef struct _ModMapDef
+{
+ ParseCommon common;
+ unsigned merge;
+ Atom modifier;
+ ExprDef *keys;
+} ModMapDef;
+
+typedef struct _GroupCompatDef
+{
+ ParseCommon common;
+ unsigned merge;
+ int group;
+ ExprDef *def;
+} GroupCompatDef;
+
+typedef struct _InterpDef
+{
+ ParseCommon common;
+ unsigned merge;
+ KeySym sym;
+ ExprDef *match;
+ VarDef *def;
+} InterpDef;
+
+typedef struct _IndicatorNameDef
+{
+ ParseCommon common;
+ unsigned merge;
+ int ndx;
+ ExprDef *name;
+ Bool virtual;
+} IndicatorNameDef;
+
+typedef struct _OutlineDef
+{
+ ParseCommon common;
+ Atom field;
+ int nPoints;
+ ExprDef *points;
+} OutlineDef;
+
+typedef struct _ShapeDef
+{
+ ParseCommon common;
+ unsigned merge;
+ Atom name;
+ int nOutlines;
+ OutlineDef *outlines;
+} ShapeDef;
+
+typedef struct _KeyDef
+{
+ ParseCommon common;
+ unsigned defined;
+ char *name;
+ ExprDef *expr;
+} KeyDef;
+
+typedef struct _RowDef
+{
+ ParseCommon common;
+ int nKeys;
+ KeyDef *keys;
+} RowDef;
+
+typedef struct _SectionDef
+{
+ ParseCommon common;
+ unsigned merge;
+ Atom name;
+ int nRows;
+ RowDef *rows;
+} SectionDef;
+
+typedef struct _OverlayKeyDef
+{
+ ParseCommon common;
+ char over[5];
+ char under[5];
+} OverlayKeyDef;
+
+typedef struct _OverlayDef
+{
+ ParseCommon common;
+ unsigned merge;
+ Atom name;
+ int nKeys;
+ OverlayKeyDef *keys;
+} OverlayDef;
+
+typedef struct _DoodadDef
+{
+ ParseCommon common;
+ unsigned merge;
+ unsigned type;
+ Atom name;
+ VarDef *body;
+} DoodadDef;
+
+/* IndicatorMapDef doesn't use the type field, but the rest of the fields
+ need to be at the same offsets as in DoodadDef. Use #define to avoid
+ any strict aliasing problems. */
+#define IndicatorMapDef DoodadDef
+
+typedef struct _XkbFile
+{
+ ParseCommon common;
+ int type;
+ char *topName;
+ char *name;
+ ParseCommon *defs;
+ int id;
+ unsigned flags;
+ Bool compiled;
+} XkbFile;
+
+extern Bool CompileKeymap(XkbFile * /* file */ ,
+ XkbFileInfo * /* result */ ,
+ unsigned /* merge */
+ );
+
+extern Bool CompileKeycodes(XkbFile * /* file */ ,
+ XkbFileInfo * /* result */ ,
+ unsigned /* merge */
+ );
+
+extern Bool CompileGeometry(XkbFile * /* file */ ,
+ XkbFileInfo * /* result */ ,
+ unsigned /* merge */
+ );
+
+extern Bool CompileKeyTypes(XkbFile * /* file */ ,
+ XkbFileInfo * /* result */ ,
+ unsigned /* merge */
+ );
+
+typedef struct _LEDInfo *LEDInfoPtr;
+
+extern Bool CompileCompatMap(XkbFile * /* file */ ,
+ XkbFileInfo * /* result */ ,
+ unsigned /* merge */ ,
+ LEDInfoPtr * /* unboundLEDs */
+ );
+
+extern Bool CompileSymbols(XkbFile * /* file */ ,
+ XkbFileInfo * /* result */ ,
+ unsigned /* merge */
+ );
+
+#define WantLongListing (1<<0)
+#define WantPartialMaps (1<<1)
+#define WantHiddenMaps (1<<2)
+#define WantFullNames (1<<3)
+#define ListRecursive (1<<4)
+
+extern char *rootDir;
+extern unsigned verboseLevel;
+extern unsigned dirsToStrip;
+
+extern Bool AddListing(char * /* file */ ,
+ char * /* map */
+ );
+
+extern Bool AddMatchingFiles(char * /* head_in */
+ );
+
+extern int AddMapOnly(char * /* map */
+ );
+
+extern int GenerateListing(char * /* filename */
+ );
+
+#endif /* XKBCOMP_H */
diff --git a/src/xkbcomp/xkbparse.c b/src/xkbcomp/xkbparse.c
new file mode 100644
index 0000000..b71df99
--- /dev/null
+++ b/src/xkbcomp/xkbparse.c
@@ -0,0 +1,3242 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ END_OF_FILE = 0,
+ ERROR_TOK = 255,
+ XKB_KEYMAP = 1,
+ XKB_KEYCODES = 2,
+ XKB_TYPES = 3,
+ XKB_SYMBOLS = 4,
+ XKB_COMPATMAP = 5,
+ XKB_GEOMETRY = 6,
+ XKB_SEMANTICS = 7,
+ XKB_LAYOUT = 8,
+ INCLUDE = 10,
+ OVERRIDE = 11,
+ AUGMENT = 12,
+ REPLACE = 13,
+ ALTERNATE = 14,
+ VIRTUAL_MODS = 20,
+ TYPE = 21,
+ INTERPRET = 22,
+ ACTION_TOK = 23,
+ KEY = 24,
+ ALIAS = 25,
+ GROUP = 26,
+ MODIFIER_MAP = 27,
+ INDICATOR = 28,
+ SHAPE = 29,
+ KEYS = 30,
+ ROW = 31,
+ SECTION = 32,
+ OVERLAY = 33,
+ TEXT = 34,
+ OUTLINE = 35,
+ SOLID = 36,
+ LOGO = 37,
+ VIRTUAL = 38,
+ EQUALS = 40,
+ PLUS = 41,
+ MINUS = 42,
+ DIVIDE = 43,
+ TIMES = 44,
+ OBRACE = 45,
+ CBRACE = 46,
+ OPAREN = 47,
+ CPAREN = 48,
+ OBRACKET = 49,
+ CBRACKET = 50,
+ DOT = 51,
+ COMMA = 52,
+ SEMI = 53,
+ EXCLAM = 54,
+ INVERT = 55,
+ STRING = 60,
+ INTEGER = 61,
+ FLOAT = 62,
+ IDENT = 63,
+ KEYNAME = 64,
+ PARTIAL = 70,
+ DEFAULT = 71,
+ HIDDEN = 72,
+ ALPHANUMERIC_KEYS = 73,
+ MODIFIER_KEYS = 74,
+ KEYPAD_KEYS = 75,
+ FUNCTION_KEYS = 76,
+ ALTERNATE_GROUP = 77
+ };
+#endif
+/* Tokens. */
+#define END_OF_FILE 0
+#define ERROR_TOK 255
+#define XKB_KEYMAP 1
+#define XKB_KEYCODES 2
+#define XKB_TYPES 3
+#define XKB_SYMBOLS 4
+#define XKB_COMPATMAP 5
+#define XKB_GEOMETRY 6
+#define XKB_SEMANTICS 7
+#define XKB_LAYOUT 8
+#define INCLUDE 10
+#define OVERRIDE 11
+#define AUGMENT 12
+#define REPLACE 13
+#define ALTERNATE 14
+#define VIRTUAL_MODS 20
+#define TYPE 21
+#define INTERPRET 22
+#define ACTION_TOK 23
+#define KEY 24
+#define ALIAS 25
+#define GROUP 26
+#define MODIFIER_MAP 27
+#define INDICATOR 28
+#define SHAPE 29
+#define KEYS 30
+#define ROW 31
+#define SECTION 32
+#define OVERLAY 33
+#define TEXT 34
+#define OUTLINE 35
+#define SOLID 36
+#define LOGO 37
+#define VIRTUAL 38
+#define EQUALS 40
+#define PLUS 41
+#define MINUS 42
+#define DIVIDE 43
+#define TIMES 44
+#define OBRACE 45
+#define CBRACE 46
+#define OPAREN 47
+#define CPAREN 48
+#define OBRACKET 49
+#define CBRACKET 50
+#define DOT 51
+#define COMMA 52
+#define SEMI 53
+#define EXCLAM 54
+#define INVERT 55
+#define STRING 60
+#define INTEGER 61
+#define FLOAT 62
+#define IDENT 63
+#define KEYNAME 64
+#define PARTIAL 70
+#define DEFAULT 71
+#define HIDDEN 72
+#define ALPHANUMERIC_KEYS 73
+#define MODIFIER_KEYS 74
+#define KEYPAD_KEYS 75
+#define FUNCTION_KEYS 76
+#define ALTERNATE_GROUP 77
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 91 "xkbparse.y"
+
+#ifdef DEBUG
+#define YYDEBUG 1
+#endif
+#define DEBUG_VAR parseDebug
+#include "parseutils.h"
+#include <X11/keysym.h>
+#include <X11/extensions/XKBgeom.h>
+#include <stdlib.h>
+
+unsigned int parseDebug;
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 110 "xkbparse.y"
+{
+ int ival;
+ unsigned uval;
+ char *str;
+ Atom sval;
+ ParseCommon *any;
+ ExprDef *expr;
+ VarDef *var;
+ VModDef *vmod;
+ InterpDef *interp;
+ KeyTypeDef *keyType;
+ SymbolsDef *syms;
+ ModMapDef *modMask;
+ GroupCompatDef *groupCompat;
+ IndicatorMapDef *ledMap;
+ IndicatorNameDef *ledName;
+ KeycodeDef *keyName;
+ KeyAliasDef *keyAlias;
+ ShapeDef *shape;
+ SectionDef *section;
+ RowDef *row;
+ KeyDef *key;
+ OverlayDef *overlay;
+ OverlayKeyDef *olKey;
+ OutlineDef *outline;
+ DoodadDef *doodad;
+ XkbFile *file;
+}
+/* Line 187 of yacc.c. */
+#line 269 "xkbparse.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 282 "xkbparse.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 18
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 706
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 65
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 73
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 184
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 335
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 257
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 4, 5, 6, 7, 8, 9, 10, 11, 2,
+ 12, 13, 14, 15, 16, 2, 2, 2, 2, 2,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 2,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 2, 2, 2, 2,
+ 52, 53, 54, 55, 56, 2, 2, 2, 2, 2,
+ 57, 58, 59, 60, 61, 62, 63, 64, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 3, 1, 2
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 12, 14, 22, 24,
+ 26, 28, 31, 33, 41, 46, 48, 50, 52, 54,
+ 56, 58, 59, 62, 64, 66, 68, 70, 72, 74,
+ 76, 78, 80, 83, 84, 87, 90, 93, 96, 99,
+ 102, 105, 108, 111, 114, 117, 120, 123, 126, 129,
+ 134, 137, 141, 146, 152, 156, 160, 162, 164, 168,
+ 175, 179, 181, 184, 186, 193, 200, 204, 206, 207,
+ 211, 215, 217, 220, 222, 226, 230, 236, 243, 250,
+ 256, 263, 270, 277, 284, 287, 289, 295, 297, 299,
+ 301, 303, 306, 308, 314, 316, 320, 322, 324, 328,
+ 335, 339, 341, 345, 349, 351, 355, 361, 365, 369,
+ 371, 377, 384, 386, 388, 390, 392, 394, 396, 398,
+ 400, 402, 404, 406, 408, 410, 412, 414, 416, 418,
+ 420, 421, 423, 425, 427, 429, 431, 433, 434, 438,
+ 440, 444, 448, 452, 456, 460, 462, 465, 468, 471,
+ 474, 476, 481, 483, 487, 491, 493, 498, 500, 504,
+ 509, 516, 518, 520, 522, 524, 526, 527, 531, 533,
+ 535, 537, 539, 542, 544, 546, 548, 550, 552, 554,
+ 556, 558, 560, 562, 563
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 66, 0, -1, 67, -1, 70, -1, 72, -1, 67,
+ 68, -1, 68, -1, 74, 69, 136, 41, 70, 42,
+ 49, -1, 4, -1, 10, -1, 11, -1, 70, 71,
+ -1, 71, -1, 74, 73, 136, 41, 77, 42, 49,
+ -1, 74, 73, 136, 77, -1, 5, -1, 6, -1,
+ 8, -1, 7, -1, 9, -1, 75, -1, -1, 75,
+ 76, -1, 76, -1, 57, -1, 58, -1, 59, -1,
+ 60, -1, 61, -1, 62, -1, 63, -1, 64, -1,
+ 77, 78, -1, -1, 116, 79, -1, 116, 82, -1,
+ 116, 85, -1, 116, 80, -1, 116, 81, -1, 116,
+ 88, -1, 116, 89, -1, 116, 94, -1, 116, 93,
+ -1, 116, 95, -1, 116, 96, -1, 116, 97, -1,
+ 116, 98, -1, 116, 112, -1, 117, 52, -1, 124,
+ 36, 120, 49, -1, 134, 49, -1, 50, 134, 49,
+ -1, 133, 36, 120, 49, -1, 22, 133, 36, 133,
+ 49, -1, 17, 83, 49, -1, 83, 48, 84, -1,
+ 84, -1, 134, -1, 134, 36, 120, -1, 19, 86,
+ 41, 87, 42, 49, -1, 128, 37, 120, -1, 128,
+ -1, 87, 79, -1, 79, -1, 18, 135, 41, 87,
+ 42, 49, -1, 21, 133, 41, 90, 42, 49, -1,
+ 90, 48, 91, -1, 91, -1, -1, 124, 36, 120,
+ -1, 124, 36, 92, -1, 134, -1, 50, 134, -1,
+ 92, -1, 45, 126, 46, -1, 45, 122, 46, -1,
+ 23, 132, 36, 120, 49, -1, 24, 134, 41, 119,
+ 42, 49, -1, 25, 135, 41, 87, 42, 49, -1,
+ 25, 132, 36, 120, 49, -1, 35, 25, 132, 36,
+ 120, 49, -1, 26, 135, 41, 108, 42, 49, -1,
+ 26, 135, 41, 110, 42, 49, -1, 29, 135, 41,
+ 99, 42, 49, -1, 99, 100, -1, 100, -1, 28,
+ 41, 101, 42, 49, -1, 79, -1, 112, -1, 95,
+ -1, 105, -1, 101, 102, -1, 102, -1, 27, 41,
+ 103, 42, 49, -1, 79, -1, 103, 48, 104, -1,
+ 104, -1, 133, -1, 41, 119, 42, -1, 30, 135,
+ 41, 106, 42, 49, -1, 106, 48, 107, -1, 107,
+ -1, 133, 36, 133, -1, 108, 48, 109, -1, 109,
+ -1, 41, 110, 42, -1, 134, 36, 41, 110, 42,
+ -1, 134, 36, 120, -1, 110, 48, 111, -1, 111,
+ -1, 45, 129, 48, 129, 46, -1, 113, 135, 41,
+ 87, 42, 49, -1, 31, -1, 32, -1, 33, -1,
+ 34, -1, 134, -1, 115, -1, 20, -1, 19, -1,
+ 18, -1, 21, -1, 23, -1, 24, -1, 25, -1,
+ 26, -1, 28, -1, 29, -1, 31, -1, 117, -1,
+ -1, 12, -1, 14, -1, 13, -1, 15, -1, 16,
+ -1, 119, -1, -1, 119, 48, 120, -1, 120, -1,
+ 120, 39, 120, -1, 120, 37, 120, -1, 120, 38,
+ 120, -1, 120, 40, 120, -1, 124, 36, 120, -1,
+ 121, -1, 38, 121, -1, 37, 121, -1, 50, 121,
+ -1, 51, 121, -1, 124, -1, 114, 43, 118, 44,
+ -1, 125, -1, 43, 120, 44, -1, 122, 48, 123,
+ -1, 123, -1, 114, 43, 118, 44, -1, 114, -1,
+ 114, 47, 114, -1, 114, 45, 120, 46, -1, 114,
+ 47, 114, 45, 120, 46, -1, 135, -1, 132, -1,
+ 131, -1, 133, -1, 127, -1, -1, 127, 48, 128,
+ -1, 128, -1, 55, -1, 29, -1, 132, -1, 38,
+ 130, -1, 130, -1, 54, -1, 53, -1, 54, -1,
+ 53, -1, 56, -1, 55, -1, 58, -1, 52, -1,
+ 137, -1, -1, 52, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 168, 168, 170, 172, 176, 182, 186, 199, 200,
+ 201, 204, 213, 217, 229, 238, 239, 240, 241, 242,
+ 245, 246, 249, 250, 253, 254, 255, 256, 257, 258,
+ 259, 260, 263, 270, 273, 278, 283, 288, 293, 298,
+ 303, 308, 313, 318, 323, 328, 333, 338, 343, 358,
+ 360, 362, 366, 377, 387, 391, 397, 401, 403, 407,
+ 416, 418, 422, 428, 432, 438, 444, 450, 452, 455,
+ 457, 459, 461, 463, 467, 469, 473, 477, 481, 485,
+ 487, 491, 493, 501, 505, 511, 515, 517, 519, 521,
+ 523, 527, 533, 537, 539, 543, 548, 552, 554, 558,
+ 562, 569, 573, 577, 583, 587, 589, 591, 595, 601,
+ 605, 615, 619, 620, 621, 622, 625, 626, 629, 631,
+ 633, 635, 637, 639, 641, 643, 645, 647, 649, 653,
+ 654, 657, 658, 659, 660, 661, 664, 665, 668, 674,
+ 678, 680, 682, 684, 686, 688, 692, 694, 696, 698,
+ 700, 702, 704, 706, 710, 716, 720, 724, 731, 739,
+ 748, 759, 766, 773, 780, 791, 792, 795, 797, 801,
+ 816, 820, 827, 828, 831, 832, 835, 838, 841, 844,
+ 845, 848, 851, 852, 855
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "END_OF_FILE", "error", "$undefined", "ERROR_TOK", "XKB_KEYMAP",
+ "XKB_KEYCODES", "XKB_TYPES", "XKB_SYMBOLS", "XKB_COMPATMAP",
+ "XKB_GEOMETRY", "XKB_SEMANTICS", "XKB_LAYOUT", "INCLUDE", "OVERRIDE",
+ "AUGMENT", "REPLACE", "ALTERNATE", "VIRTUAL_MODS", "TYPE", "INTERPRET",
+ "ACTION_TOK", "KEY", "ALIAS", "GROUP", "MODIFIER_MAP", "INDICATOR",
+ "SHAPE", "KEYS", "ROW", "SECTION", "OVERLAY", "TEXT", "OUTLINE", "SOLID",
+ "LOGO", "VIRTUAL", "EQUALS", "PLUS", "MINUS", "DIVIDE", "TIMES",
+ "OBRACE", "CBRACE", "OPAREN", "CPAREN", "OBRACKET", "CBRACKET", "DOT",
+ "COMMA", "SEMI", "EXCLAM", "INVERT", "STRING", "INTEGER", "FLOAT",
+ "IDENT", "KEYNAME", "PARTIAL", "DEFAULT", "HIDDEN", "ALPHANUMERIC_KEYS",
+ "MODIFIER_KEYS", "KEYPAD_KEYS", "FUNCTION_KEYS", "ALTERNATE_GROUP",
+ "$accept", "XkbFile", "XkbCompMapList", "XkbCompositeMap",
+ "XkbCompositeType", "XkbMapConfigList", "XkbMapConfig", "XkbConfig",
+ "FileType", "OptFlags", "Flags", "Flag", "DeclList", "Decl", "VarDecl",
+ "KeyNameDecl", "KeyAliasDecl", "VModDecl", "VModDefList", "VModDef",
+ "InterpretDecl", "InterpretMatch", "VarDeclList", "KeyTypeDecl",
+ "SymbolsDecl", "SymbolsBody", "SymbolsVarDecl", "ArrayInit",
+ "GroupCompatDecl", "ModMapDecl", "IndicatorMapDecl", "IndicatorNameDecl",
+ "ShapeDecl", "SectionDecl", "SectionBody", "SectionBodyItem", "RowBody",
+ "RowBodyItem", "Keys", "Key", "OverlayDecl", "OverlayKeyList",
+ "OverlayKey", "OutlineList", "OutlineInList", "CoordList", "Coord",
+ "DoodadDecl", "DoodadType", "FieldSpec", "Element", "OptMergeMode",
+ "MergeMode", "OptExprList", "ExprList", "Expr", "Term", "ActionList",
+ "Action", "Lhs", "Terminal", "OptKeySymList", "KeySymList", "KeySym",
+ "SignedNumber", "Number", "Float", "Integer", "KeyName", "Ident",
+ "String", "OptMapName", "MapName", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 255, 1, 2, 3, 4, 5, 6,
+ 7, 8, 10, 11, 12, 13, 14, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 60, 61, 62, 63, 64, 70, 71, 72,
+ 73, 74, 75, 76, 77
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 65, 66, 66, 66, 67, 67, 68, 69, 69,
+ 69, 70, 70, 71, 72, 73, 73, 73, 73, 73,
+ 74, 74, 75, 75, 76, 76, 76, 76, 76, 76,
+ 76, 76, 77, 77, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 79,
+ 79, 79, 80, 81, 82, 83, 83, 84, 84, 85,
+ 86, 86, 87, 87, 88, 89, 90, 90, 90, 91,
+ 91, 91, 91, 91, 92, 92, 93, 94, 95, 96,
+ 96, 97, 97, 98, 99, 99, 100, 100, 100, 100,
+ 100, 101, 101, 102, 102, 103, 103, 104, 104, 105,
+ 106, 106, 107, 108, 108, 109, 109, 109, 110, 110,
+ 111, 112, 113, 113, 113, 113, 114, 114, 115, 115,
+ 115, 115, 115, 115, 115, 115, 115, 115, 115, 116,
+ 116, 117, 117, 117, 117, 117, 118, 118, 119, 119,
+ 120, 120, 120, 120, 120, 120, 121, 121, 121, 121,
+ 121, 121, 121, 121, 122, 122, 123, 124, 124, 124,
+ 124, 125, 125, 125, 125, 126, 126, 127, 127, 128,
+ 128, 128, 129, 129, 130, 130, 131, 132, 133, 134,
+ 134, 135, 136, 136, 137
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 1, 1, 2, 1, 7, 1, 1,
+ 1, 2, 1, 7, 4, 1, 1, 1, 1, 1,
+ 1, 0, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 4,
+ 2, 3, 4, 5, 3, 3, 1, 1, 3, 6,
+ 3, 1, 2, 1, 6, 6, 3, 1, 0, 3,
+ 3, 1, 2, 1, 3, 3, 5, 6, 6, 5,
+ 6, 6, 6, 6, 2, 1, 5, 1, 1, 1,
+ 1, 2, 1, 5, 1, 3, 1, 1, 3, 6,
+ 3, 1, 3, 3, 1, 3, 5, 3, 3, 1,
+ 5, 6, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 0, 3, 1,
+ 3, 3, 3, 3, 3, 1, 2, 2, 2, 2,
+ 1, 4, 1, 3, 3, 1, 4, 1, 3, 4,
+ 6, 1, 1, 1, 1, 1, 0, 3, 1, 1,
+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 21, 24, 25, 26, 27, 28, 29, 30, 31, 0,
+ 21, 6, 21, 12, 4, 0, 20, 23, 1, 5,
+ 0, 11, 0, 8, 15, 16, 18, 17, 19, 9,
+ 10, 183, 183, 22, 183, 184, 0, 182, 33, 0,
+ 21, 33, 130, 21, 130, 131, 133, 132, 134, 135,
+ 32, 0, 129, 0, 0, 0, 120, 119, 118, 121,
+ 0, 122, 123, 124, 125, 126, 127, 128, 113, 114,
+ 115, 0, 0, 179, 178, 180, 34, 37, 38, 35,
+ 36, 39, 40, 42, 41, 43, 44, 45, 46, 47,
+ 0, 157, 117, 0, 0, 116, 48, 7, 13, 0,
+ 56, 57, 181, 0, 170, 177, 169, 0, 61, 171,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 50, 0, 54, 0, 0,
+ 0, 0, 68, 0, 0, 0, 0, 0, 0, 0,
+ 0, 51, 0, 120, 119, 121, 122, 123, 124, 125,
+ 127, 128, 0, 0, 0, 0, 0, 176, 157, 0,
+ 145, 150, 152, 163, 162, 164, 116, 161, 158, 0,
+ 0, 55, 58, 63, 0, 0, 60, 166, 0, 0,
+ 67, 73, 0, 116, 0, 0, 0, 139, 0, 0,
+ 0, 0, 0, 104, 0, 109, 0, 124, 126, 0,
+ 87, 89, 0, 85, 90, 88, 0, 0, 147, 150,
+ 146, 0, 148, 149, 137, 0, 0, 0, 0, 159,
+ 0, 0, 49, 52, 0, 62, 0, 170, 169, 0,
+ 0, 155, 0, 165, 168, 72, 0, 0, 0, 53,
+ 76, 0, 0, 79, 0, 0, 0, 175, 174, 0,
+ 173, 0, 0, 0, 0, 0, 0, 0, 0, 84,
+ 0, 0, 153, 0, 136, 141, 142, 140, 143, 144,
+ 0, 64, 59, 137, 75, 0, 74, 0, 65, 66,
+ 70, 69, 77, 138, 78, 105, 172, 0, 81, 103,
+ 82, 108, 0, 107, 0, 94, 0, 92, 0, 83,
+ 80, 111, 151, 160, 0, 154, 167, 0, 0, 0,
+ 0, 91, 0, 101, 0, 156, 110, 106, 0, 0,
+ 96, 97, 86, 0, 0, 0, 0, 0, 0, 99,
+ 100, 102, 98, 93, 95
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 9, 10, 11, 31, 12, 13, 14, 32, 22,
+ 16, 17, 42, 50, 173, 77, 78, 79, 99, 100,
+ 80, 107, 174, 81, 82, 179, 180, 181, 83, 84,
+ 201, 86, 87, 88, 202, 203, 296, 297, 319, 320,
+ 204, 312, 313, 192, 193, 194, 195, 205, 90, 158,
+ 92, 51, 52, 263, 264, 187, 160, 230, 231, 161,
+ 162, 232, 233, 108, 249, 250, 163, 164, 165, 166,
+ 167, 36, 37
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -188
+static const yytype_int16 yypact[] =
+{
+ 628, -188, -188, -188, -188, -188, -188, -188, -188, 12,
+ 4, -188, 58, -188, -188, 695, 628, -188, -188, -188,
+ 121, -188, 408, -188, -188, -188, -188, -188, -188, -188,
+ -188, -9, -9, -188, -9, -188, 19, -188, 45, 45,
+ 628, -188, 174, 620, 137, -188, -188, -188, -188, -188,
+ -188, 317, 39, -15, 50, 1, 59, -18, -188, 72,
+ 72, 106, 1, -27, 59, -188, 59, 62, -188, -188,
+ -188, 117, 1, -188, -188, -188, -188, -188, -188, -188,
+ -188, -188, -188, -188, -188, -188, -188, -188, -188, -188,
+ 59, 51, -188, 125, 146, 134, -188, -188, -188, 132,
+ -188, 163, -188, 168, -188, -188, -188, 173, 179, -188,
+ 178, 186, 190, 194, 206, 204, 208, 221, 106, 216,
+ 225, 265, 640, 265, 265, -188, 1, -188, 265, 599,
+ 599, 265, 470, 72, 265, 265, 265, 599, -26, 21,
+ 239, -188, 599, -188, -188, -188, -188, -188, -188, -188,
+ -188, -188, 265, 265, 265, 265, 265, -188, 159, 232,
+ -188, 240, -188, -188, -188, -188, -188, -188, 223, 98,
+ 156, -188, 260, -188, 485, 513, 260, 617, 1, 30,
+ -188, -188, 243, 32, 231, 192, 64, 260, 199, 528,
+ 236, 35, 127, -188, 128, -188, 251, 59, 270, 59,
+ -188, -188, 422, -188, -188, -188, 265, 556, -188, -188,
+ -188, 342, -188, -188, 265, 265, 265, 265, 265, -188,
+ 265, 265, -188, -188, 263, -188, 264, 249, 271, 281,
+ 61, -188, 279, 278, -188, -188, 280, 470, 340, -188,
+ -188, 283, 265, -188, 284, 129, 16, -188, -188, 282,
+ -188, 298, -34, 308, 236, 381, 576, 287, 321, -188,
+ 215, 325, -188, 332, 336, 158, 158, -188, -188, 260,
+ 316, -188, -188, 265, -188, 640, -188, -18, -188, -188,
+ -188, 260, -188, 260, -188, -188, -188, 35, -188, -188,
+ -188, -188, 236, 260, 346, -188, 442, -188, 72, -188,
+ -188, -188, -188, -188, 344, -188, -188, 343, 143, -28,
+ 348, -188, 176, -188, 367, -188, -188, -188, 265, 198,
+ -188, -188, -188, 359, 72, 72, 202, 362, -28, -188,
+ -188, -188, -188, -188, -188
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -188, -188, -188, 410, -188, 383, -7, -188, 399, 38,
+ -188, 409, 385, -188, -35, -188, -188, -188, -188, 301,
+ -188, -188, -47, -188, -188, -188, 191, 200, -188, -188,
+ 378, -188, -188, -188, -188, 228, -188, 148, -188, 130,
+ -188, -188, 133, -188, 197, -187, 205, 423, -188, 26,
+ -188, -188, -188, 203, -134, 89, 104, -188, 207, -29,
+ -188, -188, -188, -175, 188, 233, -188, -43, -51, -45,
+ -33, 109, -188
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -180
+static const yytype_int16 yytable[] =
+{
+ 94, 186, 234, 245, -2, 21, 95, 190, 110, 111,
+ 101, 104, 18, 318, 109, 190, 76, 113, 112, 191,
+ 114, 73, 93, 103, 75, 102, 105, 119, 74, 73,
+ 115, 116, 75, 117, 97, 105, 21, 106, 15, 143,
+ 144, 58, 145, 35, 146, 147, 197, 149, 20, 198,
+ 150, 199, 67, 68, 69, 70, 73, 120, -3, 75,
+ 40, 1, 2, 3, 4, 5, 6, 7, 8, 247,
+ 248, 72, 236, 246, -71, 140, 73, 91, 237, 75,
+ -71, 101, 184, 175, 95, 95, 41, 183, 247, 248,
+ 189, 96, 95, 196, 95, 207, 121, 95, 122, 98,
+ 93, 93, 306, 182, 200, 308, 241, 274, 93, 275,
+ 93, 102, 242, 93, -112, 1, 2, 3, 4, 5,
+ 6, 7, 8, 209, 209, 23, 209, 209, 74, 95,
+ 95, 29, 30, 235, 109, 215, 216, 217, 218, 225,
+ 225, 38, 118, 39, 95, 93, 93, 222, 168, 45,
+ 46, 47, 48, 49, 225, 91, 91, 95, 91, 105,
+ 93, 123, 95, 91, 115, 91, 257, 200, 91, 251,
+ 253, 285, 225, 93, -14, 252, 254, 254, 93, 54,
+ 126, 127, 124, 125, 326, 317, 45, 46, 47, 48,
+ 49, 254, 183, 215, 216, 217, 218, 217, 218, 128,
+ 91, 91, 214, 229, 121, 223, 122, 196, 182, 129,
+ 159, 95, 169, 170, 130, 91, 131, 172, 323, 132,
+ 176, 295, 133, 185, 324, 188, 134, 93, 91, 215,
+ 216, 217, 218, 91, 109, 135, 215, 216, 217, 218,
+ 327, 240, 136, 211, 332, 137, 328, 314, 243, 138,
+ 242, 95, 215, 216, 217, 218, 208, 210, 321, 212,
+ 213, 295, 139, 91, 300, 141, 142, 93, 221, 215,
+ 216, 217, 218, 314, 331, 206, 220, 321, 219, 238,
+ 239, 191, 91, 143, 144, 58, 145, 255, 146, 147,
+ 148, 149, -127, 65, 150, 260, 151, 215, 216, 217,
+ 218, 229, 152, 153, 265, 266, 267, 268, 154, 269,
+ 270, 256, 271, 272, -179, 155, 156, 102, 105, 157,
+ 73, 74, 91, 75, 273, 276, 277, 281, 298, 278,
+ 287, 283, 282, 284, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 293, 65, 66, 288, 67, 68,
+ 69, 70, 71, 215, 216, 217, 218, 290, 143, 144,
+ 58, 145, 303, 146, 147, 148, 149, 72, 65, 150,
+ 299, 151, 73, 74, 301, 75, 302, 152, 153, 215,
+ 216, 217, 218, 154, 242, 177, 262, 309, 315, 316,
+ 155, 156, 102, 105, 157, 73, 74, 322, 75, 143,
+ 144, 58, 145, 325, 146, 147, 148, 149, 329, 65,
+ 150, 333, 151, 24, 25, 26, 27, 28, 152, 153,
+ 19, 34, 292, 43, 154, 33, 44, 171, 279, 85,
+ 259, 155, 156, 102, 105, 157, 73, 74, 280, 75,
+ 143, 144, 58, 145, 311, 146, 147, 197, 149, 289,
+ 198, 150, 199, 67, 68, 69, 70, 330, 334, 291,
+ 143, 144, 58, 145, 258, 146, 147, 148, 149, 294,
+ 65, 150, 72, 151, 89, 307, 304, 73, 0, 286,
+ 75, 0, 305, 0, 310, 0, 0, 0, 143, 144,
+ 58, 145, 72, 146, 147, 148, 149, 73, 65, 150,
+ 75, 151, 0, 143, 144, 58, 145, 0, 146, 147,
+ 148, 149, 0, 65, 150, 177, 151, 0, 0, 0,
+ 178, 0, 0, 0, 0, 73, 0, 224, 75, 0,
+ 0, 143, 144, 58, 145, 72, 146, 147, 148, 149,
+ 73, 65, 150, 75, 151, 0, 143, 144, 58, 145,
+ 0, 146, 147, 148, 149, 226, 65, 150, 0, 151,
+ 0, 0, 0, 72, 0, 0, 0, 0, 73, 0,
+ 244, 75, 0, 0, 143, 144, 58, 145, 72, 146,
+ 147, 148, 149, 73, 65, 150, 75, 151, 0, 0,
+ 0, 0, 0, 0, 143, 144, 58, 145, 261, 146,
+ 147, 148, 149, 294, 65, 150, 72, 151, 0, 0,
+ 0, 73, 0, 0, 75, 0, 0, 143, 144, 58,
+ 145, 0, 146, 147, 148, 149, 72, 65, 150, 0,
+ 151, 73, 0, 0, 75, 143, 144, 58, 145, 0,
+ 146, 147, 148, 149, 0, 65, 227, 0, 151, 72,
+ 0, 0, 0, 0, 73, 0, 0, 75, 143, 144,
+ 58, 145, 53, 146, 147, 148, 149, 0, 65, 150,
+ 105, 151, 228, 0, 0, 75, 0, 1, 2, 3,
+ 4, 5, 6, 7, 8, 1, 2, 3, 4, 5,
+ 6, 7, 8, 0, 0, 73, 0, 0, 75, 23,
+ 24, 25, 26, 27, 28, 29, 30
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 51, 135, 177, 190, 0, 12, 51, 41, 59, 60,
+ 55, 29, 0, 41, 57, 41, 51, 62, 61, 45,
+ 63, 55, 51, 56, 58, 52, 53, 72, 56, 55,
+ 63, 64, 58, 66, 49, 53, 43, 55, 0, 18,
+ 19, 20, 21, 52, 23, 24, 25, 26, 10, 28,
+ 29, 30, 31, 32, 33, 34, 55, 90, 0, 58,
+ 41, 57, 58, 59, 60, 61, 62, 63, 64, 53,
+ 54, 50, 42, 38, 42, 118, 55, 51, 48, 58,
+ 48, 126, 133, 130, 129, 130, 41, 132, 53, 54,
+ 137, 52, 137, 138, 139, 142, 45, 142, 47, 49,
+ 129, 130, 277, 132, 139, 292, 42, 46, 137, 48,
+ 139, 52, 48, 142, 52, 57, 58, 59, 60, 61,
+ 62, 63, 64, 152, 153, 4, 155, 156, 56, 174,
+ 175, 10, 11, 178, 177, 37, 38, 39, 40, 174,
+ 175, 32, 25, 34, 189, 174, 175, 49, 122, 12,
+ 13, 14, 15, 16, 189, 129, 130, 202, 132, 53,
+ 189, 36, 207, 137, 197, 139, 199, 202, 142, 42,
+ 42, 42, 207, 202, 0, 48, 48, 48, 207, 42,
+ 48, 49, 36, 49, 318, 42, 12, 13, 14, 15,
+ 16, 48, 237, 37, 38, 39, 40, 39, 40, 36,
+ 174, 175, 43, 177, 45, 49, 47, 252, 237, 41,
+ 121, 256, 123, 124, 41, 189, 37, 128, 42, 41,
+ 131, 256, 36, 134, 48, 136, 36, 256, 202, 37,
+ 38, 39, 40, 207, 277, 41, 37, 38, 39, 40,
+ 42, 49, 36, 154, 42, 41, 48, 298, 49, 41,
+ 48, 296, 37, 38, 39, 40, 152, 153, 309, 155,
+ 156, 296, 41, 237, 49, 49, 41, 296, 45, 37,
+ 38, 39, 40, 324, 325, 36, 36, 328, 46, 36,
+ 49, 45, 256, 18, 19, 20, 21, 36, 23, 24,
+ 25, 26, 43, 28, 29, 206, 31, 37, 38, 39,
+ 40, 275, 37, 38, 215, 216, 217, 218, 43, 220,
+ 221, 41, 49, 49, 43, 50, 51, 52, 53, 54,
+ 55, 56, 296, 58, 43, 46, 48, 238, 41, 49,
+ 48, 242, 49, 49, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 255, 28, 29, 49, 31, 32,
+ 33, 34, 35, 37, 38, 39, 40, 49, 18, 19,
+ 20, 21, 46, 23, 24, 25, 26, 50, 28, 29,
+ 49, 31, 55, 56, 49, 58, 44, 37, 38, 37,
+ 38, 39, 40, 43, 48, 45, 44, 41, 44, 46,
+ 50, 51, 52, 53, 54, 55, 56, 49, 58, 18,
+ 19, 20, 21, 36, 23, 24, 25, 26, 49, 28,
+ 29, 49, 31, 5, 6, 7, 8, 9, 37, 38,
+ 10, 22, 41, 40, 43, 16, 41, 126, 237, 51,
+ 202, 50, 51, 52, 53, 54, 55, 56, 238, 58,
+ 18, 19, 20, 21, 296, 23, 24, 25, 26, 252,
+ 28, 29, 30, 31, 32, 33, 34, 324, 328, 254,
+ 18, 19, 20, 21, 42, 23, 24, 25, 26, 27,
+ 28, 29, 50, 31, 51, 287, 273, 55, -1, 246,
+ 58, -1, 275, -1, 42, -1, -1, -1, 18, 19,
+ 20, 21, 50, 23, 24, 25, 26, 55, 28, 29,
+ 58, 31, -1, 18, 19, 20, 21, -1, 23, 24,
+ 25, 26, -1, 28, 29, 45, 31, -1, -1, -1,
+ 50, -1, -1, -1, -1, 55, -1, 42, 58, -1,
+ -1, 18, 19, 20, 21, 50, 23, 24, 25, 26,
+ 55, 28, 29, 58, 31, -1, 18, 19, 20, 21,
+ -1, 23, 24, 25, 26, 42, 28, 29, -1, 31,
+ -1, -1, -1, 50, -1, -1, -1, -1, 55, -1,
+ 42, 58, -1, -1, 18, 19, 20, 21, 50, 23,
+ 24, 25, 26, 55, 28, 29, 58, 31, -1, -1,
+ -1, -1, -1, -1, 18, 19, 20, 21, 42, 23,
+ 24, 25, 26, 27, 28, 29, 50, 31, -1, -1,
+ -1, 55, -1, -1, 58, -1, -1, 18, 19, 20,
+ 21, -1, 23, 24, 25, 26, 50, 28, 29, -1,
+ 31, 55, -1, -1, 58, 18, 19, 20, 21, -1,
+ 23, 24, 25, 26, -1, 28, 29, -1, 31, 50,
+ -1, -1, -1, -1, 55, -1, -1, 58, 18, 19,
+ 20, 21, 42, 23, 24, 25, 26, -1, 28, 29,
+ 53, 31, 55, -1, -1, 58, -1, 57, 58, 59,
+ 60, 61, 62, 63, 64, 57, 58, 59, 60, 61,
+ 62, 63, 64, -1, -1, 55, -1, -1, 58, 4,
+ 5, 6, 7, 8, 9, 10, 11
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 57, 58, 59, 60, 61, 62, 63, 64, 66,
+ 67, 68, 70, 71, 72, 74, 75, 76, 0, 68,
+ 74, 71, 74, 4, 5, 6, 7, 8, 9, 10,
+ 11, 69, 73, 76, 73, 52, 136, 137, 136, 136,
+ 41, 41, 77, 70, 77, 12, 13, 14, 15, 16,
+ 78, 116, 117, 42, 42, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 28, 29, 31, 32, 33,
+ 34, 35, 50, 55, 56, 58, 79, 80, 81, 82,
+ 85, 88, 89, 93, 94, 95, 96, 97, 98, 112,
+ 113, 114, 115, 124, 133, 134, 52, 49, 49, 83,
+ 84, 134, 52, 135, 29, 53, 55, 86, 128, 132,
+ 133, 133, 132, 134, 132, 135, 135, 135, 25, 134,
+ 135, 45, 47, 36, 36, 49, 48, 49, 36, 41,
+ 41, 37, 41, 36, 36, 41, 36, 41, 41, 41,
+ 132, 49, 41, 18, 19, 21, 23, 24, 25, 26,
+ 29, 31, 37, 38, 43, 50, 51, 54, 114, 120,
+ 121, 124, 125, 131, 132, 133, 134, 135, 114, 120,
+ 120, 84, 120, 79, 87, 87, 120, 45, 50, 90,
+ 91, 92, 124, 134, 133, 120, 119, 120, 120, 87,
+ 41, 45, 108, 109, 110, 111, 134, 25, 28, 30,
+ 79, 95, 99, 100, 105, 112, 36, 87, 121, 124,
+ 121, 120, 121, 121, 43, 37, 38, 39, 40, 46,
+ 36, 45, 49, 49, 42, 79, 42, 29, 55, 114,
+ 122, 123, 126, 127, 128, 134, 42, 48, 36, 49,
+ 49, 42, 48, 49, 42, 110, 38, 53, 54, 129,
+ 130, 42, 48, 42, 48, 36, 41, 135, 42, 100,
+ 120, 42, 44, 118, 119, 120, 120, 120, 120, 120,
+ 120, 49, 49, 43, 46, 48, 46, 48, 49, 91,
+ 92, 120, 49, 120, 49, 42, 130, 48, 49, 109,
+ 49, 111, 41, 120, 27, 79, 101, 102, 41, 49,
+ 49, 49, 44, 46, 118, 123, 128, 129, 110, 41,
+ 42, 102, 106, 107, 133, 44, 46, 42, 41, 103,
+ 104, 133, 49, 42, 48, 36, 119, 42, 48, 49,
+ 107, 133, 42, 49, 104
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+#line 169 "xkbparse.y"
+ { (yyval.file)= rtrnValue= (yyvsp[(1) - (1)].file); }
+ break;
+
+ case 3:
+#line 171 "xkbparse.y"
+ { (yyval.file)= rtrnValue= (yyvsp[(1) - (1)].file); }
+ break;
+
+ case 4:
+#line 173 "xkbparse.y"
+ { (yyval.file)= rtrnValue= (yyvsp[(1) - (1)].file); }
+ break;
+
+ case 5:
+#line 177 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with XkbCompMapList\n");
+ (yyval.file)= (XkbFile *)AppendStmt(&(yyvsp[(1) - (2)].file)->common,&(yyvsp[(2) - (2)].file)->common);
+ }
+ break;
+
+ case 6:
+#line 183 "xkbparse.y"
+ { (yyval.file)= (yyvsp[(1) - (1)].file); }
+ break;
+
+ case 7:
+#line 189 "xkbparse.y"
+ {
+ fprintf(stderr, "Calling CreateXKBFile with "
+ "XkbCompositeMap type %i defs %p->common\n",
+ (yyvsp[(2) - (7)].uval), (yyvsp[(5) - (7)].file));
+ (yyval.file)= CreateXKBFile((yyvsp[(2) - (7)].uval),(yyvsp[(3) - (7)].str),&(yyvsp[(5) - (7)].file)->common,(yyvsp[(1) - (7)].uval));
+ fprintf(stderr, "Created XkbFile %p, id %i\n",
+ (yyval.file), (yyval.file)->id);
+ }
+ break;
+
+ case 8:
+#line 199 "xkbparse.y"
+ { (yyval.uval)= XkmKeymapFile; }
+ break;
+
+ case 9:
+#line 200 "xkbparse.y"
+ { (yyval.uval)= XkmSemanticsFile; }
+ break;
+
+ case 10:
+#line 201 "xkbparse.y"
+ { (yyval.uval)= XkmLayoutFile; }
+ break;
+
+ case 11:
+#line 205 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt(%p->common, %p->common) "
+ "with XkbMapConfigList\n",
+ (yyvsp[(1) - (2)].file), (yyvsp[(2) - (2)].file));
+ (yyval.file)= (XkbFile *)AppendStmt(&(yyvsp[(1) - (2)].file)->common,&(yyvsp[(2) - (2)].file)->common);
+ fprintf(stderr, "Returned XkbFile %p\n", (yyval.file));
+ }
+ break;
+
+ case 12:
+#line 214 "xkbparse.y"
+ { (yyval.file)= (yyvsp[(1) - (1)].file); }
+ break;
+
+ case 13:
+#line 220 "xkbparse.y"
+ {
+ fprintf(stderr, "Calling CreateXKBFile with "
+ "XkbMapConfig type %i defs %p\n", (yyvsp[(2) - (7)].uval), (yyvsp[(5) - (7)].any));
+ (yyval.file)= CreateXKBFile((yyvsp[(2) - (7)].uval),(yyvsp[(3) - (7)].str),(yyvsp[(5) - (7)].any),(yyvsp[(1) - (7)].uval));
+ fprintf(stderr, "Created XkbFile %p, id %i\n",
+ (yyval.file), (yyval.file)->id);
+ }
+ break;
+
+ case 14:
+#line 230 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling CreateXKBFile with XkbConfig\n");
+ (yyval.file)= CreateXKBFile((yyvsp[(2) - (4)].uval),(yyvsp[(3) - (4)].str),(yyvsp[(4) - (4)].any),(yyvsp[(1) - (4)].uval));
+ }
+ break;
+
+ case 15:
+#line 238 "xkbparse.y"
+ { (yyval.uval)= XkmKeyNamesIndex; }
+ break;
+
+ case 16:
+#line 239 "xkbparse.y"
+ { (yyval.uval)= XkmTypesIndex; }
+ break;
+
+ case 17:
+#line 240 "xkbparse.y"
+ { (yyval.uval)= XkmCompatMapIndex; }
+ break;
+
+ case 18:
+#line 241 "xkbparse.y"
+ { (yyval.uval)= XkmSymbolsIndex; }
+ break;
+
+ case 19:
+#line 242 "xkbparse.y"
+ { (yyval.uval)= XkmGeometryIndex; }
+ break;
+
+ case 20:
+#line 245 "xkbparse.y"
+ { (yyval.uval)= (yyvsp[(1) - (1)].uval); }
+ break;
+
+ case 21:
+#line 246 "xkbparse.y"
+ { (yyval.uval)= 0; }
+ break;
+
+ case 22:
+#line 249 "xkbparse.y"
+ { (yyval.uval)= (((yyvsp[(1) - (2)].uval))|((yyvsp[(2) - (2)].uval))); }
+ break;
+
+ case 23:
+#line 250 "xkbparse.y"
+ { (yyval.uval)= (yyvsp[(1) - (1)].uval); }
+ break;
+
+ case 24:
+#line 253 "xkbparse.y"
+ { (yyval.uval)= XkbLC_Partial; }
+ break;
+
+ case 25:
+#line 254 "xkbparse.y"
+ { (yyval.uval)= XkbLC_Default; }
+ break;
+
+ case 26:
+#line 255 "xkbparse.y"
+ { (yyval.uval)= XkbLC_Hidden; }
+ break;
+
+ case 27:
+#line 256 "xkbparse.y"
+ { (yyval.uval)= XkbLC_AlphanumericKeys; }
+ break;
+
+ case 28:
+#line 257 "xkbparse.y"
+ { (yyval.uval)= XkbLC_ModifierKeys; }
+ break;
+
+ case 29:
+#line 258 "xkbparse.y"
+ { (yyval.uval)= XkbLC_KeypadKeys; }
+ break;
+
+ case 30:
+#line 259 "xkbparse.y"
+ { (yyval.uval)= XkbLC_FunctionKeys; }
+ break;
+
+ case 31:
+#line 260 "xkbparse.y"
+ { (yyval.uval)= XkbLC_AlternateGroup; }
+ break;
+
+ case 32:
+#line 264 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt(%p, %p) with DeclList\n",
+ (yyvsp[(1) - (2)].any), (yyvsp[(2) - (2)].any));
+ (yyval.any)= AppendStmt((yyvsp[(1) - (2)].any),(yyvsp[(2) - (2)].any));
+ }
+ break;
+
+ case 33:
+#line 270 "xkbparse.y"
+ { (yyval.any)= NULL; }
+ break;
+
+ case 34:
+#line 274 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].var)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].var)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].var)->common;
+ }
+ break;
+
+ case 35:
+#line 279 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].vmod)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].vmod)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].vmod)->common;
+ }
+ break;
+
+ case 36:
+#line 284 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].interp)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].interp)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].interp)->common;
+ }
+ break;
+
+ case 37:
+#line 289 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].keyName)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].keyName)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].keyName)->common;
+ }
+ break;
+
+ case 38:
+#line 294 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].keyAlias)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].keyAlias)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].keyAlias)->common;
+ }
+ break;
+
+ case 39:
+#line 299 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].keyType)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].keyType)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].keyType)->common;
+ }
+ break;
+
+ case 40:
+#line 304 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].syms)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].syms)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].syms)->common;
+ }
+ break;
+
+ case 41:
+#line 309 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].modMask)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].modMask)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].modMask)->common;
+ }
+ break;
+
+ case 42:
+#line 314 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].groupCompat)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].groupCompat)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].groupCompat)->common;
+ }
+ break;
+
+ case 43:
+#line 319 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].ledMap)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].ledMap)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].ledMap)->common;
+ }
+ break;
+
+ case 44:
+#line 324 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].ledName)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].ledName)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].ledName)->common;
+ }
+ break;
+
+ case 45:
+#line 329 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].shape)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].shape)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].shape)->common;
+ }
+ break;
+
+ case 46:
+#line 334 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].section)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].section)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].section)->common;
+ }
+ break;
+
+ case 47:
+#line 339 "xkbparse.y"
+ {
+ (yyvsp[(2) - (2)].doodad)->merge= StmtSetMerge(&(yyvsp[(2) - (2)].doodad)->common,(yyvsp[(1) - (2)].uval));
+ (yyval.any)= &(yyvsp[(2) - (2)].doodad)->common;
+ }
+ break;
+
+ case 48:
+#line 344 "xkbparse.y"
+ {
+ fprintf(stderr, "Calling IncludeCreate "
+ "with \"%s\" merge %u\n", scanStr, (yyvsp[(1) - (2)].uval));
+ if ((yyvsp[(1) - (2)].uval)==MergeAltForm) {
+ yyerror("cannot use 'alternate' to include other maps");
+ (yyval.any)= &IncludeCreate(scanStr,MergeDefault)->common;
+ }
+ else {
+ (yyval.any)= &IncludeCreate(scanStr,(yyvsp[(1) - (2)].uval))->common;
+ }
+ fprintf(stderr, "Created IncludeStmt %p\n", (yyval.any));
+ }
+ break;
+
+ case 49:
+#line 359 "xkbparse.y"
+ { (yyval.var)= VarCreate((yyvsp[(1) - (4)].expr),(yyvsp[(3) - (4)].expr)); }
+ break;
+
+ case 50:
+#line 361 "xkbparse.y"
+ { (yyval.var)= BoolVarCreate((yyvsp[(1) - (2)].sval),1); }
+ break;
+
+ case 51:
+#line 363 "xkbparse.y"
+ { (yyval.var)= BoolVarCreate((yyvsp[(2) - (3)].sval),0); }
+ break;
+
+ case 52:
+#line 367 "xkbparse.y"
+ {
+ KeycodeDef *def;
+
+ def= KeycodeCreate((yyvsp[(1) - (4)].str),(yyvsp[(3) - (4)].expr));
+ if ((yyvsp[(1) - (4)].str))
+ free((yyvsp[(1) - (4)].str));
+ (yyval.keyName)= def;
+ }
+ break;
+
+ case 53:
+#line 378 "xkbparse.y"
+ {
+ KeyAliasDef *def;
+ def= KeyAliasCreate((yyvsp[(2) - (5)].str),(yyvsp[(4) - (5)].str));
+ if ((yyvsp[(2) - (5)].str)) free((yyvsp[(2) - (5)].str));
+ if ((yyvsp[(4) - (5)].str)) free((yyvsp[(4) - (5)].str));
+ (yyval.keyAlias)= def;
+ }
+ break;
+
+ case 54:
+#line 388 "xkbparse.y"
+ { (yyval.vmod)= (yyvsp[(2) - (3)].vmod); }
+ break;
+
+ case 55:
+#line 392 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with VModDefList\n");
+ (yyval.vmod)= (VModDef *)AppendStmt(&(yyvsp[(1) - (3)].vmod)->common,&(yyvsp[(3) - (3)].vmod)->common);
+ }
+ break;
+
+ case 56:
+#line 398 "xkbparse.y"
+ { (yyval.vmod)= (yyvsp[(1) - (1)].vmod); }
+ break;
+
+ case 57:
+#line 402 "xkbparse.y"
+ { (yyval.vmod)= VModCreate((yyvsp[(1) - (1)].sval),NULL); }
+ break;
+
+ case 58:
+#line 404 "xkbparse.y"
+ { (yyval.vmod)= VModCreate((yyvsp[(1) - (3)].sval),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 59:
+#line 410 "xkbparse.y"
+ {
+ (yyvsp[(2) - (6)].interp)->def= (yyvsp[(4) - (6)].var);
+ (yyval.interp)= (yyvsp[(2) - (6)].interp);
+ }
+ break;
+
+ case 60:
+#line 417 "xkbparse.y"
+ { (yyval.interp)= InterpCreate((KeySym)(yyvsp[(1) - (3)].uval),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 61:
+#line 419 "xkbparse.y"
+ { (yyval.interp)= InterpCreate((KeySym)(yyvsp[(1) - (1)].uval),NULL); }
+ break;
+
+ case 62:
+#line 423 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with VarDeclList\n");
+ (yyval.var)= (VarDef *)AppendStmt(&(yyvsp[(1) - (2)].var)->common,&(yyvsp[(2) - (2)].var)->common);
+ }
+ break;
+
+ case 63:
+#line 429 "xkbparse.y"
+ { (yyval.var)= (yyvsp[(1) - (1)].var); }
+ break;
+
+ case 64:
+#line 435 "xkbparse.y"
+ { (yyval.keyType)= KeyTypeCreate((yyvsp[(2) - (6)].sval),(yyvsp[(4) - (6)].var)); }
+ break;
+
+ case 65:
+#line 441 "xkbparse.y"
+ { (yyval.syms)= SymbolsCreate((yyvsp[(2) - (6)].str),(ExprDef *)(yyvsp[(4) - (6)].var)); }
+ break;
+
+ case 66:
+#line 445 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with SymbolsBody\n");
+ (yyval.var)= (VarDef *)AppendStmt(&(yyvsp[(1) - (3)].var)->common,&(yyvsp[(3) - (3)].var)->common);
+ }
+ break;
+
+ case 67:
+#line 451 "xkbparse.y"
+ { (yyval.var)= (yyvsp[(1) - (1)].var); }
+ break;
+
+ case 68:
+#line 452 "xkbparse.y"
+ { (yyval.var)= NULL; }
+ break;
+
+ case 69:
+#line 456 "xkbparse.y"
+ { (yyval.var)= VarCreate((yyvsp[(1) - (3)].expr),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 70:
+#line 458 "xkbparse.y"
+ { (yyval.var)= VarCreate((yyvsp[(1) - (3)].expr),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 71:
+#line 460 "xkbparse.y"
+ { (yyval.var)= BoolVarCreate((yyvsp[(1) - (1)].sval),1); }
+ break;
+
+ case 72:
+#line 462 "xkbparse.y"
+ { (yyval.var)= BoolVarCreate((yyvsp[(2) - (2)].sval),0); }
+ break;
+
+ case 73:
+#line 464 "xkbparse.y"
+ { (yyval.var)= VarCreate(NULL,(yyvsp[(1) - (1)].expr)); }
+ break;
+
+ case 74:
+#line 468 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(2) - (3)].expr); }
+ break;
+
+ case 75:
+#line 470 "xkbparse.y"
+ { (yyval.expr)= ExprCreateUnary(ExprActionList,TypeAction,(yyvsp[(2) - (3)].expr)); }
+ break;
+
+ case 76:
+#line 474 "xkbparse.y"
+ { (yyval.groupCompat)= GroupCompatCreate((yyvsp[(2) - (5)].ival),(yyvsp[(4) - (5)].expr)); }
+ break;
+
+ case 77:
+#line 478 "xkbparse.y"
+ { (yyval.modMask)= ModMapCreate((yyvsp[(2) - (6)].sval),(yyvsp[(4) - (6)].expr)); }
+ break;
+
+ case 78:
+#line 482 "xkbparse.y"
+ { (yyval.ledMap)= IndicatorMapCreate((yyvsp[(2) - (6)].sval),(yyvsp[(4) - (6)].var)); }
+ break;
+
+ case 79:
+#line 486 "xkbparse.y"
+ { (yyval.ledName)= IndicatorNameCreate((yyvsp[(2) - (5)].ival),(yyvsp[(4) - (5)].expr),False); }
+ break;
+
+ case 80:
+#line 488 "xkbparse.y"
+ { (yyval.ledName)= IndicatorNameCreate((yyvsp[(3) - (6)].ival),(yyvsp[(5) - (6)].expr),True); }
+ break;
+
+ case 81:
+#line 492 "xkbparse.y"
+ { (yyval.shape)= ShapeDeclCreate((yyvsp[(2) - (6)].sval),(OutlineDef *)&(yyvsp[(4) - (6)].outline)->common); }
+ break;
+
+ case 82:
+#line 494 "xkbparse.y"
+ {
+ OutlineDef *outlines;
+ outlines= OutlineCreate(None,(yyvsp[(4) - (6)].expr));
+ (yyval.shape)= ShapeDeclCreate((yyvsp[(2) - (6)].sval),outlines);
+ }
+ break;
+
+ case 83:
+#line 502 "xkbparse.y"
+ { (yyval.section)= SectionDeclCreate((yyvsp[(2) - (6)].sval),(yyvsp[(4) - (6)].row)); }
+ break;
+
+ case 84:
+#line 506 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with SectionBody\n");
+ (yyval.row)=(RowDef *)AppendStmt(&(yyvsp[(1) - (2)].row)->common,&(yyvsp[(2) - (2)].row)->common);
+ }
+ break;
+
+ case 85:
+#line 512 "xkbparse.y"
+ { (yyval.row)= (yyvsp[(1) - (1)].row); }
+ break;
+
+ case 86:
+#line 516 "xkbparse.y"
+ { (yyval.row)= RowDeclCreate((yyvsp[(3) - (5)].key)); }
+ break;
+
+ case 87:
+#line 518 "xkbparse.y"
+ { (yyval.row)= (RowDef *)(yyvsp[(1) - (1)].var); }
+ break;
+
+ case 88:
+#line 520 "xkbparse.y"
+ { (yyval.row)= (RowDef *)(yyvsp[(1) - (1)].doodad); }
+ break;
+
+ case 89:
+#line 522 "xkbparse.y"
+ { (yyval.row)= (RowDef *)(yyvsp[(1) - (1)].ledMap); }
+ break;
+
+ case 90:
+#line 524 "xkbparse.y"
+ { (yyval.row)= (RowDef *)(yyvsp[(1) - (1)].overlay); }
+ break;
+
+ case 91:
+#line 528 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with RowBody\n");
+ (yyval.key)=(KeyDef *)AppendStmt(&(yyvsp[(1) - (2)].key)->common,&(yyvsp[(2) - (2)].key)->common);
+ }
+ break;
+
+ case 92:
+#line 534 "xkbparse.y"
+ { (yyval.key)= (yyvsp[(1) - (1)].key); }
+ break;
+
+ case 93:
+#line 538 "xkbparse.y"
+ { (yyval.key)= (yyvsp[(3) - (5)].key); }
+ break;
+
+ case 94:
+#line 540 "xkbparse.y"
+ { (yyval.key)= (KeyDef *)(yyvsp[(1) - (1)].var); }
+ break;
+
+ case 95:
+#line 544 "xkbparse.y"
+ {
+ fprintf(stderr, "Calling AppendStmt with Keys\n");
+ (yyval.key)=(KeyDef *)AppendStmt(&(yyvsp[(1) - (3)].key)->common,&(yyvsp[(3) - (3)].key)->common);
+ }
+ break;
+
+ case 96:
+#line 549 "xkbparse.y"
+ { (yyval.key)= (yyvsp[(1) - (1)].key); }
+ break;
+
+ case 97:
+#line 553 "xkbparse.y"
+ { (yyval.key)= KeyDeclCreate((yyvsp[(1) - (1)].str),NULL); }
+ break;
+
+ case 98:
+#line 555 "xkbparse.y"
+ { (yyval.key)= KeyDeclCreate(NULL,(yyvsp[(2) - (3)].expr)); }
+ break;
+
+ case 99:
+#line 559 "xkbparse.y"
+ { (yyval.overlay)= OverlayDeclCreate((yyvsp[(2) - (6)].sval),(yyvsp[(4) - (6)].olKey)); }
+ break;
+
+ case 100:
+#line 563 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with OverlayKeyList\n");
+ (yyval.olKey)= (OverlayKeyDef *)
+ AppendStmt(&(yyvsp[(1) - (3)].olKey)->common,&(yyvsp[(3) - (3)].olKey)->common);
+ }
+ break;
+
+ case 101:
+#line 570 "xkbparse.y"
+ { (yyval.olKey)= (yyvsp[(1) - (1)].olKey); }
+ break;
+
+ case 102:
+#line 574 "xkbparse.y"
+ { (yyval.olKey)= OverlayKeyCreate((yyvsp[(1) - (3)].str),(yyvsp[(3) - (3)].str)); }
+ break;
+
+ case 103:
+#line 578 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with OutlineList\n");
+ (yyval.outline)=(OutlineDef *)AppendStmt(&(yyvsp[(1) - (3)].outline)->common,&(yyvsp[(3) - (3)].outline)->common);
+ }
+ break;
+
+ case 104:
+#line 584 "xkbparse.y"
+ { (yyval.outline)= (yyvsp[(1) - (1)].outline); }
+ break;
+
+ case 105:
+#line 588 "xkbparse.y"
+ { (yyval.outline)= OutlineCreate(None,(yyvsp[(2) - (3)].expr)); }
+ break;
+
+ case 106:
+#line 590 "xkbparse.y"
+ { (yyval.outline)= OutlineCreate((yyvsp[(1) - (5)].sval),(yyvsp[(4) - (5)].expr)); }
+ break;
+
+ case 107:
+#line 592 "xkbparse.y"
+ { (yyval.outline)= OutlineCreate((yyvsp[(1) - (3)].sval),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 108:
+#line 596 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with CoordList\n");
+ (yyval.expr)= (ExprDef *)AppendStmt(&(yyvsp[(1) - (3)].expr)->common,&(yyvsp[(3) - (3)].expr)->common);
+ }
+ break;
+
+ case 109:
+#line 602 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(1) - (1)].expr); }
+ break;
+
+ case 110:
+#line 606 "xkbparse.y"
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprCoord,TypeUnknown);
+ expr->value.coord.x= (yyvsp[(2) - (5)].ival);
+ expr->value.coord.y= (yyvsp[(4) - (5)].ival);
+ (yyval.expr)= expr;
+ }
+ break;
+
+ case 111:
+#line 616 "xkbparse.y"
+ { (yyval.doodad)= DoodadCreate((yyvsp[(1) - (6)].uval),(yyvsp[(2) - (6)].sval),(yyvsp[(4) - (6)].var)); }
+ break;
+
+ case 112:
+#line 619 "xkbparse.y"
+ { (yyval.uval)= XkbTextDoodad; }
+ break;
+
+ case 113:
+#line 620 "xkbparse.y"
+ { (yyval.uval)= XkbOutlineDoodad; }
+ break;
+
+ case 114:
+#line 621 "xkbparse.y"
+ { (yyval.uval)= XkbSolidDoodad; }
+ break;
+
+ case 115:
+#line 622 "xkbparse.y"
+ { (yyval.uval)= XkbLogoDoodad; }
+ break;
+
+ case 116:
+#line 625 "xkbparse.y"
+ { (yyval.sval)= (yyvsp[(1) - (1)].sval); }
+ break;
+
+ case 117:
+#line 626 "xkbparse.y"
+ { (yyval.sval)= (yyvsp[(1) - (1)].sval); }
+ break;
+
+ case 118:
+#line 630 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"action",False); }
+ break;
+
+ case 119:
+#line 632 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"interpret",False); }
+ break;
+
+ case 120:
+#line 634 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"type",False); }
+ break;
+
+ case 121:
+#line 636 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"key",False); }
+ break;
+
+ case 122:
+#line 638 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"group",False); }
+ break;
+
+ case 123:
+#line 640 "xkbparse.y"
+ {(yyval.sval)=XkbInternAtom(NULL,"modifier_map",False);}
+ break;
+
+ case 124:
+#line 642 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"indicator",False); }
+ break;
+
+ case 125:
+#line 644 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"shape",False); }
+ break;
+
+ case 126:
+#line 646 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"row",False); }
+ break;
+
+ case 127:
+#line 648 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"section",False); }
+ break;
+
+ case 128:
+#line 650 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"text",False); }
+ break;
+
+ case 129:
+#line 653 "xkbparse.y"
+ { (yyval.uval)= (yyvsp[(1) - (1)].uval); }
+ break;
+
+ case 130:
+#line 654 "xkbparse.y"
+ { (yyval.uval)= MergeDefault; }
+ break;
+
+ case 131:
+#line 657 "xkbparse.y"
+ { (yyval.uval)= MergeDefault; }
+ break;
+
+ case 132:
+#line 658 "xkbparse.y"
+ { (yyval.uval)= MergeAugment; }
+ break;
+
+ case 133:
+#line 659 "xkbparse.y"
+ { (yyval.uval)= MergeOverride; }
+ break;
+
+ case 134:
+#line 660 "xkbparse.y"
+ { (yyval.uval)= MergeReplace; }
+ break;
+
+ case 135:
+#line 661 "xkbparse.y"
+ { (yyval.uval)= MergeAltForm; }
+ break;
+
+ case 136:
+#line 664 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(1) - (1)].expr); }
+ break;
+
+ case 137:
+#line 665 "xkbparse.y"
+ { (yyval.expr)= NULL; }
+ break;
+
+ case 138:
+#line 669 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with ExprList\n");
+ (yyval.expr)= (ExprDef *)AppendStmt(&(yyvsp[(1) - (3)].expr)->common,&(yyvsp[(3) - (3)].expr)->common);
+ }
+ break;
+
+ case 139:
+#line 675 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(1) - (1)].expr); }
+ break;
+
+ case 140:
+#line 679 "xkbparse.y"
+ { (yyval.expr)= ExprCreateBinary(OpDivide,(yyvsp[(1) - (3)].expr),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 141:
+#line 681 "xkbparse.y"
+ { (yyval.expr)= ExprCreateBinary(OpAdd,(yyvsp[(1) - (3)].expr),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 142:
+#line 683 "xkbparse.y"
+ { (yyval.expr)= ExprCreateBinary(OpSubtract,(yyvsp[(1) - (3)].expr),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 143:
+#line 685 "xkbparse.y"
+ { (yyval.expr)= ExprCreateBinary(OpMultiply,(yyvsp[(1) - (3)].expr),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 144:
+#line 687 "xkbparse.y"
+ { (yyval.expr)= ExprCreateBinary(OpAssign,(yyvsp[(1) - (3)].expr),(yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 145:
+#line 689 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(1) - (1)].expr); }
+ break;
+
+ case 146:
+#line 693 "xkbparse.y"
+ { (yyval.expr)= ExprCreateUnary(OpNegate,(yyvsp[(2) - (2)].expr)->type,(yyvsp[(2) - (2)].expr)); }
+ break;
+
+ case 147:
+#line 695 "xkbparse.y"
+ { (yyval.expr)= ExprCreateUnary(OpUnaryPlus,(yyvsp[(2) - (2)].expr)->type,(yyvsp[(2) - (2)].expr)); }
+ break;
+
+ case 148:
+#line 697 "xkbparse.y"
+ { (yyval.expr)= ExprCreateUnary(OpNot,TypeBoolean,(yyvsp[(2) - (2)].expr)); }
+ break;
+
+ case 149:
+#line 699 "xkbparse.y"
+ { (yyval.expr)= ExprCreateUnary(OpInvert,(yyvsp[(2) - (2)].expr)->type,(yyvsp[(2) - (2)].expr)); }
+ break;
+
+ case 150:
+#line 701 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(1) - (1)].expr); }
+ break;
+
+ case 151:
+#line 703 "xkbparse.y"
+ { (yyval.expr)= ActionCreate((yyvsp[(1) - (4)].sval),(yyvsp[(3) - (4)].expr)); }
+ break;
+
+ case 152:
+#line 705 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(1) - (1)].expr); }
+ break;
+
+ case 153:
+#line 707 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(2) - (3)].expr); }
+ break;
+
+ case 154:
+#line 711 "xkbparse.y"
+ {
+ fprintf(stderr,
+ "Calling AppendStmt with ActionList\n");
+ (yyval.expr)= (ExprDef *)AppendStmt(&(yyvsp[(1) - (3)].expr)->common,&(yyvsp[(3) - (3)].expr)->common);
+ }
+ break;
+
+ case 155:
+#line 717 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(1) - (1)].expr); }
+ break;
+
+ case 156:
+#line 721 "xkbparse.y"
+ { (yyval.expr)= ActionCreate((yyvsp[(1) - (4)].sval),(yyvsp[(3) - (4)].expr)); }
+ break;
+
+ case 157:
+#line 725 "xkbparse.y"
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprIdent,TypeUnknown);
+ expr->value.str= (yyvsp[(1) - (1)].sval);
+ (yyval.expr)= expr;
+ }
+ break;
+
+ case 158:
+#line 732 "xkbparse.y"
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprFieldRef,TypeUnknown);
+ expr->value.field.element= (yyvsp[(1) - (3)].sval);
+ expr->value.field.field= (yyvsp[(3) - (3)].sval);
+ (yyval.expr)= expr;
+ }
+ break;
+
+ case 159:
+#line 740 "xkbparse.y"
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprArrayRef,TypeUnknown);
+ expr->value.array.element= None;
+ expr->value.array.field= (yyvsp[(1) - (4)].sval);
+ expr->value.array.entry= (yyvsp[(3) - (4)].expr);
+ (yyval.expr)= expr;
+ }
+ break;
+
+ case 160:
+#line 749 "xkbparse.y"
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprArrayRef,TypeUnknown);
+ expr->value.array.element= (yyvsp[(1) - (6)].sval);
+ expr->value.array.field= (yyvsp[(3) - (6)].sval);
+ expr->value.array.entry= (yyvsp[(5) - (6)].expr);
+ (yyval.expr)= expr;
+ }
+ break;
+
+ case 161:
+#line 760 "xkbparse.y"
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprValue,TypeString);
+ expr->value.str= (yyvsp[(1) - (1)].sval);
+ (yyval.expr)= expr;
+ }
+ break;
+
+ case 162:
+#line 767 "xkbparse.y"
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprValue,TypeInt);
+ expr->value.ival= (yyvsp[(1) - (1)].ival);
+ (yyval.expr)= expr;
+ }
+ break;
+
+ case 163:
+#line 774 "xkbparse.y"
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprValue,TypeFloat);
+ expr->value.ival= (yyvsp[(1) - (1)].ival);
+ (yyval.expr)= expr;
+ }
+ break;
+
+ case 164:
+#line 781 "xkbparse.y"
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprValue,TypeKeyName);
+ memset(expr->value.keyName,0,5);
+ strncpy(expr->value.keyName,(yyvsp[(1) - (1)].str),4);
+ free((yyvsp[(1) - (1)].str));
+ (yyval.expr)= expr;
+ }
+ break;
+
+ case 165:
+#line 791 "xkbparse.y"
+ { (yyval.expr)= (yyvsp[(1) - (1)].expr); }
+ break;
+
+ case 166:
+#line 792 "xkbparse.y"
+ { (yyval.expr)= NULL; }
+ break;
+
+ case 167:
+#line 796 "xkbparse.y"
+ { (yyval.expr)= AppendKeysymList((yyvsp[(1) - (3)].expr),(KeySym)(yyvsp[(3) - (3)].uval)); }
+ break;
+
+ case 168:
+#line 798 "xkbparse.y"
+ { (yyval.expr)= CreateKeysymList((KeySym)(yyvsp[(1) - (1)].uval)); }
+ break;
+
+ case 169:
+#line 802 "xkbparse.y"
+ {
+ KeySym sym;
+ if (LookupKeysym(scanStr,&sym))
+ (yyval.uval)= sym;
+ else {
+ char buf[120];
+ snprintf(buf, sizeof(buf),
+ "expected keysym, got %s",
+ uStringText(scanStr));
+ yyerror(buf);
+ yynerrs++;
+ (yyval.uval)= NoSymbol;
+ }
+ }
+ break;
+
+ case 170:
+#line 817 "xkbparse.y"
+ {
+ (yyval.uval)= XK_section;
+ }
+ break;
+
+ case 171:
+#line 821 "xkbparse.y"
+ {
+ if ((yyvsp[(1) - (1)].ival)<10) (yyval.uval)= (yyvsp[(1) - (1)].ival)+'0'; /* XK_0 .. XK_9 */
+ else (yyval.uval)= (yyvsp[(1) - (1)].ival);
+ }
+ break;
+
+ case 172:
+#line 827 "xkbparse.y"
+ { (yyval.ival)= -(yyvsp[(2) - (2)].ival); }
+ break;
+
+ case 173:
+#line 828 "xkbparse.y"
+ { (yyval.ival)= (yyvsp[(1) - (1)].ival); }
+ break;
+
+ case 174:
+#line 831 "xkbparse.y"
+ { (yyval.ival)= scanInt; }
+ break;
+
+ case 175:
+#line 832 "xkbparse.y"
+ { (yyval.ival)= scanInt*XkbGeomPtsPerMM; }
+ break;
+
+ case 176:
+#line 835 "xkbparse.y"
+ { (yyval.ival)= scanInt; }
+ break;
+
+ case 177:
+#line 838 "xkbparse.y"
+ { (yyval.ival)= scanInt; }
+ break;
+
+ case 178:
+#line 841 "xkbparse.y"
+ { (yyval.str)= scanStr; scanStr= NULL; }
+ break;
+
+ case 179:
+#line 844 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,scanStr,False); }
+ break;
+
+ case 180:
+#line 845 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,"default",False); }
+ break;
+
+ case 181:
+#line 848 "xkbparse.y"
+ { (yyval.sval)= XkbInternAtom(NULL,scanStr,False); }
+ break;
+
+ case 182:
+#line 851 "xkbparse.y"
+ { (yyval.str)= (yyvsp[(1) - (1)].str); }
+ break;
+
+ case 183:
+#line 852 "xkbparse.y"
+ { (yyval.str)= NULL; }
+ break;
+
+ case 184:
+#line 855 "xkbparse.y"
+ { (yyval.str)= scanStr; scanStr= NULL; }
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 3008 "xkbparse.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+#line 857 "xkbparse.y"
+
+void
+yyerror(const char *s)
+{
+ if (warningLevel>0) {
+ (void)fprintf(stderr,"%s: line %d of %s\n",s,lineNum,
+ (scanFile?scanFile:"(unknown)"));
+ if ((scanStr)&&(warningLevel>3))
+ (void)fprintf(stderr,"last scanned symbol is: %s\n",scanStr);
+ }
+ return;
+}
+
+
+int
+yywrap(void)
+{
+ return 1;
+}
+
+
diff --git a/src/xkbcomp/xkbparse.y b/src/xkbcomp/xkbparse.y
new file mode 100644
index 0000000..63f87bb
--- /dev/null
+++ b/src/xkbcomp/xkbparse.y
@@ -0,0 +1,799 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+%token
+ END_OF_FILE 0
+ ERROR_TOK 255
+ XKB_KEYMAP 1
+ XKB_KEYCODES 2
+ XKB_TYPES 3
+ XKB_SYMBOLS 4
+ XKB_COMPATMAP 5
+ XKB_GEOMETRY 6
+ XKB_SEMANTICS 7
+ XKB_LAYOUT 8
+ INCLUDE 10
+ OVERRIDE 11
+ AUGMENT 12
+ REPLACE 13
+ ALTERNATE 14
+ VIRTUAL_MODS 20
+ TYPE 21
+ INTERPRET 22
+ ACTION_TOK 23
+ KEY 24
+ ALIAS 25
+ GROUP 26
+ MODIFIER_MAP 27
+ INDICATOR 28
+ SHAPE 29
+ KEYS 30
+ ROW 31
+ SECTION 32
+ OVERLAY 33
+ TEXT 34
+ OUTLINE 35
+ SOLID 36
+ LOGO 37
+ VIRTUAL 38
+ EQUALS 40
+ PLUS 41
+ MINUS 42
+ DIVIDE 43
+ TIMES 44
+ OBRACE 45
+ CBRACE 46
+ OPAREN 47
+ CPAREN 48
+ OBRACKET 49
+ CBRACKET 50
+ DOT 51
+ COMMA 52
+ SEMI 53
+ EXCLAM 54
+ INVERT 55
+ STRING 60
+ INTEGER 61
+ FLOAT 62
+ IDENT 63
+ KEYNAME 64
+ PARTIAL 70
+ DEFAULT 71
+ HIDDEN 72
+ ALPHANUMERIC_KEYS 73
+ MODIFIER_KEYS 74
+ KEYPAD_KEYS 75
+ FUNCTION_KEYS 76
+ ALTERNATE_GROUP 77
+%{
+#ifdef DEBUG
+#define YYDEBUG 1
+#endif
+#define DEBUG_VAR parseDebug
+#include "parseutils.h"
+#include <X11/keysym.h>
+#include <X11/extensions/XKBgeom.h>
+#include <stdlib.h>
+
+unsigned int parseDebug;
+
+%}
+%right EQUALS
+%left PLUS MINUS
+%left TIMES DIVIDE
+%left EXCLAM INVERT
+%left OPAREN
+%start XkbFile
+%union {
+ int ival;
+ unsigned uval;
+ char *str;
+ Atom sval;
+ ParseCommon *any;
+ ExprDef *expr;
+ VarDef *var;
+ VModDef *vmod;
+ InterpDef *interp;
+ KeyTypeDef *keyType;
+ SymbolsDef *syms;
+ ModMapDef *modMask;
+ GroupCompatDef *groupCompat;
+ IndicatorMapDef *ledMap;
+ IndicatorNameDef *ledName;
+ KeycodeDef *keyName;
+ KeyAliasDef *keyAlias;
+ ShapeDef *shape;
+ SectionDef *section;
+ RowDef *row;
+ KeyDef *key;
+ OverlayDef *overlay;
+ OverlayKeyDef *olKey;
+ OutlineDef *outline;
+ DoodadDef *doodad;
+ XkbFile *file;
+}
+%type <ival> Number Integer Float SignedNumber
+%type <uval> XkbCompositeType FileType MergeMode OptMergeMode KeySym
+%type <uval> DoodadType Flag Flags OptFlags
+%type <str> KeyName MapName OptMapName
+%type <sval> FieldSpec Ident Element String
+%type <any> DeclList Decl
+%type <expr> OptExprList ExprList Expr Term Lhs Terminal ArrayInit
+%type <expr> OptKeySymList KeySymList Action ActionList Coord CoordList
+%type <var> VarDecl VarDeclList SymbolsBody SymbolsVarDecl
+%type <vmod> VModDecl VModDefList VModDef
+%type <interp> InterpretDecl InterpretMatch
+%type <keyType> KeyTypeDecl
+%type <syms> SymbolsDecl
+%type <modMask> ModMapDecl
+%type <groupCompat> GroupCompatDecl
+%type <ledMap> IndicatorMapDecl
+%type <ledName> IndicatorNameDecl
+%type <keyName> KeyNameDecl
+%type <keyAlias> KeyAliasDecl
+%type <shape> ShapeDecl
+%type <section> SectionDecl
+%type <row> SectionBody SectionBodyItem
+%type <key> RowBody RowBodyItem Keys Key
+%type <overlay> OverlayDecl
+%type <olKey> OverlayKeyList OverlayKey
+%type <outline> OutlineList OutlineInList
+%type <doodad> DoodadDecl
+%type <file> XkbFile XkbMapConfigList XkbMapConfig XkbConfig
+%type <file> XkbCompositeMap XkbCompMapList
+%%
+XkbFile : XkbCompMapList
+ { $$= rtrnValue= $1; }
+ | XkbMapConfigList
+ { $$= rtrnValue= $1; }
+ | XkbConfig
+ { $$= rtrnValue= $1; }
+ ;
+
+XkbCompMapList : XkbCompMapList XkbCompositeMap
+ { $$= (XkbFile *)AppendStmt(&$1->common,&$2->common); }
+ | XkbCompositeMap
+ { $$= $1; }
+ ;
+
+XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
+ XkbMapConfigList
+ CBRACE SEMI
+ { $$= CreateXKBFile($2,$3,&$5->common,$1); }
+ ;
+
+XkbCompositeType: XKB_KEYMAP { $$= XkmKeymapFile; }
+ | XKB_SEMANTICS { $$= XkmSemanticsFile; }
+ | XKB_LAYOUT { $$= XkmLayoutFile; }
+ ;
+
+XkbMapConfigList : XkbMapConfigList XkbMapConfig
+ { $$= (XkbFile *)AppendStmt(&$1->common,&$2->common); }
+ | XkbMapConfig
+ { $$= $1; }
+ ;
+
+XkbMapConfig : OptFlags FileType OptMapName OBRACE
+ DeclList
+ CBRACE SEMI
+ { $$= CreateXKBFile($2,$3,$5,$1); }
+ ;
+
+XkbConfig : OptFlags FileType OptMapName DeclList
+ { $$= CreateXKBFile($2,$3,$4,$1); }
+ ;
+
+
+FileType : XKB_KEYCODES { $$= XkmKeyNamesIndex; }
+ | XKB_TYPES { $$= XkmTypesIndex; }
+ | XKB_COMPATMAP { $$= XkmCompatMapIndex; }
+ | XKB_SYMBOLS { $$= XkmSymbolsIndex; }
+ | XKB_GEOMETRY { $$= XkmGeometryIndex; }
+ ;
+
+OptFlags : Flags { $$= $1; }
+ | { $$= 0; }
+ ;
+
+Flags : Flags Flag { $$= (($1)|($2)); }
+ | Flag { $$= $1; }
+ ;
+
+Flag : PARTIAL { $$= XkbLC_Partial; }
+ | DEFAULT { $$= XkbLC_Default; }
+ | HIDDEN { $$= XkbLC_Hidden; }
+ | ALPHANUMERIC_KEYS { $$= XkbLC_AlphanumericKeys; }
+ | MODIFIER_KEYS { $$= XkbLC_ModifierKeys; }
+ | KEYPAD_KEYS { $$= XkbLC_KeypadKeys; }
+ | FUNCTION_KEYS { $$= XkbLC_FunctionKeys; }
+ | ALTERNATE_GROUP { $$= XkbLC_AlternateGroup; }
+ ;
+
+DeclList : DeclList Decl
+ { $$= AppendStmt($1,$2); }
+ | { $$= NULL; }
+ ;
+
+Decl : OptMergeMode VarDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode VModDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode InterpretDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode KeyNameDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode KeyAliasDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode KeyTypeDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode SymbolsDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode ModMapDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode GroupCompatDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode IndicatorMapDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode IndicatorNameDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode ShapeDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode SectionDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | OptMergeMode DoodadDecl
+ {
+ $2->merge= StmtSetMerge(&$2->common,$1);
+ $$= &$2->common;
+ }
+ | MergeMode STRING
+ {
+ if ($1==MergeAltForm) {
+ yyerror("cannot use 'alternate' to include other maps");
+ $$= &IncludeCreate(scanStr,MergeDefault)->common;
+ }
+ else {
+ $$= &IncludeCreate(scanStr,$1)->common;
+ }
+ }
+ ;
+
+VarDecl : Lhs EQUALS Expr SEMI
+ { $$= VarCreate($1,$3); }
+ | Ident SEMI
+ { $$= BoolVarCreate($1,1); }
+ | EXCLAM Ident SEMI
+ { $$= BoolVarCreate($2,0); }
+ ;
+
+KeyNameDecl : KeyName EQUALS Expr SEMI
+ {
+ KeycodeDef *def;
+
+ def= KeycodeCreate($1,$3);
+ if ($1)
+ free($1);
+ $$= def;
+ }
+ ;
+
+KeyAliasDecl : ALIAS KeyName EQUALS KeyName SEMI
+ {
+ KeyAliasDef *def;
+ def= KeyAliasCreate($2,$4);
+ if ($2) free($2);
+ if ($4) free($4);
+ $$= def;
+ }
+ ;
+
+VModDecl : VIRTUAL_MODS VModDefList SEMI
+ { $$= $2; }
+ ;
+
+VModDefList : VModDefList COMMA VModDef
+ { $$= (VModDef *)AppendStmt(&$1->common,&$3->common); }
+ | VModDef
+ { $$= $1; }
+ ;
+
+VModDef : Ident
+ { $$= VModCreate($1,NULL); }
+ | Ident EQUALS Expr
+ { $$= VModCreate($1,$3); }
+ ;
+
+InterpretDecl : INTERPRET InterpretMatch OBRACE
+ VarDeclList
+ CBRACE SEMI
+ {
+ $2->def= $4;
+ $$= $2;
+ }
+ ;
+
+InterpretMatch : KeySym PLUS Expr
+ { $$= InterpCreate((KeySym)$1,$3); }
+ | KeySym
+ { $$= InterpCreate((KeySym)$1,NULL); }
+ ;
+
+VarDeclList : VarDeclList VarDecl
+ { $$= (VarDef *)AppendStmt(&$1->common,&$2->common); }
+ | VarDecl
+ { $$= $1; }
+ ;
+
+KeyTypeDecl : TYPE String OBRACE
+ VarDeclList
+ CBRACE SEMI
+ { $$= KeyTypeCreate($2,$4); }
+ ;
+
+SymbolsDecl : KEY KeyName OBRACE
+ SymbolsBody
+ CBRACE SEMI
+ { $$= SymbolsCreate($2,(ExprDef *)$4); }
+ ;
+
+SymbolsBody : SymbolsBody COMMA SymbolsVarDecl
+ { $$= (VarDef *)AppendStmt(&$1->common,&$3->common); }
+ | SymbolsVarDecl
+ { $$= $1; }
+ | { $$= NULL; }
+ ;
+
+SymbolsVarDecl : Lhs EQUALS Expr
+ { $$= VarCreate($1,$3); }
+ | Lhs EQUALS ArrayInit
+ { $$= VarCreate($1,$3); }
+ | Ident
+ { $$= BoolVarCreate($1,1); }
+ | EXCLAM Ident
+ { $$= BoolVarCreate($2,0); }
+ | ArrayInit
+ { $$= VarCreate(NULL,$1); }
+ ;
+
+ArrayInit : OBRACKET OptKeySymList CBRACKET
+ { $$= $2; }
+ | OBRACKET ActionList CBRACKET
+ { $$= ExprCreateUnary(ExprActionList,TypeAction,$2); }
+ ;
+
+GroupCompatDecl : GROUP Integer EQUALS Expr SEMI
+ { $$= GroupCompatCreate($2,$4); }
+ ;
+
+ModMapDecl : MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
+ { $$= ModMapCreate($2,$4); }
+ ;
+
+IndicatorMapDecl: INDICATOR String OBRACE VarDeclList CBRACE SEMI
+ { $$= IndicatorMapCreate($2,$4); }
+ ;
+
+IndicatorNameDecl: INDICATOR Integer EQUALS Expr SEMI
+ { $$= IndicatorNameCreate($2,$4,False); }
+ | VIRTUAL INDICATOR Integer EQUALS Expr SEMI
+ { $$= IndicatorNameCreate($3,$5,True); }
+ ;
+
+ShapeDecl : SHAPE String OBRACE OutlineList CBRACE SEMI
+ { $$= ShapeDeclCreate($2,(OutlineDef *)&$4->common); }
+ | SHAPE String OBRACE CoordList CBRACE SEMI
+ {
+ OutlineDef *outlines;
+ outlines= OutlineCreate(None,$4);
+ $$= ShapeDeclCreate($2,outlines);
+ }
+ ;
+
+SectionDecl : SECTION String OBRACE SectionBody CBRACE SEMI
+ { $$= SectionDeclCreate($2,$4); }
+ ;
+
+SectionBody : SectionBody SectionBodyItem
+ { $$=(RowDef *)AppendStmt(&$1->common,&$2->common);}
+ | SectionBodyItem
+ { $$= $1; }
+ ;
+
+SectionBodyItem : ROW OBRACE RowBody CBRACE SEMI
+ { $$= RowDeclCreate($3); }
+ | VarDecl
+ { $$= (RowDef *)$1; }
+ | DoodadDecl
+ { $$= (RowDef *)$1; }
+ | IndicatorMapDecl
+ { $$= (RowDef *)$1; }
+ | OverlayDecl
+ { $$= (RowDef *)$1; }
+ ;
+
+RowBody : RowBody RowBodyItem
+ { $$=(KeyDef *)AppendStmt(&$1->common,&$2->common);}
+ | RowBodyItem
+ { $$= $1; }
+ ;
+
+RowBodyItem : KEYS OBRACE Keys CBRACE SEMI
+ { $$= $3; }
+ | VarDecl
+ { $$= (KeyDef *)$1; }
+ ;
+
+Keys : Keys COMMA Key
+ { $$=(KeyDef *)AppendStmt(&$1->common,&$3->common);}
+ | Key
+ { $$= $1; }
+ ;
+
+Key : KeyName
+ { $$= KeyDeclCreate($1,NULL); }
+ | OBRACE ExprList CBRACE
+ { $$= KeyDeclCreate(NULL,$2); }
+ ;
+
+OverlayDecl : OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
+ { $$= OverlayDeclCreate($2,$4); }
+ ;
+
+OverlayKeyList : OverlayKeyList COMMA OverlayKey
+ {
+ $$= (OverlayKeyDef *)
+ AppendStmt(&$1->common,&$3->common);
+ }
+ | OverlayKey
+ { $$= $1; }
+ ;
+
+OverlayKey : KeyName EQUALS KeyName
+ { $$= OverlayKeyCreate($1,$3); }
+ ;
+
+OutlineList : OutlineList COMMA OutlineInList
+ { $$=(OutlineDef *)AppendStmt(&$1->common,&$3->common);}
+ | OutlineInList
+ { $$= $1; }
+ ;
+
+OutlineInList : OBRACE CoordList CBRACE
+ { $$= OutlineCreate(None,$2); }
+ | Ident EQUALS OBRACE CoordList CBRACE
+ { $$= OutlineCreate($1,$4); }
+ | Ident EQUALS Expr
+ { $$= OutlineCreate($1,$3); }
+ ;
+
+CoordList : CoordList COMMA Coord
+ { $$= (ExprDef *)AppendStmt(&$1->common,&$3->common); }
+ | Coord
+ { $$= $1; }
+ ;
+
+Coord : OBRACKET SignedNumber COMMA SignedNumber CBRACKET
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprCoord,TypeUnknown);
+ expr->value.coord.x= $2;
+ expr->value.coord.y= $4;
+ $$= expr;
+ }
+ ;
+
+DoodadDecl : DoodadType String OBRACE VarDeclList CBRACE SEMI
+ { $$= DoodadCreate($1,$2,$4); }
+ ;
+
+DoodadType : TEXT { $$= XkbTextDoodad; }
+ | OUTLINE { $$= XkbOutlineDoodad; }
+ | SOLID { $$= XkbSolidDoodad; }
+ | LOGO { $$= XkbLogoDoodad; }
+ ;
+
+FieldSpec : Ident { $$= $1; }
+ | Element { $$= $1; }
+ ;
+
+Element : ACTION_TOK
+ { $$= XkbInternAtom(NULL,"action",False); }
+ | INTERPRET
+ { $$= XkbInternAtom(NULL,"interpret",False); }
+ | TYPE
+ { $$= XkbInternAtom(NULL,"type",False); }
+ | KEY
+ { $$= XkbInternAtom(NULL,"key",False); }
+ | GROUP
+ { $$= XkbInternAtom(NULL,"group",False); }
+ | MODIFIER_MAP
+ {$$=XkbInternAtom(NULL,"modifier_map",False);}
+ | INDICATOR
+ { $$= XkbInternAtom(NULL,"indicator",False); }
+ | SHAPE
+ { $$= XkbInternAtom(NULL,"shape",False); }
+ | ROW
+ { $$= XkbInternAtom(NULL,"row",False); }
+ | SECTION
+ { $$= XkbInternAtom(NULL,"section",False); }
+ | TEXT
+ { $$= XkbInternAtom(NULL,"text",False); }
+ ;
+
+OptMergeMode : MergeMode { $$= $1; }
+ | { $$= MergeDefault; }
+ ;
+
+MergeMode : INCLUDE { $$= MergeDefault; }
+ | AUGMENT { $$= MergeAugment; }
+ | OVERRIDE { $$= MergeOverride; }
+ | REPLACE { $$= MergeReplace; }
+ | ALTERNATE { $$= MergeAltForm; }
+ ;
+
+OptExprList : ExprList { $$= $1; }
+ | { $$= NULL; }
+ ;
+
+ExprList : ExprList COMMA Expr
+ { $$= (ExprDef *)AppendStmt(&$1->common,&$3->common); }
+ | Expr
+ { $$= $1; }
+ ;
+
+Expr : Expr DIVIDE Expr
+ { $$= ExprCreateBinary(OpDivide,$1,$3); }
+ | Expr PLUS Expr
+ { $$= ExprCreateBinary(OpAdd,$1,$3); }
+ | Expr MINUS Expr
+ { $$= ExprCreateBinary(OpSubtract,$1,$3); }
+ | Expr TIMES Expr
+ { $$= ExprCreateBinary(OpMultiply,$1,$3); }
+ | Lhs EQUALS Expr
+ { $$= ExprCreateBinary(OpAssign,$1,$3); }
+ | Term
+ { $$= $1; }
+ ;
+
+Term : MINUS Term
+ { $$= ExprCreateUnary(OpNegate,$2->type,$2); }
+ | PLUS Term
+ { $$= ExprCreateUnary(OpUnaryPlus,$2->type,$2); }
+ | EXCLAM Term
+ { $$= ExprCreateUnary(OpNot,TypeBoolean,$2); }
+ | INVERT Term
+ { $$= ExprCreateUnary(OpInvert,$2->type,$2); }
+ | Lhs
+ { $$= $1; }
+ | FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
+ { $$= ActionCreate($1,$3); }
+ | Terminal
+ { $$= $1; }
+ | OPAREN Expr CPAREN
+ { $$= $2; }
+ ;
+
+ActionList : ActionList COMMA Action
+ { $$= (ExprDef *)AppendStmt(&$1->common,&$3->common); }
+ | Action
+ { $$= $1; }
+ ;
+
+Action : FieldSpec OPAREN OptExprList CPAREN
+ { $$= ActionCreate($1,$3); }
+ ;
+
+Lhs : FieldSpec
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprIdent,TypeUnknown);
+ expr->value.str= $1;
+ $$= expr;
+ }
+ | FieldSpec DOT FieldSpec
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprFieldRef,TypeUnknown);
+ expr->value.field.element= $1;
+ expr->value.field.field= $3;
+ $$= expr;
+ }
+ | FieldSpec OBRACKET Expr CBRACKET
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprArrayRef,TypeUnknown);
+ expr->value.array.element= None;
+ expr->value.array.field= $1;
+ expr->value.array.entry= $3;
+ $$= expr;
+ }
+ | FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprArrayRef,TypeUnknown);
+ expr->value.array.element= $1;
+ expr->value.array.field= $3;
+ expr->value.array.entry= $5;
+ $$= expr;
+ }
+ ;
+
+Terminal : String
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprValue,TypeString);
+ expr->value.str= $1;
+ $$= expr;
+ }
+ | Integer
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprValue,TypeInt);
+ expr->value.ival= $1;
+ $$= expr;
+ }
+ | Float
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprValue,TypeFloat);
+ expr->value.ival= $1;
+ $$= expr;
+ }
+ | KeyName
+ {
+ ExprDef *expr;
+ expr= ExprCreate(ExprValue,TypeKeyName);
+ memset(expr->value.keyName,0,5);
+ strncpy(expr->value.keyName,$1,4);
+ free($1);
+ $$= expr;
+ }
+ ;
+
+OptKeySymList : KeySymList { $$= $1; }
+ | { $$= NULL; }
+ ;
+
+KeySymList : KeySymList COMMA KeySym
+ { $$= AppendKeysymList($1,(KeySym)$3); }
+ | KeySym
+ { $$= CreateKeysymList((KeySym)$1); }
+ ;
+
+KeySym : IDENT
+ {
+ KeySym sym;
+ if (LookupKeysym(scanStr,&sym))
+ $$= sym;
+ else {
+ char buf[120];
+ snprintf(buf, sizeof(buf),
+ "expected keysym, got %s",
+ uStringText(scanStr));
+ yyerror(buf);
+ yynerrs++;
+ $$= NoSymbol;
+ }
+ }
+ | SECTION
+ {
+ $$= XK_section;
+ }
+ | Integer
+ {
+ if ($1<10) $$= $1+'0'; /* XK_0 .. XK_9 */
+ else $$= $1;
+ }
+ ;
+
+SignedNumber : MINUS Number { $$= -$2; }
+ | Number { $$= $1; }
+ ;
+
+Number : FLOAT { $$= scanInt; }
+ | INTEGER { $$= scanInt*XkbGeomPtsPerMM; }
+ ;
+
+Float : FLOAT { $$= scanInt; }
+ ;
+
+Integer : INTEGER { $$= scanInt; }
+ ;
+
+KeyName : KEYNAME { $$= scanStr; scanStr= NULL; }
+ ;
+
+Ident : IDENT { $$= XkbInternAtom(NULL,scanStr,False); }
+ | DEFAULT { $$= XkbInternAtom(NULL,"default",False); }
+ ;
+
+String : STRING { $$= XkbInternAtom(NULL,scanStr,False); }
+ ;
+
+OptMapName : MapName { $$= $1; }
+ | { $$= NULL; }
+ ;
+
+MapName : STRING { $$= scanStr; scanStr= NULL; }
+ ;
+%%
+void
+yyerror(const char *s)
+{
+ if (warningLevel>0) {
+ (void)fprintf(stderr,"%s: line %d of %s\n",s,lineNum,
+ (scanFile?scanFile:"(unknown)"));
+ if ((scanStr)&&(warningLevel>3))
+ (void)fprintf(stderr,"last scanned symbol is: %s\n",scanStr);
+ }
+ return;
+}
+
+
+int
+yywrap(void)
+{
+ return 1;
+}
+
diff --git a/src/xkbcomp/xkbpath.c b/src/xkbcomp/xkbpath.c
new file mode 100644
index 0000000..6802012
--- /dev/null
+++ b/src/xkbcomp/xkbpath.c
@@ -0,0 +1,420 @@
+/************************************************************
+ 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 <X11/Xlib.h>
+#include <X11/XKBlib.h>
+
+#define DEBUG_VAR debugFlags
+#include "utils.h"
+#include <stdlib.h>
+#include <X11/extensions/XKM.h>
+#include "xkbpath.h"
+
+#ifndef DFLT_XKB_CONFIG_ROOT
+#define DFLT_XKB_CONFIG_ROOT "/usr/lib/X11/xkb"
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#define PATH_CHUNK 8 /* initial szPath */
+
+static Bool noDefaultPath = False;
+static int szPath; /* number of entries allocated for includePath */
+static int nPathEntries; /* number of actual entries in includePath */
+static char **includePath; /* Holds all directories we might be including data from */
+
+/**
+ * Extract the first token from an include statement.
+ * @param str_inout Input statement, modified in-place. Can be passed in
+ * repeatedly. If str_inout is NULL, the parsing has completed.
+ * @param file_rtrn Set to the include file to be used.
+ * @param map_rtrn Set to whatever comes after ), if any.
+ * @param nextop_rtrn Set to the next operation in the complete statement.
+ * @param extra_data Set to the string between ( and ), if any.
+ *
+ * @return True if parsing was succcessful, False for an illegal string.
+ *
+ * Example: "evdev+aliases(qwerty)"
+ * str_inout = aliases(qwerty)
+ * nextop_retrn = +
+ * extra_data = NULL
+ * file_rtrn = evdev
+ * map_rtrn = NULL
+ *
+ * 2nd run with "aliases(qwerty)"
+ * str_inout = NULL
+ * file_rtrn = aliases
+ * map_rtrn = qwerty
+ * extra_data = NULL
+ * nextop_retrn = ""
+ *
+ */
+Bool
+XkbParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn,
+ char *nextop_rtrn, char **extra_data)
+{
+ char *tmp, *str, *next;
+
+ str = *str_inout;
+ if ((*str == '+') || (*str == '|'))
+ {
+ *file_rtrn = *map_rtrn = NULL;
+ *nextop_rtrn = *str;
+ next = str + 1;
+ }
+ else if (*str == '%')
+ {
+ *file_rtrn = *map_rtrn = NULL;
+ *nextop_rtrn = str[1];
+ next = str + 2;
+ }
+ else
+ {
+ /* search for tokens inside the string */
+ next = strpbrk(str, "|+");
+ if (next)
+ {
+ /* set nextop_rtrn to \0, next to next character */
+ *nextop_rtrn = *next;
+ *next++ = '\0';
+ }
+ else
+ {
+ *nextop_rtrn = '\0';
+ next = NULL;
+ }
+ /* search for :, store result in extra_data */
+ tmp = strchr(str, ':');
+ if (tmp != NULL)
+ {
+ *tmp++ = '\0';
+ *extra_data = uStringDup(tmp);
+ }
+ else
+ {
+ *extra_data = NULL;
+ }
+ tmp = strchr(str, '(');
+ if (tmp == NULL)
+ {
+ *file_rtrn = uStringDup(str);
+ *map_rtrn = NULL;
+ }
+ else if (str[0] == '(')
+ {
+ uFree(*extra_data);
+ return False;
+ }
+ else
+ {
+ *tmp++ = '\0';
+ *file_rtrn = uStringDup(str);
+ str = tmp;
+ tmp = strchr(str, ')');
+ if ((tmp == NULL) || (tmp[1] != '\0'))
+ {
+ uFree(*file_rtrn);
+ uFree(*extra_data);
+ return False;
+ }
+ *tmp++ = '\0';
+ *map_rtrn = uStringDup(str);
+ }
+ }
+ if (*nextop_rtrn == '\0')
+ *str_inout = NULL;
+ else if ((*nextop_rtrn == '|') || (*nextop_rtrn == '+'))
+ *str_inout = next;
+ else
+ return False;
+ return True;
+}
+
+/**
+ * Init memory for include paths.
+ */
+Bool
+XkbInitIncludePath(void)
+{
+ szPath = PATH_CHUNK;
+ includePath = (char **) calloc(szPath, sizeof(char *));
+ if (includePath == NULL)
+ return False;
+ return True;
+}
+
+void
+XkbAddDefaultDirectoriesToPath(void)
+{
+ if (noDefaultPath)
+ return;
+ XkbAddDirectoryToPath(DFLT_XKB_CONFIG_ROOT);
+}
+
+/**
+ * Remove all entries from the global includePath.
+ */
+void
+XkbClearIncludePath(void)
+{
+ register int i;
+
+ if (szPath > 0)
+ {
+ for (i = 0; i < nPathEntries; i++)
+ {
+ if (includePath[i] != NULL)
+ {
+ uFree(includePath[i]);
+ includePath[i] = NULL;
+ }
+ }
+ nPathEntries = 0;
+ }
+ noDefaultPath = True;
+ return;
+}
+
+/**
+ * Add the given path to the global includePath variable.
+ * If dir is NULL, the includePath is emptied.
+ */
+Bool
+XkbAddDirectoryToPath(const char *dir)
+{
+ int len;
+ if ((dir == NULL) || (dir[0] == '\0'))
+ {
+ XkbClearIncludePath();
+ return True;
+ }
+#ifdef __UNIXOS2__
+ dir = (char *) __XOS2RedirRoot(dir);
+#endif
+ len = strlen(dir);
+ if (len + 2 >= PATH_MAX)
+ { /* allow for '/' and at least one character */
+ ERROR2("Path entry (%s) too long (maxiumum length is %d)\n",
+ dir, PATH_MAX - 3);
+ return False;
+ }
+ if (nPathEntries >= szPath)
+ {
+ szPath += PATH_CHUNK;
+ includePath = (char **) realloc(includePath, szPath * sizeof(char *));
+ if (includePath == NULL)
+ {
+ WSGO("Allocation failed (includePath)\n");
+ return False;
+ }
+ }
+ includePath[nPathEntries] =
+ (char *) calloc(strlen(dir) + 1, sizeof(char));
+ if (includePath[nPathEntries] == NULL)
+ {
+ WSGO1("Allocation failed (includePath[%d])\n", nPathEntries);
+ return False;
+ }
+ strcpy(includePath[nPathEntries++], dir);
+ return True;
+}
+
+/***====================================================================***/
+
+/**
+ * Return the xkb directory based on the type.
+ * Do not free the memory returned by this function.
+ */
+char *
+XkbDirectoryForInclude(unsigned type)
+{
+ static char buf[32];
+
+ switch (type)
+ {
+ case XkmSemanticsFile:
+ strcpy(buf, "semantics");
+ break;
+ case XkmLayoutFile:
+ strcpy(buf, "layout");
+ break;
+ case XkmKeymapFile:
+ strcpy(buf, "keymap");
+ break;
+ case XkmKeyNamesIndex:
+ strcpy(buf, "keycodes");
+ break;
+ case XkmTypesIndex:
+ strcpy(buf, "types");
+ break;
+ case XkmSymbolsIndex:
+ strcpy(buf, "symbols");
+ break;
+ case XkmCompatMapIndex:
+ strcpy(buf, "compat");
+ break;
+ case XkmGeometryFile:
+ case XkmGeometryIndex:
+ strcpy(buf, "geometry");
+ break;
+ default:
+ strcpy(buf, "");
+ break;
+ }
+ return buf;
+}
+
+/***====================================================================***/
+
+typedef struct _FileCacheEntry
+{
+ char *name;
+ unsigned type;
+ char *path;
+ void *data;
+ struct _FileCacheEntry *next;
+} FileCacheEntry;
+static FileCacheEntry *fileCache;
+
+/**
+ * Add the file with the given name to the internal cache to avoid opening and
+ * parsing the file multiple times. If a cache entry for the same name + type
+ * is already present, the entry is overwritten and the data belonging to the
+ * previous entry is returned.
+ *
+ * @parameter name The name of the file (e.g. evdev).
+ * @parameter type Type of the file (XkbTypesIdx, ... or XkbSemanticsFile, ...)
+ * @parameter path The full path to the file.
+ * @parameter data Already parsed data.
+ *
+ * @return The data from the overwritten file or NULL.
+ */
+void *
+XkbAddFileToCache(char *name, unsigned type, char *path, void *data)
+{
+ FileCacheEntry *entry;
+
+ for (entry = fileCache; entry != NULL; entry = entry->next)
+ {
+ if ((type == entry->type) && (uStringEqual(name, entry->name)))
+ {
+ void *old = entry->data;
+ WSGO2("Replacing file cache entry (%s/%d)\n", name, type);
+ entry->path = path;
+ entry->data = data;
+ return old;
+ }
+ }
+ entry = uTypedAlloc(FileCacheEntry);
+ if (entry != NULL)
+ {
+ entry->name = name;
+ entry->type = type;
+ entry->path = path;
+ entry->data = data;
+ entry->next = fileCache;
+ fileCache = entry;
+ }
+ return NULL;
+}
+
+/**
+ * Search for the given name + type in the cache.
+ *
+ * @parameter name The name of the file (e.g. evdev).
+ * @parameter type Type of the file (XkbTypesIdx, ... or XkbSemanticsFile, ...)
+ * @parameter pathRtrn Set to the full path of the given entry.
+ *
+ * @return the data from the cache entry or NULL if no matching entry was found.
+ */
+void *
+XkbFindFileInCache(char *name, unsigned type, char **pathRtrn)
+{
+ FileCacheEntry *entry;
+
+ for (entry = fileCache; entry != NULL; entry = entry->next)
+ {
+ if ((type == entry->type) && (uStringEqual(name, entry->name)))
+ {
+ *pathRtrn = entry->path;
+ return entry->data;
+ }
+ }
+ return NULL;
+}
+
+/***====================================================================***/
+
+/**
+ * Search for the given file name in the include directories.
+ *
+ * @param type one of XkbTypesIndex, XkbCompatMapIndex, ..., or
+ * XkbSemanticsFile, XkmKeymapFile, ...
+ * @param pathReturn is set to the full path of the file if found.
+ *
+ * @return an FD to the file or NULL. If NULL is returned, the value of
+ * pathRtrn is undefined.
+ */
+FILE *
+XkbFindFileInPath(char *name, unsigned type, char **pathRtrn)
+{
+ register int i;
+ FILE *file = NULL;
+ int nameLen, typeLen, pathLen;
+ char buf[PATH_MAX], *typeDir;
+
+ typeDir = XkbDirectoryForInclude(type);
+ nameLen = strlen(name);
+ typeLen = strlen(typeDir);
+ for (i = 0; i < nPathEntries; i++)
+ {
+ pathLen = strlen(includePath[i]);
+ if (typeLen < 1)
+ continue;
+
+ if ((nameLen + typeLen + pathLen + 2) >= PATH_MAX)
+ {
+ ERROR3("File name (%s/%s/%s) too long\n", includePath[i],
+ typeDir, name);
+ ACTION("Ignored\n");
+ continue;
+ }
+ snprintf(buf, sizeof(buf), "%s/%s/%s", includePath[i], typeDir, name);
+ file = fopen(buf, "r");
+ if (file != NULL)
+ break;
+ }
+
+ if ((file != NULL) && (pathRtrn != NULL))
+ {
+ *pathRtrn = (char *) calloc(strlen(buf) + 1, sizeof(char));
+ if (*pathRtrn != NULL)
+ strcpy(*pathRtrn, buf);
+ }
+ return file;
+}
diff --git a/src/xkbcomp/xkbpath.h b/src/xkbcomp/xkbpath.h
new file mode 100644
index 0000000..66c3ab7
--- /dev/null
+++ b/src/xkbcomp/xkbpath.h
@@ -0,0 +1,65 @@
+/************************************************************
+ 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.
+
+ ********************************************************/
+
+#ifndef _XKBPATH_H_
+#define _XKBPATH_H_ 1
+
+extern Bool XkbInitIncludePath(void);
+
+extern void XkbClearIncludePath(void);
+
+extern void XkbAddDefaultDirectoriesToPath(void);
+
+extern Bool XkbAddDirectoryToPath(const char * /* dir */
+ );
+
+extern char *XkbDirectoryForInclude(unsigned /* type */
+ );
+
+extern FILE *XkbFindFileInPath(char * /* name */ ,
+ unsigned /* type */ ,
+ char ** /* pathRtrn */
+ );
+
+extern void *XkbAddFileToCache(char * /* name */ ,
+ unsigned /* type */ ,
+ char * /* path */ ,
+ void * /* data */
+ );
+
+extern void *XkbFindFileInCache(char * /* name */ ,
+ unsigned /* type */ ,
+ char ** /* pathRtrn */
+ );
+
+extern Bool XkbParseIncludeMap(char ** /* str_inout */ ,
+ char ** /* file_rtrn */ ,
+ char ** /* map_rtrn */ ,
+ char * /* nextop_rtrn */ ,
+ char ** /* extra_data */
+ );
+
+#endif /* _XKBPATH_H_ */
diff --git a/src/xkbcomp/xkbscan.c b/src/xkbcomp/xkbscan.c
new file mode 100644
index 0000000..31cafd4
--- /dev/null
+++ b/src/xkbcomp/xkbscan.c
@@ -0,0 +1,723 @@
+/************************************************************
+ 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 <stdio.h>
+#include <ctype.h>
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+
+#include "tokens.h"
+#define DEBUG_VAR scanDebug
+#include "utils.h"
+#include "parseutils.h"
+
+unsigned int scanDebug;
+
+FILE *yyin = NULL;
+
+static char scanFileBuf[1024] = {0};
+char *scanFile = scanFileBuf;
+int lineNum = 0;
+
+int scanInt;
+
+char *scanStr = NULL;
+static int scanStrLine = 0;
+
+#define BUFSIZE 512
+static int nInBuf = 0;
+static char buf[BUFSIZE];
+
+#ifdef DEBUG
+static char *
+tokText(int tok)
+{
+ static char buf[32];
+
+ switch (tok)
+ {
+ case END_OF_FILE:
+ snprintf(buf, sizeof(buf), "END_OF_FILE");
+ break;
+ case ERROR_TOK:
+ snprintf(buf, sizeof(buf), "ERROR");
+ break;
+
+ case XKB_KEYMAP:
+ snprintf(buf, sizeof(buf), "XKB_KEYMAP");
+ break;
+ case XKB_KEYCODES:
+ snprintf(buf, sizeof(buf), "XKB_KEYCODES");
+ break;
+ case XKB_TYPES:
+ snprintf(buf, sizeof(buf), "XKB_TYPES");
+ break;
+ case XKB_SYMBOLS:
+ snprintf(buf, sizeof(buf), "XKB_SYMBOLS");
+ break;
+ case XKB_COMPATMAP:
+ snprintf(buf, sizeof(buf), "XKB_COMPATMAP");
+ break;
+ case XKB_GEOMETRY:
+ snprintf(buf, sizeof(buf), "XKB_GEOMETRY");
+ break;
+ case XKB_SEMANTICS:
+ snprintf(buf, sizeof(buf), "XKB_SEMANTICS");
+ break;
+ case XKB_LAYOUT:
+ snprintf(buf, sizeof(buf), "XKB_LAYOUT");
+ break;
+
+ case INCLUDE:
+ snprintf(buf, sizeof(buf), "INCLUDE");
+ break;
+ case OVERRIDE:
+ snprintf(buf, sizeof(buf), "OVERRIDE");
+ break;
+ case AUGMENT:
+ snprintf(buf, sizeof(buf), "AUGMENT");
+ break;
+ case REPLACE:
+ snprintf(buf, sizeof(buf), "REPLACE");
+ break;
+ case ALTERNATE:
+ snprintf(buf, sizeof(buf), "ALTERNATE");
+ break;
+
+ case VIRTUAL_MODS:
+ snprintf(buf, sizeof(buf), "VIRTUAL_MODS");
+ break;
+ case TYPE:
+ snprintf(buf, sizeof(buf), "TYPE");
+ break;
+ case INTERPRET:
+ snprintf(buf, sizeof(buf), "INTERPRET");
+ break;
+ case ACTION_TOK:
+ snprintf(buf, sizeof(buf), "ACTION");
+ break;
+ case KEY:
+ snprintf(buf, sizeof(buf), "KEY");
+ break;
+ case ALIAS:
+ snprintf(buf, sizeof(buf), "ALIAS");
+ break;
+ case GROUP:
+ snprintf(buf, sizeof(buf), "GROUP");
+ break;
+ case MODIFIER_MAP:
+ snprintf(buf, sizeof(buf), "MODIFIER_MAP");
+ break;
+ case INDICATOR:
+ snprintf(buf, sizeof(buf), "INDICATOR");
+ break;
+ case SHAPE:
+ snprintf(buf, sizeof(buf), "SHAPE");
+ break;
+ case KEYS:
+ snprintf(buf, sizeof(buf), "KEYS");
+ break;
+ case ROW:
+ snprintf(buf, sizeof(buf), "ROW");
+ break;
+ case SECTION:
+ snprintf(buf, sizeof(buf), "SECTION");
+ break;
+ case OVERLAY:
+ snprintf(buf, sizeof(buf), "OVERLAY");
+ break;
+ case TEXT:
+ snprintf(buf, sizeof(buf), "TEXT");
+ break;
+ case OUTLINE:
+ snprintf(buf, sizeof(buf), "OUTLINE");
+ break;
+ case SOLID:
+ snprintf(buf, sizeof(buf), "SOLID");
+ break;
+ case LOGO:
+ snprintf(buf, sizeof(buf), "LOGO");
+ break;
+ case VIRTUAL:
+ snprintf(buf, sizeof(buf), "VIRTUAL");
+ break;
+
+ case EQUALS:
+ snprintf(buf, sizeof(buf), "EQUALS");
+ break;
+ case PLUS:
+ snprintf(buf, sizeof(buf), "PLUS");
+ break;
+ case MINUS:
+ snprintf(buf, sizeof(buf), "MINUS");
+ break;
+ case DIVIDE:
+ snprintf(buf, sizeof(buf), "DIVIDE");
+ break;
+ case TIMES:
+ snprintf(buf, sizeof(buf), "TIMES");
+ break;
+ case OBRACE:
+ snprintf(buf, sizeof(buf), "OBRACE");
+ break;
+ case CBRACE:
+ snprintf(buf, sizeof(buf), "CBRACE");
+ break;
+ case OPAREN:
+ snprintf(buf, sizeof(buf), "OPAREN");
+ break;
+ case CPAREN:
+ snprintf(buf, sizeof(buf), "CPAREN");
+ break;
+ case OBRACKET:
+ snprintf(buf, sizeof(buf), "OBRACKET");
+ break;
+ case CBRACKET:
+ snprintf(buf, sizeof(buf), "CBRACKET");
+ break;
+ case DOT:
+ snprintf(buf, sizeof(buf), "DOT");
+ break;
+ case COMMA:
+ snprintf(buf, sizeof(buf), "COMMA");
+ break;
+ case SEMI:
+ snprintf(buf, sizeof(buf), "SEMI");
+ break;
+ case EXCLAM:
+ snprintf(buf, sizeof(buf), "EXCLAM");
+ break;
+ case INVERT:
+ snprintf(buf, sizeof(buf), "INVERT");
+ break;
+
+ case STRING:
+ snprintf(buf, sizeof(buf), "STRING (%s)", scanStr);
+ break;
+ case INTEGER:
+ snprintf(buf, sizeof(buf), "INTEGER (0x%x)", scanInt);
+ break;
+ case FLOAT:
+ snprintf(buf, sizeof(buf), "FLOAT (%d.%d)",
+ scanInt / XkbGeomPtsPerMM, scanInt % XkbGeomPtsPerMM);
+ break;
+ case IDENT:
+ snprintf(buf, sizeof(buf), "IDENT (%s)", scanStr);
+ break;
+ case KEYNAME:
+ snprintf(buf, sizeof(buf), "KEYNAME (%s)", scanStr);
+ break;
+
+ case PARTIAL:
+ snprintf(buf, sizeof(buf), "PARTIAL");
+ break;
+ case DEFAULT:
+ snprintf(buf, sizeof(buf), "DEFAULT");
+ break;
+ case HIDDEN:
+ snprintf(buf, sizeof(buf), "HIDDEN");
+ break;
+
+ case ALPHANUMERIC_KEYS:
+ snprintf(buf, sizeof(buf), "ALPHANUMERIC_KEYS");
+ break;
+ case MODIFIER_KEYS:
+ snprintf(buf, sizeof(buf), "MODIFIER_KEYS");
+ break;
+ case KEYPAD_KEYS:
+ snprintf(buf, sizeof(buf), "KEYPAD_KEYS");
+ break;
+ case FUNCTION_KEYS:
+ snprintf(buf, sizeof(buf), "FUNCTION_KEYS");
+ break;
+ case ALTERNATE_GROUP:
+ snprintf(buf, sizeof(buf), "ALTERNATE_GROUP");
+ break;
+
+ default:
+ snprintf(buf, sizeof(buf), "UNKNOWN");
+ break;
+ }
+ return buf;
+}
+#endif
+
+int
+setScanState(char *file, int line)
+{
+ if (file != NULL)
+ strncpy(scanFile, file, 1024);
+ if (line >= 0)
+ lineNum = line;
+ return 1;
+}
+
+static int
+yyGetString(void)
+{
+ int ch;
+
+ nInBuf = 0;
+ while (((ch = getc(yyin)) != EOF) && (ch != '"'))
+ {
+ if (ch == '\\')
+ {
+ if ((ch = getc(yyin)) != EOF)
+ {
+ if (ch == 'n')
+ ch = '\n';
+ else if (ch == 't')
+ ch = '\t';
+ else if (ch == 'v')
+ ch = '\v';
+ else if (ch == 'b')
+ ch = '\b';
+ else if (ch == 'r')
+ ch = '\r';
+ else if (ch == 'f')
+ ch = '\f';
+ else if (ch == 'e')
+ ch = '\033';
+ else if (ch == '0')
+ {
+ int tmp, stop;
+ ch = stop = 0;
+ if (((tmp = getc(yyin)) != EOF) && (isdigit(tmp))
+ && (tmp != '8') && (tmp != '9'))
+ {
+ ch = (ch * 8) + (tmp - '0');
+ }
+ else
+ {
+ stop = 1;
+ ungetc(tmp, yyin);
+ }
+ if (!stop)
+ {
+ if (((tmp = getc(yyin)) != EOF)
+ && (isdigit(tmp)) && (tmp != '8') && (tmp != '9'))
+ {
+ ch = (ch * 8) + (tmp - '0');
+ }
+ else
+ {
+ stop = 1;
+ ungetc(tmp, yyin);
+ }
+ }
+ if (!stop)
+ {
+ if (((tmp = getc(yyin)) != EOF)
+ && (isdigit(tmp)) && (tmp != '8') && (tmp != '9'))
+ {
+ ch = (ch * 8) + (tmp - '0');
+ }
+ else
+ {
+ stop = 1;
+ ungetc(tmp, yyin);
+ }
+ }
+ }
+ }
+ else
+ return ERROR_TOK;
+ }
+ if (nInBuf < BUFSIZE - 1)
+ buf[nInBuf++] = ch;
+ }
+ if (ch == '"')
+ {
+ buf[nInBuf++] = '\0';
+ if (scanStr)
+ uFree(scanStr);
+ scanStr = (char *) uStringDup(buf);
+ scanStrLine = lineNum;
+ return STRING;
+ }
+ return ERROR_TOK;
+}
+
+static int
+yyGetKeyName(void)
+{
+ int ch;
+
+ nInBuf = 0;
+ while (((ch = getc(yyin)) != EOF) && (ch != '>'))
+ {
+ if (ch == '\\')
+ {
+ if ((ch = getc(yyin)) != EOF)
+ {
+ if (ch == 'n')
+ ch = '\n';
+ else if (ch == 't')
+ ch = '\t';
+ else if (ch == 'v')
+ ch = '\v';
+ else if (ch == 'b')
+ ch = '\b';
+ else if (ch == 'r')
+ ch = '\r';
+ else if (ch == 'f')
+ ch = '\f';
+ else if (ch == 'e')
+ ch = '\033';
+ else if (ch == '0')
+ {
+ int tmp, stop;
+ ch = stop = 0;
+ if (((tmp = getc(yyin)) != EOF) && (isdigit(tmp))
+ && (tmp != '8') && (tmp != '9'))
+ {
+ ch = (ch * 8) + (tmp - '0');
+ }
+ else
+ {
+ stop = 1;
+ ungetc(tmp, yyin);
+ }
+ if ((!stop) && ((tmp = getc(yyin)) != EOF)
+ && (isdigit(tmp)) && (tmp != '8') && (tmp != '9'))
+ {
+ ch = (ch * 8) + (tmp - '0');
+ }
+ else
+ {
+ stop = 1;
+ ungetc(tmp, yyin);
+ }
+ if ((!stop) && ((tmp = getc(yyin)) != EOF)
+ && (isdigit(tmp)) && (tmp != '8') && (tmp != '9'))
+ {
+ ch = (ch * 8) + (tmp - '0');
+ }
+ else
+ {
+ stop = 1;
+ ungetc(tmp, yyin);
+ }
+ }
+ }
+ else
+ return ERROR_TOK;
+ }
+
+ if (nInBuf < BUFSIZE - 1)
+ buf[nInBuf++] = ch;
+ }
+ if ((ch == '>') && (nInBuf < 5))
+ {
+ buf[nInBuf++] = '\0';
+ if (scanStr)
+ uFree(scanStr);
+ scanStr = (char *) uStringDup(buf);
+ scanStrLine = lineNum;
+ return KEYNAME;
+ }
+ return ERROR_TOK;
+}
+
+static struct _Keyword
+{
+ const char *keyword;
+ int token;
+} keywords[] =
+{
+ {
+ "xkb_keymap", XKB_KEYMAP},
+ {
+ "xkb_keycodes", XKB_KEYCODES},
+ {
+ "xkb_types", XKB_TYPES},
+ {
+ "xkb_symbols", XKB_SYMBOLS},
+ {
+ "xkb_compat", XKB_COMPATMAP},
+ {
+ "xkb_compat_map", XKB_COMPATMAP},
+ {
+ "xkb_compatibility", XKB_COMPATMAP},
+ {
+ "xkb_compatibility_map", XKB_COMPATMAP},
+ {
+ "xkb_geometry", XKB_GEOMETRY},
+ {
+ "xkb_semantics", XKB_SEMANTICS},
+ {
+ "xkb_layout", XKB_LAYOUT},
+ {
+ "include", INCLUDE},
+ {
+ "override", OVERRIDE},
+ {
+ "augment", AUGMENT},
+ {
+ "replace", REPLACE},
+ {
+ "alternate", ALTERNATE},
+ {
+ "partial", PARTIAL},
+ {
+ "default", DEFAULT},
+ {
+ "hidden", HIDDEN},
+ {
+ "virtual_modifiers", VIRTUAL_MODS},
+ {
+ "type", TYPE},
+ {
+ "interpret", INTERPRET},
+ {
+ "action", ACTION_TOK},
+ {
+ "key", KEY},
+ {
+ "alias", ALIAS},
+ {
+ "group", GROUP},
+ {
+ "modmap", MODIFIER_MAP},
+ {
+ "mod_map", MODIFIER_MAP},
+ {
+ "modifier_map", MODIFIER_MAP},
+ {
+ "indicator", INDICATOR},
+ {
+ "shape", SHAPE},
+ {
+ "row", ROW},
+ {
+ "keys", KEYS},
+ {
+ "section", SECTION},
+ {
+ "overlay", OVERLAY},
+ {
+ "text", TEXT},
+ {
+ "outline", OUTLINE},
+ {
+ "solid", SOLID},
+ {
+ "logo", LOGO},
+ {
+ "virtual", VIRTUAL},
+ {
+ "alphanumeric_keys", ALPHANUMERIC_KEYS},
+ {
+ "modifier_keys", MODIFIER_KEYS},
+ {
+ "keypad_keys", KEYPAD_KEYS},
+ {
+ "function_keys", FUNCTION_KEYS},
+ {
+ "alternate_group", ALTERNATE_GROUP}
+};
+static int numKeywords = sizeof(keywords) / sizeof(struct _Keyword);
+
+static int
+yyGetIdent(int first)
+{
+ int ch, i, found;
+ int rtrn = IDENT;
+
+ buf[0] = first;
+ nInBuf = 1;
+ while (((ch = getc(yyin)) != EOF) && (isalnum(ch) || (ch == '_')))
+ {
+ if (nInBuf < BUFSIZE - 1)
+ buf[nInBuf++] = ch;
+ }
+ buf[nInBuf++] = '\0';
+ found = 0;
+
+ for (i = 0; (!found) && (i < numKeywords); i++)
+ {
+ if (uStrCaseCmp(buf, keywords[i].keyword) == 0)
+ {
+ rtrn = keywords[i].token;
+ found = 1;
+ }
+ }
+ if (!found)
+ {
+ if (scanStr)
+ uFree(scanStr);
+ scanStr = (char *) uStringDup(buf);
+ scanStrLine = lineNum;
+ rtrn = IDENT;
+ }
+
+ if ((ch != EOF) && (!isspace(ch)))
+ ungetc(ch, yyin);
+ else if (ch == '\n')
+ lineNum++;
+
+ return rtrn;
+}
+
+static int
+yyGetNumber(int ch)
+{
+ int isFloat = 0;
+
+ buf[0] = ch;
+ nInBuf = 1;
+ while (((ch = getc(yyin)) != EOF)
+ && (isxdigit(ch) || ((nInBuf == 1) && (ch == 'x'))))
+ {
+ buf[nInBuf++] = ch;
+ }
+ if (ch == '.')
+ {
+ isFloat = 1;
+ buf[nInBuf++] = ch;
+ while (((ch = getc(yyin)) != EOF) && (isxdigit(ch)))
+ {
+ buf[nInBuf++] = ch;
+ }
+ }
+ buf[nInBuf++] = '\0';
+ if ((ch != EOF) && (!isspace(ch)))
+ ungetc(ch, yyin);
+
+ if (isFloat)
+ {
+ float tmp;
+ if (sscanf(buf, "%g", &tmp) == 1)
+ {
+ scanInt = tmp * XkbGeomPtsPerMM;
+ return FLOAT;
+ }
+ }
+ else if (sscanf(buf, "%i", &scanInt) == 1)
+ return INTEGER;
+ fprintf(stderr, "Malformed number %s\n", buf);
+ return ERROR_TOK;
+}
+
+int
+yylex(void)
+{
+ int ch;
+ int rtrn;
+
+ do
+ {
+ ch = getc(yyin);
+ if (ch == '\n')
+ {
+ lineNum++;
+ }
+ else if (ch == '#')
+ { /* handle shell style '#' comments */
+ do
+ {
+ ch = getc(yyin);
+ }
+ while ((ch != '\n') && (ch != EOF));
+ lineNum++;
+ }
+ else if (ch == '/')
+ { /* handle C++ style double-/ comments */
+ int newch = getc(yyin);
+ if (newch == '/')
+ {
+ do
+ {
+ ch = getc(yyin);
+ }
+ while ((ch != '\n') && (ch != EOF));
+ lineNum++;
+ }
+ else if (newch != EOF)
+ {
+ ungetc(newch, yyin);
+ }
+ }
+ }
+ while ((ch != EOF) && (isspace(ch)));
+ if (ch == '=')
+ rtrn = EQUALS;
+ else if (ch == '+')
+ rtrn = PLUS;
+ else if (ch == '-')
+ rtrn = MINUS;
+ else if (ch == '/')
+ rtrn = DIVIDE;
+ else if (ch == '*')
+ rtrn = TIMES;
+ else if (ch == '{')
+ rtrn = OBRACE;
+ else if (ch == '}')
+ rtrn = CBRACE;
+ else if (ch == '(')
+ rtrn = OPAREN;
+ else if (ch == ')')
+ rtrn = CPAREN;
+ else if (ch == '[')
+ rtrn = OBRACKET;
+ else if (ch == ']')
+ rtrn = CBRACKET;
+ else if (ch == '.')
+ rtrn = DOT;
+ else if (ch == ',')
+ rtrn = COMMA;
+ else if (ch == ';')
+ rtrn = SEMI;
+ else if (ch == '!')
+ rtrn = EXCLAM;
+ else if (ch == '~')
+ rtrn = INVERT;
+ else if (ch == '"')
+ rtrn = yyGetString();
+ else if (ch == '<')
+ rtrn = yyGetKeyName();
+ else if (isalpha(ch) || (ch == '_'))
+ rtrn = yyGetIdent(ch);
+ else if (isdigit(ch))
+ rtrn = yyGetNumber(ch);
+ else if (ch == EOF)
+ rtrn = END_OF_FILE;
+ else
+ {
+#ifdef DEBUG
+ if (debugFlags)
+ fprintf(stderr,
+ "Unexpected character %c (%d) in input stream\n", ch, ch);
+#endif
+ rtrn = ERROR_TOK;
+ }
+#ifdef DEBUG
+ if (debugFlags & 0x2)
+ fprintf(stderr, "scan: %s\n", tokText(rtrn));
+#endif
+ return rtrn;
+}