TMparse.c revision 697b1baf
1444c061aSmrg/* $Xorg: TMparse.c,v 1.6 2001/02/09 02:03:58 xorgcvs Exp $ */
2444c061aSmrg
3444c061aSmrg/***********************************************************
4697b1bafSmrgCopyright 1993 Sun Microsystems, Inc.  All rights reserved.
5697b1bafSmrg
6697b1bafSmrgPermission is hereby granted, free of charge, to any person obtaining a
7697b1bafSmrgcopy of this software and associated documentation files (the "Software"),
8697b1bafSmrgto deal in the Software without restriction, including without limitation
9697b1bafSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
10697b1bafSmrgand/or sell copies of the Software, and to permit persons to whom the
11697b1bafSmrgSoftware is furnished to do so, subject to the following conditions:
12697b1bafSmrg
13697b1bafSmrgThe above copyright notice and this permission notice (including the next
14697b1bafSmrgparagraph) shall be included in all copies or substantial portions of the
15697b1bafSmrgSoftware.
16697b1bafSmrg
17697b1bafSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18697b1bafSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19697b1bafSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20697b1bafSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21697b1bafSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22697b1bafSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23697b1bafSmrgDEALINGS IN THE SOFTWARE.
24697b1bafSmrg
25697b1bafSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
26444c061aSmrg
27444c061aSmrg                        All Rights Reserved
28444c061aSmrg
29444c061aSmrgPermission to use, copy, modify, and distribute this software and its
30444c061aSmrgdocumentation for any purpose and without fee is hereby granted,
31444c061aSmrgprovided that the above copyright notice appear in all copies and that
32444c061aSmrgboth that copyright notice and this permission notice appear in
33697b1bafSmrgsupporting documentation, and that the name of Digital not be
34444c061aSmrgused in advertising or publicity pertaining to distribution of the
35444c061aSmrgsoftware without specific, written prior permission.
36444c061aSmrg
37444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43444c061aSmrgSOFTWARE.
44444c061aSmrg
45444c061aSmrg******************************************************************/
46444c061aSmrg/* $XFree86: xc/lib/Xt/TMparse.c,v 3.10tsi Exp $ */
47444c061aSmrg
48444c061aSmrg/*
49444c061aSmrg
50444c061aSmrgCopyright 1987, 1988, 1998  The Open Group
51444c061aSmrg
52444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
53444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
54444c061aSmrgthe above copyright notice appear in all copies and that both that
55444c061aSmrgcopyright notice and this permission notice appear in supporting
56444c061aSmrgdocumentation.
57444c061aSmrg
58444c061aSmrgThe above copyright notice and this permission notice shall be included in
59444c061aSmrgall copies or substantial portions of the Software.
60444c061aSmrg
61444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
64444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
65444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
66444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
67444c061aSmrg
68444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
69444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
70444c061aSmrgin this Software without prior written authorization from The Open Group.
71444c061aSmrg
72444c061aSmrg*/
73444c061aSmrg
74444c061aSmrg#ifdef HAVE_CONFIG_H
75444c061aSmrg#include <config.h>
76444c061aSmrg#endif
77444c061aSmrg#include "IntrinsicI.h"
78444c061aSmrg#include "StringDefs.h"
79444c061aSmrg#include <ctype.h>
80444c061aSmrg#include <stdlib.h>
81444c061aSmrg#ifndef NOTASCII
82444c061aSmrg#define XK_LATIN1
83444c061aSmrg#endif
84444c061aSmrg#define XK_MISCELLANY
85444c061aSmrg#include <X11/keysymdef.h>
86444c061aSmrg
87444c061aSmrg#ifdef CACHE_TRANSLATIONS
88444c061aSmrg# ifdef REFCNT_TRANSLATIONS
89444c061aSmrg#  define CACHED XtCacheAll | XtCacheRefCount
90444c061aSmrg# else
91444c061aSmrg#  define CACHED XtCacheAll
92444c061aSmrg# endif
93444c061aSmrg#else
94444c061aSmrg# define CACHED XtCacheNone
95444c061aSmrg#endif
96444c061aSmrg
97444c061aSmrg#ifndef MAX
98444c061aSmrg#define MAX(a,b) (((a) > (b)) ? (a) : (b))
99444c061aSmrg#endif
100444c061aSmrg
101444c061aSmrg#ifndef MIN
102444c061aSmrg#define MIN(a,b) (((a) < (b)) ? (a) : (b))
103444c061aSmrg#endif
104444c061aSmrg
105444c061aSmrgstatic String XtNtranslationParseError = "translationParseError";
106444c061aSmrg
107444c061aSmrgtypedef int		EventType;
108444c061aSmrg
109444c061aSmrgtypedef String (*ParseProc)(
110444c061aSmrg    String /* str; */,
111444c061aSmrg    Opaque /* closure; */,
112444c061aSmrg    EventPtr /* event; */,
113444c061aSmrg    Boolean* /* error */);
114444c061aSmrg
115444c061aSmrgtypedef TMShortCard	Value;
116444c061aSmrgtypedef void (*ModifierProc)(Value, LateBindingsPtr*, Boolean, Value*);
117444c061aSmrg
118444c061aSmrgtypedef struct _ModifierRec {
119444c061aSmrg    char*      name;
120444c061aSmrg    XrmQuark   signature;
121444c061aSmrg    ModifierProc modifierParseProc;
122444c061aSmrg    Value      value;
123444c061aSmrg} ModifierRec, *ModifierKeys;
124444c061aSmrg
125444c061aSmrgtypedef struct _EventKey {
126444c061aSmrg    char    	*event;
127444c061aSmrg    XrmQuark	signature;
128444c061aSmrg    EventType	eventType;
129444c061aSmrg    ParseProc	parseDetail;
130444c061aSmrg    Opaque	closure;
131444c061aSmrg}EventKey, *EventKeys;
132444c061aSmrg
133444c061aSmrgtypedef struct {
134444c061aSmrg    char	*name;
135444c061aSmrg    XrmQuark	signature;
136444c061aSmrg    Value	value;
137444c061aSmrg} NameValueRec, *NameValueTable;
138444c061aSmrg
139444c061aSmrgstatic void ParseModImmed(Value, LateBindingsPtr*, Boolean, Value*);
140444c061aSmrgstatic void ParseModSym(Value, LateBindingsPtr*, Boolean, Value*);
141444c061aSmrgstatic String PanicModeRecovery(String);
142444c061aSmrgstatic String CheckForPoundSign(String, _XtTranslateOp, _XtTranslateOp *);
143444c061aSmrgstatic KeySym StringToKeySym(String, Boolean *);
144444c061aSmrgstatic ModifierRec modifiers[] = {
145444c061aSmrg    {"Shift",	0,	ParseModImmed,ShiftMask},
146444c061aSmrg    {"Lock",	0,	ParseModImmed,LockMask},
147444c061aSmrg    {"Ctrl",	0,	ParseModImmed,ControlMask},
148444c061aSmrg    {"Mod1",	0,	ParseModImmed,Mod1Mask},
149444c061aSmrg    {"Mod2",	0,	ParseModImmed,Mod2Mask},
150444c061aSmrg    {"Mod3",	0,	ParseModImmed,Mod3Mask},
151444c061aSmrg    {"Mod4",	0,	ParseModImmed,Mod4Mask},
152444c061aSmrg    {"Mod5",	0,	ParseModImmed,Mod5Mask},
153444c061aSmrg    {"Meta",	0,	ParseModSym,  XK_Meta_L},
154444c061aSmrg    {"m",       0,      ParseModSym,  XK_Meta_L},
155444c061aSmrg    {"h",       0,      ParseModSym,  XK_Hyper_L},
156444c061aSmrg    {"su",      0,      ParseModSym,  XK_Super_L},
157444c061aSmrg    {"a",       0,      ParseModSym,  XK_Alt_L},
158444c061aSmrg    {"Hyper",   0,      ParseModSym,  XK_Hyper_L},
159444c061aSmrg    {"Super",   0,      ParseModSym,  XK_Super_L},
160444c061aSmrg    {"Alt",     0,      ParseModSym,  XK_Alt_L},
161444c061aSmrg    {"Button1",	0,	ParseModImmed,Button1Mask},
162444c061aSmrg    {"Button2",	0,	ParseModImmed,Button2Mask},
163444c061aSmrg    {"Button3",	0,	ParseModImmed,Button3Mask},
164444c061aSmrg    {"Button4",	0,	ParseModImmed,Button4Mask},
165444c061aSmrg    {"Button5",	0,	ParseModImmed,Button5Mask},
166444c061aSmrg    {"c",	0,	ParseModImmed,ControlMask},
167444c061aSmrg    {"s",	0,	ParseModImmed,ShiftMask},
168444c061aSmrg    {"l",	0,	ParseModImmed,LockMask},
169444c061aSmrg};
170444c061aSmrg
171444c061aSmrgstatic NameValueRec buttonNames[] = {
172444c061aSmrg    {"Button1",	0,	Button1},
173444c061aSmrg    {"Button2", 0,	Button2},
174444c061aSmrg    {"Button3", 0,	Button3},
175444c061aSmrg    {"Button4", 0,	Button4},
176444c061aSmrg    {"Button5", 0,	Button5},
177444c061aSmrg    {NULL, NULLQUARK, 0},
178444c061aSmrg};
179444c061aSmrg
180444c061aSmrgstatic NameValueRec motionDetails[] = {
181444c061aSmrg    {"Normal",		0,	NotifyNormal},
182444c061aSmrg    {"Hint",		0,	NotifyHint},
183444c061aSmrg    {NULL, NULLQUARK, 0},
184444c061aSmrg};
185444c061aSmrg
186444c061aSmrgstatic NameValueRec notifyModes[] = {
187444c061aSmrg    {"Normal",		0,	NotifyNormal},
188444c061aSmrg    {"Grab",		0,	NotifyGrab},
189444c061aSmrg    {"Ungrab",		0,	NotifyUngrab},
190444c061aSmrg    {"WhileGrabbed",    0,	NotifyWhileGrabbed},
191444c061aSmrg    {NULL, NULLQUARK, 0},
192444c061aSmrg};
193444c061aSmrg
194444c061aSmrg#if 0
195444c061aSmrgstatic NameValueRec notifyDetail[] = {
196444c061aSmrg    {"Ancestor",	    0,	NotifyAncestor},
197444c061aSmrg    {"Virtual",		    0,	NotifyVirtual},
198444c061aSmrg    {"Inferior",	    0,	NotifyInferior},
199444c061aSmrg    {"Nonlinear",	    0,	NotifyNonlinear},
200444c061aSmrg    {"NonlinearVirtual",    0,	NotifyNonlinearVirtual},
201444c061aSmrg    {"Pointer",		    0,	NotifyPointer},
202444c061aSmrg    {"PointerRoot",	    0,	NotifyPointerRoot},
203444c061aSmrg    {"DetailNone",	    0,	NotifyDetailNone},
204444c061aSmrg    {NULL, NULLQUARK, 0},
205444c061aSmrg};
206444c061aSmrg
207444c061aSmrgstatic NameValueRec visibilityNotify[] = {
208444c061aSmrg    {"Unobscured",	    0,	VisibilityUnobscured},
209444c061aSmrg    {"PartiallyObscured",   0,	VisibilityPartiallyObscured},
210444c061aSmrg    {"FullyObscured",       0,	VisibilityFullyObscured},
211444c061aSmrg    {NULL, NULLQUARK, 0},
212444c061aSmrg};
213444c061aSmrg
214444c061aSmrgstatic NameValueRec circulation[] = {
215444c061aSmrg    {"OnTop",       0,	PlaceOnTop},
216444c061aSmrg    {"OnBottom",    0,	PlaceOnBottom},
217444c061aSmrg    {NULL, NULLQUARK, 0},
218444c061aSmrg};
219444c061aSmrg
220444c061aSmrgstatic NameValueRec propertyChanged[] = {
221444c061aSmrg    {"NewValue",    0,	PropertyNewValue},
222444c061aSmrg    {"Delete",      0,	PropertyDelete},
223444c061aSmrg    {NULL, NULLQUARK, 0},
224444c061aSmrg};
225444c061aSmrg#endif /*0*/
226444c061aSmrg
227444c061aSmrgstatic NameValueRec mappingNotify[] = {
228444c061aSmrg    {"Modifier",	0,	MappingModifier},
229444c061aSmrg    {"Keyboard",	0,	MappingKeyboard},
230444c061aSmrg    {"Pointer",	0,	MappingPointer},
231444c061aSmrg    {NULL, NULLQUARK, 0},
232444c061aSmrg};
233444c061aSmrg
234444c061aSmrgstatic String ParseKeySym(String, Opaque, EventPtr, Boolean*);
235444c061aSmrgstatic String ParseKeyAndModifiers(String, Opaque, EventPtr, Boolean*);
236444c061aSmrgstatic String ParseTable(String, Opaque, EventPtr, Boolean*);
237444c061aSmrgstatic String ParseImmed(String, Opaque, EventPtr, Boolean*);
238444c061aSmrgstatic String ParseAddModifier(String, Opaque, EventPtr, Boolean*);
239444c061aSmrgstatic String ParseNone(String, Opaque, EventPtr, Boolean*);
240444c061aSmrgstatic String ParseAtom(String, Opaque, EventPtr, Boolean*);
241444c061aSmrg
242444c061aSmrgstatic EventKey events[] = {
243444c061aSmrg
244444c061aSmrg/* Event Name,	  Quark, Event Type,	Detail Parser, Closure */
245444c061aSmrg
246444c061aSmrg{"KeyPress",	    NULLQUARK, KeyPress,	ParseKeySym,	NULL},
247444c061aSmrg{"Key", 	    NULLQUARK, KeyPress,	ParseKeySym,	NULL},
248444c061aSmrg{"KeyDown",	    NULLQUARK, KeyPress,	ParseKeySym,	NULL},
249444c061aSmrg{"Ctrl",            NULLQUARK, KeyPress, ParseKeyAndModifiers,(Opaque)ControlMask},
250444c061aSmrg{"Shift",           NULLQUARK, KeyPress, ParseKeyAndModifiers,(Opaque)ShiftMask},
251444c061aSmrg{"Meta",            NULLQUARK, KeyPress,   ParseKeyAndModifiers,(Opaque)NULL},
252444c061aSmrg{"KeyUp",	    NULLQUARK, KeyRelease,	ParseKeySym,	NULL},
253444c061aSmrg{"KeyRelease",	    NULLQUARK, KeyRelease,	ParseKeySym,	NULL},
254444c061aSmrg
255444c061aSmrg{"ButtonPress",     NULLQUARK, ButtonPress,  ParseTable,(Opaque)buttonNames},
256444c061aSmrg{"BtnDown",	    NULLQUARK, ButtonPress,  ParseTable,(Opaque)buttonNames},
257444c061aSmrg{"Btn1Down",	    NULLQUARK, ButtonPress,	ParseImmed,(Opaque)Button1},
258444c061aSmrg{"Btn2Down", 	    NULLQUARK, ButtonPress,	ParseImmed,(Opaque)Button2},
259444c061aSmrg{"Btn3Down", 	    NULLQUARK, ButtonPress,	ParseImmed,(Opaque)Button3},
260444c061aSmrg{"Btn4Down", 	    NULLQUARK, ButtonPress,	ParseImmed,(Opaque)Button4},
261444c061aSmrg{"Btn5Down", 	    NULLQUARK, ButtonPress,	ParseImmed,(Opaque)Button5},
262444c061aSmrg
263444c061aSmrg/* Event Name,	  Quark, Event Type,	Detail Parser, Closure */
264444c061aSmrg
265444c061aSmrg{"ButtonRelease",   NULLQUARK, ButtonRelease,  ParseTable,(Opaque)buttonNames},
266444c061aSmrg{"BtnUp", 	    NULLQUARK, ButtonRelease,  ParseTable,(Opaque)buttonNames},
267444c061aSmrg{"Btn1Up", 	    NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button1},
268444c061aSmrg{"Btn2Up", 	    NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button2},
269444c061aSmrg{"Btn3Up", 	    NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button3},
270444c061aSmrg{"Btn4Up", 	    NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button4},
271444c061aSmrg{"Btn5Up", 	    NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button5},
272444c061aSmrg
273444c061aSmrg{"MotionNotify",    NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails},
274444c061aSmrg{"PtrMoved", 	    NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails},
275444c061aSmrg{"Motion", 	    NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails},
276444c061aSmrg{"MouseMoved", 	    NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails},
277444c061aSmrg{"BtnMotion",  NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)AnyButtonMask},
278444c061aSmrg{"Btn1Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button1Mask},
279444c061aSmrg{"Btn2Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button2Mask},
280444c061aSmrg{"Btn3Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button3Mask},
281444c061aSmrg{"Btn4Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button4Mask},
282444c061aSmrg{"Btn5Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button5Mask},
283444c061aSmrg
284444c061aSmrg{"EnterNotify",     NULLQUARK, EnterNotify,    ParseTable,(Opaque)notifyModes},
285444c061aSmrg{"Enter",	    NULLQUARK, EnterNotify,    ParseTable,(Opaque)notifyModes},
286444c061aSmrg{"EnterWindow",     NULLQUARK, EnterNotify,    ParseTable,(Opaque)notifyModes},
287444c061aSmrg
288444c061aSmrg{"LeaveNotify",     NULLQUARK, LeaveNotify,    ParseTable,(Opaque)notifyModes},
289444c061aSmrg{"LeaveWindow",     NULLQUARK, LeaveNotify,    ParseTable,(Opaque)notifyModes},
290444c061aSmrg{"Leave",	    NULLQUARK, LeaveNotify,    ParseTable,(Opaque)notifyModes},
291444c061aSmrg
292444c061aSmrg/* Event Name,	  Quark, Event Type,	Detail Parser, Closure */
293444c061aSmrg
294444c061aSmrg{"FocusIn",	    NULLQUARK, FocusIn,	  ParseTable,(Opaque)notifyModes},
295444c061aSmrg
296444c061aSmrg{"FocusOut",	    NULLQUARK, FocusOut,       ParseTable,(Opaque)notifyModes},
297444c061aSmrg
298444c061aSmrg{"KeymapNotify",    NULLQUARK, KeymapNotify,	ParseNone,	NULL},
299444c061aSmrg{"Keymap",	    NULLQUARK, KeymapNotify,	ParseNone,	NULL},
300444c061aSmrg
301444c061aSmrg{"Expose", 	    NULLQUARK, Expose,		ParseNone,	NULL},
302444c061aSmrg
303444c061aSmrg{"GraphicsExpose",  NULLQUARK, GraphicsExpose,	ParseNone,	NULL},
304444c061aSmrg{"GrExp",	    NULLQUARK, GraphicsExpose,	ParseNone,	NULL},
305444c061aSmrg
306444c061aSmrg{"NoExpose",	    NULLQUARK, NoExpose,	ParseNone,	NULL},
307444c061aSmrg{"NoExp",	    NULLQUARK, NoExpose,	ParseNone,	NULL},
308444c061aSmrg
309444c061aSmrg{"VisibilityNotify",NULLQUARK, VisibilityNotify,ParseNone,	NULL},
310444c061aSmrg{"Visible",	    NULLQUARK, VisibilityNotify,ParseNone,	NULL},
311444c061aSmrg
312444c061aSmrg{"CreateNotify",    NULLQUARK, CreateNotify,	ParseNone,	NULL},
313444c061aSmrg{"Create",	    NULLQUARK, CreateNotify,	ParseNone,	NULL},
314444c061aSmrg
315444c061aSmrg/* Event Name,	  Quark, Event Type,	Detail Parser, Closure */
316444c061aSmrg
317444c061aSmrg{"DestroyNotify",   NULLQUARK, DestroyNotify,	ParseNone,	NULL},
318444c061aSmrg{"Destroy",	    NULLQUARK, DestroyNotify,	ParseNone,	NULL},
319444c061aSmrg
320444c061aSmrg{"UnmapNotify",     NULLQUARK, UnmapNotify,	ParseNone,	NULL},
321444c061aSmrg{"Unmap",	    NULLQUARK, UnmapNotify,	ParseNone,	NULL},
322444c061aSmrg
323444c061aSmrg{"MapNotify",	    NULLQUARK, MapNotify,	ParseNone,	NULL},
324444c061aSmrg{"Map",		    NULLQUARK, MapNotify,	ParseNone,	NULL},
325444c061aSmrg
326444c061aSmrg{"MapRequest",	    NULLQUARK, MapRequest,	ParseNone,	NULL},
327444c061aSmrg{"MapReq",	    NULLQUARK, MapRequest,	ParseNone,	NULL},
328444c061aSmrg
329444c061aSmrg{"ReparentNotify",  NULLQUARK, ReparentNotify,	ParseNone,	NULL},
330444c061aSmrg{"Reparent",	    NULLQUARK, ReparentNotify,	ParseNone,	NULL},
331444c061aSmrg
332444c061aSmrg{"ConfigureNotify", NULLQUARK, ConfigureNotify,	ParseNone,	NULL},
333444c061aSmrg{"Configure",	    NULLQUARK, ConfigureNotify,	ParseNone,	NULL},
334444c061aSmrg
335444c061aSmrg{"ConfigureRequest",NULLQUARK, ConfigureRequest,ParseNone,	NULL},
336444c061aSmrg{"ConfigureReq",    NULLQUARK, ConfigureRequest,ParseNone,	NULL},
337444c061aSmrg
338444c061aSmrg/* Event Name,	  Quark, Event Type,	Detail Parser, Closure */
339444c061aSmrg
340444c061aSmrg{"GravityNotify",   NULLQUARK, GravityNotify,	ParseNone,	NULL},
341444c061aSmrg{"Grav",	    NULLQUARK, GravityNotify,	ParseNone,	NULL},
342444c061aSmrg
343444c061aSmrg{"ResizeRequest",   NULLQUARK, ResizeRequest,	ParseNone,	NULL},
344444c061aSmrg{"ResReq",	    NULLQUARK, ResizeRequest,	ParseNone,	NULL},
345444c061aSmrg
346444c061aSmrg{"CirculateNotify", NULLQUARK, CirculateNotify,	ParseNone,	NULL},
347444c061aSmrg{"Circ",	    NULLQUARK, CirculateNotify,	ParseNone,	NULL},
348444c061aSmrg
349444c061aSmrg{"CirculateRequest",NULLQUARK, CirculateRequest,ParseNone,	NULL},
350444c061aSmrg{"CircReq",	    NULLQUARK, CirculateRequest,ParseNone,	NULL},
351444c061aSmrg
352444c061aSmrg{"PropertyNotify",  NULLQUARK, PropertyNotify,	ParseAtom,	NULL},
353444c061aSmrg{"Prop",	    NULLQUARK, PropertyNotify,	ParseAtom,	NULL},
354444c061aSmrg
355444c061aSmrg{"SelectionClear",  NULLQUARK, SelectionClear,	ParseAtom,	NULL},
356444c061aSmrg{"SelClr",	    NULLQUARK, SelectionClear,	ParseAtom,	NULL},
357444c061aSmrg
358444c061aSmrg{"SelectionRequest",NULLQUARK, SelectionRequest,ParseAtom,	NULL},
359444c061aSmrg{"SelReq",	    NULLQUARK, SelectionRequest,ParseAtom,	NULL},
360444c061aSmrg
361444c061aSmrg/* Event Name,	  Quark, Event Type,	Detail Parser, Closure */
362444c061aSmrg
363444c061aSmrg{"SelectionNotify", NULLQUARK, SelectionNotify,	ParseAtom,	NULL},
364444c061aSmrg{"Select",	    NULLQUARK, SelectionNotify,	ParseAtom,	NULL},
365444c061aSmrg
366444c061aSmrg{"ColormapNotify",  NULLQUARK, ColormapNotify,	ParseNone,	NULL},
367444c061aSmrg{"Clrmap",	    NULLQUARK, ColormapNotify,	ParseNone,	NULL},
368444c061aSmrg
369444c061aSmrg{"ClientMessage",   NULLQUARK, ClientMessage,	ParseAtom,	NULL},
370444c061aSmrg{"Message",	    NULLQUARK, ClientMessage,	ParseAtom,	NULL},
371444c061aSmrg
372444c061aSmrg{"MappingNotify",   NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify},
373444c061aSmrg{"Mapping",	    NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify},
374444c061aSmrg
375444c061aSmrg#ifdef DEBUG
376444c061aSmrg# ifdef notdef
377444c061aSmrg{"Timer",	    NULLQUARK, _XtTimerEventType,ParseNone,	NULL},
378444c061aSmrg{"EventTimer",	    NULLQUARK, _XtEventTimerEventType,ParseNone,NULL},
3791bd39548Schristos# endif /* notdef */
380444c061aSmrg#endif /* DEBUG */
381444c061aSmrg
382444c061aSmrg/* Event Name,	  Quark, Event Type,	Detail Parser, Closure */
383444c061aSmrg
384444c061aSmrg};
385444c061aSmrg
386444c061aSmrg#ifndef __UNIXOS2__
387444c061aSmrg#define IsNewline(str) ((str) == '\n')
388444c061aSmrg#else
389444c061aSmrg#define IsNewline(str) ((str) == '\n' || (str) == '\r')
390444c061aSmrg#endif
391444c061aSmrg
392444c061aSmrg#define ScanFor(str, ch) \
393444c061aSmrg    while ((*(str) != (ch)) && (*(str) != '\0') && !IsNewline(*(str))) (str)++
394444c061aSmrg
395444c061aSmrg#define ScanNumeric(str)  while ('0' <= *(str) && *(str) <= '9') (str)++
396444c061aSmrg
397444c061aSmrg#define ScanAlphanumeric(str) \
398444c061aSmrg    while (('A' <= *(str) && *(str) <= 'Z') || \
399444c061aSmrg           ('a' <= *(str) && *(str) <= 'z') || \
400444c061aSmrg           ('0' <= *(str) && *(str) <= '9')) (str)++
401444c061aSmrg
402444c061aSmrg#ifndef __UNIXOS2__
403444c061aSmrg#define ScanWhitespace(str) \
404444c061aSmrg    while (*(str) == ' ' || *(str) == '\t') (str)++
405444c061aSmrg#else
406444c061aSmrg#define ScanWhitespace(str) \
407444c061aSmrg    while (*(str) == ' ' || *(str) == '\t' || *(str) == '\r') (str)++
408444c061aSmrg#endif
409444c061aSmrg
410444c061aSmrgstatic Boolean initialized = FALSE;
411444c061aSmrgstatic XrmQuark QMeta;
412444c061aSmrgstatic XrmQuark QCtrl;
413444c061aSmrgstatic XrmQuark QNone;
414444c061aSmrgstatic XrmQuark QAny;
415444c061aSmrg
416444c061aSmrgstatic void FreeEventSeq(
417444c061aSmrg    EventSeqPtr eventSeq)
418444c061aSmrg{
419444c061aSmrg    register EventSeqPtr evs = eventSeq;
420444c061aSmrg
421444c061aSmrg    while (evs != NULL) {
422444c061aSmrg	evs->state = (StatePtr) evs;
423444c061aSmrg	if (evs->next != NULL
424444c061aSmrg	    && evs->next->state == (StatePtr) evs->next)
425444c061aSmrg	    evs->next = NULL;
426444c061aSmrg	evs = evs->next;
427444c061aSmrg    }
428444c061aSmrg
429444c061aSmrg    evs = eventSeq;
430444c061aSmrg    while (evs != NULL) {
431444c061aSmrg	register EventPtr event = evs;
432444c061aSmrg	evs = evs->next;
433444c061aSmrg	if (evs == event) evs = NULL;
434444c061aSmrg	XtFree((char *)event);
435444c061aSmrg    }
436444c061aSmrg}
437444c061aSmrg
438444c061aSmrgstatic void CompileNameValueTable(
439444c061aSmrg    NameValueTable table)
440444c061aSmrg{
441444c061aSmrg    register int i;
442444c061aSmrg
443444c061aSmrg    for (i=0; table[i].name; i++)
444444c061aSmrg        table[i].signature = XrmPermStringToQuark(table[i].name);
445444c061aSmrg}
446444c061aSmrg
447444c061aSmrgstatic int OrderEvents(_Xconst void *a, _Xconst void *b)
448444c061aSmrg{
449444c061aSmrg    return ((((_Xconst EventKey *)a)->signature <
450444c061aSmrg	     ((_Xconst EventKey *)b)->signature) ? -1 : 1);
451444c061aSmrg}
452444c061aSmrg
453444c061aSmrgstatic void Compile_XtEventTable(
454444c061aSmrg    EventKeys	table,
455444c061aSmrg    Cardinal	count)
456444c061aSmrg{
457444c061aSmrg    register int i;
458444c061aSmrg    register EventKeys entry = table;
459444c061aSmrg
460444c061aSmrg    for (i=count; --i >= 0; entry++)
461444c061aSmrg	entry->signature = XrmPermStringToQuark(entry->event);
462444c061aSmrg    qsort(table, count, sizeof(EventKey), OrderEvents);
463444c061aSmrg}
464444c061aSmrg
465444c061aSmrgstatic int OrderModifiers(_Xconst void *a, _Xconst void *b)
466444c061aSmrg{
467444c061aSmrg    return ((((_Xconst ModifierRec *)a)->signature <
468444c061aSmrg	     ((_Xconst ModifierRec *)b)->signature) ? -1 : 1);
469444c061aSmrg}
470444c061aSmrg
471444c061aSmrgstatic void Compile_XtModifierTable(
472444c061aSmrg    ModifierKeys table,
473444c061aSmrg    Cardinal count)
474444c061aSmrg{
475444c061aSmrg    register int i;
476444c061aSmrg    register ModifierKeys entry = table;
477444c061aSmrg
478444c061aSmrg    for (i=count; --i >= 0; entry++)
479444c061aSmrg	entry->signature = XrmPermStringToQuark(entry->name);
480444c061aSmrg    qsort(table, count, sizeof(ModifierRec), OrderModifiers);
481444c061aSmrg}
482444c061aSmrg
483444c061aSmrgstatic String PanicModeRecovery(
484444c061aSmrg    String str)
485444c061aSmrg{
486444c061aSmrg     ScanFor(str,'\n');
487444c061aSmrg     if (*str == '\n') str++;
488444c061aSmrg     return str;
489444c061aSmrg
490444c061aSmrg}
491444c061aSmrg
492444c061aSmrg
493444c061aSmrgstatic void Syntax(
494444c061aSmrg    String str0,String str1)
495444c061aSmrg{
496444c061aSmrg    Cardinal num_params = 2;
497444c061aSmrg    String params[2];
498444c061aSmrg
499444c061aSmrg    params[0] = str0;
500444c061aSmrg    params[1] = str1;
501444c061aSmrg    XtWarningMsg(XtNtranslationParseError,"parseError",XtCXtToolkitError,
502444c061aSmrg		 "translation table syntax error: %s %s",params,&num_params);
503444c061aSmrg}
504444c061aSmrg
505444c061aSmrg
506444c061aSmrg
507444c061aSmrgstatic Cardinal LookupTMEventType(
508444c061aSmrg  String eventStr,
509444c061aSmrg  Boolean *error)
510444c061aSmrg{
511444c061aSmrg    register int   i = 0, left, right;
512444c061aSmrg    register XrmQuark	signature;
513444c061aSmrg    static int 	previous = 0;
514444c061aSmrg
515444c061aSmrg    LOCK_PROCESS;
516444c061aSmrg    if ((signature = StringToQuark(eventStr)) == events[previous].signature) {
517444c061aSmrg	UNLOCK_PROCESS;
518444c061aSmrg	return (Cardinal) previous;
519444c061aSmrg    }
520444c061aSmrg
521444c061aSmrg    left = 0;
522444c061aSmrg    right = XtNumber(events) - 1;
523444c061aSmrg    while (left <= right) {
524444c061aSmrg	i = (left + right) >> 1;
525444c061aSmrg	if (signature < events[i].signature)
526444c061aSmrg	    right = i - 1;
527444c061aSmrg	else if (signature > events[i].signature)
528444c061aSmrg	    left = i + 1;
529444c061aSmrg	else {
530444c061aSmrg	    previous = i;
531444c061aSmrg	    UNLOCK_PROCESS;
532444c061aSmrg	    return (Cardinal) i;
533444c061aSmrg	}
534444c061aSmrg    }
535444c061aSmrg
536444c061aSmrg    Syntax("Unknown event type :  ",eventStr);
537444c061aSmrg    *error = TRUE;
538444c061aSmrg    UNLOCK_PROCESS;
539444c061aSmrg    return (Cardinal) i;
540444c061aSmrg}
541444c061aSmrg
542444c061aSmrgstatic void StoreLateBindings(
543444c061aSmrg    KeySym  keysymL,
544444c061aSmrg    Boolean notL,
545444c061aSmrg    KeySym keysymR,
546444c061aSmrg    Boolean notR,
547444c061aSmrg    LateBindingsPtr* lateBindings)
548444c061aSmrg{
549444c061aSmrg    LateBindingsPtr temp;
550444c061aSmrg    Boolean pair = FALSE;
551444c061aSmrg    unsigned long count,number;
552444c061aSmrg    if (lateBindings != NULL){
553444c061aSmrg        temp = *lateBindings;
554444c061aSmrg        if (temp != NULL) {
555444c061aSmrg            for (count = 0; temp[count].keysym; count++){/*EMPTY*/}
556444c061aSmrg        }
557444c061aSmrg        else count = 0;
558444c061aSmrg        if (! keysymR){
559444c061aSmrg             number = 1;pair = FALSE;
560444c061aSmrg        } else{
561444c061aSmrg             number = 2;pair = TRUE;
562444c061aSmrg        }
563444c061aSmrg
564444c061aSmrg        temp = (LateBindingsPtr)XtRealloc((char *)temp,
565444c061aSmrg            (unsigned)((count+number+1) * sizeof(LateBindings)) );
566444c061aSmrg        *lateBindings = temp;
567444c061aSmrg        temp[count].knot = notL;
568444c061aSmrg        temp[count].pair = pair;
569444c061aSmrg	if (count == 0)
570444c061aSmrg	    temp[count].ref_count = 1;
571444c061aSmrg        temp[count++].keysym = keysymL;
572444c061aSmrg        if (keysymR){
573444c061aSmrg            temp[count].knot = notR;
574444c061aSmrg            temp[count].pair = FALSE;
575444c061aSmrg	    temp[count].ref_count = 0;
576444c061aSmrg            temp[count++].keysym = keysymR;
577444c061aSmrg        }
578444c061aSmrg        temp[count].knot = temp[count].pair = FALSE;
579444c061aSmrg        temp[count].ref_count = 0;
580444c061aSmrg        temp[count].keysym = 0;
581444c061aSmrg    }
582444c061aSmrg}
583444c061aSmrg
584444c061aSmrgstatic void _XtParseKeysymMod(
585444c061aSmrg    String name,
586444c061aSmrg    LateBindingsPtr* lateBindings,
587444c061aSmrg    Boolean notFlag,
588444c061aSmrg    Value *valueP,
589444c061aSmrg    Boolean *error)
590444c061aSmrg{
591444c061aSmrg    KeySym keySym;
592444c061aSmrg    keySym = StringToKeySym(name, error);
593444c061aSmrg    *valueP = 0;
594444c061aSmrg    if (keySym != NoSymbol) {
595444c061aSmrg        StoreLateBindings(keySym,notFlag,(KeySym) NULL,FALSE,lateBindings);
596444c061aSmrg    }
597444c061aSmrg}
598444c061aSmrg
599444c061aSmrgstatic Boolean _XtLookupModifier(
600444c061aSmrg    XrmQuark signature,
601444c061aSmrg    LateBindingsPtr* lateBindings,
602444c061aSmrg    Boolean notFlag,
603444c061aSmrg    Value *valueP,
604444c061aSmrg    Bool constMask)
605444c061aSmrg{
606444c061aSmrg    register int i, left, right;
607444c061aSmrg    static int previous = 0;
608444c061aSmrg
609444c061aSmrg    LOCK_PROCESS;
610444c061aSmrg    if (signature == modifiers[previous].signature) {
611444c061aSmrg	if (constMask)  *valueP = modifiers[previous].value;
612444c061aSmrg	else /* if (modifiers[previous].modifierParseProc) always true */
613444c061aSmrg	   (*modifiers[previous].modifierParseProc)
614444c061aSmrg	      (modifiers[previous].value, lateBindings, notFlag, valueP);
615444c061aSmrg	UNLOCK_PROCESS;
616444c061aSmrg	return TRUE;
617444c061aSmrg    }
618444c061aSmrg
619444c061aSmrg    left = 0;
620444c061aSmrg    right = XtNumber(modifiers) - 1;
621444c061aSmrg    while (left <= right) {
622444c061aSmrg	i = (left + right) >> 1;
623444c061aSmrg	if (signature < modifiers[i].signature)
624444c061aSmrg	    right = i - 1;
625444c061aSmrg	else if (signature > modifiers[i].signature)
626444c061aSmrg	    left = i + 1;
627444c061aSmrg	else {
628444c061aSmrg	    previous = i;
629444c061aSmrg	    if (constMask)  *valueP = modifiers[i].value;
630444c061aSmrg	    else /* if (modifiers[i].modifierParseProc) always true */
631444c061aSmrg		(*modifiers[i].modifierParseProc)
632444c061aSmrg		    (modifiers[i].value, lateBindings, notFlag, valueP);
633444c061aSmrg	    UNLOCK_PROCESS;
634444c061aSmrg	    return TRUE;
635444c061aSmrg	}
636444c061aSmrg    }
637444c061aSmrg    UNLOCK_PROCESS;
638444c061aSmrg    return FALSE;
639444c061aSmrg}
640444c061aSmrg
641444c061aSmrg
642444c061aSmrgstatic String ScanIdent(
643444c061aSmrg    register String str)
644444c061aSmrg{
645444c061aSmrg    ScanAlphanumeric(str);
646444c061aSmrg    while (
647444c061aSmrg	   ('A' <= *str && *str <= 'Z')
648444c061aSmrg	|| ('a' <= *str && *str <= 'z')
649444c061aSmrg	|| ('0' <= *str && *str <= '9')
650444c061aSmrg	|| (*str == '-')
651444c061aSmrg	|| (*str == '_')
652444c061aSmrg	|| (*str == '$')
653444c061aSmrg	) str++;
654444c061aSmrg    return str;
655444c061aSmrg}
656444c061aSmrg
657444c061aSmrgstatic String FetchModifierToken(
658444c061aSmrg    String str,
659444c061aSmrg    XrmQuark *token_return)
660444c061aSmrg{
661444c061aSmrg    String start = str;
662444c061aSmrg
663444c061aSmrg    if (*str == '$') {
664444c061aSmrg        *token_return = QMeta;
665444c061aSmrg        str++;
666444c061aSmrg        return str;
667444c061aSmrg    }
668444c061aSmrg    if (*str == '^') {
669444c061aSmrg        *token_return = QCtrl;
670444c061aSmrg        str++;
671444c061aSmrg        return str;
672444c061aSmrg    }
673444c061aSmrg    str = ScanIdent(str);
674444c061aSmrg    if (start != str) {
675444c061aSmrg	char modStrbuf[100];
676444c061aSmrg	char* modStr;
677444c061aSmrg
678444c061aSmrg	modStr = XtStackAlloc ((size_t)(str - start + 1), modStrbuf);
679444c061aSmrg	if (modStr == NULL) _XtAllocError (NULL);
680444c061aSmrg	(void) memmove(modStr, start, str-start);
681444c061aSmrg	modStr[str-start] = '\0';
682444c061aSmrg	*token_return = XrmStringToQuark(modStr);
683444c061aSmrg	XtStackFree (modStr, modStrbuf);
684444c061aSmrg	return str;
685444c061aSmrg    }
686444c061aSmrg    return str;
687444c061aSmrg}
688444c061aSmrg
689444c061aSmrgstatic String ParseModifiers(
690444c061aSmrg    register String str,
691444c061aSmrg    EventPtr event,
692444c061aSmrg    Boolean* error)
693444c061aSmrg{
694444c061aSmrg    register String start;
695444c061aSmrg    Boolean notFlag, exclusive, keysymAsMod;
696444c061aSmrg    Value maskBit;
697444c061aSmrg    XrmQuark Qmod;
698444c061aSmrg
699444c061aSmrg    ScanWhitespace(str);
700444c061aSmrg    start = str;
701444c061aSmrg    str = FetchModifierToken(str, &Qmod);
702444c061aSmrg    exclusive = FALSE;
703444c061aSmrg    if (start != str) {
704444c061aSmrg	if (Qmod == QNone) {
705444c061aSmrg	    event->event.modifierMask = ~0;
706444c061aSmrg	    event->event.modifiers = 0;
707444c061aSmrg	    ScanWhitespace(str);
708444c061aSmrg	    return str;
709444c061aSmrg	} else if (Qmod == QAny) { /*backward compatability*/
710444c061aSmrg	    event->event.modifierMask = 0;
711444c061aSmrg	    event->event.modifiers = AnyModifier;
712444c061aSmrg	    ScanWhitespace(str);
713444c061aSmrg	    return str;
714444c061aSmrg	}
715444c061aSmrg	str = start; /*if plain modifier, reset to beginning */
716444c061aSmrg    }
717444c061aSmrg    else while (*str == '!' || *str == ':') {
718444c061aSmrg        if (*str == '!') {
719444c061aSmrg             exclusive = TRUE;
720444c061aSmrg             str++;
721444c061aSmrg             ScanWhitespace(str);
722444c061aSmrg        }
723444c061aSmrg        if (*str == ':') {
724444c061aSmrg             event->event.standard = TRUE;
725444c061aSmrg             str++;
726444c061aSmrg             ScanWhitespace(str);
727444c061aSmrg        }
728444c061aSmrg    }
729444c061aSmrg
730444c061aSmrg    while (*str != '<') {
731444c061aSmrg        if (*str == '~') {
732444c061aSmrg             notFlag = TRUE;
733444c061aSmrg             str++;
734444c061aSmrg          } else
735444c061aSmrg              notFlag = FALSE;
736444c061aSmrg        if (*str == '@') {
737444c061aSmrg            keysymAsMod = TRUE;
738444c061aSmrg            str++;
739444c061aSmrg        }
740444c061aSmrg        else keysymAsMod = FALSE;
741444c061aSmrg	start = str;
742444c061aSmrg        str = FetchModifierToken(str, &Qmod);
743444c061aSmrg        if (start == str) {
744444c061aSmrg            Syntax("Modifier or '<' expected","");
745444c061aSmrg            *error = TRUE;
746444c061aSmrg            return PanicModeRecovery(str);
747444c061aSmrg        }
748444c061aSmrg         if (keysymAsMod) {
749444c061aSmrg             _XtParseKeysymMod(XrmQuarkToString(Qmod),
750444c061aSmrg			       &event->event.lateModifiers,
751444c061aSmrg			       notFlag,&maskBit, error);
752444c061aSmrg	     if (*error)
753444c061aSmrg                 return PanicModeRecovery(str);
754444c061aSmrg
755444c061aSmrg         } else
756444c061aSmrg  	     if (!_XtLookupModifier(Qmod, &event->event.lateModifiers,
757444c061aSmrg				    notFlag, &maskBit, FALSE)) {
758444c061aSmrg	         Syntax("Unknown modifier name:  ", XrmQuarkToString(Qmod));
759444c061aSmrg                 *error = TRUE;
760444c061aSmrg                 return PanicModeRecovery(str);
761444c061aSmrg             }
762444c061aSmrg        event->event.modifierMask |= maskBit;
763444c061aSmrg	if (notFlag) event->event.modifiers &= ~maskBit;
764444c061aSmrg	else event->event.modifiers |= maskBit;
765444c061aSmrg        ScanWhitespace(str);
766444c061aSmrg    }
767444c061aSmrg    if (exclusive) event->event.modifierMask = ~0;
768444c061aSmrg    return str;
769444c061aSmrg}
770444c061aSmrg
771444c061aSmrgstatic String ParseXtEventType(
772444c061aSmrg    register String str,
773444c061aSmrg    EventPtr event,
774444c061aSmrg    Cardinal *tmEventP,
775444c061aSmrg    Boolean* error)
776444c061aSmrg{
777444c061aSmrg    String start = str;
778444c061aSmrg    char eventTypeStrbuf[100];
779444c061aSmrg    char* eventTypeStr;
780444c061aSmrg
781444c061aSmrg    ScanAlphanumeric(str);
782444c061aSmrg    eventTypeStr = XtStackAlloc ((size_t)(str - start + 1), eventTypeStrbuf);
783444c061aSmrg    if (eventTypeStr == NULL) _XtAllocError (NULL);
784444c061aSmrg    (void) memmove(eventTypeStr, start, str-start);
785444c061aSmrg    eventTypeStr[str-start] = '\0';
786444c061aSmrg    *tmEventP = LookupTMEventType(eventTypeStr,error);
787444c061aSmrg    XtStackFree (eventTypeStr, eventTypeStrbuf);
788444c061aSmrg    if (*error)
789444c061aSmrg        return PanicModeRecovery(str);
790444c061aSmrg    event->event.eventType = events[*tmEventP].eventType;
791444c061aSmrg    return str;
792444c061aSmrg}
793444c061aSmrg
794444c061aSmrgstatic unsigned long StrToHex(
795444c061aSmrg    String str)
796444c061aSmrg{
797444c061aSmrg    register char   c;
798444c061aSmrg    register unsigned long    val = 0;
799444c061aSmrg
800444c061aSmrg    while ((c = *str)) {
801444c061aSmrg	if ('0' <= c && c <= '9') val = val*16+c-'0';
802444c061aSmrg	else if ('a' <= c && c <= 'z') val = val*16+c-'a'+10;
803444c061aSmrg	else if ('A' <= c && c <= 'Z') val = val*16+c-'A'+10;
804444c061aSmrg	else return 0;
805444c061aSmrg	str++;
806444c061aSmrg    }
807444c061aSmrg
808444c061aSmrg    return val;
809444c061aSmrg}
810444c061aSmrg
811444c061aSmrgstatic unsigned long StrToOct(
812444c061aSmrg    String str)
813444c061aSmrg{
814444c061aSmrg    register char c;
815444c061aSmrg    register unsigned long  val = 0;
816444c061aSmrg
817444c061aSmrg    while ((c = *str)) {
818444c061aSmrg        if ('0' <= c && c <= '7') val = val*8+c-'0'; else return 0;
819444c061aSmrg	str++;
820444c061aSmrg    }
821444c061aSmrg
822444c061aSmrg    return val;
823444c061aSmrg}
824444c061aSmrg
825444c061aSmrgstatic unsigned long StrToNum(
826444c061aSmrg    String str)
827444c061aSmrg{
828444c061aSmrg    register char c;
829444c061aSmrg    register unsigned long val = 0;
830444c061aSmrg
831444c061aSmrg    if (*str == '0') {
832444c061aSmrg	str++;
833444c061aSmrg	if (*str == 'x' || *str == 'X') return StrToHex(++str);
834444c061aSmrg	else return StrToOct(str);
835444c061aSmrg    }
836444c061aSmrg
837444c061aSmrg    while ((c = *str)) {
838444c061aSmrg	if ('0' <= c && c <= '9') val = val*10+c-'0';
839444c061aSmrg	else return 0;
840444c061aSmrg	str++;
841444c061aSmrg    }
842444c061aSmrg
843444c061aSmrg    return val;
844444c061aSmrg}
845444c061aSmrg
846444c061aSmrgstatic KeySym StringToKeySym(
847444c061aSmrg    String str,
848444c061aSmrg    Boolean *error)
849444c061aSmrg{
850444c061aSmrg    KeySym k;
851444c061aSmrg
852444c061aSmrg    if (str == NULL || *str == '\0') return (KeySym) 0;
853444c061aSmrg
854444c061aSmrg#ifndef NOTASCII
855444c061aSmrg    /* special case single character ASCII, for speed */
856444c061aSmrg    if (*(str+1) == '\0') {
857444c061aSmrg	if (' ' <= *str && *str <= '~') return XK_space + (*str - ' ');
858444c061aSmrg    }
859444c061aSmrg#endif
860444c061aSmrg
861444c061aSmrg    if ('0' <= *str && *str <= '9') return (KeySym) StrToNum(str);
862444c061aSmrg    k = XStringToKeysym(str);
863444c061aSmrg    if (k != NoSymbol) return k;
864444c061aSmrg
865444c061aSmrg#ifdef NOTASCII
866444c061aSmrg    /* fall-back case to preserve backwards compatibility; no-one
867444c061aSmrg     * should be relying upon this!
868444c061aSmrg     */
869444c061aSmrg    if (*(str+1) == '\0') return (KeySym) *str;
870444c061aSmrg#endif
871444c061aSmrg
872444c061aSmrg    Syntax("Unknown keysym name: ", str);
873444c061aSmrg    *error = TRUE;
874444c061aSmrg    return NoSymbol;
875444c061aSmrg}
876444c061aSmrg/* ARGSUSED */
877444c061aSmrgstatic void ParseModImmed(
878444c061aSmrg    Value value,
879444c061aSmrg    LateBindingsPtr* lateBindings,
880444c061aSmrg    Boolean notFlag,
881444c061aSmrg    Value* valueP)
882444c061aSmrg{
883444c061aSmrg    *valueP = value;
884444c061aSmrg}
885444c061aSmrg
886444c061aSmrg /* is only valid with keysyms that have an _L and _R in their name;
887444c061aSmrg  * and ignores keysym lookup errors (i.e. assumes only valid keysyms)
888444c061aSmrg  */
889444c061aSmrgstatic void ParseModSym(
890444c061aSmrg    Value value,
891444c061aSmrg    LateBindingsPtr* lateBindings,
892444c061aSmrg    Boolean notFlag,
893444c061aSmrg    Value* valueP)
894444c061aSmrg{
895444c061aSmrg    register KeySym keysymL = (KeySym)value;
896444c061aSmrg    register KeySym keysymR = keysymL + 1; /* valid for supported keysyms */
897444c061aSmrg    StoreLateBindings(keysymL,notFlag,keysymR,notFlag,lateBindings);
898444c061aSmrg    *valueP = 0;
899444c061aSmrg}
900444c061aSmrg
901444c061aSmrg#ifdef sparc
902444c061aSmrg/*
903444c061aSmrg * The stupid optimizer in SunOS 4.0.3 and below generates bogus code that
904444c061aSmrg * causes the value of the most recently used variable to be returned instead
905444c061aSmrg * of the value passed in.
906444c061aSmrg */
907444c061aSmrgstatic String stupid_optimizer_kludge;
908444c061aSmrg#define BROKEN_OPTIMIZER_HACK(val) stupid_optimizer_kludge = (val)
909444c061aSmrg#else
910444c061aSmrg#define BROKEN_OPTIMIZER_HACK(val) val
911444c061aSmrg#endif
912444c061aSmrg
913444c061aSmrg/* ARGSUSED */
914444c061aSmrgstatic String ParseImmed(
915444c061aSmrg    register String str,
916444c061aSmrg    register Opaque closure,
917444c061aSmrg    register EventPtr event,
918444c061aSmrg    Boolean* error)
919444c061aSmrg{
920444c061aSmrg    event->event.eventCode = (unsigned long)closure;
921444c061aSmrg    event->event.eventCodeMask = ~0UL;
922444c061aSmrg
923444c061aSmrg    return BROKEN_OPTIMIZER_HACK(str);
924444c061aSmrg}
925444c061aSmrg
926444c061aSmrg/* ARGSUSED */
927444c061aSmrgstatic String ParseAddModifier(
928444c061aSmrg    register String str,
929444c061aSmrg    register Opaque closure,
930444c061aSmrg    register EventPtr event,
931444c061aSmrg    Boolean* error)
932444c061aSmrg{
933444c061aSmrg    register unsigned long modval = (unsigned long)closure;
934444c061aSmrg    event->event.modifiers |= modval;
935444c061aSmrg    if (modval != AnyButtonMask) /* AnyButtonMask is don't-care mask */
936444c061aSmrg	event->event.modifierMask |= modval;
937444c061aSmrg
938444c061aSmrg    return BROKEN_OPTIMIZER_HACK(str);
939444c061aSmrg}
940444c061aSmrg
941444c061aSmrg
942444c061aSmrgstatic String ParseKeyAndModifiers(
943444c061aSmrg    String str,
944444c061aSmrg    Opaque closure,
945444c061aSmrg    EventPtr event,
946444c061aSmrg    Boolean* error)
947444c061aSmrg{
948444c061aSmrg    str = ParseKeySym(str, closure, event,error);
949444c061aSmrg    if ((unsigned long) closure == 0) {
950444c061aSmrg	Value metaMask; /* unused */
951444c061aSmrg	(void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE,
952444c061aSmrg				 &metaMask, FALSE);
953444c061aSmrg    } else {
954444c061aSmrg	event->event.modifiers |= (unsigned long) closure;
955444c061aSmrg	event->event.modifierMask |= (unsigned long) closure;
956444c061aSmrg    }
957444c061aSmrg    return str;
958444c061aSmrg}
959444c061aSmrg
960444c061aSmrg/*ARGSUSED*/
961444c061aSmrgstatic String ParseKeySym(
962444c061aSmrg    register String str,
963444c061aSmrg    Opaque closure,
964444c061aSmrg    EventPtr event,
965444c061aSmrg    Boolean* error)
966444c061aSmrg{
967444c061aSmrg    char *start;
968444c061aSmrg    char keySymNamebuf[100];
969444c061aSmrg    char* keySymName;
970444c061aSmrg
971444c061aSmrg    ScanWhitespace(str);
972444c061aSmrg
973444c061aSmrg    if (*str == '\\') {
974444c061aSmrg	keySymName = keySymNamebuf;
975444c061aSmrg	str++;
976444c061aSmrg	keySymName[0] = *str;
977444c061aSmrg	if (*str != '\0' && !IsNewline(*str)) str++;
978444c061aSmrg	keySymName[1] = '\0';
979444c061aSmrg	event->event.eventCode = StringToKeySym(keySymName, error);
980444c061aSmrg	event->event.eventCodeMask = ~0L;
981444c061aSmrg    } else if (*str == ',' || *str == ':' ||
982444c061aSmrg             /* allow leftparen to be single char symbol,
983444c061aSmrg              * for backwards compatibility
984444c061aSmrg              */
985444c061aSmrg             (*str == '(' && *(str+1) >= '0' && *(str+1) <= '9')) {
986444c061aSmrg	keySymName = keySymNamebuf; /* just so we can stackfree it later */
987444c061aSmrg	/* no detail */
988444c061aSmrg	event->event.eventCode = 0L;
989444c061aSmrg        event->event.eventCodeMask = 0L;
990444c061aSmrg    } else {
991444c061aSmrg	start = str;
992444c061aSmrg	while (
993444c061aSmrg		*str != ','
994444c061aSmrg		&& *str != ':'
995444c061aSmrg		&& *str != ' '
996444c061aSmrg		&& *str != '\t'
997444c061aSmrg                && !IsNewline(*str)
998444c061aSmrg                && (*str != '(' || *(str+1) <= '0' || *(str+1) >= '9')
999444c061aSmrg		&& *str != '\0') str++;
1000444c061aSmrg	keySymName = XtStackAlloc ((size_t)(str - start + 1), keySymNamebuf);
1001444c061aSmrg	(void) memmove(keySymName, start, str-start);
1002444c061aSmrg	keySymName[str-start] = '\0';
1003444c061aSmrg	event->event.eventCode = StringToKeySym(keySymName, error);
1004444c061aSmrg	event->event.eventCodeMask = ~0L;
1005444c061aSmrg    }
1006444c061aSmrg    if (*error) {
1007444c061aSmrg	/* We never get here when keySymName hasn't been allocated */
1008444c061aSmrg	if (keySymName[0] == '<') {
1009444c061aSmrg	    /* special case for common error */
1010444c061aSmrg	    XtWarningMsg(XtNtranslationParseError, "missingComma",
1011444c061aSmrg			 XtCXtToolkitError,
1012444c061aSmrg		     "... possibly due to missing ',' in event sequence.",
1013444c061aSmrg		     (String*)NULL, (Cardinal*)NULL);
1014444c061aSmrg	}
1015444c061aSmrg	XtStackFree (keySymName, keySymNamebuf);
1016444c061aSmrg	return PanicModeRecovery(str);
1017444c061aSmrg    }
1018444c061aSmrg    if (event->event.standard)
1019444c061aSmrg	event->event.matchEvent = _XtMatchUsingStandardMods;
1020444c061aSmrg    else
1021444c061aSmrg	event->event.matchEvent = _XtMatchUsingDontCareMods;
1022444c061aSmrg
1023444c061aSmrg    XtStackFree (keySymName, keySymNamebuf);
1024444c061aSmrg
1025444c061aSmrg    return str;
1026444c061aSmrg}
1027444c061aSmrg
1028444c061aSmrgstatic String ParseTable(
1029444c061aSmrg    register String str,
1030444c061aSmrg    Opaque closure,
1031444c061aSmrg    EventPtr event,
1032444c061aSmrg    Boolean* error)
1033444c061aSmrg{
1034444c061aSmrg    register String start = str;
1035444c061aSmrg    register XrmQuark signature;
1036444c061aSmrg    NameValueTable table = (NameValueTable) closure;
1037444c061aSmrg    char tableSymName[100];
1038444c061aSmrg
1039444c061aSmrg    event->event.eventCode = 0L;
1040444c061aSmrg    ScanAlphanumeric(str);
1041444c061aSmrg    if (str == start) {event->event.eventCodeMask = 0L; return str; }
1042444c061aSmrg    if (str-start >= 99) {
1043444c061aSmrg	Syntax("Invalid Detail Type (string is too long).", "");
1044444c061aSmrg	*error = TRUE;
1045444c061aSmrg	return str;
1046444c061aSmrg    }
1047444c061aSmrg    (void) memmove(tableSymName, start, str-start);
1048444c061aSmrg    tableSymName[str-start] = '\0';
1049444c061aSmrg    signature = StringToQuark(tableSymName);
1050444c061aSmrg    for (; table->signature != NULLQUARK; table++)
1051444c061aSmrg	if (table->signature == signature) {
1052444c061aSmrg	    event->event.eventCode = table->value;
1053444c061aSmrg	    event->event.eventCodeMask = ~0L;
1054444c061aSmrg	    return str;
1055444c061aSmrg	}
1056444c061aSmrg
1057444c061aSmrg    Syntax("Unknown Detail Type:  ", tableSymName);
1058444c061aSmrg    *error = TRUE;
1059444c061aSmrg    return PanicModeRecovery(str);
1060444c061aSmrg}
1061444c061aSmrg
1062444c061aSmrg/*ARGSUSED*/
1063444c061aSmrgstatic String ParseNone(
1064444c061aSmrg    String str,
1065444c061aSmrg    Opaque closure,
1066444c061aSmrg    EventPtr event,
1067444c061aSmrg    Boolean* error)
1068444c061aSmrg{
1069444c061aSmrg    event->event.eventCode = 0;
1070444c061aSmrg    event->event.eventCodeMask = 0;
1071444c061aSmrg
1072444c061aSmrg    return BROKEN_OPTIMIZER_HACK(str);
1073444c061aSmrg}
1074444c061aSmrg
1075444c061aSmrg/*ARGSUSED*/
1076444c061aSmrgstatic String ParseAtom(
1077444c061aSmrg    String str,
1078444c061aSmrg    Opaque closure,
1079444c061aSmrg    EventPtr event,
1080444c061aSmrg    Boolean* error)
1081444c061aSmrg{
1082444c061aSmrg    ScanWhitespace(str);
1083444c061aSmrg
1084444c061aSmrg    if (*str == ',' || *str == ':') {
1085444c061aSmrg	/* no detail */
1086444c061aSmrg	event->event.eventCode = 0L;
1087444c061aSmrg        event->event.eventCodeMask = 0L;
1088444c061aSmrg    } else {
1089444c061aSmrg	char *start, atomName[1000];
1090444c061aSmrg	start = str;
1091444c061aSmrg	while (
1092444c061aSmrg		*str != ','
1093444c061aSmrg		&& *str != ':'
1094444c061aSmrg		&& *str != ' '
1095444c061aSmrg		&& *str != '\t'
1096444c061aSmrg                && !IsNewline(*str)
1097444c061aSmrg		&& *str != '\0') str++;
1098444c061aSmrg	if (str-start >= 999) {
1099444c061aSmrg	    Syntax( "Atom name must be less than 1000 characters long.", "" );
1100444c061aSmrg	    *error = TRUE;
1101444c061aSmrg	    return str;
1102444c061aSmrg	}
1103444c061aSmrg	(void) memmove(atomName, start, str-start);
1104444c061aSmrg	atomName[str-start] = '\0';
1105444c061aSmrg	event->event.eventCode = XrmStringToQuark(atomName);
1106444c061aSmrg	event->event.matchEvent = _XtMatchAtom;
1107444c061aSmrg    }
1108444c061aSmrg    return str;
1109444c061aSmrg}
1110444c061aSmrg
1111444c061aSmrgstatic ModifierMask buttonModifierMasks[] = {
1112444c061aSmrg    0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask
1113444c061aSmrg};
1114444c061aSmrgstatic String ParseRepeat(String, int *, Boolean *, Boolean *);
1115444c061aSmrg
1116444c061aSmrgstatic String ParseEvent(
1117444c061aSmrg    register String str,
1118444c061aSmrg    EventPtr	event,
1119444c061aSmrg    int*	reps,
1120444c061aSmrg    Boolean*	plus,
1121444c061aSmrg    Boolean* error)
1122444c061aSmrg{
1123444c061aSmrg    Cardinal	tmEvent;
1124444c061aSmrg
1125444c061aSmrg    str = ParseModifiers(str, event,error);
1126444c061aSmrg    if (*error) return str;
1127444c061aSmrg    if (*str != '<') {
1128444c061aSmrg         Syntax("Missing '<' while parsing event type.","");
1129444c061aSmrg         *error = TRUE;
1130444c061aSmrg         return PanicModeRecovery(str);
1131444c061aSmrg    }
1132444c061aSmrg    else str++;
1133444c061aSmrg    str = ParseXtEventType(str, event, &tmEvent,error);
1134444c061aSmrg    if (*error) return str;
1135444c061aSmrg    if (*str != '>'){
1136444c061aSmrg         Syntax("Missing '>' while parsing event type","");
1137444c061aSmrg         *error = TRUE;
1138444c061aSmrg         return PanicModeRecovery(str);
1139444c061aSmrg    }
1140444c061aSmrg    else str++;
1141444c061aSmrg    if (*str == '(') {
1142444c061aSmrg	str = ParseRepeat(str, reps, plus, error);
1143444c061aSmrg	if (*error) return str;
1144444c061aSmrg    }
1145444c061aSmrg    str = (*(events[tmEvent].parseDetail))(
1146444c061aSmrg        str, events[tmEvent].closure, event,error);
1147444c061aSmrg    if (*error) return str;
1148444c061aSmrg
1149444c061aSmrg/* gross hack! ||| this kludge is related to the X11 protocol deficiency w.r.t.
1150444c061aSmrg * modifiers in grabs.
1151444c061aSmrg */
1152444c061aSmrg    if ((event->event.eventType == ButtonRelease)
1153444c061aSmrg	&& (event->event.modifiers | event->event.modifierMask) /* any */
1154444c061aSmrg        && (event->event.modifiers != AnyModifier))
1155444c061aSmrg    {
1156444c061aSmrg	event->event.modifiers
1157444c061aSmrg	    |= buttonModifierMasks[event->event.eventCode];
1158444c061aSmrg	/* the button that is going up will always be in the modifiers... */
1159444c061aSmrg    }
1160444c061aSmrg
1161444c061aSmrg    return str;
1162444c061aSmrg}
1163444c061aSmrg
1164444c061aSmrgstatic String ParseQuotedStringEvent(
1165444c061aSmrg    register String str,
1166444c061aSmrg    register EventPtr event,
1167444c061aSmrg    Boolean *error)
1168444c061aSmrg{
1169444c061aSmrg    Value metaMask;
1170444c061aSmrg    char	s[2];
1171444c061aSmrg
1172444c061aSmrg    if (*str=='^') {
1173444c061aSmrg	str++;
1174444c061aSmrg	event->event.modifiers = ControlMask;
1175444c061aSmrg    } else if (*str == '$') {
1176444c061aSmrg	str++;
1177444c061aSmrg	(void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE,
1178444c061aSmrg				 &metaMask, FALSE);
1179444c061aSmrg    }
1180444c061aSmrg    if (*str == '\\')
1181444c061aSmrg	str++;
1182444c061aSmrg    s[0] = *str;
1183444c061aSmrg    s[1] = '\0';
1184444c061aSmrg    if (*str != '\0' && !IsNewline(*str)) str++;
1185444c061aSmrg    event->event.eventType = KeyPress;
1186444c061aSmrg    event->event.eventCode = StringToKeySym(s, error);
1187444c061aSmrg    if (*error) return PanicModeRecovery(str);
1188444c061aSmrg    event->event.eventCodeMask = ~0L;
1189444c061aSmrg    event->event.matchEvent = _XtMatchUsingStandardMods;
1190444c061aSmrg    event->event.standard = TRUE;
1191444c061aSmrg
1192444c061aSmrg    return str;
1193444c061aSmrg}
1194444c061aSmrg
1195444c061aSmrg
1196444c061aSmrgstatic EventSeqRec timerEventRec = {
1197444c061aSmrg    {0, 0, NULL, _XtEventTimerEventType, 0L, 0L, NULL, False},
1198444c061aSmrg    /* (StatePtr) -1 */ NULL,
1199444c061aSmrg    NULL,
1200444c061aSmrg    NULL
1201444c061aSmrg};
1202444c061aSmrg
1203444c061aSmrgstatic void RepeatDown(
1204444c061aSmrg    EventPtr *eventP,
1205444c061aSmrg    int reps,
1206444c061aSmrg    ActionPtr **actionsP)
1207444c061aSmrg{
1208444c061aSmrg    EventRec upEventRec;
1209444c061aSmrg    register EventPtr event, downEvent;
1210444c061aSmrg    EventPtr upEvent = &upEventRec;
1211444c061aSmrg    register int i;
1212444c061aSmrg
1213444c061aSmrg    downEvent = event = *eventP;
1214444c061aSmrg    *upEvent = *downEvent;
1215444c061aSmrg    upEvent->event.eventType = ((event->event.eventType == ButtonPress) ?
1216444c061aSmrg	ButtonRelease : KeyRelease);
1217444c061aSmrg    if ((upEvent->event.eventType == ButtonRelease)
1218444c061aSmrg	&& (upEvent->event.modifiers != AnyModifier)
1219444c061aSmrg        && (upEvent->event.modifiers | upEvent->event.modifierMask))
1220444c061aSmrg	upEvent->event.modifiers
1221444c061aSmrg	    |= buttonModifierMasks[event->event.eventCode];
1222444c061aSmrg
1223444c061aSmrg    if (event->event.lateModifiers)
1224444c061aSmrg	event->event.lateModifiers->ref_count += (reps - 1) * 2;
1225444c061aSmrg
1226444c061aSmrg    for (i=1; i<reps; i++) {
1227444c061aSmrg
1228444c061aSmrg	/* up */
1229444c061aSmrg	event->next = XtNew(EventSeqRec);
1230444c061aSmrg	event = event->next;
1231444c061aSmrg	*event = *upEvent;
1232444c061aSmrg
1233444c061aSmrg	/* timer */
1234444c061aSmrg	event->next = XtNew(EventSeqRec);
1235444c061aSmrg	event = event->next;
1236444c061aSmrg	*event = timerEventRec;
1237444c061aSmrg
1238444c061aSmrg	/* down */
1239444c061aSmrg	event->next = XtNew(EventSeqRec);
1240444c061aSmrg	event = event->next;
1241444c061aSmrg	*event = *downEvent;
1242444c061aSmrg
1243444c061aSmrg    }
1244444c061aSmrg
1245444c061aSmrg    event->next = NULL;
1246444c061aSmrg    *eventP = event;
1247444c061aSmrg    *actionsP = &event->actions;
1248444c061aSmrg}
1249444c061aSmrg
1250444c061aSmrgstatic void RepeatDownPlus(
1251444c061aSmrg    EventPtr *eventP,
1252444c061aSmrg    int reps,
1253444c061aSmrg    ActionPtr **actionsP)
1254444c061aSmrg{
1255444c061aSmrg    EventRec upEventRec;
1256444c061aSmrg    register EventPtr event, downEvent, lastDownEvent = NULL;
1257444c061aSmrg    EventPtr upEvent = &upEventRec;
1258444c061aSmrg    register int i;
1259444c061aSmrg
1260444c061aSmrg    downEvent = event = *eventP;
1261444c061aSmrg    *upEvent = *downEvent;
1262444c061aSmrg    upEvent->event.eventType = ((event->event.eventType == ButtonPress) ?
1263444c061aSmrg	ButtonRelease : KeyRelease);
1264444c061aSmrg    if ((upEvent->event.eventType == ButtonRelease)
1265444c061aSmrg	&& (upEvent->event.modifiers != AnyModifier)
1266444c061aSmrg        && (upEvent->event.modifiers | upEvent->event.modifierMask))
1267444c061aSmrg	upEvent->event.modifiers
1268444c061aSmrg	    |= buttonModifierMasks[event->event.eventCode];
1269444c061aSmrg
1270444c061aSmrg    if (event->event.lateModifiers)
1271444c061aSmrg	event->event.lateModifiers->ref_count += reps * 2 - 1;
1272444c061aSmrg
1273444c061aSmrg    for (i=0; i<reps; i++) {
1274444c061aSmrg
1275444c061aSmrg	if (i > 0) {
1276444c061aSmrg	/* down */
1277444c061aSmrg	event->next = XtNew(EventSeqRec);
1278444c061aSmrg	event = event->next;
1279444c061aSmrg	*event = *downEvent;
1280444c061aSmrg	}
1281444c061aSmrg	lastDownEvent = event;
1282444c061aSmrg
1283444c061aSmrg	/* up */
1284444c061aSmrg	event->next = XtNew(EventSeqRec);
1285444c061aSmrg	event = event->next;
1286444c061aSmrg	*event = *upEvent;
1287444c061aSmrg
1288444c061aSmrg	/* timer */
1289444c061aSmrg	event->next = XtNew(EventSeqRec);
1290444c061aSmrg	event = event->next;
1291444c061aSmrg	*event = timerEventRec;
1292444c061aSmrg
1293444c061aSmrg    }
1294444c061aSmrg
1295444c061aSmrg    event->next = lastDownEvent;
1296444c061aSmrg    *eventP = event;
1297444c061aSmrg    *actionsP = &lastDownEvent->actions;
1298444c061aSmrg}
1299444c061aSmrg
1300444c061aSmrgstatic void RepeatUp(
1301444c061aSmrg    EventPtr *eventP,
1302444c061aSmrg    int reps,
1303444c061aSmrg    ActionPtr **actionsP)
1304444c061aSmrg{
1305444c061aSmrg    EventRec upEventRec;
1306444c061aSmrg    register EventPtr event, downEvent;
1307444c061aSmrg    EventPtr upEvent = &upEventRec;
1308444c061aSmrg    register int i;
1309444c061aSmrg
1310444c061aSmrg    /* the event currently sitting in *eventP is an "up" event */
1311444c061aSmrg    /* we want to make it a "down" event followed by an "up" event, */
1312444c061aSmrg    /* so that sequence matching on the "state" side works correctly. */
1313444c061aSmrg
1314444c061aSmrg    downEvent = event = *eventP;
1315444c061aSmrg    *upEvent = *downEvent;
1316444c061aSmrg    downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ?
1317444c061aSmrg	ButtonPress : KeyPress);
1318444c061aSmrg    if ((downEvent->event.eventType == ButtonPress)
1319444c061aSmrg	&& (downEvent->event.modifiers != AnyModifier)
1320444c061aSmrg        && (downEvent->event.modifiers | downEvent->event.modifierMask))
1321444c061aSmrg	downEvent->event.modifiers
1322444c061aSmrg	    &= ~buttonModifierMasks[event->event.eventCode];
1323444c061aSmrg
1324444c061aSmrg    if (event->event.lateModifiers)
1325444c061aSmrg	event->event.lateModifiers->ref_count += reps * 2 - 1;
1326444c061aSmrg
1327444c061aSmrg    /* up */
1328444c061aSmrg    event->next = XtNew(EventSeqRec);
1329444c061aSmrg    event = event->next;
1330444c061aSmrg    *event = *upEvent;
1331444c061aSmrg
1332444c061aSmrg    for (i=1; i<reps; i++) {
1333444c061aSmrg
1334444c061aSmrg	/* timer */
1335444c061aSmrg	event->next = XtNew(EventSeqRec);
1336444c061aSmrg	event = event->next;
1337444c061aSmrg	*event = timerEventRec;
1338444c061aSmrg
1339444c061aSmrg	/* down */
1340444c061aSmrg	event->next = XtNew(EventSeqRec);
1341444c061aSmrg	event = event->next;
1342444c061aSmrg	*event = *downEvent;
1343444c061aSmrg
1344444c061aSmrg	/* up */
1345444c061aSmrg	event->next = XtNew(EventSeqRec);
1346444c061aSmrg	event = event->next;
1347444c061aSmrg	*event = *upEvent;
1348444c061aSmrg
1349444c061aSmrg	}
1350444c061aSmrg
1351444c061aSmrg    event->next = NULL;
1352444c061aSmrg    *eventP = event;
1353444c061aSmrg    *actionsP = &event->actions;
1354444c061aSmrg}
1355444c061aSmrg
1356444c061aSmrgstatic void RepeatUpPlus(
1357444c061aSmrg    EventPtr *eventP,
1358444c061aSmrg    int reps,
1359444c061aSmrg    ActionPtr **actionsP)
1360444c061aSmrg{
1361444c061aSmrg    EventRec upEventRec;
1362444c061aSmrg    register EventPtr event, downEvent, lastUpEvent = NULL;
1363444c061aSmrg    EventPtr upEvent = &upEventRec;
1364444c061aSmrg    register int i;
1365444c061aSmrg
1366444c061aSmrg    /* the event currently sitting in *eventP is an "up" event */
1367444c061aSmrg    /* we want to make it a "down" event followed by an "up" event, */
1368444c061aSmrg    /* so that sequence matching on the "state" side works correctly. */
1369444c061aSmrg
1370444c061aSmrg    downEvent = event = *eventP;
1371444c061aSmrg    *upEvent = *downEvent;
1372444c061aSmrg    downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ?
1373444c061aSmrg	ButtonPress : KeyPress);
1374444c061aSmrg    if ((downEvent->event.eventType == ButtonPress)
1375444c061aSmrg	&& (downEvent->event.modifiers != AnyModifier)
1376444c061aSmrg        && (downEvent->event.modifiers | downEvent->event.modifierMask))
1377444c061aSmrg	downEvent->event.modifiers
1378444c061aSmrg	    &= ~buttonModifierMasks[event->event.eventCode];
1379444c061aSmrg
1380444c061aSmrg    if (event->event.lateModifiers)
1381444c061aSmrg	event->event.lateModifiers->ref_count += reps * 2;
1382444c061aSmrg
1383444c061aSmrg    for (i=0; i<reps; i++) {
1384444c061aSmrg
1385444c061aSmrg	/* up */
1386444c061aSmrg	event->next = XtNew(EventSeqRec);
1387444c061aSmrg	lastUpEvent = event = event->next;
1388444c061aSmrg	*event = *upEvent;
1389444c061aSmrg
1390444c061aSmrg	/* timer */
1391444c061aSmrg	event->next = XtNew(EventSeqRec);
1392444c061aSmrg	event = event->next;
1393444c061aSmrg	*event = timerEventRec;
1394444c061aSmrg
1395444c061aSmrg	/* down */
1396444c061aSmrg	event->next = XtNew(EventSeqRec);
1397444c061aSmrg        event = event->next;
1398444c061aSmrg	*event = *downEvent;
1399444c061aSmrg
1400444c061aSmrg	}
1401444c061aSmrg
1402444c061aSmrg    event->next = lastUpEvent;
1403444c061aSmrg    *eventP = event;
1404444c061aSmrg    *actionsP = &lastUpEvent->actions;
1405444c061aSmrg}
1406444c061aSmrg
1407444c061aSmrgstatic void RepeatOther(
1408444c061aSmrg    EventPtr *eventP,
1409444c061aSmrg    int reps,
1410444c061aSmrg    ActionPtr **actionsP)
1411444c061aSmrg{
1412444c061aSmrg    register EventPtr event, tempEvent;
1413444c061aSmrg    register int i;
1414444c061aSmrg
1415444c061aSmrg    tempEvent = event = *eventP;
1416444c061aSmrg
1417444c061aSmrg    if (event->event.lateModifiers)
1418444c061aSmrg	event->event.lateModifiers->ref_count += reps - 1;
1419444c061aSmrg
1420444c061aSmrg    for (i=1; i<reps; i++) {
1421444c061aSmrg	event->next = XtNew(EventSeqRec);
1422444c061aSmrg	event = event->next;
1423444c061aSmrg	*event = *tempEvent;
1424444c061aSmrg    }
1425444c061aSmrg
1426444c061aSmrg    *eventP = event;
1427444c061aSmrg    *actionsP = &event->actions;
1428444c061aSmrg}
1429444c061aSmrg
1430444c061aSmrgstatic void RepeatOtherPlus(
1431444c061aSmrg    EventPtr *eventP,
1432444c061aSmrg    int reps,
1433444c061aSmrg    ActionPtr **actionsP)
1434444c061aSmrg{
1435444c061aSmrg    register EventPtr event, tempEvent;
1436444c061aSmrg    register int i;
1437444c061aSmrg
1438444c061aSmrg    tempEvent = event = *eventP;
1439444c061aSmrg
1440444c061aSmrg    if (event->event.lateModifiers)
1441444c061aSmrg	event->event.lateModifiers->ref_count += reps - 1;
1442444c061aSmrg
1443444c061aSmrg    for (i=1; i<reps; i++) {
1444444c061aSmrg	event->next = XtNew(EventSeqRec);
1445444c061aSmrg	event = event->next;
1446444c061aSmrg	*event = *tempEvent;
1447444c061aSmrg    }
1448444c061aSmrg
1449444c061aSmrg    event->next = event;
1450444c061aSmrg    *eventP = event;
1451444c061aSmrg    *actionsP = &event->actions;
1452444c061aSmrg}
1453444c061aSmrg
1454444c061aSmrgstatic void RepeatEvent(
1455444c061aSmrg    EventPtr *eventP,
1456444c061aSmrg    int reps,
1457444c061aSmrg    Boolean plus,
1458444c061aSmrg    ActionPtr **actionsP)
1459444c061aSmrg{
1460444c061aSmrg    switch ((*eventP)->event.eventType) {
1461444c061aSmrg
1462444c061aSmrg	case ButtonPress:
1463444c061aSmrg	case KeyPress:
1464444c061aSmrg	    if (plus) RepeatDownPlus(eventP, reps, actionsP);
1465444c061aSmrg	    else RepeatDown(eventP, reps, actionsP);
1466444c061aSmrg	    break;
1467444c061aSmrg
1468444c061aSmrg	case ButtonRelease:
1469444c061aSmrg	case KeyRelease:
1470444c061aSmrg	    if (plus) RepeatUpPlus(eventP, reps, actionsP);
1471444c061aSmrg	    else RepeatUp(eventP, reps, actionsP);
1472444c061aSmrg	    break;
1473444c061aSmrg
1474444c061aSmrg	default:
1475444c061aSmrg	    if (plus) RepeatOtherPlus(eventP, reps, actionsP);
1476444c061aSmrg	    else RepeatOther(eventP, reps, actionsP);
1477444c061aSmrg    }
1478444c061aSmrg}
1479444c061aSmrg
1480444c061aSmrgstatic String ParseRepeat(
1481444c061aSmrg    register String str,
1482444c061aSmrg    int	*reps,
1483444c061aSmrg    Boolean *plus, Boolean *error)
1484444c061aSmrg{
1485444c061aSmrg
1486444c061aSmrg    /*** Parse the repetitions, for double click etc... ***/
1487444c061aSmrg    if (*str != '(' || !(isdigit(str[1]) || str[1] == '+' || str[1] == ')'))
1488444c061aSmrg	return str;
1489444c061aSmrg    str++;
1490444c061aSmrg    if (isdigit(*str)) {
1491444c061aSmrg	String start = str;
1492444c061aSmrg	char repStr[7];
1493444c061aSmrg	size_t len;
1494444c061aSmrg
1495444c061aSmrg	ScanNumeric(str);
1496444c061aSmrg	len = (str - start);
1497444c061aSmrg	if (len < sizeof repStr) {
1498444c061aSmrg	    (void) memmove(repStr, start, len);
1499444c061aSmrg	    repStr[len] = '\0';
1500444c061aSmrg	    *reps = StrToNum(repStr);
1501444c061aSmrg	} else {
1502444c061aSmrg	    Syntax("Repeat count too large.", "");
1503444c061aSmrg	    *error = TRUE;
1504444c061aSmrg	    return str;
1505444c061aSmrg	}
1506444c061aSmrg    }
1507444c061aSmrg    if (*reps == 0) {
1508444c061aSmrg	Syntax("Missing repeat count.","");
1509444c061aSmrg	*error = True;
1510444c061aSmrg	return str;
1511444c061aSmrg    }
1512444c061aSmrg
1513444c061aSmrg    if (*str == '+') {
1514444c061aSmrg	*plus = TRUE;
1515444c061aSmrg	str++;
1516444c061aSmrg    }
1517444c061aSmrg    if (*str == ')')
1518444c061aSmrg	str++;
1519444c061aSmrg    else {
1520444c061aSmrg	Syntax("Missing ')'.","");
1521444c061aSmrg	*error = TRUE;
1522444c061aSmrg    }
1523444c061aSmrg
1524444c061aSmrg    return str;
1525444c061aSmrg}
1526444c061aSmrg
1527444c061aSmrg/***********************************************************************
1528444c061aSmrg * ParseEventSeq
1529444c061aSmrg * Parses the left hand side of a translation table production
1530444c061aSmrg * up to, and consuming the ":".
1531444c061aSmrg * Takes a pointer to a char* (where to start parsing) and returns an
1532444c061aSmrg * event seq (in a passed in variable), having updated the String
1533444c061aSmrg **********************************************************************/
1534444c061aSmrg
1535444c061aSmrgstatic String ParseEventSeq(
1536444c061aSmrg    register String str,
1537444c061aSmrg    EventSeqPtr *eventSeqP,
1538444c061aSmrg    ActionPtr	**actionsP,
1539444c061aSmrg    Boolean *error)
1540444c061aSmrg{
1541444c061aSmrg    EventSeqPtr *nextEvent = eventSeqP;
1542444c061aSmrg
1543444c061aSmrg    *eventSeqP = NULL;
1544444c061aSmrg
1545444c061aSmrg    while ( *str != '\0' && !IsNewline(*str)) {
1546444c061aSmrg	static Event	nullEvent =
15472265a131Smrg             {0, 0,NULL, 0, 0L, 0L,_XtRegularMatch,FALSE};
1548444c061aSmrg	EventPtr	event;
1549444c061aSmrg
1550444c061aSmrg	ScanWhitespace(str);
1551444c061aSmrg
1552444c061aSmrg	if (*str == '"') {
1553444c061aSmrg	    str++;
1554444c061aSmrg	    while (*str != '"' && *str != '\0' && !IsNewline(*str)) {
1555444c061aSmrg                event = XtNew(EventRec);
1556444c061aSmrg                event->event = nullEvent;
1557444c061aSmrg                event->state = /* (StatePtr) -1 */ NULL;
1558444c061aSmrg                event->next = NULL;
1559444c061aSmrg                event->actions = NULL;
1560444c061aSmrg		str = ParseQuotedStringEvent(str, event,error);
1561444c061aSmrg		if (*error) {
1562444c061aSmrg		    XtWarningMsg(XtNtranslationParseError, "nonLatin1",
1563444c061aSmrg			XtCXtToolkitError,
1564444c061aSmrg			"... probably due to non-Latin1 character in quoted string",
1565444c061aSmrg			(String*)NULL, (Cardinal*)NULL);
1566444c061aSmrg		    return PanicModeRecovery(str);
1567444c061aSmrg		}
1568444c061aSmrg		*nextEvent = event;
1569444c061aSmrg		*actionsP = &event->actions;
1570444c061aSmrg		nextEvent = &event->next;
1571444c061aSmrg	    }
1572444c061aSmrg	    if (*str != '"') {
1573444c061aSmrg                Syntax("Missing '\"'.","");
1574444c061aSmrg                *error = TRUE;
1575444c061aSmrg                return PanicModeRecovery(str);
1576444c061aSmrg             }
1577444c061aSmrg             else str++;
1578444c061aSmrg	} else {
1579444c061aSmrg	    int reps = 0;
1580444c061aSmrg	    Boolean plus = FALSE;
1581444c061aSmrg
1582444c061aSmrg            event = XtNew(EventRec);
1583444c061aSmrg            event->event = nullEvent;
1584444c061aSmrg            event->state = /* (StatePtr) -1 */ NULL;
1585444c061aSmrg            event->next = NULL;
1586444c061aSmrg            event->actions = NULL;
1587444c061aSmrg
1588444c061aSmrg	    str = ParseEvent(str, event, &reps, &plus, error);
1589444c061aSmrg            if (*error) return str;
1590444c061aSmrg	    *nextEvent = event;
1591444c061aSmrg	    *actionsP = &event->actions;
1592444c061aSmrg	    if (reps > 1 || plus)
1593444c061aSmrg		RepeatEvent(&event, reps, plus, actionsP);
1594444c061aSmrg	    nextEvent = &event->next;
1595444c061aSmrg	}
1596444c061aSmrg	ScanWhitespace(str);
1597444c061aSmrg        if (*str == ':') break;
1598444c061aSmrg        else {
1599444c061aSmrg            if (*str != ',') {
1600444c061aSmrg                Syntax("',' or ':' expected while parsing event sequence.","");
1601444c061aSmrg                *error = TRUE;
1602444c061aSmrg                return PanicModeRecovery(str);
1603444c061aSmrg	    } else str++;
1604444c061aSmrg        }
1605444c061aSmrg    }
1606444c061aSmrg
1607444c061aSmrg    if (*str != ':') {
1608444c061aSmrg        Syntax("Missing ':'after event sequence.","");
1609444c061aSmrg        *error = TRUE;
1610444c061aSmrg        return PanicModeRecovery(str);
1611444c061aSmrg    } else str++;
1612444c061aSmrg
1613444c061aSmrg    return str;
1614444c061aSmrg}
1615444c061aSmrg
1616444c061aSmrg
1617444c061aSmrgstatic String ParseActionProc(
1618444c061aSmrg    register String str,
1619444c061aSmrg    XrmQuark *actionProcNameP,
1620444c061aSmrg    Boolean *error)
1621444c061aSmrg{
1622444c061aSmrg    register String start = str;
1623444c061aSmrg    char procName[200];
1624444c061aSmrg
1625444c061aSmrg    str = ScanIdent(str);
1626444c061aSmrg    if (str-start >= 199) {
1627444c061aSmrg	Syntax("Action procedure name is longer than 199 chars","");
1628444c061aSmrg	*error = TRUE;
1629444c061aSmrg	return str;
1630444c061aSmrg    }
1631444c061aSmrg    (void) memmove(procName, start, str-start);
1632444c061aSmrg    procName[str-start] = '\0';
1633444c061aSmrg    *actionProcNameP = XrmStringToQuark( procName );
1634444c061aSmrg    return str;
1635444c061aSmrg}
1636444c061aSmrg
1637444c061aSmrg
1638444c061aSmrgstatic String ParseString(
1639444c061aSmrg    register String str,
1640444c061aSmrg    String *strP)
1641444c061aSmrg{
1642444c061aSmrg    register String start;
1643444c061aSmrg
1644444c061aSmrg    if (*str == '"') {
1645444c061aSmrg	register unsigned prev_len, len;
1646444c061aSmrg	str++;
1647444c061aSmrg	start = str;
1648444c061aSmrg	*strP = NULL;
1649444c061aSmrg	prev_len = 0;
1650444c061aSmrg
1651444c061aSmrg	while (*str != '"' && *str != '\0') {
1652444c061aSmrg	    /* \"  produces double quote embedded in a quoted parameter
1653444c061aSmrg	     * \\" produces backslash as last character of a quoted parameter
1654444c061aSmrg	     */
1655444c061aSmrg	    if (*str == '\\' &&
1656444c061aSmrg		(*(str+1) == '"' || (*(str+1) == '\\' && *(str+2) == '"'))) {
1657444c061aSmrg		len = prev_len + (str-start+2);
1658444c061aSmrg		*strP = XtRealloc(*strP, len);
1659444c061aSmrg		(void) memmove(*strP + prev_len, start, str-start);
1660444c061aSmrg		prev_len = len-1;
1661444c061aSmrg		str++;
1662444c061aSmrg		(*strP)[prev_len-1] = *str;
1663444c061aSmrg		(*strP)[prev_len] = '\0';
1664444c061aSmrg		start = str+1;
1665444c061aSmrg	    }
1666444c061aSmrg	    str++;
1667444c061aSmrg	}
1668444c061aSmrg	len = prev_len + (str-start+1);
1669444c061aSmrg	*strP = XtRealloc(*strP, len);
1670444c061aSmrg	(void) memmove( *strP + prev_len, start, str-start);
1671444c061aSmrg	(*strP)[len-1] = '\0';
1672444c061aSmrg	if (*str == '"') str++; else
1673444c061aSmrg            XtWarningMsg(XtNtranslationParseError,"parseString",
1674444c061aSmrg                      XtCXtToolkitError,"Missing '\"'.",
1675444c061aSmrg		      (String *)NULL, (Cardinal *)NULL);
1676444c061aSmrg    } else {
1677444c061aSmrg	/* scan non-quoted string, stop on whitespace, ',' or ')' */
1678444c061aSmrg	start = str;
1679444c061aSmrg	while (*str != ' '
1680444c061aSmrg		&& *str != '\t'
1681444c061aSmrg		&& *str != ','
1682444c061aSmrg		&& *str != ')'
1683444c061aSmrg                && !IsNewline(*str)
1684444c061aSmrg		&& *str != '\0') str++;
1685444c061aSmrg	*strP = __XtMalloc((unsigned)(str-start+1));
1686444c061aSmrg	(void) memmove(*strP, start, str-start);
1687444c061aSmrg	(*strP)[str-start] = '\0';
1688444c061aSmrg    }
1689444c061aSmrg    return str;
1690444c061aSmrg}
1691444c061aSmrg
1692444c061aSmrg
1693444c061aSmrgstatic String ParseParamSeq(
1694444c061aSmrg    register String str,
1695444c061aSmrg    String **paramSeqP,
1696444c061aSmrg    Cardinal *paramNumP)
1697444c061aSmrg{
1698444c061aSmrg    typedef struct _ParamRec *ParamPtr;
1699444c061aSmrg    typedef struct _ParamRec {
1700444c061aSmrg	ParamPtr next;
1701444c061aSmrg	String	param;
1702444c061aSmrg    } ParamRec;
1703444c061aSmrg
1704444c061aSmrg    ParamPtr params = NULL;
1705444c061aSmrg    register Cardinal num_params = 0;
1706444c061aSmrg    register Cardinal i;
1707444c061aSmrg
1708444c061aSmrg    ScanWhitespace(str);
1709444c061aSmrg    while (*str != ')' && *str != '\0' && !IsNewline(*str)) {
1710444c061aSmrg	String newStr;
1711444c061aSmrg	str = ParseString(str, &newStr);
1712444c061aSmrg	if (newStr != NULL) {
1713444c061aSmrg	    ParamPtr temp = (ParamRec*)
1714444c061aSmrg		ALLOCATE_LOCAL( (unsigned)sizeof(ParamRec) );
1715444c061aSmrg	    if (temp == NULL) _XtAllocError (NULL);
1716444c061aSmrg
1717444c061aSmrg	    num_params++;
1718444c061aSmrg	    temp->next = params;
1719444c061aSmrg	    params = temp;
1720444c061aSmrg	    temp->param = newStr;
1721444c061aSmrg	    ScanWhitespace(str);
1722444c061aSmrg	    if (*str == ',') {
1723444c061aSmrg		str++;
1724444c061aSmrg		ScanWhitespace(str);
1725444c061aSmrg	    }
1726444c061aSmrg	}
1727444c061aSmrg    }
1728444c061aSmrg
1729444c061aSmrg    if (num_params != 0) {
1730444c061aSmrg	String *paramP = (String *)
1731444c061aSmrg		__XtMalloc( (unsigned)(num_params+1) * sizeof(String) );
1732444c061aSmrg	*paramSeqP = paramP;
1733444c061aSmrg	*paramNumP = num_params;
1734444c061aSmrg	paramP += num_params; /* list is LIFO right now */
1735444c061aSmrg	*paramP-- = NULL;
1736444c061aSmrg	for (i=0; i < num_params; i++) {
1737444c061aSmrg	    ParamPtr next = params->next;
1738444c061aSmrg	    *paramP-- = params->param;
1739444c061aSmrg	    DEALLOCATE_LOCAL( (char *)params );
1740444c061aSmrg	    params = next;
1741444c061aSmrg	}
1742444c061aSmrg    } else {
1743444c061aSmrg	*paramSeqP = NULL;
1744444c061aSmrg	*paramNumP = 0;
1745444c061aSmrg    }
1746444c061aSmrg
1747444c061aSmrg    return str;
1748444c061aSmrg}
1749444c061aSmrg
1750444c061aSmrgstatic String ParseAction(
1751444c061aSmrg    String str,
1752444c061aSmrg    ActionPtr actionP,
1753444c061aSmrg    XrmQuark* quarkP,
1754444c061aSmrg    Boolean* error)
1755444c061aSmrg{
1756444c061aSmrg    str = ParseActionProc(str, quarkP, error);
1757444c061aSmrg    if (*error) return str;
1758444c061aSmrg
1759444c061aSmrg    if (*str == '(') {
1760444c061aSmrg	str++;
1761444c061aSmrg	str = ParseParamSeq(str, &actionP->params, &actionP->num_params);
1762444c061aSmrg    } else {
1763444c061aSmrg        Syntax("Missing '(' while parsing action sequence","");
1764444c061aSmrg        *error = TRUE;
1765444c061aSmrg        return str;
1766444c061aSmrg    }
1767444c061aSmrg    if (*str == ')') str++;
1768444c061aSmrg    else{
1769444c061aSmrg        Syntax("Missing ')' while parsing action sequence","");
1770444c061aSmrg        *error = TRUE;
1771444c061aSmrg        return str;
1772444c061aSmrg    }
1773444c061aSmrg    return str;
1774444c061aSmrg}
1775444c061aSmrg
1776444c061aSmrg
1777444c061aSmrgstatic String ParseActionSeq(
1778444c061aSmrg    TMParseStateTree   	parseTree,
1779444c061aSmrg    String 		str,
1780444c061aSmrg    ActionPtr 		*actionsP,
1781444c061aSmrg    Boolean		*error)
1782444c061aSmrg{
1783444c061aSmrg    ActionPtr *nextActionP = actionsP;
1784444c061aSmrg
1785444c061aSmrg    *actionsP = NULL;
1786444c061aSmrg    while (*str != '\0' && !IsNewline(*str)) {
1787444c061aSmrg	register ActionPtr	action;
1788444c061aSmrg	XrmQuark quark;
1789444c061aSmrg
1790444c061aSmrg	action = XtNew(ActionRec);
1791444c061aSmrg        action->params = NULL;
1792444c061aSmrg        action->num_params = 0;
1793444c061aSmrg        action->next = NULL;
1794444c061aSmrg
1795444c061aSmrg	str = ParseAction(str, action, &quark, error);
1796444c061aSmrg	if (*error) return PanicModeRecovery(str);
1797444c061aSmrg
1798444c061aSmrg	action->idx = _XtGetQuarkIndex(parseTree, quark);
1799444c061aSmrg	ScanWhitespace(str);
1800444c061aSmrg	*nextActionP = action;
1801444c061aSmrg	nextActionP = &action->next;
1802444c061aSmrg    }
1803444c061aSmrg    if (IsNewline(*str)) str++;
1804444c061aSmrg    ScanWhitespace(str);
1805444c061aSmrg    return str;
1806444c061aSmrg}
1807444c061aSmrg
1808444c061aSmrg
1809444c061aSmrgstatic void ShowProduction(
1810444c061aSmrg  String currentProduction)
1811444c061aSmrg{
1812444c061aSmrg    Cardinal num_params = 1;
1813444c061aSmrg    String params[1];
1814444c061aSmrg    size_t len;
1815444c061aSmrg    char *eol, *production, productionbuf[500];
1816444c061aSmrg
1817444c061aSmrg#ifdef __UNIXOS2__
1818444c061aSmrg    eol = strchr(currentProduction, '\r');
1819444c061aSmrg    if (!eol) /* try '\n' as well below */
1820444c061aSmrg#endif
1821444c061aSmrg        eol = strchr(currentProduction, '\n');
1822444c061aSmrg    if (eol) len = eol - currentProduction;
1823444c061aSmrg    else len = strlen (currentProduction);
1824444c061aSmrg    production = XtStackAlloc (len + 1, productionbuf);
1825444c061aSmrg    if (production == NULL) _XtAllocError (NULL);
1826444c061aSmrg    (void) memmove(production, currentProduction, len);
1827444c061aSmrg    production[len] = '\0';
1828444c061aSmrg
1829444c061aSmrg    params[0] = production;
1830444c061aSmrg    XtWarningMsg(XtNtranslationParseError, "showLine", XtCXtToolkitError,
1831444c061aSmrg		 "... found while parsing '%s'", params, &num_params);
1832444c061aSmrg
1833444c061aSmrg    XtStackFree (production, productionbuf);
1834444c061aSmrg}
1835444c061aSmrg
1836444c061aSmrg/***********************************************************************
1837444c061aSmrg * ParseTranslationTableProduction
1838444c061aSmrg * Parses one line of event bindings.
1839444c061aSmrg ***********************************************************************/
1840444c061aSmrg
1841444c061aSmrgstatic String ParseTranslationTableProduction(
1842444c061aSmrg    TMParseStateTree	 parseTree,
1843444c061aSmrg    register String str,
1844444c061aSmrg    Boolean* error)
1845444c061aSmrg{
1846444c061aSmrg    EventSeqPtr	eventSeq = NULL;
1847444c061aSmrg    ActionPtr	*actionsP;
1848444c061aSmrg    String	production = str;
1849444c061aSmrg
18502265a131Smrg    actionsP = NULL;
1851444c061aSmrg    str = ParseEventSeq(str, &eventSeq, &actionsP,error);
1852444c061aSmrg    if (*error == TRUE) {
1853444c061aSmrg	ShowProduction(production);
1854444c061aSmrg        FreeEventSeq(eventSeq);
1855444c061aSmrg        return (str);
1856444c061aSmrg    }
1857444c061aSmrg    ScanWhitespace(str);
1858444c061aSmrg    str = ParseActionSeq(parseTree, str, actionsP, error);
1859444c061aSmrg    if (*error == TRUE) {
1860444c061aSmrg	ShowProduction(production);
1861444c061aSmrg        FreeEventSeq(eventSeq);
1862444c061aSmrg        return (str);
1863444c061aSmrg    }
1864444c061aSmrg
1865444c061aSmrg    _XtAddEventSeqToStateTree(eventSeq, parseTree);
1866444c061aSmrg    FreeEventSeq(eventSeq);
1867444c061aSmrg    return (str);
1868444c061aSmrg}
1869444c061aSmrg
1870444c061aSmrgstatic String CheckForPoundSign(
1871444c061aSmrg    String str,
1872444c061aSmrg    _XtTranslateOp defaultOp,
1873444c061aSmrg    _XtTranslateOp *actualOpRtn)
1874444c061aSmrg{
1875444c061aSmrg    String start;
1876444c061aSmrg    char operation[20];
1877444c061aSmrg    _XtTranslateOp opType;
1878444c061aSmrg
1879444c061aSmrg    opType = defaultOp;
1880444c061aSmrg    ScanWhitespace(str);
1881444c061aSmrg    if (*str == '#') {
1882444c061aSmrg	int len;
1883444c061aSmrg	str++;
1884444c061aSmrg	start = str;
1885444c061aSmrg	str = ScanIdent(str);
1886444c061aSmrg	len = MIN(19, str-start);
1887444c061aSmrg	(void) memmove(operation, start, len);
1888444c061aSmrg	operation[len] = '\0';
1889444c061aSmrg	if (!strcmp(operation,"replace"))
1890444c061aSmrg	  opType = XtTableReplace;
1891444c061aSmrg	else if (!strcmp(operation,"augment"))
1892444c061aSmrg	  opType = XtTableAugment;
1893444c061aSmrg	else if (!strcmp(operation,"override"))
1894444c061aSmrg	  opType = XtTableOverride;
1895444c061aSmrg	ScanWhitespace(str);
1896444c061aSmrg	if (IsNewline(*str)) {
1897444c061aSmrg	    str++;
1898444c061aSmrg	    ScanWhitespace(str);
1899444c061aSmrg	}
1900444c061aSmrg    }
1901444c061aSmrg    *actualOpRtn = opType;
1902444c061aSmrg    return str;
1903444c061aSmrg}
1904444c061aSmrg
1905444c061aSmrgstatic XtTranslations ParseTranslationTable(
1906444c061aSmrg    String 	source,
1907444c061aSmrg    Boolean	isAccelerator,
1908444c061aSmrg    _XtTranslateOp defaultOp,
1909444c061aSmrg    Boolean*	error)
1910444c061aSmrg{
1911444c061aSmrg    XtTranslations		xlations;
1912444c061aSmrg    TMStateTree			stateTrees[8];
1913444c061aSmrg    TMParseStateTreeRec		parseTreeRec, *parseTree = &parseTreeRec;
1914444c061aSmrg    XrmQuark			stackQuarks[200];
1915444c061aSmrg    TMBranchHeadRec		stackBranchHeads[200];
1916444c061aSmrg    StatePtr			stackComplexBranchHeads[200];
1917444c061aSmrg    _XtTranslateOp		actualOp;
1918444c061aSmrg
1919444c061aSmrg    if (source == NULL)
1920444c061aSmrg      return (XtTranslations)NULL;
1921444c061aSmrg
1922444c061aSmrg    source = CheckForPoundSign(source, defaultOp, &actualOp);
1923444c061aSmrg    if (isAccelerator && actualOp == XtTableReplace)
1924444c061aSmrg	actualOp = defaultOp;
1925444c061aSmrg
1926444c061aSmrg    parseTree->isSimple = TRUE;
1927444c061aSmrg    parseTree->mappingNotifyInterest = FALSE;
1928444c061aSmrg    parseTree->isAccelerator = isAccelerator;
1929444c061aSmrg    parseTree->isStackBranchHeads =
1930444c061aSmrg      parseTree->isStackQuarks =
1931444c061aSmrg	parseTree->isStackComplexBranchHeads = TRUE;
1932444c061aSmrg
1933444c061aSmrg    parseTree->numQuarks =
1934444c061aSmrg      parseTree->numBranchHeads =
1935444c061aSmrg	parseTree->numComplexBranchHeads = 0;
1936444c061aSmrg
1937444c061aSmrg    parseTree->quarkTblSize =
1938444c061aSmrg      parseTree->branchHeadTblSize =
1939444c061aSmrg	parseTree->complexBranchHeadTblSize = 200;
1940444c061aSmrg
1941444c061aSmrg    parseTree->quarkTbl = stackQuarks;
1942444c061aSmrg    parseTree->branchHeadTbl = stackBranchHeads;
1943444c061aSmrg    parseTree->complexBranchHeadTbl = stackComplexBranchHeads;
1944444c061aSmrg
1945444c061aSmrg    while (source != NULL && *source != '\0') {
1946444c061aSmrg	source =  ParseTranslationTableProduction(parseTree, source, error);
1947444c061aSmrg	if (*error == TRUE) break;
1948444c061aSmrg    }
1949444c061aSmrg    stateTrees[0] = _XtParseTreeToStateTree(parseTree);
1950444c061aSmrg
1951444c061aSmrg    if (!parseTree->isStackQuarks)
1952444c061aSmrg      XtFree((char *)parseTree->quarkTbl);
1953444c061aSmrg    if (!parseTree->isStackBranchHeads)
1954444c061aSmrg      XtFree((char *)parseTree->branchHeadTbl);
1955444c061aSmrg    if (!parseTree->isStackComplexBranchHeads)
1956444c061aSmrg      XtFree((char *)parseTree->complexBranchHeadTbl);
1957444c061aSmrg
1958444c061aSmrg    xlations = _XtCreateXlations(stateTrees, 1, NULL, NULL);
1959444c061aSmrg    xlations->operation = actualOp;
1960444c061aSmrg
1961444c061aSmrg#ifdef notdef
1962444c061aSmrg    XtFree(stateTrees);
1963444c061aSmrg#endif /* notdef */
1964444c061aSmrg    return xlations;
1965444c061aSmrg}
1966444c061aSmrg
1967444c061aSmrg/*** public procedures ***/
1968444c061aSmrg
1969444c061aSmrg/*ARGSUSED*/
1970444c061aSmrgBoolean XtCvtStringToAcceleratorTable(
1971444c061aSmrg    Display*	dpy,
1972444c061aSmrg    XrmValuePtr args,
1973444c061aSmrg    Cardinal    *num_args,
1974444c061aSmrg    XrmValuePtr from,
1975444c061aSmrg    XrmValuePtr to,
1976444c061aSmrg    XtPointer	*closure)
1977444c061aSmrg{
1978444c061aSmrg    String str;
1979444c061aSmrg    Boolean error = FALSE;
1980444c061aSmrg
1981444c061aSmrg    if (*num_args != 0)
1982444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
1983444c061aSmrg	  "wrongParameters","cvtStringToAcceleratorTable",XtCXtToolkitError,
1984444c061aSmrg          "String to AcceleratorTable conversion needs no extra arguments",
1985444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
1986444c061aSmrg    str = (String)(from->addr);
1987444c061aSmrg    if (str == NULL) {
1988444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
1989444c061aSmrg	  "badParameters","cvtStringToAcceleratorTable",XtCXtToolkitError,
1990444c061aSmrg          "String to AcceleratorTable conversion needs string",
1991444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
1992444c061aSmrg	return FALSE;
1993444c061aSmrg    }
1994444c061aSmrg    if (to->addr != NULL) {
1995444c061aSmrg	if (to->size < sizeof(XtAccelerators)) {
1996444c061aSmrg	    to->size = sizeof(XtAccelerators);
1997444c061aSmrg	    return FALSE;
1998444c061aSmrg	}
1999444c061aSmrg	*(XtAccelerators*)to->addr =
2000444c061aSmrg	    (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, &error);
2001444c061aSmrg    }
2002444c061aSmrg    else {
2003444c061aSmrg	static XtAccelerators staticStateTable;
2004444c061aSmrg	staticStateTable =
2005444c061aSmrg	    (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, &error);
2006444c061aSmrg	to->addr = (XPointer) &staticStateTable;
2007444c061aSmrg	to->size = sizeof(XtAccelerators);
2008444c061aSmrg    }
2009444c061aSmrg    if (error == TRUE)
2010444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2011444c061aSmrg	  "parseError","cvtStringToAcceleratorTable",XtCXtToolkitError,
2012444c061aSmrg          "String to AcceleratorTable conversion encountered errors",
2013444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2014444c061aSmrg    return (error != TRUE);
2015444c061aSmrg}
2016444c061aSmrg
2017444c061aSmrg
2018444c061aSmrg/*ARGSUSED*/
2019444c061aSmrgBoolean
2020444c061aSmrgXtCvtStringToTranslationTable(
2021444c061aSmrg    Display	*dpy,
2022444c061aSmrg    XrmValuePtr args,
2023444c061aSmrg    Cardinal    *num_args,
2024444c061aSmrg    XrmValuePtr from,
2025444c061aSmrg    XrmValuePtr to,
2026444c061aSmrg    XtPointer	*closure_ret)
2027444c061aSmrg{
2028444c061aSmrg    String str;
2029444c061aSmrg    Boolean error = FALSE;
2030444c061aSmrg
2031444c061aSmrg    if (*num_args != 0)
2032444c061aSmrg      XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2033444c061aSmrg	    "wrongParameters","cvtStringToTranslationTable",XtCXtToolkitError,
2034444c061aSmrg	    "String to TranslationTable conversion needs no extra arguments",
2035444c061aSmrg	    (String *)NULL, (Cardinal *)NULL);
2036444c061aSmrg    str = (String)(from->addr);
2037444c061aSmrg    if (str == NULL) {
2038444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2039444c061aSmrg	  "badParameters","cvtStringToTranslation",XtCXtToolkitError,
2040444c061aSmrg          "String to TranslationTable conversion needs string",
2041444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2042444c061aSmrg	return FALSE;
2043444c061aSmrg    }
2044444c061aSmrg    if (to->addr != NULL) {
2045444c061aSmrg	if (to->size < sizeof(XtTranslations)) {
2046444c061aSmrg	    to->size = sizeof(XtTranslations);
2047444c061aSmrg	    return FALSE;
2048444c061aSmrg	}
2049444c061aSmrg	*(XtTranslations*)to->addr =
2050444c061aSmrg	    ParseTranslationTable(str, FALSE, XtTableReplace, &error);
2051444c061aSmrg    }
2052444c061aSmrg    else {
2053444c061aSmrg	static XtTranslations staticStateTable;
2054444c061aSmrg	staticStateTable =
2055444c061aSmrg	    ParseTranslationTable(str, FALSE, XtTableReplace, &error);
2056444c061aSmrg	to->addr = (XPointer) &staticStateTable;
2057444c061aSmrg	to->size = sizeof(XtTranslations);
2058444c061aSmrg    }
2059444c061aSmrg    if (error == TRUE)
2060444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2061444c061aSmrg	  "parseError","cvtStringToTranslationTable",XtCXtToolkitError,
2062444c061aSmrg          "String to TranslationTable conversion encountered errors",
2063444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2064444c061aSmrg    return (error != TRUE);
2065444c061aSmrg}
2066444c061aSmrg
2067444c061aSmrg
2068444c061aSmrg/*
2069444c061aSmrg * Parses a user's or applications translation table
2070444c061aSmrg */
2071444c061aSmrgXtAccelerators XtParseAcceleratorTable(
2072444c061aSmrg    _Xconst char* source)
2073444c061aSmrg{
2074444c061aSmrg    Boolean error = FALSE;
2075444c061aSmrg    XtAccelerators ret =
2076444c061aSmrg	(XtAccelerators) ParseTranslationTable ((char *)source, TRUE, XtTableAugment, &error);
2077444c061aSmrg    if (error == TRUE)
2078444c061aSmrg        XtWarningMsg ("parseError", "cvtStringToAcceleratorTable",
2079444c061aSmrg	  XtCXtToolkitError,
2080444c061aSmrg          "String to AcceleratorTable conversion encountered errors",
2081444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2082444c061aSmrg    return ret;
2083444c061aSmrg}
2084444c061aSmrg
2085444c061aSmrgXtTranslations XtParseTranslationTable(
2086444c061aSmrg    _Xconst char* source)
2087444c061aSmrg{
2088444c061aSmrg    Boolean error = FALSE;
2089444c061aSmrg    XtTranslations ret = ParseTranslationTable((char *)source, FALSE, XtTableReplace, &error);
2090444c061aSmrg    if (error == TRUE)
2091444c061aSmrg        XtWarningMsg ("parseError",
2092444c061aSmrg	  "cvtStringToTranslationTable", XtCXtToolkitError,
2093444c061aSmrg          "String to TranslationTable conversion encountered errors",
2094444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2095444c061aSmrg    return ret;
2096444c061aSmrg}
2097444c061aSmrg
2098444c061aSmrgvoid _XtTranslateInitialize(void)
2099444c061aSmrg{
2100444c061aSmrg    LOCK_PROCESS;
2101444c061aSmrg    if (initialized) {
2102444c061aSmrg	XtWarningMsg("translationError","xtTranslateInitialize",
2103444c061aSmrg                  XtCXtToolkitError,"Initializing Translation manager twice.",
2104444c061aSmrg                    (String *)NULL, (Cardinal *)NULL);
2105444c061aSmrg	UNLOCK_PROCESS;
2106444c061aSmrg	return;
2107444c061aSmrg    }
2108444c061aSmrg
2109444c061aSmrg    initialized = TRUE;
2110444c061aSmrg    UNLOCK_PROCESS;
2111444c061aSmrg    QMeta = XrmPermStringToQuark("Meta");
2112444c061aSmrg    QCtrl = XrmPermStringToQuark("Ctrl");
2113444c061aSmrg    QNone = XrmPermStringToQuark("None");
2114444c061aSmrg    QAny  = XrmPermStringToQuark("Any");
2115444c061aSmrg
2116444c061aSmrg    Compile_XtEventTable( events, XtNumber(events) );
2117444c061aSmrg    Compile_XtModifierTable( modifiers, XtNumber(modifiers) );
2118444c061aSmrg    CompileNameValueTable( buttonNames );
2119444c061aSmrg    CompileNameValueTable( notifyModes );
2120444c061aSmrg    CompileNameValueTable( motionDetails );
2121444c061aSmrg#if 0
2122444c061aSmrg    CompileNameValueTable( notifyDetail );
2123444c061aSmrg    CompileNameValueTable( visibilityNotify );
2124444c061aSmrg    CompileNameValueTable( circulation );
2125444c061aSmrg    CompileNameValueTable( propertyChanged );
2126444c061aSmrg#endif
2127444c061aSmrg    CompileNameValueTable( mappingNotify );
2128444c061aSmrg}
2129444c061aSmrg
2130444c061aSmrgvoid _XtAddTMConverters(
2131444c061aSmrg    ConverterTable table)
2132444c061aSmrg{
2133444c061aSmrg     _XtTableAddConverter(table,
2134444c061aSmrg	     _XtQString,
2135444c061aSmrg	     XrmPermStringToQuark(XtRTranslationTable),
2136444c061aSmrg 	     XtCvtStringToTranslationTable, (XtConvertArgList) NULL,
2137444c061aSmrg	     (Cardinal)0, True, CACHED, _XtFreeTranslations, True);
2138444c061aSmrg     _XtTableAddConverter(table, _XtQString,
2139444c061aSmrg	     XrmPermStringToQuark(XtRAcceleratorTable),
2140444c061aSmrg 	     XtCvtStringToAcceleratorTable, (XtConvertArgList) NULL,
2141444c061aSmrg	     (Cardinal)0, True, CACHED, _XtFreeTranslations, True);
2142444c061aSmrg     _XtTableAddConverter(table,
2143444c061aSmrg	     XrmPermStringToQuark( _XtRStateTablePair ),
2144444c061aSmrg	     XrmPermStringToQuark(XtRTranslationTable),
2145444c061aSmrg 	     _XtCvtMergeTranslations, (XtConvertArgList) NULL,
2146444c061aSmrg	     (Cardinal)0, True, CACHED, _XtFreeTranslations, True);
2147444c061aSmrg}
2148