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