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