Home | History | Annotate | Line # | Download | only in src
      1 /***********************************************************
      2 Copyright (c) 1993, Oracle and/or its affiliates.
      3 
      4 Permission is hereby granted, free of charge, to any person obtaining a
      5 copy of this software and associated documentation files (the "Software"),
      6 to deal in the Software without restriction, including without limitation
      7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 and/or sell copies of the Software, and to permit persons to whom the
      9 Software is furnished to do so, subject to the following conditions:
     10 
     11 The above copyright notice and this permission notice (including the next
     12 paragraph) shall be included in all copies or substantial portions of the
     13 Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21 DEALINGS IN THE SOFTWARE.
     22 
     23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
     24 
     25                         All Rights Reserved
     26 
     27 Permission to use, copy, modify, and distribute this software and its
     28 documentation for any purpose and without fee is hereby granted,
     29 provided that the above copyright notice appear in all copies and that
     30 both that copyright notice and this permission notice appear in
     31 supporting documentation, and that the name of Digital not be
     32 used in advertising or publicity pertaining to distribution of the
     33 software without specific, written prior permission.
     34 
     35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     41 SOFTWARE.
     42 
     43 ******************************************************************/
     44 
     45 /*
     46 
     47 Copyright 1987, 1988, 1998  The Open Group
     48 
     49 Permission to use, copy, modify, distribute, and sell this software and its
     50 documentation for any purpose is hereby granted without fee, provided that
     51 the above copyright notice appear in all copies and that both that
     52 copyright notice and this permission notice appear in supporting
     53 documentation.
     54 
     55 The above copyright notice and this permission notice shall be included in
     56 all copies or substantial portions of the Software.
     57 
     58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     64 
     65 Except as contained in this notice, the name of The Open Group shall not be
     66 used in advertising or otherwise to promote the sale, use or other dealings
     67 in 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 
    102 static _Xconst char *XtNtranslationParseError = "translationParseError";
    103 
    104 typedef int EventType;
    105 
    106 #define PARSE_PROC_DECL String, Opaque, EventPtr, Boolean*
    107 
    108 typedef String(*ParseProc) (String /* str; */ ,
    109                             Opaque /* closure; */ ,
    110                             EventPtr /* event; */ ,
    111                             Boolean * /* error */ );
    112 
    113 typedef TMShortCard Value;
    114 typedef void (*ModifierProc) (Value, LateBindingsPtr *, Boolean, Value *);
    115 
    116 typedef struct _ModifierRec {
    117     const char *name;
    118     XrmQuark signature;
    119     ModifierProc modifierParseProc;
    120     Value value;
    121 } ModifierRec, *ModifierKeys;
    122 
    123 typedef struct _EventKey {
    124     const char *event;
    125     XrmQuark signature;
    126     EventType eventType;
    127     ParseProc parseDetail;
    128     Opaque closure;
    129 } EventKey, *EventKeys;
    130 
    131 typedef struct {
    132     const char *name;
    133     XrmQuark signature;
    134     Value value;
    135 } NameValueRec, *NameValueTable;
    136 
    137 static void ParseModImmed(Value, LateBindingsPtr *, Boolean, Value *);
    138 static void ParseModSym(Value, LateBindingsPtr *, Boolean, Value *);
    139 static String PanicModeRecovery(String);
    140 static String CheckForPoundSign(String, _XtTranslateOp, _XtTranslateOp *);
    141 static KeySym StringToKeySym(String, Boolean *);
    142 /* *INDENT-OFF* */
    143 static 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 
    170 static NameValueRec motionDetails[] = {
    171     {"Normal",              0,         NotifyNormal},
    172     {"Hint",                0,         NotifyHint},
    173     {NULL,                  NULLQUARK, 0},
    174 };
    175 
    176 static 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
    185 static 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 
    197 static NameValueRec visibilityNotify[] = {
    198     {"Unobscured",          0,         VisibilityUnobscured},
    199     {"PartiallyObscured",   0,         VisibilityPartiallyObscured},
    200     {"FullyObscured",       0,         VisibilityFullyObscured},
    201     {NULL,                  NULLQUARK, 0},
    202 };
    203 
    204 static NameValueRec circulation[] = {
    205     {"OnTop",               0,         PlaceOnTop},
    206     {"OnBottom",            0,         PlaceOnBottom},
    207     {NULL,                  NULLQUARK, 0},
    208 };
    209 
    210 static NameValueRec propertyChanged[] = {
    211     {"NewValue",            0,         PropertyNewValue},
    212     {"Delete",              0,         PropertyDelete},
    213     {NULL,                  NULLQUARK, 0},
    214 };
    215 #endif /*0*/
    216 
    217 static NameValueRec mappingNotify[] = {
    218     {"Modifier",            0,         MappingModifier},
    219     {"Keyboard",            0,         MappingKeyboard},
    220     {"Pointer",             0,         MappingPointer},
    221     {NULL,                  NULLQUARK, 0},
    222 };
    223 /* *INDENT-ON* */
    224 
    225 static String ParseKeySym(PARSE_PROC_DECL);
    226 static String ParseKeyAndModifiers(PARSE_PROC_DECL);
    227 static String ParseTable(PARSE_PROC_DECL);
    228 static String ParseButton(PARSE_PROC_DECL);
    229 static String ParseImmed(PARSE_PROC_DECL);
    230 static String ParseAddModifier(PARSE_PROC_DECL);
    231 static String ParseNone(PARSE_PROC_DECL);
    232 static String ParseAtom(PARSE_PROC_DECL);
    233 
    234 /* *INDENT-OFF* */
    235 static 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 
    395 static Boolean initialized = FALSE;
    396 static XrmQuark QMeta;
    397 static XrmQuark QCtrl;
    398 static XrmQuark QNone;
    399 static XrmQuark QAny;
    400 
    401 static void
    402 FreeEventSeq(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 
    424 static void
    425 CompileNameValueTable(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 
    433 static int
    434 OrderEvents(_Xconst void *a, _Xconst void *b)
    435 {
    436     return ((((_Xconst EventKey *) a)->signature <
    437              ((_Xconst EventKey *) b)->signature) ? -1 : 1);
    438 }
    439 
    440 static void
    441 Compile_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 
    451 static int
    452 OrderModifiers(_Xconst void *a, _Xconst void *b)
    453 {
    454     return ((((_Xconst ModifierRec *) a)->signature <
    455              ((_Xconst ModifierRec *) b)->signature) ? -1 : 1);
    456 }
    457 
    458 static void
    459 Compile_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 
    469 static String
    470 PanicModeRecovery(String str)
    471 {
    472     ScanFor(str, '\n');
    473     if (*str == '\n')
    474         str++;
    475     return str;
    476 
    477 }
    478 
    479 static void
    480 Syntax(_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 
    491 static Cardinal
    492 LookupTMEventType(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 
    525 static void
    526 StoreLateBindings(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 
    576 static 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 
    592 static 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 
    637 static String
    638 ScanIdent(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 
    652 static String
    653 FetchModifierToken(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 
    683 static String
    684 ParseModifiers(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 
    771 static String
    772 ParseXtEventType(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 
    795 static unsigned long
    796 StrToHex(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 
    816 static unsigned long
    817 StrToOct(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 
    833 static unsigned long
    834 StrToNum(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 
    858 static KeySym
    859 StringToKeySym(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 
    893 static void
    894 ParseModImmed(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  */
    905 static void
    906 ParseModSym(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  */
    922 static 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 
    929 static String
    930 ParseImmed(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 
    941 static String
    942 ParseAddModifier(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 
    956 static String
    957 ParseKeyAndModifiers(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 
    976 static String
    977 ParseKeySym(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 
   1044 static String
   1045 ParseTable(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 
   1078 static String
   1079 ParseButton(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 
   1119 static String
   1120 ParseNone(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 
   1131 static String
   1132 ParseAtom(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 
   1163 static ModifierMask buttonModifierMasks[] = {
   1164     0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask
   1165 };
   1166 
   1167 static String ParseRepeat(String, int *, Boolean *, Boolean *);
   1168 
   1169 static String
   1170 ParseEvent(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 
   1224 static String
   1225 ParseQuotedStringEvent(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 
   1258 static EventSeqRec timerEventRec = {
   1259     {0, 0, NULL, _XtEventTimerEventType, 0L, 0L, NULL, False},
   1260     /* (StatePtr) -1 */ NULL,
   1261     NULL,
   1262     NULL
   1263 };
   1264 
   1265 static void
   1266 RepeatDown(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 
   1314 static void
   1315 RepeatDownPlus(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 
   1366 static void
   1367 RepeatUp(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 
   1424 static void
   1425 RepeatUpPlus(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 
   1476 static void
   1477 RepeatOther(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 
   1498 static void
   1499 RepeatOtherPlus(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 
   1521 static void
   1522 RepeatEvent(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 
   1550 static String
   1551 ParseRepeat(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 
   1605 static String
   1606 ParseEventSeq(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 
   1695 static String
   1696 ParseActionProc(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 
   1713 static String
   1714 ParseString(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 
   1769 static String
   1770 ParseParamSeq(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 
   1829 static String
   1830 ParseAction(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 
   1855 static String
   1856 ParseActionSeq(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 
   1894 static void
   1895 ShowProduction(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 
   1925 static String
   1926 ParseTranslationTableProduction(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 
   1953 static String
   1954 CheckForPoundSign(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 
   1990 static XtTranslations
   1991 ParseTranslationTable(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 
   2053 Boolean
   2054 XtCvtStringToAcceleratorTable(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 
   2106 Boolean
   2107 XtCvtStringToTranslationTable(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  */
   2160 XtAccelerators
   2161 XtParseAcceleratorTable(_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 
   2176 XtTranslations
   2177 XtParseTranslationTable(_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 
   2190 void
   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 
   2223 void
   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