1/*********************************************************** 2Copyright (c) 1993, Oracle and/or its affiliates. 3 4Permission is hereby granted, free of charge, to any person obtaining a 5copy of this software and associated documentation files (the "Software"), 6to deal in the Software without restriction, including without limitation 7the rights to use, copy, modify, merge, publish, distribute, sublicense, 8and/or sell copies of the Software, and to permit persons to whom the 9Software is furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice (including the next 12paragraph) shall be included in all copies or substantial portions of the 13Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21DEALINGS IN THE SOFTWARE. 22 23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 24 25 All Rights Reserved 26 27Permission to use, copy, modify, and distribute this software and its 28documentation for any purpose and without fee is hereby granted, 29provided that the above copyright notice appear in all copies and that 30both that copyright notice and this permission notice appear in 31supporting documentation, and that the name of Digital not be 32used in advertising or publicity pertaining to distribution of the 33software without specific, written prior permission. 34 35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 41SOFTWARE. 42 43******************************************************************/ 44 45/* 46 47Copyright 1987, 1988, 1998 The Open Group 48 49Permission to use, copy, modify, distribute, and sell this software and its 50documentation for any purpose is hereby granted without fee, provided that 51the above copyright notice appear in all copies and that both that 52copyright notice and this permission notice appear in supporting 53documentation. 54 55The above copyright notice and this permission notice shall be included in 56all copies or substantial portions of the Software. 57 58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64 65Except as contained in this notice, the name of The Open Group shall not be 66used in advertising or otherwise to promote the sale, use or other dealings 67in this Software without prior written authorization from The Open Group. 68 69*/ 70 71#ifdef HAVE_CONFIG_H 72#include <config.h> 73#endif 74#include "IntrinsicI.h" 75#include "StringDefs.h" 76#include <ctype.h> 77#include <stdlib.h> 78#ifndef NOTASCII 79#define XK_LATIN1 80#endif 81#define XK_MISCELLANY 82#include <X11/keysymdef.h> 83 84#ifdef CACHE_TRANSLATIONS 85#ifdef REFCNT_TRANSLATIONS 86#define CACHED XtCacheAll | XtCacheRefCount 87#else 88#define CACHED XtCacheAll 89#endif 90#else 91#define CACHED XtCacheNone 92#endif 93 94#ifndef MAX 95#define MAX(a,b) (((a) > (b)) ? (a) : (b)) 96#endif 97 98#ifndef MIN 99#define MIN(a,b) (((a) < (b)) ? (a) : (b)) 100#endif 101 102static _Xconst char *XtNtranslationParseError = "translationParseError"; 103 104typedef int EventType; 105 106#define PARSE_PROC_DECL String, Opaque, EventPtr, Boolean* 107 108typedef String(*ParseProc) (String /* str; */ , 109 Opaque /* closure; */ , 110 EventPtr /* event; */ , 111 Boolean * /* error */ ); 112 113typedef TMShortCard Value; 114typedef void (*ModifierProc) (Value, LateBindingsPtr *, Boolean, Value *); 115 116typedef struct _ModifierRec { 117 const char *name; 118 XrmQuark signature; 119 ModifierProc modifierParseProc; 120 Value value; 121} ModifierRec, *ModifierKeys; 122 123typedef struct _EventKey { 124 const char *event; 125 XrmQuark signature; 126 EventType eventType; 127 ParseProc parseDetail; 128 Opaque closure; 129} EventKey, *EventKeys; 130 131typedef struct { 132 const char *name; 133 XrmQuark signature; 134 Value value; 135} NameValueRec, *NameValueTable; 136 137static void ParseModImmed(Value, LateBindingsPtr *, Boolean, Value *); 138static void ParseModSym(Value, LateBindingsPtr *, Boolean, Value *); 139static String PanicModeRecovery(String); 140static String CheckForPoundSign(String, _XtTranslateOp, _XtTranslateOp *); 141static KeySym StringToKeySym(String, Boolean *); 142/* *INDENT-OFF* */ 143static ModifierRec modifiers[] = { 144 {"Shift", 0, ParseModImmed, ShiftMask}, 145 {"Lock", 0, ParseModImmed, LockMask}, 146 {"Ctrl", 0, ParseModImmed, ControlMask}, 147 {"Mod1", 0, ParseModImmed, Mod1Mask}, 148 {"Mod2", 0, ParseModImmed, Mod2Mask}, 149 {"Mod3", 0, ParseModImmed, Mod3Mask}, 150 {"Mod4", 0, ParseModImmed, Mod4Mask}, 151 {"Mod5", 0, ParseModImmed, Mod5Mask}, 152 {"Meta", 0, ParseModSym, XK_Meta_L}, 153 {"m", 0, ParseModSym, XK_Meta_L}, 154 {"h", 0, ParseModSym, XK_Hyper_L}, 155 {"su", 0, ParseModSym, XK_Super_L}, 156 {"a", 0, ParseModSym, XK_Alt_L}, 157 {"Hyper", 0, ParseModSym, XK_Hyper_L}, 158 {"Super", 0, ParseModSym, XK_Super_L}, 159 {"Alt", 0, ParseModSym, XK_Alt_L}, 160 {"Button1", 0, ParseModImmed, Button1Mask}, 161 {"Button2", 0, ParseModImmed, Button2Mask}, 162 {"Button3", 0, ParseModImmed, Button3Mask}, 163 {"Button4", 0, ParseModImmed, Button4Mask}, 164 {"Button5", 0, ParseModImmed, Button5Mask}, 165 {"c", 0, ParseModImmed, ControlMask}, 166 {"s", 0, ParseModImmed, ShiftMask}, 167 {"l", 0, ParseModImmed, LockMask}, 168}; 169 170static NameValueRec motionDetails[] = { 171 {"Normal", 0, NotifyNormal}, 172 {"Hint", 0, NotifyHint}, 173 {NULL, NULLQUARK, 0}, 174}; 175 176static NameValueRec notifyModes[] = { 177 {"Normal", 0, NotifyNormal}, 178 {"Grab", 0, NotifyGrab}, 179 {"Ungrab", 0, NotifyUngrab}, 180 {"WhileGrabbed", 0, NotifyWhileGrabbed}, 181 {NULL, NULLQUARK, 0}, 182}; 183 184#if 0 185static NameValueRec notifyDetail[] = { 186 {"Ancestor", 0, NotifyAncestor}, 187 {"Virtual", 0, NotifyVirtual}, 188 {"Inferior", 0, NotifyInferior}, 189 {"Nonlinear", 0, NotifyNonlinear}, 190 {"NonlinearVirtual", 0, NotifyNonlinearVirtual}, 191 {"Pointer", 0, NotifyPointer}, 192 {"PointerRoot", 0, NotifyPointerRoot}, 193 {"DetailNone", 0, NotifyDetailNone}, 194 {NULL, NULLQUARK, 0}, 195}; 196 197static NameValueRec visibilityNotify[] = { 198 {"Unobscured", 0, VisibilityUnobscured}, 199 {"PartiallyObscured", 0, VisibilityPartiallyObscured}, 200 {"FullyObscured", 0, VisibilityFullyObscured}, 201 {NULL, NULLQUARK, 0}, 202}; 203 204static NameValueRec circulation[] = { 205 {"OnTop", 0, PlaceOnTop}, 206 {"OnBottom", 0, PlaceOnBottom}, 207 {NULL, NULLQUARK, 0}, 208}; 209 210static NameValueRec propertyChanged[] = { 211 {"NewValue", 0, PropertyNewValue}, 212 {"Delete", 0, PropertyDelete}, 213 {NULL, NULLQUARK, 0}, 214}; 215#endif /*0*/ 216 217static NameValueRec mappingNotify[] = { 218 {"Modifier", 0, MappingModifier}, 219 {"Keyboard", 0, MappingKeyboard}, 220 {"Pointer", 0, MappingPointer}, 221 {NULL, NULLQUARK, 0}, 222}; 223/* *INDENT-ON* */ 224 225static String ParseKeySym(PARSE_PROC_DECL); 226static String ParseKeyAndModifiers(PARSE_PROC_DECL); 227static String ParseTable(PARSE_PROC_DECL); 228static String ParseButton(PARSE_PROC_DECL); 229static String ParseImmed(PARSE_PROC_DECL); 230static String ParseAddModifier(PARSE_PROC_DECL); 231static String ParseNone(PARSE_PROC_DECL); 232static String ParseAtom(PARSE_PROC_DECL); 233 234/* *INDENT-OFF* */ 235static EventKey events[] = { 236 237/* Event Name, Quark, Event Type, Detail Parser, Closure */ 238 239{"KeyPress", NULLQUARK, KeyPress, ParseKeySym, NULL}, 240{"Key", NULLQUARK, KeyPress, ParseKeySym, NULL}, 241{"KeyDown", NULLQUARK, KeyPress, ParseKeySym, NULL}, 242{"Ctrl", NULLQUARK, KeyPress, ParseKeyAndModifiers, (Opaque)ControlMask}, 243{"Shift", NULLQUARK, KeyPress, ParseKeyAndModifiers, (Opaque)ShiftMask}, 244{"Meta", NULLQUARK, KeyPress, ParseKeyAndModifiers, (Opaque)NULL}, 245{"KeyUp", NULLQUARK, KeyRelease, ParseKeySym, NULL}, 246{"KeyRelease", NULLQUARK, KeyRelease, ParseKeySym, NULL}, 247 248{"ButtonPress", NULLQUARK, ButtonPress, ParseButton, NULL }, 249{"BtnDown", NULLQUARK, ButtonPress, ParseButton, NULL }, 250{"Btn1Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button1}, 251{"Btn2Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button2}, 252{"Btn3Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button3}, 253{"Btn4Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button4}, 254{"Btn5Down", NULLQUARK, ButtonPress, ParseImmed, (Opaque)Button5}, 255 256/* Event Name, Quark, Event Type, Detail Parser, Closure */ 257 258{"ButtonRelease", NULLQUARK, ButtonRelease, ParseButton, NULL }, 259{"BtnUp", NULLQUARK, ButtonRelease, ParseButton, NULL }, 260{"Btn1Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button1}, 261{"Btn2Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button2}, 262{"Btn3Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button3}, 263{"Btn4Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button4}, 264{"Btn5Up", NULLQUARK, ButtonRelease, ParseImmed, (Opaque)Button5}, 265 266{"MotionNotify", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, 267{"PtrMoved", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, 268{"Motion", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, 269{"MouseMoved", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, 270{"BtnMotion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)AnyButtonMask}, 271{"Btn1Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button1Mask}, 272{"Btn2Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button2Mask}, 273{"Btn3Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button3Mask}, 274{"Btn4Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button4Mask}, 275{"Btn5Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button5Mask}, 276 277{"EnterNotify", NULLQUARK, EnterNotify, ParseTable, (Opaque)notifyModes}, 278{"Enter", NULLQUARK, EnterNotify, ParseTable, (Opaque)notifyModes}, 279{"EnterWindow", NULLQUARK, EnterNotify, ParseTable, (Opaque)notifyModes}, 280 281{"LeaveNotify", NULLQUARK, LeaveNotify, ParseTable, (Opaque)notifyModes}, 282{"LeaveWindow", NULLQUARK, LeaveNotify, ParseTable, (Opaque)notifyModes}, 283{"Leave", NULLQUARK, LeaveNotify, ParseTable, (Opaque)notifyModes}, 284 285/* Event Name, Quark, Event Type, Detail Parser, Closure */ 286 287{"FocusIn", NULLQUARK, FocusIn, ParseTable, (Opaque)notifyModes}, 288 289{"FocusOut", NULLQUARK, FocusOut, ParseTable, (Opaque)notifyModes}, 290 291{"KeymapNotify", NULLQUARK, KeymapNotify, ParseNone, NULL}, 292{"Keymap", NULLQUARK, KeymapNotify, ParseNone, NULL}, 293 294{"Expose", NULLQUARK, Expose, ParseNone, NULL}, 295 296{"GraphicsExpose", NULLQUARK, GraphicsExpose, ParseNone, NULL}, 297{"GrExp", NULLQUARK, GraphicsExpose, ParseNone, NULL}, 298 299{"NoExpose", NULLQUARK, NoExpose, ParseNone, NULL}, 300{"NoExp", NULLQUARK, NoExpose, ParseNone, NULL}, 301 302{"VisibilityNotify",NULLQUARK, VisibilityNotify,ParseNone, NULL}, 303{"Visible", NULLQUARK, VisibilityNotify,ParseNone, NULL}, 304 305{"CreateNotify", NULLQUARK, CreateNotify, ParseNone, NULL}, 306{"Create", NULLQUARK, CreateNotify, ParseNone, NULL}, 307 308/* Event Name, Quark, Event Type, Detail Parser, Closure */ 309 310{"DestroyNotify", NULLQUARK, DestroyNotify, ParseNone, NULL}, 311{"Destroy", NULLQUARK, DestroyNotify, ParseNone, NULL}, 312 313{"UnmapNotify", NULLQUARK, UnmapNotify, ParseNone, NULL}, 314{"Unmap", NULLQUARK, UnmapNotify, ParseNone, NULL}, 315 316{"MapNotify", NULLQUARK, MapNotify, ParseNone, NULL}, 317{"Map", NULLQUARK, MapNotify, ParseNone, NULL}, 318 319{"MapRequest", NULLQUARK, MapRequest, ParseNone, NULL}, 320{"MapReq", NULLQUARK, MapRequest, ParseNone, NULL}, 321 322{"ReparentNotify", NULLQUARK, ReparentNotify, ParseNone, NULL}, 323{"Reparent", NULLQUARK, ReparentNotify, ParseNone, NULL}, 324 325{"ConfigureNotify", NULLQUARK, ConfigureNotify, ParseNone, NULL}, 326{"Configure", NULLQUARK, ConfigureNotify, ParseNone, NULL}, 327 328{"ConfigureRequest",NULLQUARK, ConfigureRequest,ParseNone, NULL}, 329{"ConfigureReq", NULLQUARK, ConfigureRequest,ParseNone, NULL}, 330 331/* Event Name, Quark, Event Type, Detail Parser, Closure */ 332 333{"GravityNotify", NULLQUARK, GravityNotify, ParseNone, NULL}, 334{"Grav", NULLQUARK, GravityNotify, ParseNone, NULL}, 335 336{"ResizeRequest", NULLQUARK, ResizeRequest, ParseNone, NULL}, 337{"ResReq", NULLQUARK, ResizeRequest, ParseNone, NULL}, 338 339{"CirculateNotify", NULLQUARK, CirculateNotify, ParseNone, NULL}, 340{"Circ", NULLQUARK, CirculateNotify, ParseNone, NULL}, 341 342{"CirculateRequest",NULLQUARK, CirculateRequest,ParseNone, NULL}, 343{"CircReq", NULLQUARK, CirculateRequest,ParseNone, NULL}, 344 345{"PropertyNotify", NULLQUARK, PropertyNotify, ParseAtom, NULL}, 346{"Prop", NULLQUARK, PropertyNotify, ParseAtom, NULL}, 347 348{"SelectionClear", NULLQUARK, SelectionClear, ParseAtom, NULL}, 349{"SelClr", NULLQUARK, SelectionClear, ParseAtom, NULL}, 350 351{"SelectionRequest",NULLQUARK, SelectionRequest,ParseAtom, NULL}, 352{"SelReq", NULLQUARK, SelectionRequest,ParseAtom, NULL}, 353 354/* Event Name, Quark, Event Type, Detail Parser, Closure */ 355 356{"SelectionNotify", NULLQUARK, SelectionNotify, ParseAtom, NULL}, 357{"Select", NULLQUARK, SelectionNotify, ParseAtom, NULL}, 358 359{"ColormapNotify", NULLQUARK, ColormapNotify, ParseNone, NULL}, 360{"Clrmap", NULLQUARK, ColormapNotify, ParseNone, NULL}, 361 362{"ClientMessage", NULLQUARK, ClientMessage, ParseAtom, NULL}, 363{"Message", NULLQUARK, ClientMessage, ParseAtom, NULL}, 364 365{"MappingNotify", NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify}, 366{"Mapping", NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify}, 367 368#ifdef DEBUG 369# ifdef notdef 370{"Timer", NULLQUARK, _XtTimerEventType, ParseNone, NULL}, 371{"EventTimer", NULLQUARK, _XtEventTimerEventType, ParseNone,NULL}, 372# endif /* notdef */ 373#endif /* DEBUG */ 374 375/* Event Name, Quark, Event Type, Detail Parser, Closure */ 376 377}; 378/* *INDENT-ON* */ 379 380#define IsNewline(str) ((str) == '\n') 381 382#define ScanFor(str, ch) \ 383 while ((*(str) != (ch)) && (*(str) != '\0') && !IsNewline(*(str))) (str)++ 384 385#define ScanNumeric(str) while ('0' <= *(str) && *(str) <= '9') (str)++ 386 387#define ScanAlphanumeric(str) \ 388 while (('A' <= *(str) && *(str) <= 'Z') || \ 389 ('a' <= *(str) && *(str) <= 'z') || \ 390 ('0' <= *(str) && *(str) <= '9')) (str)++ 391 392#define ScanWhitespace(str) \ 393 while (*(str) == ' ' || *(str) == '\t') (str)++ 394 395static Boolean initialized = FALSE; 396static XrmQuark QMeta; 397static XrmQuark QCtrl; 398static XrmQuark QNone; 399static XrmQuark QAny; 400 401static void 402FreeEventSeq(EventSeqPtr eventSeq) 403{ 404 register EventSeqPtr evs = eventSeq; 405 406 while (evs != NULL) { 407 evs->state = (StatePtr) evs; 408 if (evs->next != NULL && evs->next->state == (StatePtr) evs->next) 409 evs->next = NULL; 410 evs = evs->next; 411 } 412 413 evs = eventSeq; 414 while (evs != NULL) { 415 register EventPtr event = evs; 416 417 evs = evs->next; 418 if (evs == event) 419 evs = NULL; 420 XtFree((char *) event); 421 } 422} 423 424static void 425CompileNameValueTable(NameValueTable table) 426{ 427 register int i; 428 429 for (i = 0; table[i].name; i++) 430 table[i].signature = XrmPermStringToQuark(table[i].name); 431} 432 433static int 434OrderEvents(_Xconst void *a, _Xconst void *b) 435{ 436 return ((((_Xconst EventKey *) a)->signature < 437 ((_Xconst EventKey *) b)->signature) ? -1 : 1); 438} 439 440static void 441Compile_XtEventTable(EventKeys table, Cardinal count) 442{ 443 register int i; 444 register EventKeys entry = table; 445 446 for (i = (int) count; --i >= 0; entry++) 447 entry->signature = XrmPermStringToQuark(entry->event); 448 qsort(table, count, sizeof(EventKey), OrderEvents); 449} 450 451static int 452OrderModifiers(_Xconst void *a, _Xconst void *b) 453{ 454 return ((((_Xconst ModifierRec *) a)->signature < 455 ((_Xconst ModifierRec *) b)->signature) ? -1 : 1); 456} 457 458static void 459Compile_XtModifierTable(ModifierKeys table, Cardinal count) 460{ 461 register int i; 462 register ModifierKeys entry = table; 463 464 for (i = (int) count; --i >= 0; entry++) 465 entry->signature = XrmPermStringToQuark(entry->name); 466 qsort(table, count, sizeof(ModifierRec), OrderModifiers); 467} 468 469static String 470PanicModeRecovery(String str) 471{ 472 ScanFor(str, '\n'); 473 if (*str == '\n') 474 str++; 475 return str; 476 477} 478 479static void 480Syntax(_Xconst char *str0, _Xconst char *str1) 481{ 482 Cardinal num_params = 2; 483 String params[2]; 484 485 params[0] = (String) str0; 486 params[1] = (String) str1; 487 XtWarningMsg(XtNtranslationParseError, "parseError", XtCXtToolkitError, 488 "translation table syntax error: %s %s", params, &num_params); 489} 490 491static Cardinal 492LookupTMEventType(String eventStr, Boolean *error) 493{ 494 register int i = 0, left, right; 495 register XrmQuark signature; 496 static int previous = 0; 497 498 LOCK_PROCESS; 499 if ((signature = StringToQuark(eventStr)) == events[previous].signature) { 500 UNLOCK_PROCESS; 501 return (Cardinal) previous; 502 } 503 504 left = 0; 505 right = XtNumber(events) - 1; 506 while (left <= right) { 507 i = (left + right) >> 1; 508 if (signature < events[i].signature) 509 right = i - 1; 510 else if (signature > events[i].signature) 511 left = i + 1; 512 else { 513 previous = i; 514 UNLOCK_PROCESS; 515 return (Cardinal) i; 516 } 517 } 518 519 Syntax("Unknown event type : ", eventStr); 520 *error = TRUE; 521 UNLOCK_PROCESS; 522 return (Cardinal) i; 523} 524 525static void 526StoreLateBindings(KeySym keysymL, 527 Boolean notL, 528 KeySym keysymR, 529 Boolean notR, 530 LateBindingsPtr *lateBindings) 531{ 532 LateBindingsPtr temp; 533 534 if (lateBindings != NULL) { 535 Boolean pair = FALSE; 536 unsigned long count; 537 unsigned long number; 538 539 temp = *lateBindings; 540 if (temp != NULL) { 541 for (count = 0; temp[count].keysym; count++) { 542 /*EMPTY*/ 543 } 544 } 545 else 546 count = 0; 547 if (!keysymR) { 548 number = 1; 549 pair = FALSE; 550 } 551 else { 552 number = 2; 553 pair = TRUE; 554 } 555 556 temp = XtReallocArray(temp, (Cardinal) (count + number + 1), 557 (Cardinal) sizeof(LateBindings)); 558 *lateBindings = temp; 559 XtSetBit(temp[count].knot, notL); 560 XtSetBit(temp[count].pair, pair); 561 if (count == 0) 562 temp[count].ref_count = 1; 563 temp[count++].keysym = keysymL; 564 if (keysymR) { 565 XtSetBit(temp[count].knot, notR); 566 temp[count].pair = FALSE; 567 temp[count].ref_count = 0; 568 temp[count++].keysym = keysymR; 569 } 570 temp[count].knot = temp[count].pair = FALSE; 571 temp[count].ref_count = 0; 572 temp[count].keysym = 0; 573 } 574} 575 576static void 577_XtParseKeysymMod(String name, 578 LateBindingsPtr *lateBindings, 579 Boolean notFlag, 580 Value *valueP, 581 Boolean *error) 582{ 583 KeySym keySym; 584 585 keySym = StringToKeySym(name, error); 586 *valueP = 0; 587 if (keySym != NoSymbol) { 588 StoreLateBindings(keySym, notFlag, (KeySym) NULL, FALSE, lateBindings); 589 } 590} 591 592static Boolean 593_XtLookupModifier(XrmQuark signature, 594 LateBindingsPtr *lateBindings, 595 Boolean notFlag, 596 Value *valueP, 597 Bool constMask) 598{ 599 int left, right; 600 static int previous = 0; 601 602 LOCK_PROCESS; 603 if (signature == modifiers[previous].signature) { 604 if (constMask) 605 *valueP = modifiers[previous].value; 606 else /* if (modifiers[previous].modifierParseProc) always true */ 607 (*modifiers[previous].modifierParseProc) 608 (modifiers[previous].value, lateBindings, notFlag, valueP); 609 UNLOCK_PROCESS; 610 return TRUE; 611 } 612 613 left = 0; 614 right = XtNumber(modifiers) - 1; 615 while (left <= right) { 616 int i = (left + right) >> 1; 617 618 if (signature < modifiers[i].signature) 619 right = i - 1; 620 else if (signature > modifiers[i].signature) 621 left = i + 1; 622 else { 623 previous = i; 624 if (constMask) 625 *valueP = modifiers[i].value; 626 else /* if (modifiers[i].modifierParseProc) always true */ 627 (*modifiers[i].modifierParseProc) 628 (modifiers[i].value, lateBindings, notFlag, valueP); 629 UNLOCK_PROCESS; 630 return TRUE; 631 } 632 } 633 UNLOCK_PROCESS; 634 return FALSE; 635} 636 637static String 638ScanIdent(register String str) 639{ 640 ScanAlphanumeric(str); 641 while (('A' <= *str && *str <= 'Z') 642 || ('a' <= *str && *str <= 'z') 643 || ('0' <= *str && *str <= '9') 644 || (*str == '-') 645 || (*str == '_') 646 || (*str == '$') 647 ) 648 str++; 649 return str; 650} 651 652static String 653FetchModifierToken(String str, XrmQuark *token_return) 654{ 655 String start = str; 656 657 if (*str == '$') { 658 *token_return = QMeta; 659 str++; 660 } 661 else if (*str == '^') { 662 *token_return = QCtrl; 663 str++; 664 } 665 else { 666 str = ScanIdent(str); 667 if (start != str) { 668 char modStrbuf[100]; 669 char *modStr; 670 671 modStr = XtStackAlloc((size_t) (str - start + 1), modStrbuf); 672 if (modStr == NULL) 673 _XtAllocError(NULL); 674 (void) memcpy(modStr, start, (size_t) (str - start)); 675 modStr[str - start] = '\0'; 676 *token_return = XrmStringToQuark(modStr); 677 XtStackFree(modStr, modStrbuf); 678 } 679 } 680 return str; 681} 682 683static String 684ParseModifiers(register String str, EventPtr event, Boolean *error) 685{ 686 register String start; 687 Boolean notFlag, exclusive, keysymAsMod; 688 Value maskBit; 689 XrmQuark Qmod = QNone; 690 691 ScanWhitespace(str); 692 start = str; 693 str = FetchModifierToken(str, &Qmod); 694 exclusive = FALSE; 695 if (start != str) { 696 if (Qmod == QNone) { 697 event->event.modifierMask = (unsigned long) (~0); 698 event->event.modifiers = 0; 699 ScanWhitespace(str); 700 return str; 701 } 702 else if (Qmod == QAny) { /*backward compatibility */ 703 event->event.modifierMask = 0; 704 event->event.modifiers = AnyModifier; 705 ScanWhitespace(str); 706 return str; 707 } 708 str = start; /*if plain modifier, reset to beginning */ 709 } 710 else 711 while (*str == '!' || *str == ':') { 712 if (*str == '!') { 713 exclusive = TRUE; 714 str++; 715 ScanWhitespace(str); 716 } 717 if (*str == ':') { 718 event->event.standard = TRUE; 719 str++; 720 ScanWhitespace(str); 721 } 722 } 723 724 while (*str != '<') { 725 if (*str == '~') { 726 notFlag = TRUE; 727 str++; 728 } 729 else 730 notFlag = FALSE; 731 if (*str == '@') { 732 keysymAsMod = TRUE; 733 str++; 734 } 735 else 736 keysymAsMod = FALSE; 737 start = str; 738 str = FetchModifierToken(str, &Qmod); 739 if (start == str) { 740 Syntax("Modifier or '<' expected", ""); 741 *error = TRUE; 742 return PanicModeRecovery(str); 743 } 744 if (keysymAsMod) { 745 _XtParseKeysymMod(XrmQuarkToString(Qmod), 746 &event->event.lateModifiers, 747 notFlag, &maskBit, error); 748 if (*error) 749 return PanicModeRecovery(str); 750 751 } 752 else if (!_XtLookupModifier(Qmod, &event->event.lateModifiers, 753 notFlag, &maskBit, FALSE)) { 754 Syntax("Unknown modifier name: ", XrmQuarkToString(Qmod)); 755 *error = TRUE; 756 return PanicModeRecovery(str); 757 } 758 event->event.modifierMask |= maskBit; 759 if (notFlag) 760 event->event.modifiers = 761 (event->event.modifiers & (TMLongCard) (~maskBit)); 762 else 763 event->event.modifiers |= maskBit; 764 ScanWhitespace(str); 765 } 766 if (exclusive) 767 event->event.modifierMask = (unsigned long) (~0); 768 return str; 769} 770 771static String 772ParseXtEventType(register String str, 773 EventPtr event, 774 Cardinal *tmEventP, 775 Boolean *error) 776{ 777 String start = str; 778 char eventTypeStrbuf[100]; 779 char *eventTypeStr; 780 781 ScanAlphanumeric(str); 782 eventTypeStr = XtStackAlloc((size_t) (str - start + 1), eventTypeStrbuf); 783 if (eventTypeStr == NULL) 784 _XtAllocError(NULL); 785 (void) memcpy(eventTypeStr, start, (size_t) (str - start)); 786 eventTypeStr[str - start] = '\0'; 787 *tmEventP = LookupTMEventType(eventTypeStr, error); 788 XtStackFree(eventTypeStr, eventTypeStrbuf); 789 if (*error) 790 return PanicModeRecovery(str); 791 event->event.eventType = (TMLongCard) events[*tmEventP].eventType; 792 return str; 793} 794 795static unsigned long 796StrToHex(String str) 797{ 798 register char c; 799 register unsigned long val = 0; 800 801 while ((c = *str)) { 802 if ('0' <= c && c <= '9') 803 val = (unsigned long) (val * 16 + (unsigned long) c - '0'); 804 else if ('a' <= c && c <= 'z') 805 val = (unsigned long) (val * 16 + (unsigned long) c - 'a' + 10); 806 else if ('A' <= c && c <= 'Z') 807 val = (unsigned long) (val * 16 + (unsigned long) c - 'A' + 10); 808 else 809 return 0; 810 str++; 811 } 812 813 return val; 814} 815 816static unsigned long 817StrToOct(String str) 818{ 819 register char c; 820 register unsigned long val = 0; 821 822 while ((c = *str)) { 823 if ('0' <= c && c <= '7') 824 val = val * 8 + (unsigned long) c - '0'; 825 else 826 return 0; 827 str++; 828 } 829 830 return val; 831} 832 833static unsigned long 834StrToNum(String str) 835{ 836 register char c; 837 register unsigned long val = 0; 838 839 if (*str == '0') { 840 str++; 841 if (*str == 'x' || *str == 'X') 842 return StrToHex(++str); 843 else 844 return StrToOct(str); 845 } 846 847 while ((c = *str)) { 848 if ('0' <= c && c <= '9') 849 val = val * 10 + (unsigned long) c - '0'; 850 else 851 return 0; 852 str++; 853 } 854 855 return val; 856} 857 858static KeySym 859StringToKeySym(String str, Boolean *error) 860{ 861 KeySym k; 862 863 if (str == NULL || *str == '\0') 864 return (KeySym) 0; 865 866#ifndef NOTASCII 867 /* special case single character ASCII, for speed */ 868 if (*(str + 1) == '\0') { 869 if (' ' <= *str && *str <= '~') 870 return (KeySym) (XK_space + (*str - ' ')); 871 } 872#endif 873 874 if ('0' <= *str && *str <= '9') 875 return (KeySym) StrToNum(str); 876 k = XStringToKeysym(str); 877 if (k != NoSymbol) 878 return k; 879 880#ifdef NOTASCII 881 /* fall-back case to preserve backwards compatibility; no-one 882 * should be relying upon this! 883 */ 884 if (*(str + 1) == '\0') 885 return (KeySym) * str; 886#endif 887 888 Syntax("Unknown keysym name: ", str); 889 *error = TRUE; 890 return NoSymbol; 891} 892 893static void 894ParseModImmed(Value value, 895 LateBindingsPtr *lateBindings _X_UNUSED, 896 Boolean notFlag _X_UNUSED, 897 Value *valueP) 898{ 899 *valueP = value; 900} 901 902/* is only valid with keysyms that have an _L and _R in their name; 903 * and ignores keysym lookup errors (i.e. assumes only valid keysyms) 904 */ 905static void 906ParseModSym(Value value, 907 LateBindingsPtr *lateBindings, Boolean notFlag, Value *valueP) 908{ 909 register KeySym keysymL = (KeySym) value; 910 register KeySym keysymR = keysymL + 1; /* valid for supported keysyms */ 911 912 StoreLateBindings(keysymL, notFlag, keysymR, notFlag, lateBindings); 913 *valueP = 0; 914} 915 916#ifdef sparc 917/* 918 * The stupid optimizer in SunOS 4.0.3 and below generates bogus code that 919 * causes the value of the most recently used variable to be returned instead 920 * of the value passed in. 921 */ 922static String stupid_optimizer_kludge; 923 924#define BROKEN_OPTIMIZER_HACK(val) stupid_optimizer_kludge = (val) 925#else 926#define BROKEN_OPTIMIZER_HACK(val) val 927#endif 928 929static String 930ParseImmed(register String str, 931 register Opaque closure, 932 register EventPtr event, 933 Boolean *error _X_UNUSED) 934{ 935 event->event.eventCode = (unsigned long) closure; 936 event->event.eventCodeMask = (unsigned long) (~0UL); 937 938 return BROKEN_OPTIMIZER_HACK(str); 939} 940 941static String 942ParseAddModifier(register String str, 943 register Opaque closure, 944 register EventPtr event, 945 Boolean *error _X_UNUSED) 946{ 947 register unsigned long modval = (unsigned long) closure; 948 949 event->event.modifiers |= modval; 950 if (modval != AnyButtonMask) /* AnyButtonMask is don't-care mask */ 951 event->event.modifierMask |= modval; 952 953 return BROKEN_OPTIMIZER_HACK(str); 954} 955 956static String 957ParseKeyAndModifiers(String str, 958 Opaque closure, 959 EventPtr event, 960 Boolean *error) 961{ 962 str = ParseKeySym(str, closure, event, error); 963 if ((unsigned long) closure == 0) { 964 Value metaMask; /* unused */ 965 966 (void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE, 967 &metaMask, FALSE); 968 } 969 else { 970 event->event.modifiers |= (unsigned long) closure; 971 event->event.modifierMask |= (unsigned long) closure; 972 } 973 return str; 974} 975 976static String 977ParseKeySym(register String str, 978 Opaque closure _X_UNUSED, 979 EventPtr event, 980 Boolean *error) 981{ 982 String start; 983 char keySymNamebuf[100]; 984 char *keySymName = NULL; 985 986 ScanWhitespace(str); 987 988 if (*str == '\\') { 989 keySymName = keySymNamebuf; 990 str++; 991 keySymName[0] = *str; 992 if (*str != '\0' && !IsNewline(*str)) 993 str++; 994 keySymName[1] = '\0'; 995 event->event.eventCode = StringToKeySym(keySymName, error); 996 event->event.eventCodeMask = (unsigned long) (~0L); 997 } 998 else if (*str == ',' || *str == ':' || 999 /* allow leftparen to be single char symbol, 1000 * for backwards compatibility 1001 */ 1002 (*str == '(' && *(str + 1) >= '0' && *(str + 1) <= '9')) { 1003 keySymName = keySymNamebuf; /* just so we can stackfree it later */ 1004 keySymName[0] = '\0'; 1005 /* no detail */ 1006 event->event.eventCode = 0L; 1007 event->event.eventCodeMask = 0L; 1008 } 1009 else { 1010 start = str; 1011 while (*str != ',' 1012 && *str != ':' && *str != ' ' && *str != '\t' && !IsNewline(*str) 1013 && (*str != '(' || *(str + 1) <= '0' || *(str + 1) >= '9') 1014 && *str != '\0') 1015 str++; 1016 keySymName = XtStackAlloc((size_t) (str - start + 1), keySymNamebuf); 1017 (void) memcpy(keySymName, start, (size_t) (str - start)); 1018 keySymName[str - start] = '\0'; 1019 event->event.eventCode = StringToKeySym(keySymName, error); 1020 event->event.eventCodeMask = (unsigned long) (~0L); 1021 } 1022 if (*error && keySymName) { 1023 /* We never get here when keySymName hasn't been allocated */ 1024 if (keySymName[0] == '<') { 1025 /* special case for common error */ 1026 XtWarningMsg(XtNtranslationParseError, "missingComma", 1027 XtCXtToolkitError, 1028 "... possibly due to missing ',' in event sequence.", 1029 (String *) NULL, (Cardinal *) NULL); 1030 } 1031 XtStackFree(keySymName, keySymNamebuf); 1032 return PanicModeRecovery(str); 1033 } 1034 if (event->event.standard) 1035 event->event.matchEvent = _XtMatchUsingStandardMods; 1036 else 1037 event->event.matchEvent = _XtMatchUsingDontCareMods; 1038 1039 XtStackFree(keySymName, keySymNamebuf); 1040 1041 return str; 1042} 1043 1044static String 1045ParseTable(register String str, Opaque closure, EventPtr event, Boolean *error) 1046{ 1047 register String start = str; 1048 register XrmQuark signature; 1049 NameValueTable table = (NameValueTable) closure; 1050 char tableSymName[100]; 1051 1052 event->event.eventCode = 0L; 1053 ScanAlphanumeric(str); 1054 if (str == start) { 1055 event->event.eventCodeMask = 0L; 1056 return str; 1057 } 1058 if (str - start >= 99) { 1059 Syntax("Invalid Detail Type (string is too long).", ""); 1060 *error = TRUE; 1061 return str; 1062 } 1063 (void) memcpy(tableSymName, start, (size_t) (str - start)); 1064 tableSymName[str - start] = '\0'; 1065 signature = StringToQuark(tableSymName); 1066 for (; table->signature != NULLQUARK; table++) 1067 if (table->signature == signature) { 1068 event->event.eventCode = table->value; 1069 event->event.eventCodeMask = (unsigned long) (~0L); 1070 return str; 1071 } 1072 1073 Syntax("Unknown Detail Type: ", tableSymName); 1074 *error = TRUE; 1075 return PanicModeRecovery(str); 1076} 1077 1078static String 1079ParseButton(String str, Opaque closure _X_UNUSED, EventPtr event, Boolean *error) 1080{ 1081 String start = str; 1082 char buttonStr[7]; 1083 size_t len; 1084 static const char buttonPrefix[] = "Button"; 1085 unsigned long button; 1086 1087 event->event.eventCode = 0L; 1088 if (strncmp(str, buttonPrefix, sizeof(buttonPrefix)-1) != 0) { 1089 event->event.eventCodeMask = 0L; 1090 return str; 1091 } 1092 str += sizeof(buttonPrefix)-1; 1093 start = str; 1094 ScanNumeric(str); 1095 if (str == start) { 1096 Syntax("Missing button number", ""); 1097 *error = TRUE; 1098 return PanicModeRecovery(str); 1099 } 1100 len = (size_t) (str - start); 1101 if (len >= sizeof buttonStr) { 1102 Syntax("Button number too long", ""); 1103 *error = TRUE; 1104 return PanicModeRecovery(str); 1105 } 1106 (void) memcpy(buttonStr, start, len); 1107 buttonStr[len] = '\0'; 1108 button = StrToNum(buttonStr); 1109 if (button < 1 || 255 < button) { 1110 Syntax("Invalid button number", buttonStr); 1111 *error = TRUE; 1112 return PanicModeRecovery(str); 1113 } 1114 event->event.eventCode = button; 1115 event->event.eventCodeMask = (unsigned long) (~0L); 1116 return str; 1117} 1118 1119static String 1120ParseNone(String str, 1121 Opaque closure _X_UNUSED, 1122 EventPtr event, 1123 Boolean *error _X_UNUSED) 1124{ 1125 event->event.eventCode = 0; 1126 event->event.eventCodeMask = 0; 1127 1128 return BROKEN_OPTIMIZER_HACK(str); 1129} 1130 1131static String 1132ParseAtom(String str, Opaque closure _X_UNUSED, EventPtr event, Boolean *error) 1133{ 1134 ScanWhitespace(str); 1135 1136 if (*str == ',' || *str == ':') { 1137 /* no detail */ 1138 event->event.eventCode = 0L; 1139 event->event.eventCodeMask = 0L; 1140 } 1141 else { 1142 String start; 1143 char atomName[1000]; 1144 1145 start = str; 1146 while (*str != ',' 1147 && *str != ':' && *str != ' ' && *str != '\t' && !IsNewline(*str) 1148 && *str != '\0') 1149 str++; 1150 if (str - start >= 999) { 1151 Syntax("Atom name must be less than 1000 characters long.", ""); 1152 *error = TRUE; 1153 return str; 1154 } 1155 (void) memcpy(atomName, start, (size_t) (str - start)); 1156 atomName[str - start] = '\0'; 1157 event->event.eventCode = (TMLongCard) XrmStringToQuark(atomName); 1158 event->event.matchEvent = _XtMatchAtom; 1159 } 1160 return str; 1161} 1162 1163static ModifierMask buttonModifierMasks[] = { 1164 0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask 1165}; 1166 1167static String ParseRepeat(String, int *, Boolean *, Boolean *); 1168 1169static String 1170ParseEvent(register String str, 1171 EventPtr event, int *reps, 1172 Boolean *plus, 1173 Boolean *error) 1174{ 1175 Cardinal tmEvent; 1176 1177 str = ParseModifiers(str, event, error); 1178 if (*error) 1179 return str; 1180 if (*str != '<') { 1181 Syntax("Missing '<' while parsing event type.", ""); 1182 *error = TRUE; 1183 return PanicModeRecovery(str); 1184 } 1185 else 1186 str++; 1187 str = ParseXtEventType(str, event, &tmEvent, error); 1188 if (*error) 1189 return str; 1190 if (*str != '>') { 1191 Syntax("Missing '>' while parsing event type", ""); 1192 *error = TRUE; 1193 return PanicModeRecovery(str); 1194 } 1195 else 1196 str++; 1197 if (*str == '(') { 1198 str = ParseRepeat(str, reps, plus, error); 1199 if (*error) 1200 return str; 1201 } 1202 str = 1203 (*(events[tmEvent].parseDetail)) (str, events[tmEvent].closure, event, 1204 error); 1205 if (*error) 1206 return str; 1207 1208/* gross hack! ||| this kludge is related to the X11 protocol deficiency w.r.t. 1209 * modifiers in grabs. 1210 */ 1211 if ((event->event.eventType == ButtonRelease) 1212 && (event->event.modifiers | event->event.modifierMask) /* any */ 1213 &&(event->event.modifiers != AnyModifier)) { 1214 event->event.modifiers = (event->event.modifiers 1215 | (TMLongCard) buttonModifierMasks[event-> 1216 event. 1217 eventCode]); 1218 /* the button that is going up will always be in the modifiers... */ 1219 } 1220 1221 return str; 1222} 1223 1224static String 1225ParseQuotedStringEvent(register String str, 1226 register EventPtr event, 1227 Boolean *error) 1228{ 1229 Value metaMask; 1230 char s[2]; 1231 1232 if (*str == '^') { 1233 str++; 1234 event->event.modifiers = ControlMask; 1235 } 1236 else if (*str == '$') { 1237 str++; 1238 (void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE, 1239 &metaMask, FALSE); 1240 } 1241 if (*str == '\\') 1242 str++; 1243 s[0] = *str; 1244 s[1] = '\0'; 1245 if (*str != '\0' && !IsNewline(*str)) 1246 str++; 1247 event->event.eventType = KeyPress; 1248 event->event.eventCode = StringToKeySym(s, error); 1249 if (*error) 1250 return PanicModeRecovery(str); 1251 event->event.eventCodeMask = (unsigned long) (~0L); 1252 event->event.matchEvent = _XtMatchUsingStandardMods; 1253 event->event.standard = TRUE; 1254 1255 return str; 1256} 1257 1258static EventSeqRec timerEventRec = { 1259 {0, 0, NULL, _XtEventTimerEventType, 0L, 0L, NULL, False}, 1260 /* (StatePtr) -1 */ NULL, 1261 NULL, 1262 NULL 1263}; 1264 1265static void 1266RepeatDown(EventPtr *eventP, int reps, ActionPtr **actionsP) 1267{ 1268 EventRec upEventRec; 1269 register EventPtr event, downEvent; 1270 EventPtr upEvent = &upEventRec; 1271 register int i; 1272 1273 downEvent = event = *eventP; 1274 *upEvent = *downEvent; 1275 upEvent->event.eventType = ((event->event.eventType == ButtonPress) ? 1276 ButtonRelease : KeyRelease); 1277 if ((upEvent->event.eventType == ButtonRelease) 1278 && (upEvent->event.modifiers != AnyModifier) 1279 && (upEvent->event.modifiers | upEvent->event.modifierMask)) 1280 upEvent->event.modifiers = (upEvent->event.modifiers 1281 | (TMLongCard) buttonModifierMasks[event-> 1282 event. 1283 eventCode]); 1284 1285 if (event->event.lateModifiers) 1286 event->event.lateModifiers->ref_count = 1287 (unsigned short) (event->event.lateModifiers->ref_count + 1288 (reps - 1) * 2); 1289 1290 for (i = 1; i < reps; i++) { 1291 1292 /* up */ 1293 event->next = XtNew(EventSeqRec); 1294 event = event->next; 1295 *event = *upEvent; 1296 1297 /* timer */ 1298 event->next = XtNew(EventSeqRec); 1299 event = event->next; 1300 *event = timerEventRec; 1301 1302 /* down */ 1303 event->next = XtNew(EventSeqRec); 1304 event = event->next; 1305 *event = *downEvent; 1306 1307 } 1308 1309 event->next = NULL; 1310 *eventP = event; 1311 *actionsP = &event->actions; 1312} 1313 1314static void 1315RepeatDownPlus(EventPtr *eventP, int reps, ActionPtr **actionsP) 1316{ 1317 EventRec upEventRec; 1318 register EventPtr event, downEvent, lastDownEvent = NULL; 1319 EventPtr upEvent = &upEventRec; 1320 register int i; 1321 1322 downEvent = event = *eventP; 1323 *upEvent = *downEvent; 1324 upEvent->event.eventType = ((event->event.eventType == ButtonPress) ? 1325 ButtonRelease : KeyRelease); 1326 if ((upEvent->event.eventType == ButtonRelease) 1327 && (upEvent->event.modifiers != AnyModifier) 1328 && (upEvent->event.modifiers | upEvent->event.modifierMask)) 1329 upEvent->event.modifiers = (upEvent->event.modifiers 1330 | (TMLongCard) buttonModifierMasks[event-> 1331 event. 1332 eventCode]); 1333 1334 if (event->event.lateModifiers) 1335 event->event.lateModifiers->ref_count = 1336 (unsigned short) (event->event.lateModifiers->ref_count + reps * 2 - 1337 1); 1338 1339 for (i = 0; i < reps; i++) { 1340 1341 if (i > 0) { 1342 /* down */ 1343 event->next = XtNew(EventSeqRec); 1344 event = event->next; 1345 *event = *downEvent; 1346 } 1347 lastDownEvent = event; 1348 1349 /* up */ 1350 event->next = XtNew(EventSeqRec); 1351 event = event->next; 1352 *event = *upEvent; 1353 1354 /* timer */ 1355 event->next = XtNew(EventSeqRec); 1356 event = event->next; 1357 *event = timerEventRec; 1358 1359 } 1360 1361 event->next = lastDownEvent; 1362 *eventP = event; 1363 *actionsP = &lastDownEvent->actions; 1364} 1365 1366static void 1367RepeatUp(EventPtr *eventP, int reps, ActionPtr **actionsP) 1368{ 1369 EventRec upEventRec; 1370 register EventPtr event, downEvent; 1371 EventPtr upEvent = &upEventRec; 1372 register int i; 1373 1374 /* the event currently sitting in *eventP is an "up" event */ 1375 /* we want to make it a "down" event followed by an "up" event, */ 1376 /* so that sequence matching on the "state" side works correctly. */ 1377 1378 downEvent = event = *eventP; 1379 *upEvent = *downEvent; 1380 downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ? 1381 ButtonPress : KeyPress); 1382 if ((downEvent->event.eventType == ButtonPress) 1383 && (downEvent->event.modifiers != AnyModifier) 1384 && (downEvent->event.modifiers | downEvent->event.modifierMask)) 1385 downEvent->event.modifiers = (downEvent->event.modifiers 1386 & 1387 (TMLongCard) (~buttonModifierMasks 1388 [event->event.eventCode])); 1389 1390 if (event->event.lateModifiers) 1391 event->event.lateModifiers->ref_count = 1392 (unsigned short) (event->event.lateModifiers->ref_count + reps * 2 - 1393 1); 1394 1395 /* up */ 1396 event->next = XtNew(EventSeqRec); 1397 event = event->next; 1398 *event = *upEvent; 1399 1400 for (i = 1; i < reps; i++) { 1401 1402 /* timer */ 1403 event->next = XtNew(EventSeqRec); 1404 event = event->next; 1405 *event = timerEventRec; 1406 1407 /* down */ 1408 event->next = XtNew(EventSeqRec); 1409 event = event->next; 1410 *event = *downEvent; 1411 1412 /* up */ 1413 event->next = XtNew(EventSeqRec); 1414 event = event->next; 1415 *event = *upEvent; 1416 1417 } 1418 1419 event->next = NULL; 1420 *eventP = event; 1421 *actionsP = &event->actions; 1422} 1423 1424static void 1425RepeatUpPlus(EventPtr *eventP, int reps, ActionPtr **actionsP) 1426{ 1427 EventRec upEventRec; 1428 register EventPtr event, downEvent, lastUpEvent = NULL; 1429 EventPtr upEvent = &upEventRec; 1430 register int i; 1431 1432 /* the event currently sitting in *eventP is an "up" event */ 1433 /* we want to make it a "down" event followed by an "up" event, */ 1434 /* so that sequence matching on the "state" side works correctly. */ 1435 1436 downEvent = event = *eventP; 1437 *upEvent = *downEvent; 1438 downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ? 1439 ButtonPress : KeyPress); 1440 if ((downEvent->event.eventType == ButtonPress) 1441 && (downEvent->event.modifiers != AnyModifier) 1442 && (downEvent->event.modifiers | downEvent->event.modifierMask)) 1443 downEvent->event.modifiers = (downEvent->event.modifiers 1444 & 1445 (TMLongCard) (~buttonModifierMasks 1446 [event->event.eventCode])); 1447 1448 if (event->event.lateModifiers) 1449 event->event.lateModifiers->ref_count = 1450 (unsigned short) (event->event.lateModifiers->ref_count + reps * 2); 1451 1452 for (i = 0; i < reps; i++) { 1453 1454 /* up */ 1455 event->next = XtNew(EventSeqRec); 1456 lastUpEvent = event = event->next; 1457 *event = *upEvent; 1458 1459 /* timer */ 1460 event->next = XtNew(EventSeqRec); 1461 event = event->next; 1462 *event = timerEventRec; 1463 1464 /* down */ 1465 event->next = XtNew(EventSeqRec); 1466 event = event->next; 1467 *event = *downEvent; 1468 1469 } 1470 1471 event->next = lastUpEvent; 1472 *eventP = event; 1473 *actionsP = &lastUpEvent->actions; 1474} 1475 1476static void 1477RepeatOther(EventPtr *eventP, int reps, ActionPtr **actionsP) 1478{ 1479 register EventPtr event, tempEvent; 1480 register int i; 1481 1482 tempEvent = event = *eventP; 1483 1484 if (event->event.lateModifiers) 1485 event->event.lateModifiers->ref_count = 1486 (unsigned short) (event->event.lateModifiers->ref_count + reps - 1); 1487 1488 for (i = 1; i < reps; i++) { 1489 event->next = XtNew(EventSeqRec); 1490 event = event->next; 1491 *event = *tempEvent; 1492 } 1493 1494 *eventP = event; 1495 *actionsP = &event->actions; 1496} 1497 1498static void 1499RepeatOtherPlus(EventPtr *eventP, int reps, ActionPtr **actionsP) 1500{ 1501 register EventPtr event, tempEvent; 1502 register int i; 1503 1504 tempEvent = event = *eventP; 1505 1506 if (event->event.lateModifiers) 1507 event->event.lateModifiers->ref_count = 1508 (unsigned short) (event->event.lateModifiers->ref_count + reps - 1); 1509 1510 for (i = 1; i < reps; i++) { 1511 event->next = XtNew(EventSeqRec); 1512 event = event->next; 1513 *event = *tempEvent; 1514 } 1515 1516 event->next = event; 1517 *eventP = event; 1518 *actionsP = &event->actions; 1519} 1520 1521static void 1522RepeatEvent(EventPtr *eventP, int reps, Boolean plus, ActionPtr **actionsP) 1523{ 1524 switch ((*eventP)->event.eventType) { 1525 1526 case ButtonPress: 1527 case KeyPress: 1528 if (plus) 1529 RepeatDownPlus(eventP, reps, actionsP); 1530 else 1531 RepeatDown(eventP, reps, actionsP); 1532 break; 1533 1534 case ButtonRelease: 1535 case KeyRelease: 1536 if (plus) 1537 RepeatUpPlus(eventP, reps, actionsP); 1538 else 1539 RepeatUp(eventP, reps, actionsP); 1540 break; 1541 1542 default: 1543 if (plus) 1544 RepeatOtherPlus(eventP, reps, actionsP); 1545 else 1546 RepeatOther(eventP, reps, actionsP); 1547 } 1548} 1549 1550static String 1551ParseRepeat(register String str, int *reps, Boolean *plus, Boolean *error) 1552{ 1553 1554 /*** Parse the repetitions, for double click etc... ***/ 1555 if (*str != '(' || 1556 !(isdigit((unsigned char) str[1]) || str[1] == '+' || str[1] == ')')) 1557 return str; 1558 str++; 1559 if (isdigit((unsigned char) *str)) { 1560 String start = str; 1561 char repStr[7]; 1562 size_t len; 1563 1564 ScanNumeric(str); 1565 len = (size_t) (str - start); 1566 if (len < sizeof repStr) { 1567 (void) memcpy(repStr, start, len); 1568 repStr[len] = '\0'; 1569 *reps = (int) StrToNum(repStr); 1570 } 1571 else { 1572 Syntax("Repeat count too large.", ""); 1573 *error = TRUE; 1574 return str; 1575 } 1576 } 1577 if (*reps == 0) { 1578 Syntax("Missing repeat count.", ""); 1579 *error = True; 1580 return str; 1581 } 1582 1583 if (*str == '+') { 1584 *plus = TRUE; 1585 str++; 1586 } 1587 if (*str == ')') 1588 str++; 1589 else { 1590 Syntax("Missing ')'.", ""); 1591 *error = TRUE; 1592 } 1593 1594 return str; 1595} 1596 1597/*********************************************************************** 1598 * ParseEventSeq 1599 * Parses the left hand side of a translation table production 1600 * up to, and consuming the ":". 1601 * Takes a pointer to a char* (where to start parsing) and returns an 1602 * event seq (in a passed in variable), having updated the String 1603 **********************************************************************/ 1604 1605static String 1606ParseEventSeq(register String str, 1607 EventSeqPtr *eventSeqP, 1608 ActionPtr ** actionsP, 1609 Boolean *error) 1610{ 1611 EventSeqPtr *nextEvent = eventSeqP; 1612 1613 *eventSeqP = NULL; 1614 1615 while (*str != '\0' && !IsNewline(*str)) { 1616 static Event nullEvent = 1617 { 0, 0, NULL, 0, 0L, 0L, _XtRegularMatch, FALSE }; 1618 EventPtr event; 1619 1620 ScanWhitespace(str); 1621 1622 if (*str == '"') { 1623 str++; 1624 while (*str != '"' && *str != '\0' && !IsNewline(*str)) { 1625 event = XtNew(EventRec); 1626 event->event = nullEvent; 1627 event->state = /* (StatePtr) -1 */ NULL; 1628 event->next = NULL; 1629 event->actions = NULL; 1630 str = ParseQuotedStringEvent(str, event, error); 1631 if (*error) { 1632 XtWarningMsg(XtNtranslationParseError, "nonLatin1", 1633 XtCXtToolkitError, 1634 "... probably due to non-Latin1 character in quoted string", 1635 (String *) NULL, (Cardinal *) NULL); 1636 XtFree((char *) event); 1637 return PanicModeRecovery(str); 1638 } 1639 *nextEvent = event; 1640 *actionsP = &event->actions; 1641 nextEvent = &event->next; 1642 } 1643 if (*str != '"') { 1644 Syntax("Missing '\"'.", ""); 1645 *error = TRUE; 1646 return PanicModeRecovery(str); 1647 } 1648 else 1649 str++; 1650 } 1651 else { 1652 int reps = 0; 1653 Boolean plus = FALSE; 1654 1655 event = XtNew(EventRec); 1656 event->event = nullEvent; 1657 event->state = /* (StatePtr) -1 */ NULL; 1658 event->next = NULL; 1659 event->actions = NULL; 1660 1661 str = ParseEvent(str, event, &reps, &plus, error); 1662 if (*error) 1663 return str; 1664 *nextEvent = event; 1665 *actionsP = &event->actions; 1666 if (reps > 1 || plus) 1667 RepeatEvent(&event, reps, plus, actionsP); 1668 nextEvent = &event->next; 1669 } 1670 ScanWhitespace(str); 1671 if (*str == ':') 1672 break; 1673 else { 1674 if (*str != ',') { 1675 Syntax("',' or ':' expected while parsing event sequence.", ""); 1676 *error = TRUE; 1677 return PanicModeRecovery(str); 1678 } 1679 else 1680 str++; 1681 } 1682 } 1683 1684 if (*str != ':') { 1685 Syntax("Missing ':'after event sequence.", ""); 1686 *error = TRUE; 1687 return PanicModeRecovery(str); 1688 } 1689 else 1690 str++; 1691 1692 return str; 1693} 1694 1695static String 1696ParseActionProc(register String str, XrmQuark *actionProcNameP, Boolean *error) 1697{ 1698 register String start = str; 1699 char procName[200]; 1700 1701 str = ScanIdent(str); 1702 if (str - start >= 199) { 1703 Syntax("Action procedure name is longer than 199 chars", ""); 1704 *error = TRUE; 1705 return str; 1706 } 1707 (void) memcpy(procName, start, (size_t) (str - start)); 1708 procName[str - start] = '\0'; 1709 *actionProcNameP = XrmStringToQuark(procName); 1710 return str; 1711} 1712 1713static String 1714ParseString(register String str, _XtString *strP) 1715{ 1716 register String start; 1717 1718 if (*str == '"') { 1719 register unsigned prev_len, len; 1720 1721 str++; 1722 start = str; 1723 *strP = NULL; 1724 prev_len = 0; 1725 1726 while (*str != '"' && *str != '\0') { 1727 /* \" produces double quote embedded in a quoted parameter 1728 * \\" produces backslash as last character of a quoted parameter 1729 */ 1730 if (*str == '\\' && 1731 (*(str + 1) == '"' || 1732 (*(str + 1) == '\\' && *(str + 2) == '"'))) { 1733 len = (unsigned) (prev_len + (str - start + 2)); 1734 *strP = XtRealloc(*strP, len); 1735 (void) memcpy(*strP + prev_len, start, (size_t) (str - start)); 1736 prev_len = len - 1; 1737 str++; 1738 (*strP)[prev_len - 1] = *str; 1739 (*strP)[prev_len] = '\0'; 1740 start = str + 1; 1741 } 1742 str++; 1743 } 1744 len = (unsigned) (prev_len + (str - start + 1)); 1745 *strP = XtRealloc(*strP, len); 1746 (void) memcpy(*strP + prev_len, start, (size_t) (str - start)); 1747 (*strP)[len - 1] = '\0'; 1748 if (*str == '"') 1749 str++; 1750 else 1751 XtWarningMsg(XtNtranslationParseError, "parseString", 1752 XtCXtToolkitError, "Missing '\"'.", 1753 (String *) NULL, (Cardinal *) NULL); 1754 } 1755 else { 1756 /* scan non-quoted string, stop on whitespace, ',' or ')' */ 1757 start = str; 1758 while (*str != ' ' 1759 && *str != '\t' && *str != ',' && *str != ')' && !IsNewline(*str) 1760 && *str != '\0') 1761 str++; 1762 *strP = __XtMalloc((unsigned) (str - start + 1)); 1763 (void) memcpy(*strP, start, (size_t) (str - start)); 1764 (*strP)[str - start] = '\0'; 1765 } 1766 return str; 1767} 1768 1769static String 1770ParseParamSeq(register String str, String **paramSeqP, Cardinal *paramNumP) 1771{ 1772 typedef struct _ParamRec *ParamPtr; 1773 typedef struct _ParamRec { 1774 ParamPtr next; 1775 String param; 1776 } ParamRec; 1777 1778 ParamPtr params = NULL; 1779 Cardinal num_params = 0; 1780 1781 ScanWhitespace(str); 1782 while (*str != ')' && *str != '\0' && !IsNewline(*str)) { 1783 _XtString newStr; 1784 1785 str = ParseString(str, &newStr); 1786 if (newStr != NULL) { 1787 ParamPtr temp = (ParamRec *) 1788 ALLOCATE_LOCAL((unsigned) sizeof(ParamRec)); 1789 1790 if (temp == NULL) 1791 _XtAllocError(NULL); 1792 1793 num_params++; 1794 temp->next = params; 1795 params = temp; 1796 temp->param = newStr; 1797 ScanWhitespace(str); 1798 if (*str == ',') { 1799 str++; 1800 ScanWhitespace(str); 1801 } 1802 } 1803 } 1804 1805 if (num_params != 0) { 1806 String *paramP = XtMallocArray(num_params + 1, (Cardinal)sizeof(String)); 1807 Cardinal i; 1808 1809 *paramSeqP = paramP; 1810 *paramNumP = num_params; 1811 paramP += num_params; /* list is LIFO right now */ 1812 *paramP-- = NULL; 1813 for (i = 0; i < num_params; i++) { 1814 ParamPtr next = params->next; 1815 1816 *paramP-- = params->param; 1817 DEALLOCATE_LOCAL((char *) params); 1818 params = next; 1819 } 1820 } 1821 else { 1822 *paramSeqP = NULL; 1823 *paramNumP = 0; 1824 } 1825 1826 return str; 1827} 1828 1829static String 1830ParseAction(String str, ActionPtr actionP, XrmQuark *quarkP, Boolean *error) 1831{ 1832 str = ParseActionProc(str, quarkP, error); 1833 if (*error) 1834 return str; 1835 1836 if (*str == '(') { 1837 str++; 1838 str = ParseParamSeq(str, &actionP->params, &actionP->num_params); 1839 } 1840 else { 1841 Syntax("Missing '(' while parsing action sequence", ""); 1842 *error = TRUE; 1843 return str; 1844 } 1845 if (*str == ')') 1846 str++; 1847 else { 1848 Syntax("Missing ')' while parsing action sequence", ""); 1849 *error = TRUE; 1850 return str; 1851 } 1852 return str; 1853} 1854 1855static String 1856ParseActionSeq(TMParseStateTree parseTree, 1857 String str, 1858 ActionPtr *actionsP, 1859 Boolean *error) 1860{ 1861 ActionPtr *nextActionP; 1862 1863 if ((nextActionP = actionsP) != NULL) 1864 *actionsP = NULL; 1865 1866 while (*str != '\0' && !IsNewline(*str)) { 1867 register ActionPtr action; 1868 XrmQuark quark = NULLQUARK; 1869 1870 action = XtNew(ActionRec); 1871 action->params = NULL; 1872 action->num_params = 0; 1873 action->next = NULL; 1874 1875 str = ParseAction(str, action, &quark, error); 1876 if (*error) { 1877 XtFree((char *) action); 1878 return PanicModeRecovery(str); 1879 } 1880 1881 action->idx = _XtGetQuarkIndex(parseTree, quark); 1882 ScanWhitespace(str); 1883 if (nextActionP) { 1884 *nextActionP = action; 1885 nextActionP = &action->next; 1886 } 1887 } 1888 if (IsNewline(*str)) 1889 str++; 1890 ScanWhitespace(str); 1891 return str; 1892} 1893 1894static void 1895ShowProduction(String currentProduction) 1896{ 1897 Cardinal num_params = 1; 1898 String params[1]; 1899 size_t len; 1900 char *eol, *production, productionbuf[500]; 1901 1902 eol = strchr(currentProduction, '\n'); 1903 if (eol) 1904 len = (size_t) (eol - currentProduction); 1905 else 1906 len = strlen(currentProduction); 1907 production = XtStackAlloc(len + 1, productionbuf); 1908 if (production == NULL) 1909 _XtAllocError(NULL); 1910 (void) memcpy(production, currentProduction, len); 1911 production[len] = '\0'; 1912 1913 params[0] = production; 1914 XtWarningMsg(XtNtranslationParseError, "showLine", XtCXtToolkitError, 1915 "... found while parsing '%s'", params, &num_params); 1916 1917 XtStackFree(production, productionbuf); 1918} 1919 1920/*********************************************************************** 1921 * ParseTranslationTableProduction 1922 * Parses one line of event bindings. 1923 ***********************************************************************/ 1924 1925static String 1926ParseTranslationTableProduction(TMParseStateTree parseTree, 1927 register String str, 1928 Boolean *error) 1929{ 1930 EventSeqPtr eventSeq = NULL; 1931 ActionPtr *actionsP; 1932 String production = str; 1933 1934 actionsP = NULL; 1935 str = ParseEventSeq(str, &eventSeq, &actionsP, error); 1936 if (*error == TRUE) { 1937 ShowProduction(production); 1938 } 1939 else { 1940 ScanWhitespace(str); 1941 str = ParseActionSeq(parseTree, str, actionsP, error); 1942 if (*error == TRUE) { 1943 ShowProduction(production); 1944 } 1945 else { 1946 _XtAddEventSeqToStateTree(eventSeq, parseTree); 1947 } 1948 } 1949 FreeEventSeq(eventSeq); 1950 return (str); 1951} 1952 1953static String 1954CheckForPoundSign(String str, 1955 _XtTranslateOp defaultOp, 1956 _XtTranslateOp *actualOpRtn) 1957{ 1958 _XtTranslateOp opType; 1959 1960 opType = defaultOp; 1961 ScanWhitespace(str); 1962 1963 if (*str == '#') { 1964 String start; 1965 char operation[20]; 1966 int len; 1967 1968 str++; 1969 start = str; 1970 str = ScanIdent(str); 1971 len = MIN(19, (int) (str - start)); 1972 (void) memcpy(operation, start, (size_t) len); 1973 operation[len] = '\0'; 1974 if (!strcmp(operation, "replace")) 1975 opType = XtTableReplace; 1976 else if (!strcmp(operation, "augment")) 1977 opType = XtTableAugment; 1978 else if (!strcmp(operation, "override")) 1979 opType = XtTableOverride; 1980 ScanWhitespace(str); 1981 if (IsNewline(*str)) { 1982 str++; 1983 ScanWhitespace(str); 1984 } 1985 } 1986 *actualOpRtn = opType; 1987 return str; 1988} 1989 1990static XtTranslations 1991ParseTranslationTable(String source, 1992 Boolean isAccelerator, 1993 _XtTranslateOp defaultOp, 1994 Boolean *error) 1995{ 1996 XtTranslations xlations; 1997 TMStateTree stateTrees[8]; 1998 TMParseStateTreeRec parseTreeRec, *parseTree = &parseTreeRec; 1999 XrmQuark stackQuarks[200]; 2000 TMBranchHeadRec stackBranchHeads[200]; 2001 StatePtr stackComplexBranchHeads[200]; 2002 _XtTranslateOp actualOp; 2003 2004 if (source == NULL) 2005 return (XtTranslations) NULL; 2006 2007 source = CheckForPoundSign(source, defaultOp, &actualOp); 2008 if (isAccelerator && actualOp == XtTableReplace) 2009 actualOp = defaultOp; 2010 2011 parseTree->isSimple = TRUE; 2012 parseTree->mappingNotifyInterest = FALSE; 2013 XtSetBit(parseTree->isAccelerator, isAccelerator); 2014 parseTree->isStackBranchHeads = 2015 parseTree->isStackQuarks = parseTree->isStackComplexBranchHeads = TRUE; 2016 2017 parseTree->numQuarks = 2018 parseTree->numBranchHeads = parseTree->numComplexBranchHeads = 0; 2019 2020 parseTree->quarkTblSize = 2021 parseTree->branchHeadTblSize = 2022 parseTree->complexBranchHeadTblSize = 200; 2023 2024 parseTree->quarkTbl = stackQuarks; 2025 parseTree->branchHeadTbl = stackBranchHeads; 2026 parseTree->complexBranchHeadTbl = stackComplexBranchHeads; 2027 2028 while (source != NULL && *source != '\0') { 2029 source = ParseTranslationTableProduction(parseTree, source, error); 2030 if (*error == TRUE) 2031 break; 2032 } 2033 stateTrees[0] = _XtParseTreeToStateTree(parseTree); 2034 2035 if (!parseTree->isStackQuarks) 2036 XtFree((char *) parseTree->quarkTbl); 2037 if (!parseTree->isStackBranchHeads) 2038 XtFree((char *) parseTree->branchHeadTbl); 2039 if (!parseTree->isStackComplexBranchHeads) 2040 XtFree((char *) parseTree->complexBranchHeadTbl); 2041 2042 xlations = _XtCreateXlations(stateTrees, 1, NULL, NULL); 2043 xlations->operation = (unsigned char) actualOp; 2044 2045#ifdef notdef 2046 XtFree(stateTrees); 2047#endif /* notdef */ 2048 return xlations; 2049} 2050 2051/*** public procedures ***/ 2052 2053Boolean 2054XtCvtStringToAcceleratorTable(Display *dpy, 2055 XrmValuePtr args _X_UNUSED, 2056 Cardinal *num_args, 2057 XrmValuePtr from, 2058 XrmValuePtr to, 2059 XtPointer *closure _X_UNUSED) 2060{ 2061 String str; 2062 Boolean error = FALSE; 2063 2064 if (*num_args != 0) 2065 XtAppWarningMsg(XtDisplayToApplicationContext(dpy), 2066 "wrongParameters", "cvtStringToAcceleratorTable", 2067 XtCXtToolkitError, 2068 "String to AcceleratorTable conversion needs no extra arguments", 2069 (String *) NULL, (Cardinal *) NULL); 2070 str = (String) (from->addr); 2071 if (str == NULL) { 2072 XtAppWarningMsg(XtDisplayToApplicationContext(dpy), 2073 "badParameters", "cvtStringToAcceleratorTable", 2074 XtCXtToolkitError, 2075 "String to AcceleratorTable conversion needs string", 2076 (String *) NULL, (Cardinal *) NULL); 2077 return FALSE; 2078 } 2079 if (to->addr != NULL) { 2080 if (to->size < sizeof(XtAccelerators)) { 2081 to->size = sizeof(XtAccelerators); 2082 return FALSE; 2083 } 2084 *(XtAccelerators *) to->addr = 2085 (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, 2086 &error); 2087 } 2088 else { 2089 static XtAccelerators staticStateTable; 2090 2091 staticStateTable = 2092 (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, 2093 &error); 2094 to->addr = (XPointer) &staticStateTable; 2095 to->size = sizeof(XtAccelerators); 2096 } 2097 if (error == TRUE) 2098 XtAppWarningMsg(XtDisplayToApplicationContext(dpy), 2099 "parseError", "cvtStringToAcceleratorTable", 2100 XtCXtToolkitError, 2101 "String to AcceleratorTable conversion encountered errors", 2102 (String *) NULL, (Cardinal *) NULL); 2103 return (error != TRUE); 2104} 2105 2106Boolean 2107XtCvtStringToTranslationTable(Display *dpy, 2108 XrmValuePtr args _X_UNUSED, 2109 Cardinal *num_args, 2110 XrmValuePtr from, 2111 XrmValuePtr to, 2112 XtPointer *closure_ret _X_UNUSED) 2113{ 2114 String str; 2115 Boolean error = FALSE; 2116 2117 if (*num_args != 0) 2118 XtAppWarningMsg(XtDisplayToApplicationContext(dpy), 2119 "wrongParameters", "cvtStringToTranslationTable", 2120 XtCXtToolkitError, 2121 "String to TranslationTable conversion needs no extra arguments", 2122 (String *) NULL, (Cardinal *) NULL); 2123 str = (String) (from->addr); 2124 if (str == NULL) { 2125 XtAppWarningMsg(XtDisplayToApplicationContext(dpy), 2126 "badParameters", "cvtStringToTranslation", 2127 XtCXtToolkitError, 2128 "String to TranslationTable conversion needs string", 2129 (String *) NULL, (Cardinal *) NULL); 2130 return FALSE; 2131 } 2132 if (to->addr != NULL) { 2133 if (to->size < sizeof(XtTranslations)) { 2134 to->size = sizeof(XtTranslations); 2135 return FALSE; 2136 } 2137 *(XtTranslations *) to->addr = 2138 ParseTranslationTable(str, FALSE, XtTableReplace, &error); 2139 } 2140 else { 2141 static XtTranslations staticStateTable; 2142 2143 staticStateTable = 2144 ParseTranslationTable(str, FALSE, XtTableReplace, &error); 2145 to->addr = (XPointer) &staticStateTable; 2146 to->size = sizeof(XtTranslations); 2147 } 2148 if (error == TRUE) 2149 XtAppWarningMsg(XtDisplayToApplicationContext(dpy), 2150 "parseError", "cvtStringToTranslationTable", 2151 XtCXtToolkitError, 2152 "String to TranslationTable conversion encountered errors", 2153 (String *) NULL, (Cardinal *) NULL); 2154 return (error != TRUE); 2155} 2156 2157/* 2158 * Parses a user's or applications translation table 2159 */ 2160XtAccelerators 2161XtParseAcceleratorTable(_Xconst char *source) 2162{ 2163 Boolean error = FALSE; 2164 XtAccelerators ret = 2165 (XtAccelerators) ParseTranslationTable(source, TRUE, XtTableAugment, 2166 &error); 2167 2168 if (error == TRUE) 2169 XtWarningMsg("parseError", "cvtStringToAcceleratorTable", 2170 XtCXtToolkitError, 2171 "String to AcceleratorTable conversion encountered errors", 2172 (String *) NULL, (Cardinal *) NULL); 2173 return ret; 2174} 2175 2176XtTranslations 2177XtParseTranslationTable(_Xconst char *source) 2178{ 2179 Boolean error = FALSE; 2180 XtTranslations ret = 2181 ParseTranslationTable(source, FALSE, XtTableReplace, &error); 2182 if (error == TRUE) 2183 XtWarningMsg("parseError", 2184 "cvtStringToTranslationTable", XtCXtToolkitError, 2185 "String to TranslationTable conversion encountered errors", 2186 (String *) NULL, (Cardinal *) NULL); 2187 return ret; 2188} 2189 2190void 2191_XtTranslateInitialize(void) 2192{ 2193 LOCK_PROCESS; 2194 if (initialized) { 2195 XtWarningMsg("translationError", "xtTranslateInitialize", 2196 XtCXtToolkitError, 2197 "Initializing Translation manager twice.", (String *) NULL, 2198 (Cardinal *) NULL); 2199 UNLOCK_PROCESS; 2200 return; 2201 } 2202 2203 initialized = TRUE; 2204 UNLOCK_PROCESS; 2205 QMeta = XrmPermStringToQuark("Meta"); 2206 QCtrl = XrmPermStringToQuark("Ctrl"); 2207 QNone = XrmPermStringToQuark("None"); 2208 QAny = XrmPermStringToQuark("Any"); 2209 2210 Compile_XtEventTable(events, XtNumber(events)); 2211 Compile_XtModifierTable(modifiers, XtNumber(modifiers)); 2212 CompileNameValueTable(notifyModes); 2213 CompileNameValueTable(motionDetails); 2214#if 0 2215 CompileNameValueTable(notifyDetail); 2216 CompileNameValueTable(visibilityNotify); 2217 CompileNameValueTable(circulation); 2218 CompileNameValueTable(propertyChanged); 2219#endif 2220 CompileNameValueTable(mappingNotify); 2221} 2222 2223void 2224_XtAddTMConverters(ConverterTable table) 2225{ 2226 _XtTableAddConverter(table, 2227 _XtQString, 2228 XrmPermStringToQuark(XtRTranslationTable), 2229 XtCvtStringToTranslationTable, (XtConvertArgList) NULL, 2230 (Cardinal) 0, True, CACHED, _XtFreeTranslations, True); 2231 _XtTableAddConverter(table, _XtQString, 2232 XrmPermStringToQuark(XtRAcceleratorTable), 2233 XtCvtStringToAcceleratorTable, (XtConvertArgList) NULL, 2234 (Cardinal) 0, True, CACHED, _XtFreeTranslations, True); 2235 _XtTableAddConverter(table, 2236 XrmPermStringToQuark(_XtRStateTablePair), 2237 XrmPermStringToQuark(XtRTranslationTable), 2238 _XtCvtMergeTranslations, (XtConvertArgList) NULL, 2239 (Cardinal) 0, True, CACHED, _XtFreeTranslations, True); 2240} 2241