diff options
author | Dan Nicholson <dbn.lists@gmail.com> | 2009-03-27 06:55:32 -0700 |
---|---|---|
committer | Dan Nicholson <dbn.lists@gmail.com> | 2009-03-27 06:55:32 -0700 |
commit | 0c1bbb05d975cf7b3411259900500cc122fc136b (patch) | |
tree | 6e5c9c6adf8674c48da18c55993b530e69fac5fa /src | |
parent | f4d8e2932cdd60653d2f762ad7502e6ec5710fe5 (diff) | |
download | libxkbcommon-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')
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 != §ion->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; +} |