/*********************************************************** Copyright (c) 1993, Oracle and/or its affiliates. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. Copyright 1987, 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. ******************************************************************/ /* Copyright 1987, 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. */ #ifdef HAVE_CONFIG_H #include #endif #include "IntrinsicI.h" #include "StringDefs.h" #include #include #ifndef NOTASCII #define XK_LATIN1 #endif #define XK_MISCELLANY #include #ifdef CACHE_TRANSLATIONS #ifdef REFCNT_TRANSLATIONS #define CACHED XtCacheAll | XtCacheRefCount #else #define CACHED XtCacheAll #endif #else #define CACHED XtCacheNone #endif #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif static _Xconst char *XtNtranslationParseError = "translationParseError"; typedef int EventType; #define PARSE_PROC_DECL String, Opaque, EventPtr, Boolean* typedef String(*ParseProc) (String /* str; */ , Opaque /* closure; */ , EventPtr /* event; */ , Boolean * /* error */ ); typedef TMShortCard Value; typedef void (*ModifierProc) (Value, LateBindingsPtr *, Boolean, Value *); typedef struct _ModifierRec { const char *name; XrmQuark signature; ModifierProc modifierParseProc; Value value; } ModifierRec, *ModifierKeys; typedef struct _EventKey { const char *event; XrmQuark signature; EventType eventType; ParseProc parseDetail; Opaque closure; } EventKey, *EventKeys; typedef struct { const char *name; XrmQuark signature; Value value; } NameValueRec, *NameValueTable; static void ParseModImmed(Value, LateBindingsPtr *, Boolean, Value *); static void ParseModSym(Value, LateBindingsPtr *, Boolean, Value *); static String PanicModeRecovery(String); static String CheckForPoundSign(String, _XtTranslateOp, _XtTranslateOp *); static KeySym StringToKeySym(String, Boolean *); /* *INDENT-OFF* */ static ModifierRec modifiers[] = { {"Shift", 0, ParseModImmed, ShiftMask}, {"Lock", 0, ParseModImmed, LockMask}, {"Ctrl", 0, ParseModImmed, ControlMask}, {"Mod1", 0, ParseModImmed, Mod1Mask}, {"Mod2", 0, ParseModImmed, Mod2Mask}, {"Mod3", 0, ParseModImmed, Mod3Mask}, {"Mod4", 0, ParseModImmed, Mod4Mask}, {"Mod5", 0, ParseModImmed, Mod5Mask}, {"Meta", 0, ParseModSym, XK_Meta_L}, {"m", 0, ParseModSym, XK_Meta_L}, {"h", 0, ParseModSym, XK_Hyper_L}, {"su", 0, ParseModSym, XK_Super_L}, {"a", 0, ParseModSym, XK_Alt_L}, {"Hyper", 0, ParseModSym, XK_Hyper_L}, {"Super", 0, ParseModSym, XK_Super_L}, {"Alt", 0, ParseModSym, XK_Alt_L}, {"Button1", 0, ParseModImmed, Button1Mask}, {"Button2", 0, ParseModImmed, Button2Mask}, {"Button3", 0, ParseModImmed, Button3Mask}, {"Button4", 0, ParseModImmed, Button4Mask}, {"Button5", 0, ParseModImmed, Button5Mask}, {"c", 0, ParseModImmed, ControlMask}, {"s", 0, ParseModImmed, ShiftMask}, {"l", 0, ParseModImmed, LockMask}, }; static NameValueRec motionDetails[] = { {"Normal", 0, NotifyNormal}, {"Hint", 0, NotifyHint}, {NULL, NULLQUARK, 0}, }; static NameValueRec notifyModes[] = { {"Normal", 0, NotifyNormal}, {"Grab", 0, NotifyGrab}, {"Ungrab", 0, NotifyUngrab}, {"WhileGrabbed", 0, NotifyWhileGrabbed}, {NULL, NULLQUARK, 0}, }; #if 0 static NameValueRec notifyDetail[] = { {"Ancestor", 0, NotifyAncestor}, {"Virtual", 0, NotifyVirtual}, {"Inferior", 0, NotifyInferior}, {"Nonlinear", 0, NotifyNonlinear}, {"NonlinearVirtual", 0, NotifyNonlinearVirtual}, {"Pointer", 0, NotifyPointer}, {"PointerRoot", 0, NotifyPointerRoot}, {"DetailNone", 0, NotifyDetailNone}, {NULL, NULLQUARK, 0}, }; static NameValueRec visibilityNotify[] = { {"Unobscured", 0, VisibilityUnobscured}, {"PartiallyObscured", 0, VisibilityPartiallyObscured}, {"FullyObscured", 0, VisibilityFullyObscured}, {NULL, NULLQUARK, 0}, }; static NameValueRec circulation[] = { {"OnTop", 0, PlaceOnTop}, {"OnBottom", 0, PlaceOnBottom}, {NULL, NULLQUARK, 0}, }; static NameValueRec propertyChanged[] = { {"NewValue", 0, PropertyNewValue}, {"Delete", 0, PropertyDelete}, {NULL, NULLQUARK, 0}, }; #endif /*0*/ static NameValueRec mappingNotify[] = { {"Modifier", 0, MappingModifier}, {"Keyboard", 0, MappingKeyboard}, {"Pointer", 0, MappingPointer}, {NULL, NULLQUARK, 0}, }; /* *INDENT-ON* */ static String ParseKeySym(PARSE_PROC_DECL); static String ParseKeyAndModifiers(PARSE_PROC_DECL); static String ParseTable(PARSE_PROC_DECL); static String ParseButton(PARSE_PROC_DECL); static String ParseImmed(PARSE_PROC_DECL); static String ParseAddModifier(PARSE_PROC_DECL); static String ParseNone(PARSE_PROC_DECL); static String ParseAtom(PARSE_PROC_DECL); /* *INDENT-OFF* */ static EventKey events[] = { /* Event Name, Quark, Event Type, Detail Parser, Closure */ {"KeyPress", NULLQUARK, KeyPress, ParseKeySym, NULL}, {"Key", NULLQUARK, KeyPress, ParseKeySym, NULL}, {"KeyDown", NULLQUARK, KeyPress, ParseKeySym, NULL}, {"Ctrl", NULLQUARK, KeyPress, ParseKeyAndModifiers, (Opaque)ControlMask}, {"Shift", NULLQUARK, KeyPress, ParseKeyAndModifiers, (Opaque)ShiftMask}, {"Meta", NULLQUARK, KeyPress, ParseKeyAndModifiers, (Opaque)NULL}, {"KeyUp", NULLQUARK, KeyRelease, ParseKeySym, NULL}, {"KeyRelease", NULLQUARK, KeyRelease, ParseKeySym, NULL}, {"ButtonPress", NULLQUARK, ButtonPress, ParseButton, NULL }, {"BtnDown", NULLQUARK, ButtonPress, ParseButton, NULL }, {"Btn1Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button1}, {"Btn2Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button2}, {"Btn3Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button3}, {"Btn4Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button4}, {"Btn5Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button5}, /* Event Name, Quark, Event Type, Detail Parser, Closure */ {"ButtonRelease", NULLQUARK, ButtonRelease, ParseButton, NULL }, {"BtnUp", NULLQUARK, ButtonRelease, ParseButton, NULL }, {"Btn1Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button1}, {"Btn2Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button2}, {"Btn3Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button3}, {"Btn4Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button4}, {"Btn5Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button5}, {"MotionNotify", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, {"PtrMoved", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, {"Motion", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, {"MouseMoved", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, {"BtnMotion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)AnyButtonMask}, {"Btn1Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button1Mask}, {"Btn2Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button2Mask}, {"Btn3Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button3Mask}, {"Btn4Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button4Mask}, {"Btn5Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button5Mask}, {"EnterNotify", NULLQUARK, EnterNotify, ParseTable, (Opaque)notifyModes}, {"Enter", NULLQUARK, EnterNotify, ParseTable, (Opaque)notifyModes}, {"EnterWindow", NULLQUARK, EnterNotify, ParseTable, (Opaque)notifyModes}, {"LeaveNotify", NULLQUARK, LeaveNotify, ParseTable, (Opaque)notifyModes}, {"LeaveWindow", NULLQUARK, LeaveNotify, ParseTable, (Opaque)notifyModes}, {"Leave", NULLQUARK, LeaveNotify, ParseTable, (Opaque)notifyModes}, /* Event Name, Quark, Event Type, Detail Parser, Closure */ {"FocusIn", NULLQUARK, FocusIn, ParseTable, (Opaque)notifyModes}, {"FocusOut", NULLQUARK, FocusOut, ParseTable, (Opaque)notifyModes}, {"KeymapNotify", NULLQUARK, KeymapNotify, ParseNone, NULL}, {"Keymap", NULLQUARK, KeymapNotify, ParseNone, NULL}, {"Expose", NULLQUARK, Expose, ParseNone, NULL}, {"GraphicsExpose", NULLQUARK, GraphicsExpose, ParseNone, NULL}, {"GrExp", NULLQUARK, GraphicsExpose, ParseNone, NULL}, {"NoExpose", NULLQUARK, NoExpose, ParseNone, NULL}, {"NoExp", NULLQUARK, NoExpose, ParseNone, NULL}, {"VisibilityNotify",NULLQUARK, VisibilityNotify,ParseNone, NULL}, {"Visible", NULLQUARK, VisibilityNotify,ParseNone, NULL}, {"CreateNotify", NULLQUARK, CreateNotify, ParseNone, NULL}, {"Create", NULLQUARK, CreateNotify, ParseNone, NULL}, /* Event Name, Quark, Event Type, Detail Parser, Closure */ {"DestroyNotify", NULLQUARK, DestroyNotify, ParseNone, NULL}, {"Destroy", NULLQUARK, DestroyNotify, ParseNone, NULL}, {"UnmapNotify", NULLQUARK, UnmapNotify, ParseNone, NULL}, {"Unmap", NULLQUARK, UnmapNotify, ParseNone, NULL}, {"MapNotify", NULLQUARK, MapNotify, ParseNone, NULL}, {"Map", NULLQUARK, MapNotify, ParseNone, NULL}, {"MapRequest", NULLQUARK, MapRequest, ParseNone, NULL}, {"MapReq", NULLQUARK, MapRequest, ParseNone, NULL}, {"ReparentNotify", NULLQUARK, ReparentNotify, ParseNone, NULL}, {"Reparent", NULLQUARK, ReparentNotify, ParseNone, NULL}, {"ConfigureNotify", NULLQUARK, ConfigureNotify, ParseNone, NULL}, {"Configure", NULLQUARK, ConfigureNotify, ParseNone, NULL}, {"ConfigureRequest",NULLQUARK, ConfigureRequest,ParseNone, NULL}, {"ConfigureReq", NULLQUARK, ConfigureRequest,ParseNone, NULL}, /* Event Name, Quark, Event Type, Detail Parser, Closure */ {"GravityNotify", NULLQUARK, GravityNotify, ParseNone, NULL}, {"Grav", NULLQUARK, GravityNotify, ParseNone, NULL}, {"ResizeRequest", NULLQUARK, ResizeRequest, ParseNone, NULL}, {"ResReq", NULLQUARK, ResizeRequest, ParseNone, NULL}, {"CirculateNotify", NULLQUARK, CirculateNotify, ParseNone, NULL}, {"Circ", NULLQUARK, CirculateNotify, ParseNone, NULL}, {"CirculateRequest",NULLQUARK, CirculateRequest,ParseNone, NULL}, {"CircReq", NULLQUARK, CirculateRequest,ParseNone, NULL}, {"PropertyNotify", NULLQUARK, PropertyNotify, ParseAtom, NULL}, {"Prop", NULLQUARK, PropertyNotify, ParseAtom, NULL}, {"SelectionClear", NULLQUARK, SelectionClear, ParseAtom, NULL}, {"SelClr", NULLQUARK, SelectionClear, ParseAtom, NULL}, {"SelectionRequest",NULLQUARK, SelectionRequest,ParseAtom, NULL}, {"SelReq", NULLQUARK, SelectionRequest,ParseAtom, NULL}, /* Event Name, Quark, Event Type, Detail Parser, Closure */ {"SelectionNotify", NULLQUARK, SelectionNotify, ParseAtom, NULL}, {"Select", NULLQUARK, SelectionNotify, ParseAtom, NULL}, {"ColormapNotify", NULLQUARK, ColormapNotify, ParseNone, NULL}, {"Clrmap", NULLQUARK, ColormapNotify, ParseNone, NULL}, {"ClientMessage", NULLQUARK, ClientMessage, ParseAtom, NULL}, {"Message", NULLQUARK, ClientMessage, ParseAtom, NULL}, {"MappingNotify", NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify}, {"Mapping", NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify}, #ifdef DEBUG # ifdef notdef {"Timer", NULLQUARK, _XtTimerEventType, ParseNone, NULL}, {"EventTimer", NULLQUARK, _XtEventTimerEventType, ParseNone,NULL}, # endif /* notdef */ #endif /* DEBUG */ /* Event Name, Quark, Event Type, Detail Parser, Closure */ }; /* *INDENT-ON* */ #define IsNewline(str) ((str) == '\n') #define ScanFor(str, ch) \ while ((*(str) != (ch)) && (*(str) != '\0') && !IsNewline(*(str))) (str)++ #define ScanNumeric(str) while ('0' <= *(str) && *(str) <= '9') (str)++ #define ScanAlphanumeric(str) \ while (('A' <= *(str) && *(str) <= 'Z') || \ ('a' <= *(str) && *(str) <= 'z') || \ ('0' <= *(str) && *(str) <= '9')) (str)++ #define ScanWhitespace(str) \ while (*(str) == ' ' || *(str) == '\t') (str)++ static Boolean initialized = FALSE; static XrmQuark QMeta; static XrmQuark QCtrl; static XrmQuark QNone; static XrmQuark QAny; static void FreeEventSeq(EventSeqPtr eventSeq) { register EventSeqPtr evs = eventSeq; while (evs != NULL) { evs->state = (StatePtr) evs; if (evs->next != NULL && evs->next->state == (StatePtr) evs->next) evs->next = NULL; evs = evs->next; } evs = eventSeq; while (evs != NULL) { register EventPtr event = evs; evs = evs->next; if (evs == event) evs = NULL; XtFree((char *) event); } } static void CompileNameValueTable(NameValueTable table) { register int i; for (i = 0; table[i].name; i++) table[i].signature = XrmPermStringToQuark(table[i].name); } static int OrderEvents(_Xconst void *a, _Xconst void *b) { return ((((_Xconst EventKey *) a)->signature < ((_Xconst EventKey *) b)->signature) ? -1 : 1); } static void Compile_XtEventTable(EventKeys table, Cardinal count) { register int i; register EventKeys entry = table; for (i = (int) count; --i >= 0; entry++) entry->signature = XrmPermStringToQuark(entry->event); qsort(table, count, sizeof(EventKey), OrderEvents); } static int OrderModifiers(_Xconst void *a, _Xconst void *b) { return ((((_Xconst ModifierRec *) a)->signature < ((_Xconst ModifierRec *) b)->signature) ? -1 : 1); } static void Compile_XtModifierTable(ModifierKeys table, Cardinal count) { register int i; register ModifierKeys entry = table; for (i = (int) count; --i >= 0; entry++) entry->signature = XrmPermStringToQuark(entry->name); qsort(table, count, sizeof(ModifierRec), OrderModifiers); } static String PanicModeRecovery(String str) { ScanFor(str, '\n'); if (*str == '\n') str++; return str; } static void Syntax(_Xconst char *str0, _Xconst char *str1) { Cardinal num_params = 2; String params[2]; params[0] = (String) str0; params[1] = (String) str1; XtWarningMsg(XtNtranslationParseError, "parseError", XtCXtToolkitError, "translation table syntax error: %s %s", params, &num_params); } static Cardinal LookupTMEventType(String eventStr, Boolean *error) { register int i = 0, left, right; register XrmQuark signature; static int previous = 0; LOCK_PROCESS; if ((signature = StringToQuark(eventStr)) == events[previous].signature) { UNLOCK_PROCESS; return (Cardinal) previous; } left = 0; right = XtNumber(events) - 1; while (left <= right) { i = (left + right) >> 1; if (signature < events[i].signature) right = i - 1; else if (signature > events[i].signature) left = i + 1; else { previous = i; UNLOCK_PROCESS; return (Cardinal) i; } } Syntax("Unknown event type : ", eventStr); *error = TRUE; UNLOCK_PROCESS; return (Cardinal) i; } static void StoreLateBindings(KeySym keysymL, Boolean notL, KeySym keysymR, Boolean notR, LateBindingsPtr *lateBindings) { LateBindingsPtr temp; if (lateBindings != NULL) { Boolean pair = FALSE; unsigned long count; unsigned long number; temp = *lateBindings; if (temp != NULL) { for (count = 0; temp[count].keysym; count++) { /*EMPTY*/ } } else count = 0; if (!keysymR) { number = 1; pair = FALSE; } else { number = 2; pair = TRUE; } temp = (LateBindingsPtr) XtRealloc((char *) temp, (unsigned) ((count + number + 1) * sizeof(LateBindings))); *lateBindings = temp; XtSetBit(temp[count].knot, notL); XtSetBit(temp[count].pair, pair); if (count == 0) temp[count].ref_count = 1; temp[count++].keysym = keysymL; if (keysymR) { XtSetBit(temp[count].knot, notR); temp[count].pair = FALSE; temp[count].ref_count = 0; temp[count++].keysym = keysymR; } temp[count].knot = temp[count].pair = FALSE; temp[count].ref_count = 0; temp[count].keysym = 0; } } static void _XtParseKeysymMod(String name, LateBindingsPtr *lateBindings, Boolean notFlag, Value *valueP, Boolean *error) { KeySym keySym; keySym = StringToKeySym(name, error); *valueP = 0; if (keySym != NoSymbol) { StoreLateBindings(keySym, notFlag, (KeySym) NULL, FALSE, lateBindings); } } static Boolean _XtLookupModifier(XrmQuark signature, LateBindingsPtr *lateBindings, Boolean notFlag, Value *valueP, Bool constMask) { int left, right; static int previous = 0; LOCK_PROCESS; if (signature == modifiers[previous].signature) { if (constMask) *valueP = modifiers[previous].value; else /* if (modifiers[previous].modifierParseProc) always true */ (*modifiers[previous].modifierParseProc) (modifiers[previous].value, lateBindings, notFlag, valueP); UNLOCK_PROCESS; return TRUE; } left = 0; right = XtNumber(modifiers) - 1; while (left <= right) { int i = (left + right) >> 1; if (signature < modifiers[i].signature) right = i - 1; else if (signature > modifiers[i].signature) left = i + 1; else { previous = i; if (constMask) *valueP = modifiers[i].value; else /* if (modifiers[i].modifierParseProc) always true */ (*modifiers[i].modifierParseProc) (modifiers[i].value, lateBindings, notFlag, valueP); UNLOCK_PROCESS; return TRUE; } } UNLOCK_PROCESS; return FALSE; } static String ScanIdent(register String str) { ScanAlphanumeric(str); while (('A' <= *str && *str <= 'Z') || ('a' <= *str && *str <= 'z') || ('0' <= *str && *str <= '9') || (*str == '-') || (*str == '_') || (*str == '$') ) str++; return str; } static String FetchModifierToken(String str, XrmQuark *token_return) { String start = str; if (*str == '$') { *token_return = QMeta; str++; } else if (*str == '^') { *token_return = QCtrl; str++; } else { str = ScanIdent(str); if (start != str) { char modStrbuf[100]; char *modStr; modStr = XtStackAlloc((size_t) (str - start + 1), modStrbuf); if (modStr == NULL) _XtAllocError(NULL); (void) memcpy(modStr, start, (size_t) (str - start)); modStr[str - start] = '\0'; *token_return = XrmStringToQuark(modStr); XtStackFree(modStr, modStrbuf); } } return str; } static String ParseModifiers(register String str, EventPtr event, Boolean *error) { register String start; Boolean notFlag, exclusive, keysymAsMod; Value maskBit; XrmQuark Qmod = QNone; ScanWhitespace(str); start = str; str = FetchModifierToken(str, &Qmod); exclusive = FALSE; if (start != str) { if (Qmod == QNone) { event->event.modifierMask = (unsigned long) (~0); event->event.modifiers = 0; ScanWhitespace(str); return str; } else if (Qmod == QAny) { /*backward compatibility */ event->event.modifierMask = 0; event->event.modifiers = AnyModifier; ScanWhitespace(str); return str; } str = start; /*if plain modifier, reset to beginning */ } else while (*str == '!' || *str == ':') { if (*str == '!') { exclusive = TRUE; str++; ScanWhitespace(str); } if (*str == ':') { event->event.standard = TRUE; str++; ScanWhitespace(str); } } while (*str != '<') { if (*str == '~') { notFlag = TRUE; str++; } else notFlag = FALSE; if (*str == '@') { keysymAsMod = TRUE; str++; } else keysymAsMod = FALSE; start = str; str = FetchModifierToken(str, &Qmod); if (start == str) { Syntax("Modifier or '<' expected", ""); *error = TRUE; return PanicModeRecovery(str); } if (keysymAsMod) { _XtParseKeysymMod(XrmQuarkToString(Qmod), &event->event.lateModifiers, notFlag, &maskBit, error); if (*error) return PanicModeRecovery(str); } else if (!_XtLookupModifier(Qmod, &event->event.lateModifiers, notFlag, &maskBit, FALSE)) { Syntax("Unknown modifier name: ", XrmQuarkToString(Qmod)); *error = TRUE; return PanicModeRecovery(str); } event->event.modifierMask |= maskBit; if (notFlag) event->event.modifiers = (event->event.modifiers & (TMLongCard) (~maskBit)); else event->event.modifiers |= maskBit; ScanWhitespace(str); } if (exclusive) event->event.modifierMask = (unsigned long) (~0); return str; } static String ParseXtEventType(register String str, EventPtr event, Cardinal *tmEventP, Boolean *error) { String start = str; char eventTypeStrbuf[100]; char *eventTypeStr; ScanAlphanumeric(str); eventTypeStr = XtStackAlloc((size_t) (str - start + 1), eventTypeStrbuf); if (eventTypeStr == NULL) _XtAllocError(NULL); (void) memcpy(eventTypeStr, start, (size_t) (str - start)); eventTypeStr[str - start] = '\0'; *tmEventP = LookupTMEventType(eventTypeStr, error); XtStackFree(eventTypeStr, eventTypeStrbuf); if (*error) return PanicModeRecovery(str); event->event.eventType = (TMLongCard) events[*tmEventP].eventType; return str; } static unsigned long StrToHex(String str) { register char c; register unsigned long val = 0; while ((c = *str)) { if ('0' <= c && c <= '9') val = (unsigned long) (val * 16 + (unsigned long) c - '0'); else if ('a' <= c && c <= 'z') val = (unsigned long) (val * 16 + (unsigned long) c - 'a' + 10); else if ('A' <= c && c <= 'Z') val = (unsigned long) (val * 16 + (unsigned long) c - 'A' + 10); else return 0; str++; } return val; } static unsigned long StrToOct(String str) { register char c; register unsigned long val = 0; while ((c = *str)) { if ('0' <= c && c <= '7') val = val * 8 + (unsigned long) c - '0'; else return 0; str++; } return val; } static unsigned long StrToNum(String str) { register char c; register unsigned long val = 0; if (*str == '0') { str++; if (*str == 'x' || *str == 'X') return StrToHex(++str); else return StrToOct(str); } while ((c = *str)) { if ('0' <= c && c <= '9') val = val * 10 + (unsigned long) c - '0'; else return 0; str++; } return val; } static KeySym StringToKeySym(String str, Boolean *error) { KeySym k; if (str == NULL || *str == '\0') return (KeySym) 0; #ifndef NOTASCII /* special case single character ASCII, for speed */ if (*(str + 1) == '\0') { if (' ' <= *str && *str <= '~') return (KeySym) (XK_space + (*str - ' ')); } #endif if ('0' <= *str && *str <= '9') return (KeySym) StrToNum(str); k = XStringToKeysym(str); if (k != NoSymbol) return k; #ifdef NOTASCII /* fall-back case to preserve backwards compatibility; no-one * should be relying upon this! */ if (*(str + 1) == '\0') return (KeySym) * str; #endif Syntax("Unknown keysym name: ", str); *error = TRUE; return NoSymbol; } static void ParseModImmed(Value value, LateBindingsPtr *lateBindings _X_UNUSED, Boolean notFlag _X_UNUSED, Value *valueP) { *valueP = value; } /* is only valid with keysyms that have an _L and _R in their name; * and ignores keysym lookup errors (i.e. assumes only valid keysyms) */ static void ParseModSym(Value value, LateBindingsPtr *lateBindings, Boolean notFlag, Value *valueP) { register KeySym keysymL = (KeySym) value; register KeySym keysymR = keysymL + 1; /* valid for supported keysyms */ StoreLateBindings(keysymL, notFlag, keysymR, notFlag, lateBindings); *valueP = 0; } #ifdef sparc /* * The stupid optimizer in SunOS 4.0.3 and below generates bogus code that * causes the value of the most recently used variable to be returned instead * of the value passed in. */ static String stupid_optimizer_kludge; #define BROKEN_OPTIMIZER_HACK(val) stupid_optimizer_kludge = (val) #else #define BROKEN_OPTIMIZER_HACK(val) val #endif static String ParseImmed(register String str, register Opaque closure, register EventPtr event, Boolean *error _X_UNUSED) { event->event.eventCode = (unsigned long) closure; event->event.eventCodeMask = (unsigned long) (~0UL); return BROKEN_OPTIMIZER_HACK(str); } static String ParseAddModifier(register String str, register Opaque closure, register EventPtr event, Boolean *error _X_UNUSED) { register unsigned long modval = (unsigned long) closure; event->event.modifiers |= modval; if (modval != AnyButtonMask) /* AnyButtonMask is don't-care mask */ event->event.modifierMask |= modval; return BROKEN_OPTIMIZER_HACK(str); } static String ParseKeyAndModifiers(String str, Opaque closure, EventPtr event, Boolean *error) { str = ParseKeySym(str, closure, event, error); if ((unsigned long) closure == 0) { Value metaMask; /* unused */ (void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE, &metaMask, FALSE); } else { event->event.modifiers |= (unsigned long) closure; event->event.modifierMask |= (unsigned long) closure; } return str; } static String ParseKeySym(register String str, Opaque closure _X_UNUSED, EventPtr event, Boolean *error) { String start; char keySymNamebuf[100]; char *keySymName = NULL; ScanWhitespace(str); if (*str == '\\') { keySymName = keySymNamebuf; str++; keySymName[0] = *str; if (*str != '\0' && !IsNewline(*str)) str++; keySymName[1] = '\0'; event->event.eventCode = StringToKeySym(keySymName, error); event->event.eventCodeMask = (unsigned long) (~0L); } else if (*str == ',' || *str == ':' || /* allow leftparen to be single char symbol, * for backwards compatibility */ (*str == '(' && *(str + 1) >= '0' && *(str + 1) <= '9')) { keySymName = keySymNamebuf; /* just so we can stackfree it later */ keySymName[0] = '\0'; /* no detail */ event->event.eventCode = 0L; event->event.eventCodeMask = 0L; } else { start = str; while (*str != ',' && *str != ':' && *str != ' ' && *str != '\t' && !IsNewline(*str) && (*str != '(' || *(str + 1) <= '0' || *(str + 1) >= '9') && *str != '\0') str++; keySymName = XtStackAlloc((size_t) (str - start + 1), keySymNamebuf); (void) memcpy(keySymName, start, (size_t) (str - start)); keySymName[str - start] = '\0'; event->event.eventCode = StringToKeySym(keySymName, error); event->event.eventCodeMask = (unsigned long) (~0L); } if (*error && keySymName) { /* We never get here when keySymName hasn't been allocated */ if (keySymName[0] == '<') { /* special case for common error */ XtWarningMsg(XtNtranslationParseError, "missingComma", XtCXtToolkitError, "... possibly due to missing ',' in event sequence.", (String *) NULL, (Cardinal *) NULL); } XtStackFree(keySymName, keySymNamebuf); return PanicModeRecovery(str); } if (event->event.standard) event->event.matchEvent = _XtMatchUsingStandardMods; else event->event.matchEvent = _XtMatchUsingDontCareMods; XtStackFree(keySymName, keySymNamebuf); return str; } static String ParseTable(register String str, Opaque closure, EventPtr event, Boolean *error) { register String start = str; register XrmQuark signature; NameValueTable table = (NameValueTable) closure; char tableSymName[100]; event->event.eventCode = 0L; ScanAlphanumeric(str); if (str == start) { event->event.eventCodeMask = 0L; return str; } if (str - start >= 99) { Syntax("Invalid Detail Type (string is too long).", ""); *error = TRUE; return str; } (void) memcpy(tableSymName, start, (size_t) (str - start)); tableSymName[str - start] = '\0'; signature = StringToQuark(tableSymName); for (; table->signature != NULLQUARK; table++) if (table->signature == signature) { event->event.eventCode = table->value; event->event.eventCodeMask = (unsigned long) (~0L); return str; } Syntax("Unknown Detail Type: ", tableSymName); *error = TRUE; return PanicModeRecovery(str); } static String ParseButton(String str, Opaque closure, EventPtr event, Boolean *error) { String start = str; char buttonStr[7]; size_t len; static const char buttonPrefix[] = "Button"; unsigned long button; event->event.eventCode = 0L; if (strncmp(str, buttonPrefix, sizeof(buttonPrefix)-1) != 0) { event->event.eventCodeMask = 0L; return str; } str += sizeof(buttonPrefix)-1; start = str; ScanNumeric(str); if (str == start) { Syntax("Missing button number", ""); *error = TRUE; return PanicModeRecovery(str); } len = (size_t) (str - start); if (len >= sizeof buttonStr) { Syntax("Button number too long", ""); *error = TRUE; return PanicModeRecovery(str); } (void) memcpy(buttonStr, start, len); buttonStr[len] = '\0'; button = StrToNum(buttonStr); if (button < 1 || 255 < button) { Syntax("Invalid button number", buttonStr); *error = TRUE; return PanicModeRecovery(str); } event->event.eventCode = button; event->event.eventCodeMask = (unsigned long) (~0L); return str; } static String ParseNone(String str, Opaque closure _X_UNUSED, EventPtr event, Boolean *error _X_UNUSED) { event->event.eventCode = 0; event->event.eventCodeMask = 0; return BROKEN_OPTIMIZER_HACK(str); } static String ParseAtom(String str, Opaque closure _X_UNUSED, EventPtr event, Boolean *error) { ScanWhitespace(str); if (*str == ',' || *str == ':') { /* no detail */ event->event.eventCode = 0L; event->event.eventCodeMask = 0L; } else { String start; char atomName[1000]; start = str; while (*str != ',' && *str != ':' && *str != ' ' && *str != '\t' && !IsNewline(*str) && *str != '\0') str++; if (str - start >= 999) { Syntax("Atom name must be less than 1000 characters long.", ""); *error = TRUE; return str; } (void) memcpy(atomName, start, (size_t) (str - start)); atomName[str - start] = '\0'; event->event.eventCode = (TMLongCard) XrmStringToQuark(atomName); event->event.matchEvent = _XtMatchAtom; } return str; } static ModifierMask buttonModifierMasks[] = { 0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask }; static String ParseRepeat(String, int *, Boolean *, Boolean *); static String ParseEvent(register String str, EventPtr event, int *reps, Boolean *plus, Boolean *error) { Cardinal tmEvent; str = ParseModifiers(str, event, error); if (*error) return str; if (*str != '<') { Syntax("Missing '<' while parsing event type.", ""); *error = TRUE; return PanicModeRecovery(str); } else str++; str = ParseXtEventType(str, event, &tmEvent, error); if (*error) return str; if (*str != '>') { Syntax("Missing '>' while parsing event type", ""); *error = TRUE; return PanicModeRecovery(str); } else str++; if (*str == '(') { str = ParseRepeat(str, reps, plus, error); if (*error) return str; } str = (*(events[tmEvent].parseDetail)) (str, events[tmEvent].closure, event, error); if (*error) return str; /* gross hack! ||| this kludge is related to the X11 protocol deficiency w.r.t. * modifiers in grabs. */ if ((event->event.eventType == ButtonRelease) && (event->event.modifiers | event->event.modifierMask) /* any */ &&(event->event.modifiers != AnyModifier)) { event->event.modifiers = (event->event.modifiers | (TMLongCard) buttonModifierMasks[event-> event. eventCode]); /* the button that is going up will always be in the modifiers... */ } return str; } static String ParseQuotedStringEvent(register String str, register EventPtr event, Boolean *error) { Value metaMask; char s[2]; if (*str == '^') { str++; event->event.modifiers = ControlMask; } else if (*str == '$') { str++; (void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE, &metaMask, FALSE); } if (*str == '\\') str++; s[0] = *str; s[1] = '\0'; if (*str != '\0' && !IsNewline(*str)) str++; event->event.eventType = KeyPress; event->event.eventCode = StringToKeySym(s, error); if (*error) return PanicModeRecovery(str); event->event.eventCodeMask = (unsigned long) (~0L); event->event.matchEvent = _XtMatchUsingStandardMods; event->event.standard = TRUE; return str; } static EventSeqRec timerEventRec = { {0, 0, NULL, _XtEventTimerEventType, 0L, 0L, NULL, False}, /* (StatePtr) -1 */ NULL, NULL, NULL }; static void RepeatDown(EventPtr *eventP, int reps, ActionPtr **actionsP) { EventRec upEventRec; register EventPtr event, downEvent; EventPtr upEvent = &upEventRec; register int i; downEvent = event = *eventP; *upEvent = *downEvent; upEvent->event.eventType = ((event->event.eventType == ButtonPress) ? ButtonRelease : KeyRelease); if ((upEvent->event.eventType == ButtonRelease) && (upEvent->event.modifiers != AnyModifier) && (upEvent->event.modifiers | upEvent->event.modifierMask)) upEvent->event.modifiers = (upEvent->event.modifiers | (TMLongCard) buttonModifierMasks[event-> event. eventCode]); if (event->event.lateModifiers) event->event.lateModifiers->ref_count = (unsigned short) (event->event.lateModifiers->ref_count + (reps - 1) * 2); for (i = 1; i < reps; i++) { /* up */ event->next = XtNew(EventSeqRec); event = event->next; *event = *upEvent; /* timer */ event->next = XtNew(EventSeqRec); event = event->next; *event = timerEventRec; /* down */ event->next = XtNew(EventSeqRec); event = event->next; *event = *downEvent; } event->next = NULL; *eventP = event; *actionsP = &event->actions; } static void RepeatDownPlus(EventPtr *eventP, int reps, ActionPtr **actionsP) { EventRec upEventRec; register EventPtr event, downEvent, lastDownEvent = NULL; EventPtr upEvent = &upEventRec; register int i; downEvent = event = *eventP; *upEvent = *downEvent; upEvent->event.eventType = ((event->event.eventType == ButtonPress) ? ButtonRelease : KeyRelease); if ((upEvent->event.eventType == ButtonRelease) && (upEvent->event.modifiers != AnyModifier) && (upEvent->event.modifiers | upEvent->event.modifierMask)) upEvent->event.modifiers = (upEvent->event.modifiers | (TMLongCard) buttonModifierMasks[event-> event. eventCode]); if (event->event.lateModifiers) event->event.lateModifiers->ref_count = (unsigned short) (event->event.lateModifiers->ref_count + reps * 2 - 1); for (i = 0; i < reps; i++) { if (i > 0) { /* down */ event->next = XtNew(EventSeqRec); event = event->next; *event = *downEvent; } lastDownEvent = event; /* up */ event->next = XtNew(EventSeqRec); event = event->next; *event = *upEvent; /* timer */ event->next = XtNew(EventSeqRec); event = event->next; *event = timerEventRec; } event->next = lastDownEvent; *eventP = event; *actionsP = &lastDownEvent->actions; } static void RepeatUp(EventPtr *eventP, int reps, ActionPtr **actionsP) { EventRec upEventRec; register EventPtr event, downEvent; EventPtr upEvent = &upEventRec; register int i; /* the event currently sitting in *eventP is an "up" event */ /* we want to make it a "down" event followed by an "up" event, */ /* so that sequence matching on the "state" side works correctly. */ downEvent = event = *eventP; *upEvent = *downEvent; downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ? ButtonPress : KeyPress); if ((downEvent->event.eventType == ButtonPress) && (downEvent->event.modifiers != AnyModifier) && (downEvent->event.modifiers | downEvent->event.modifierMask)) downEvent->event.modifiers = (downEvent->event.modifiers & (TMLongCard) (~buttonModifierMasks [event->event.eventCode])); if (event->event.lateModifiers) event->event.lateModifiers->ref_count = (unsigned short) (event->event.lateModifiers->ref_count + reps * 2 - 1); /* up */ event->next = XtNew(EventSeqRec); event = event->next; *event = *upEvent; for (i = 1; i < reps; i++) { /* timer */ event->next = XtNew(EventSeqRec); event = event->next; *event = timerEventRec; /* down */ event->next = XtNew(EventSeqRec); event = event->next; *event = *downEvent; /* up */ event->next = XtNew(EventSeqRec); event = event->next; *event = *upEvent; } event->next = NULL; *eventP = event; *actionsP = &event->actions; } static void RepeatUpPlus(EventPtr *eventP, int reps, ActionPtr **actionsP) { EventRec upEventRec; register EventPtr event, downEvent, lastUpEvent = NULL; EventPtr upEvent = &upEventRec; register int i; /* the event currently sitting in *eventP is an "up" event */ /* we want to make it a "down" event followed by an "up" event, */ /* so that sequence matching on the "state" side works correctly. */ downEvent = event = *eventP; *upEvent = *downEvent; downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ? ButtonPress : KeyPress); if ((downEvent->event.eventType == ButtonPress) && (downEvent->event.modifiers != AnyModifier) && (downEvent->event.modifiers | downEvent->event.modifierMask)) downEvent->event.modifiers = (downEvent->event.modifiers & (TMLongCard) (~buttonModifierMasks [event->event.eventCode])); if (event->event.lateModifiers) event->event.lateModifiers->ref_count = (unsigned short) (event->event.lateModifiers->ref_count + reps * 2); for (i = 0; i < reps; i++) { /* up */ event->next = XtNew(EventSeqRec); lastUpEvent = event = event->next; *event = *upEvent; /* timer */ event->next = XtNew(EventSeqRec); event = event->next; *event = timerEventRec; /* down */ event->next = XtNew(EventSeqRec); event = event->next; *event = *downEvent; } event->next = lastUpEvent; *eventP = event; *actionsP = &lastUpEvent->actions; } static void RepeatOther(EventPtr *eventP, int reps, ActionPtr **actionsP) { register EventPtr event, tempEvent; register int i; tempEvent = event = *eventP; if (event->event.lateModifiers) event->event.lateModifiers->ref_count = (unsigned short) (event->event.lateModifiers->ref_count + reps - 1); for (i = 1; i < reps; i++) { event->next = XtNew(EventSeqRec); event = event->next; *event = *tempEvent; } *eventP = event; *actionsP = &event->actions; } static void RepeatOtherPlus(EventPtr *eventP, int reps, ActionPtr **actionsP) { register EventPtr event, tempEvent; register int i; tempEvent = event = *eventP; if (event->event.lateModifiers) event->event.lateModifiers->ref_count = (unsigned short) (event->event.lateModifiers->ref_count + reps - 1); for (i = 1; i < reps; i++) { event->next = XtNew(EventSeqRec); event = event->next; *event = *tempEvent; } event->next = event; *eventP = event; *actionsP = &event->actions; } static void RepeatEvent(EventPtr *eventP, int reps, Boolean plus, ActionPtr **actionsP) { switch ((*eventP)->event.eventType) { case ButtonPress: case KeyPress: if (plus) RepeatDownPlus(eventP, reps, actionsP); else RepeatDown(eventP, reps, actionsP); break; case ButtonRelease: case KeyRelease: if (plus) RepeatUpPlus(eventP, reps, actionsP); else RepeatUp(eventP, reps, actionsP); break; default: if (plus) RepeatOtherPlus(eventP, reps, actionsP); else RepeatOther(eventP, reps, actionsP); } } static String ParseRepeat(register String str, int *reps, Boolean *plus, Boolean *error) { /*** Parse the repetitions, for double click etc... ***/ if (*str != '(' || !(isdigit((unsigned char) str[1]) || str[1] == '+' || str[1] == ')')) return str; str++; if (isdigit((unsigned char) *str)) { String start = str; char repStr[7]; size_t len; ScanNumeric(str); len = (size_t) (str - start); if (len < sizeof repStr) { (void) memcpy(repStr, start, len); repStr[len] = '\0'; *reps = (int) StrToNum(repStr); } else { Syntax("Repeat count too large.", ""); *error = TRUE; return str; } } if (*reps == 0) { Syntax("Missing repeat count.", ""); *error = True; return str; } if (*str == '+') { *plus = TRUE; str++; } if (*str == ')') str++; else { Syntax("Missing ')'.", ""); *error = TRUE; } return str; } /*********************************************************************** * ParseEventSeq * Parses the left hand side of a translation table production * up to, and consuming the ":". * Takes a pointer to a char* (where to start parsing) and returns an * event seq (in a passed in variable), having updated the String **********************************************************************/ static String ParseEventSeq(register String str, EventSeqPtr *eventSeqP, ActionPtr ** actionsP, Boolean *error) { EventSeqPtr *nextEvent = eventSeqP; *eventSeqP = NULL; while (*str != '\0' && !IsNewline(*str)) { static Event nullEvent = { 0, 0, NULL, 0, 0L, 0L, _XtRegularMatch, FALSE }; EventPtr event; ScanWhitespace(str); if (*str == '"') { str++; while (*str != '"' && *str != '\0' && !IsNewline(*str)) { event = XtNew(EventRec); event->event = nullEvent; event->state = /* (StatePtr) -1 */ NULL; event->next = NULL; event->actions = NULL; str = ParseQuotedStringEvent(str, event, error); if (*error) { XtWarningMsg(XtNtranslationParseError, "nonLatin1", XtCXtToolkitError, "... probably due to non-Latin1 character in quoted string", (String *) NULL, (Cardinal *) NULL); XtFree((char *) event); return PanicModeRecovery(str); } *nextEvent = event; *actionsP = &event->actions; nextEvent = &event->next; } if (*str != '"') { Syntax("Missing '\"'.", ""); *error = TRUE; return PanicModeRecovery(str); } else str++; } else { int reps = 0; Boolean plus = FALSE; event = XtNew(EventRec); event->event = nullEvent; event->state = /* (StatePtr) -1 */ NULL; event->next = NULL; event->actions = NULL; str = ParseEvent(str, event, &reps, &plus, error); if (*error) return str; *nextEvent = event; *actionsP = &event->actions; if (reps > 1 || plus) RepeatEvent(&event, reps, plus, actionsP); nextEvent = &event->next; } ScanWhitespace(str); if (*str == ':') break; else { if (*str != ',') { Syntax("',' or ':' expected while parsing event sequence.", ""); *error = TRUE; return PanicModeRecovery(str); } else str++; } } if (*str != ':') { Syntax("Missing ':'after event sequence.", ""); *error = TRUE; return PanicModeRecovery(str); } else str++; return str; } static String ParseActionProc(register String str, XrmQuark *actionProcNameP, Boolean *error) { register String start = str; char procName[200]; str = ScanIdent(str); if (str - start >= 199) { Syntax("Action procedure name is longer than 199 chars", ""); *error = TRUE; return str; } (void) memcpy(procName, start, (size_t) (str - start)); procName[str - start] = '\0'; *actionProcNameP = XrmStringToQuark(procName); return str; } static String ParseString(register String str, _XtString *strP) { register String start; if (*str == '"') { register unsigned prev_len, len; str++; start = str; *strP = NULL; prev_len = 0; while (*str != '"' && *str != '\0') { /* \" produces double quote embedded in a quoted parameter * \\" produces backslash as last character of a quoted parameter */ if (*str == '\\' && (*(str + 1) == '"' || (*(str + 1) == '\\' && *(str + 2) == '"'))) { len = (unsigned) (prev_len + (str - start + 2)); *strP = XtRealloc(*strP, len); (void) memcpy(*strP + prev_len, start, (size_t) (str - start)); prev_len = len - 1; str++; (*strP)[prev_len - 1] = *str; (*strP)[prev_len] = '\0'; start = str + 1; } str++; } len = (unsigned) (prev_len + (str - start + 1)); *strP = XtRealloc(*strP, len); (void) memcpy(*strP + prev_len, start, (size_t) (str - start)); (*strP)[len - 1] = '\0'; if (*str == '"') str++; else XtWarningMsg(XtNtranslationParseError, "parseString", XtCXtToolkitError, "Missing '\"'.", (String *) NULL, (Cardinal *) NULL); } else { /* scan non-quoted string, stop on whitespace, ',' or ')' */ start = str; while (*str != ' ' && *str != '\t' && *str != ',' && *str != ')' && !IsNewline(*str) && *str != '\0') str++; *strP = __XtMalloc((unsigned) (str - start + 1)); (void) memcpy(*strP, start, (size_t) (str - start)); (*strP)[str - start] = '\0'; } return str; } static String ParseParamSeq(register String str, String **paramSeqP, Cardinal *paramNumP) { typedef struct _ParamRec *ParamPtr; typedef struct _ParamRec { ParamPtr next; String param; } ParamRec; ParamPtr params = NULL; Cardinal num_params = 0; ScanWhitespace(str); while (*str != ')' && *str != '\0' && !IsNewline(*str)) { _XtString newStr; str = ParseString(str, &newStr); if (newStr != NULL) { ParamPtr temp = (ParamRec *) ALLOCATE_LOCAL((unsigned) sizeof(ParamRec)); if (temp == NULL) _XtAllocError(NULL); num_params++; temp->next = params; params = temp; temp->param = newStr; ScanWhitespace(str); if (*str == ',') { str++; ScanWhitespace(str); } } } if (num_params != 0) { String *paramP = (String *) __XtMalloc((Cardinal) ((num_params + 1) * sizeof(String))); Cardinal i; *paramSeqP = paramP; *paramNumP = num_params; paramP += num_params; /* list is LIFO right now */ *paramP-- = NULL; for (i = 0; i < num_params; i++) { ParamPtr next = params->next; *paramP-- = params->param; DEALLOCATE_LOCAL((char *) params); params = next; } } else { *paramSeqP = NULL; *paramNumP = 0; } return str; } static String ParseAction(String str, ActionPtr actionP, XrmQuark *quarkP, Boolean *error) { str = ParseActionProc(str, quarkP, error); if (*error) return str; if (*str == '(') { str++; str = ParseParamSeq(str, &actionP->params, &actionP->num_params); } else { Syntax("Missing '(' while parsing action sequence", ""); *error = TRUE; return str; } if (*str == ')') str++; else { Syntax("Missing ')' while parsing action sequence", ""); *error = TRUE; return str; } return str; } static String ParseActionSeq(TMParseStateTree parseTree, String str, ActionPtr *actionsP, Boolean *error) { ActionPtr *nextActionP; if ((nextActionP = actionsP) != NULL) *actionsP = NULL; while (*str != '\0' && !IsNewline(*str)) { register ActionPtr action; XrmQuark quark = NULLQUARK; action = XtNew(ActionRec); action->params = NULL; action->num_params = 0; action->next = NULL; str = ParseAction(str, action, &quark, error); if (*error) { XtFree((char *) action); return PanicModeRecovery(str); } action->idx = _XtGetQuarkIndex(parseTree, quark); ScanWhitespace(str); if (nextActionP) { *nextActionP = action; nextActionP = &action->next; } } if (IsNewline(*str)) str++; ScanWhitespace(str); return str; } static void ShowProduction(String currentProduction) { Cardinal num_params = 1; String params[1]; size_t len; char *eol, *production, productionbuf[500]; eol = strchr(currentProduction, '\n'); if (eol) len = (size_t) (eol - currentProduction); else len = strlen(currentProduction); production = XtStackAlloc(len + 1, productionbuf); if (production == NULL) _XtAllocError(NULL); (void) memcpy(production, currentProduction, len); production[len] = '\0'; params[0] = production; XtWarningMsg(XtNtranslationParseError, "showLine", XtCXtToolkitError, "... found while parsing '%s'", params, &num_params); XtStackFree(production, productionbuf); } /*********************************************************************** * ParseTranslationTableProduction * Parses one line of event bindings. ***********************************************************************/ static String ParseTranslationTableProduction(TMParseStateTree parseTree, register String str, Boolean *error) { EventSeqPtr eventSeq = NULL; ActionPtr *actionsP; String production = str; actionsP = NULL; str = ParseEventSeq(str, &eventSeq, &actionsP, error); if (*error == TRUE) { ShowProduction(production); } else { ScanWhitespace(str); str = ParseActionSeq(parseTree, str, actionsP, error); if (*error == TRUE) { ShowProduction(production); } else { _XtAddEventSeqToStateTree(eventSeq, parseTree); } } FreeEventSeq(eventSeq); return (str); } static String CheckForPoundSign(String str, _XtTranslateOp defaultOp, _XtTranslateOp *actualOpRtn) { _XtTranslateOp opType; opType = defaultOp; ScanWhitespace(str); if (*str == '#') { String start; char operation[20]; int len; str++; start = str; str = ScanIdent(str); len = MIN(19, (int) (str - start)); (void) memcpy(operation, start, (size_t) len); operation[len] = '\0'; if (!strcmp(operation, "replace")) opType = XtTableReplace; else if (!strcmp(operation, "augment")) opType = XtTableAugment; else if (!strcmp(operation, "override")) opType = XtTableOverride; ScanWhitespace(str); if (IsNewline(*str)) { str++; ScanWhitespace(str); } } *actualOpRtn = opType; return str; } static XtTranslations ParseTranslationTable(String source, Boolean isAccelerator, _XtTranslateOp defaultOp, Boolean *error) { XtTranslations xlations; TMStateTree stateTrees[8]; TMParseStateTreeRec parseTreeRec, *parseTree = &parseTreeRec; XrmQuark stackQuarks[200]; TMBranchHeadRec stackBranchHeads[200]; StatePtr stackComplexBranchHeads[200]; _XtTranslateOp actualOp; if (source == NULL) return (XtTranslations) NULL; source = CheckForPoundSign(source, defaultOp, &actualOp); if (isAccelerator && actualOp == XtTableReplace) actualOp = defaultOp; parseTree->isSimple = TRUE; parseTree->mappingNotifyInterest = FALSE; XtSetBit(parseTree->isAccelerator, isAccelerator); parseTree->isStackBranchHeads = parseTree->isStackQuarks = parseTree->isStackComplexBranchHeads = TRUE; parseTree->numQuarks = parseTree->numBranchHeads = parseTree->numComplexBranchHeads = 0; parseTree->quarkTblSize = parseTree->branchHeadTblSize = parseTree->complexBranchHeadTblSize = 200; parseTree->quarkTbl = stackQuarks; parseTree->branchHeadTbl = stackBranchHeads; parseTree->complexBranchHeadTbl = stackComplexBranchHeads; while (source != NULL && *source != '\0') { source = ParseTranslationTableProduction(parseTree, source, error); if (*error == TRUE) break; } stateTrees[0] = _XtParseTreeToStateTree(parseTree); if (!parseTree->isStackQuarks) XtFree((char *) parseTree->quarkTbl); if (!parseTree->isStackBranchHeads) XtFree((char *) parseTree->branchHeadTbl); if (!parseTree->isStackComplexBranchHeads) XtFree((char *) parseTree->complexBranchHeadTbl); xlations = _XtCreateXlations(stateTrees, 1, NULL, NULL); xlations->operation = (unsigned char) actualOp; #ifdef notdef XtFree(stateTrees); #endif /* notdef */ return xlations; } /*** public procedures ***/ Boolean XtCvtStringToAcceleratorTable(Display *dpy, XrmValuePtr args _X_UNUSED, Cardinal *num_args, XrmValuePtr from, XrmValuePtr to, XtPointer *closure _X_UNUSED) { String str; Boolean error = FALSE; if (*num_args != 0) XtAppWarningMsg(XtDisplayToApplicationContext(dpy), "wrongParameters", "cvtStringToAcceleratorTable", XtCXtToolkitError, "String to AcceleratorTable conversion needs no extra arguments", (String *) NULL, (Cardinal *) NULL); str = (String) (from->addr); if (str == NULL) { XtAppWarningMsg(XtDisplayToApplicationContext(dpy), "badParameters", "cvtStringToAcceleratorTable", XtCXtToolkitError, "String to AcceleratorTable conversion needs string", (String *) NULL, (Cardinal *) NULL); return FALSE; } if (to->addr != NULL) { if (to->size < sizeof(XtAccelerators)) { to->size = sizeof(XtAccelerators); return FALSE; } *(XtAccelerators *) to->addr = (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, &error); } else { static XtAccelerators staticStateTable; staticStateTable = (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, &error); to->addr = (XPointer) &staticStateTable; to->size = sizeof(XtAccelerators); } if (error == TRUE) XtAppWarningMsg(XtDisplayToApplicationContext(dpy), "parseError", "cvtStringToAcceleratorTable", XtCXtToolkitError, "String to AcceleratorTable conversion encountered errors", (String *) NULL, (Cardinal *) NULL); return (error != TRUE); } Boolean XtCvtStringToTranslationTable(Display *dpy, XrmValuePtr args _X_UNUSED, Cardinal *num_args, XrmValuePtr from, XrmValuePtr to, XtPointer *closure_ret _X_UNUSED) { String str; Boolean error = FALSE; if (*num_args != 0) XtAppWarningMsg(XtDisplayToApplicationContext(dpy), "wrongParameters", "cvtStringToTranslationTable", XtCXtToolkitError, "String to TranslationTable conversion needs no extra arguments", (String *) NULL, (Cardinal *) NULL); str = (String) (from->addr); if (str == NULL) { XtAppWarningMsg(XtDisplayToApplicationContext(dpy), "badParameters", "cvtStringToTranslation", XtCXtToolkitError, "String to TranslationTable conversion needs string", (String *) NULL, (Cardinal *) NULL); return FALSE; } if (to->addr != NULL) { if (to->size < sizeof(XtTranslations)) { to->size = sizeof(XtTranslations); return FALSE; } *(XtTranslations *) to->addr = ParseTranslationTable(str, FALSE, XtTableReplace, &error); } else { static XtTranslations staticStateTable; staticStateTable = ParseTranslationTable(str, FALSE, XtTableReplace, &error); to->addr = (XPointer) &staticStateTable; to->size = sizeof(XtTranslations); } if (error == TRUE) XtAppWarningMsg(XtDisplayToApplicationContext(dpy), "parseError", "cvtStringToTranslationTable", XtCXtToolkitError, "String to TranslationTable conversion encountered errors", (String *) NULL, (Cardinal *) NULL); return (error != TRUE); } /* * Parses a user's or applications translation table */ XtAccelerators XtParseAcceleratorTable(_Xconst char *source) { Boolean error = FALSE; XtAccelerators ret = (XtAccelerators) ParseTranslationTable(source, TRUE, XtTableAugment, &error); if (error == TRUE) XtWarningMsg("parseError", "cvtStringToAcceleratorTable", XtCXtToolkitError, "String to AcceleratorTable conversion encountered errors", (String *) NULL, (Cardinal *) NULL); return ret; } XtTranslations XtParseTranslationTable(_Xconst char *source) { Boolean error = FALSE; XtTranslations ret = ParseTranslationTable(source, FALSE, XtTableReplace, &error); if (error == TRUE) XtWarningMsg("parseError", "cvtStringToTranslationTable", XtCXtToolkitError, "String to TranslationTable conversion encountered errors", (String *) NULL, (Cardinal *) NULL); return ret; } void _XtTranslateInitialize(void) { LOCK_PROCESS; if (initialized) { XtWarningMsg("translationError", "xtTranslateInitialize", XtCXtToolkitError, "Initializing Translation manager twice.", (String *) NULL, (Cardinal *) NULL); UNLOCK_PROCESS; return; } initialized = TRUE; UNLOCK_PROCESS; QMeta = XrmPermStringToQuark("Meta"); QCtrl = XrmPermStringToQuark("Ctrl"); QNone = XrmPermStringToQuark("None"); QAny = XrmPermStringToQuark("Any"); Compile_XtEventTable(events, XtNumber(events)); Compile_XtModifierTable(modifiers, XtNumber(modifiers)); CompileNameValueTable(notifyModes); CompileNameValueTable(motionDetails); #if 0 CompileNameValueTable(notifyDetail); CompileNameValueTable(visibilityNotify); CompileNameValueTable(circulation); CompileNameValueTable(propertyChanged); #endif CompileNameValueTable(mappingNotify); } void _XtAddTMConverters(ConverterTable table) { _XtTableAddConverter(table, _XtQString, XrmPermStringToQuark(XtRTranslationTable), XtCvtStringToTranslationTable, (XtConvertArgList) NULL, (Cardinal) 0, True, CACHED, _XtFreeTranslations, True); _XtTableAddConverter(table, _XtQString, XrmPermStringToQuark(XtRAcceleratorTable), XtCvtStringToAcceleratorTable, (XtConvertArgList) NULL, (Cardinal) 0, True, CACHED, _XtFreeTranslations, True); _XtTableAddConverter(table, XrmPermStringToQuark(_XtRStateTablePair), XrmPermStringToQuark(XtRTranslationTable), _XtCvtMergeTranslations, (XtConvertArgList) NULL, (Cardinal) 0, True, CACHED, _XtFreeTranslations, True); }