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