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