TMparse.c revision 4f45da70
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 {
116444c061aSmrg    char*      name;
117444c061aSmrg    XrmQuark   signature;
118444c061aSmrg    ModifierProc modifierParseProc;
119444c061aSmrg    Value      value;
120444c061aSmrg} ModifierRec, *ModifierKeys;
121444c061aSmrg
122444c061aSmrgtypedef struct _EventKey {
123444c061aSmrg    char    	*event;
124444c061aSmrg    XrmQuark	signature;
125444c061aSmrg    EventType	eventType;
126444c061aSmrg    ParseProc	parseDetail;
127444c061aSmrg    Opaque	closure;
128444c061aSmrg}EventKey, *EventKeys;
129444c061aSmrg
130444c061aSmrgtypedef struct {
131444c061aSmrg    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#ifndef __UNIXOS2__
384444c061aSmrg#define IsNewline(str) ((str) == '\n')
385444c061aSmrg#else
386444c061aSmrg#define IsNewline(str) ((str) == '\n' || (str) == '\r')
387444c061aSmrg#endif
388444c061aSmrg
389444c061aSmrg#define ScanFor(str, ch) \
390444c061aSmrg    while ((*(str) != (ch)) && (*(str) != '\0') && !IsNewline(*(str))) (str)++
391444c061aSmrg
392444c061aSmrg#define ScanNumeric(str)  while ('0' <= *(str) && *(str) <= '9') (str)++
393444c061aSmrg
394444c061aSmrg#define ScanAlphanumeric(str) \
395444c061aSmrg    while (('A' <= *(str) && *(str) <= 'Z') || \
396444c061aSmrg           ('a' <= *(str) && *(str) <= 'z') || \
397444c061aSmrg           ('0' <= *(str) && *(str) <= '9')) (str)++
398444c061aSmrg
399444c061aSmrg#ifndef __UNIXOS2__
400444c061aSmrg#define ScanWhitespace(str) \
401444c061aSmrg    while (*(str) == ' ' || *(str) == '\t') (str)++
402444c061aSmrg#else
403444c061aSmrg#define ScanWhitespace(str) \
404444c061aSmrg    while (*(str) == ' ' || *(str) == '\t' || *(str) == '\r') (str)++
405444c061aSmrg#endif
406444c061aSmrg
407444c061aSmrgstatic Boolean initialized = FALSE;
408444c061aSmrgstatic XrmQuark QMeta;
409444c061aSmrgstatic XrmQuark QCtrl;
410444c061aSmrgstatic XrmQuark QNone;
411444c061aSmrgstatic XrmQuark QAny;
412444c061aSmrg
413444c061aSmrgstatic void FreeEventSeq(
414444c061aSmrg    EventSeqPtr eventSeq)
415444c061aSmrg{
416444c061aSmrg    register EventSeqPtr evs = eventSeq;
417444c061aSmrg
418444c061aSmrg    while (evs != NULL) {
419444c061aSmrg	evs->state = (StatePtr) evs;
420444c061aSmrg	if (evs->next != NULL
421444c061aSmrg	    && evs->next->state == (StatePtr) evs->next)
422444c061aSmrg	    evs->next = NULL;
423444c061aSmrg	evs = evs->next;
424444c061aSmrg    }
425444c061aSmrg
426444c061aSmrg    evs = eventSeq;
427444c061aSmrg    while (evs != NULL) {
428444c061aSmrg	register EventPtr event = evs;
429444c061aSmrg	evs = evs->next;
430444c061aSmrg	if (evs == event) evs = NULL;
431444c061aSmrg	XtFree((char *)event);
432444c061aSmrg    }
433444c061aSmrg}
434444c061aSmrg
435444c061aSmrgstatic void CompileNameValueTable(
436444c061aSmrg    NameValueTable table)
437444c061aSmrg{
438444c061aSmrg    register int i;
439444c061aSmrg
440444c061aSmrg    for (i=0; table[i].name; i++)
441444c061aSmrg        table[i].signature = XrmPermStringToQuark(table[i].name);
442444c061aSmrg}
443444c061aSmrg
444444c061aSmrgstatic int OrderEvents(_Xconst void *a, _Xconst void *b)
445444c061aSmrg{
446444c061aSmrg    return ((((_Xconst EventKey *)a)->signature <
447444c061aSmrg	     ((_Xconst EventKey *)b)->signature) ? -1 : 1);
448444c061aSmrg}
449444c061aSmrg
450444c061aSmrgstatic void Compile_XtEventTable(
451444c061aSmrg    EventKeys	table,
452444c061aSmrg    Cardinal	count)
453444c061aSmrg{
454444c061aSmrg    register int i;
455444c061aSmrg    register EventKeys entry = table;
456444c061aSmrg
457444c061aSmrg    for (i=count; --i >= 0; entry++)
458444c061aSmrg	entry->signature = XrmPermStringToQuark(entry->event);
459444c061aSmrg    qsort(table, count, sizeof(EventKey), OrderEvents);
460444c061aSmrg}
461444c061aSmrg
462444c061aSmrgstatic int OrderModifiers(_Xconst void *a, _Xconst void *b)
463444c061aSmrg{
464444c061aSmrg    return ((((_Xconst ModifierRec *)a)->signature <
465444c061aSmrg	     ((_Xconst ModifierRec *)b)->signature) ? -1 : 1);
466444c061aSmrg}
467444c061aSmrg
468444c061aSmrgstatic void Compile_XtModifierTable(
469444c061aSmrg    ModifierKeys table,
470444c061aSmrg    Cardinal count)
471444c061aSmrg{
472444c061aSmrg    register int i;
473444c061aSmrg    register ModifierKeys entry = table;
474444c061aSmrg
475444c061aSmrg    for (i=count; --i >= 0; entry++)
476444c061aSmrg	entry->signature = XrmPermStringToQuark(entry->name);
477444c061aSmrg    qsort(table, count, sizeof(ModifierRec), OrderModifiers);
478444c061aSmrg}
479444c061aSmrg
480444c061aSmrgstatic String PanicModeRecovery(
481444c061aSmrg    String str)
482444c061aSmrg{
483444c061aSmrg     ScanFor(str,'\n');
484444c061aSmrg     if (*str == '\n') str++;
485444c061aSmrg     return str;
486444c061aSmrg
487444c061aSmrg}
488444c061aSmrg
489444c061aSmrg
490444c061aSmrgstatic void Syntax(
491444c061aSmrg    String str0,String str1)
492444c061aSmrg{
493444c061aSmrg    Cardinal num_params = 2;
494444c061aSmrg    String params[2];
495444c061aSmrg
496444c061aSmrg    params[0] = str0;
497444c061aSmrg    params[1] = str1;
498444c061aSmrg    XtWarningMsg(XtNtranslationParseError,"parseError",XtCXtToolkitError,
499444c061aSmrg		 "translation table syntax error: %s %s",params,&num_params);
500444c061aSmrg}
501444c061aSmrg
502444c061aSmrg
503444c061aSmrg
504444c061aSmrgstatic Cardinal LookupTMEventType(
505444c061aSmrg  String eventStr,
506444c061aSmrg  Boolean *error)
507444c061aSmrg{
508444c061aSmrg    register int   i = 0, left, right;
509444c061aSmrg    register XrmQuark	signature;
510444c061aSmrg    static int 	previous = 0;
511444c061aSmrg
512444c061aSmrg    LOCK_PROCESS;
513444c061aSmrg    if ((signature = StringToQuark(eventStr)) == events[previous].signature) {
514444c061aSmrg	UNLOCK_PROCESS;
515444c061aSmrg	return (Cardinal) previous;
516444c061aSmrg    }
517444c061aSmrg
518444c061aSmrg    left = 0;
519444c061aSmrg    right = XtNumber(events) - 1;
520444c061aSmrg    while (left <= right) {
521444c061aSmrg	i = (left + right) >> 1;
522444c061aSmrg	if (signature < events[i].signature)
523444c061aSmrg	    right = i - 1;
524444c061aSmrg	else if (signature > events[i].signature)
525444c061aSmrg	    left = i + 1;
526444c061aSmrg	else {
527444c061aSmrg	    previous = i;
528444c061aSmrg	    UNLOCK_PROCESS;
529444c061aSmrg	    return (Cardinal) i;
530444c061aSmrg	}
531444c061aSmrg    }
532444c061aSmrg
533444c061aSmrg    Syntax("Unknown event type :  ",eventStr);
534444c061aSmrg    *error = TRUE;
535444c061aSmrg    UNLOCK_PROCESS;
536444c061aSmrg    return (Cardinal) i;
537444c061aSmrg}
538444c061aSmrg
539444c061aSmrgstatic void StoreLateBindings(
540444c061aSmrg    KeySym  keysymL,
541444c061aSmrg    Boolean notL,
542444c061aSmrg    KeySym keysymR,
543444c061aSmrg    Boolean notR,
544444c061aSmrg    LateBindingsPtr* lateBindings)
545444c061aSmrg{
546444c061aSmrg    LateBindingsPtr temp;
547444c061aSmrg    Boolean pair = FALSE;
548444c061aSmrg    unsigned long count,number;
549444c061aSmrg    if (lateBindings != NULL){
550444c061aSmrg        temp = *lateBindings;
551444c061aSmrg        if (temp != NULL) {
552444c061aSmrg            for (count = 0; temp[count].keysym; count++){/*EMPTY*/}
553444c061aSmrg        }
554444c061aSmrg        else count = 0;
555444c061aSmrg        if (! keysymR){
556444c061aSmrg             number = 1;pair = FALSE;
557444c061aSmrg        } else{
558444c061aSmrg             number = 2;pair = TRUE;
559444c061aSmrg        }
560444c061aSmrg
561444c061aSmrg        temp = (LateBindingsPtr)XtRealloc((char *)temp,
562444c061aSmrg            (unsigned)((count+number+1) * sizeof(LateBindings)) );
563444c061aSmrg        *lateBindings = temp;
564444c061aSmrg        temp[count].knot = notL;
565444c061aSmrg        temp[count].pair = pair;
566444c061aSmrg	if (count == 0)
567444c061aSmrg	    temp[count].ref_count = 1;
568444c061aSmrg        temp[count++].keysym = keysymL;
569444c061aSmrg        if (keysymR){
570444c061aSmrg            temp[count].knot = notR;
571444c061aSmrg            temp[count].pair = FALSE;
572444c061aSmrg	    temp[count].ref_count = 0;
573444c061aSmrg            temp[count++].keysym = keysymR;
574444c061aSmrg        }
575444c061aSmrg        temp[count].knot = temp[count].pair = FALSE;
576444c061aSmrg        temp[count].ref_count = 0;
577444c061aSmrg        temp[count].keysym = 0;
578444c061aSmrg    }
579444c061aSmrg}
580444c061aSmrg
581444c061aSmrgstatic void _XtParseKeysymMod(
582444c061aSmrg    String name,
583444c061aSmrg    LateBindingsPtr* lateBindings,
584444c061aSmrg    Boolean notFlag,
585444c061aSmrg    Value *valueP,
586444c061aSmrg    Boolean *error)
587444c061aSmrg{
588444c061aSmrg    KeySym keySym;
589444c061aSmrg    keySym = StringToKeySym(name, error);
590444c061aSmrg    *valueP = 0;
591444c061aSmrg    if (keySym != NoSymbol) {
592444c061aSmrg        StoreLateBindings(keySym,notFlag,(KeySym) NULL,FALSE,lateBindings);
593444c061aSmrg    }
594444c061aSmrg}
595444c061aSmrg
596444c061aSmrgstatic Boolean _XtLookupModifier(
597444c061aSmrg    XrmQuark signature,
598444c061aSmrg    LateBindingsPtr* lateBindings,
599444c061aSmrg    Boolean notFlag,
600444c061aSmrg    Value *valueP,
601444c061aSmrg    Bool constMask)
602444c061aSmrg{
603444c061aSmrg    register int i, left, right;
604444c061aSmrg    static int previous = 0;
605444c061aSmrg
606444c061aSmrg    LOCK_PROCESS;
607444c061aSmrg    if (signature == modifiers[previous].signature) {
608444c061aSmrg	if (constMask)  *valueP = modifiers[previous].value;
609444c061aSmrg	else /* if (modifiers[previous].modifierParseProc) always true */
610444c061aSmrg	   (*modifiers[previous].modifierParseProc)
611444c061aSmrg	      (modifiers[previous].value, lateBindings, notFlag, valueP);
612444c061aSmrg	UNLOCK_PROCESS;
613444c061aSmrg	return TRUE;
614444c061aSmrg    }
615444c061aSmrg
616444c061aSmrg    left = 0;
617444c061aSmrg    right = XtNumber(modifiers) - 1;
618444c061aSmrg    while (left <= right) {
619444c061aSmrg	i = (left + right) >> 1;
620444c061aSmrg	if (signature < modifiers[i].signature)
621444c061aSmrg	    right = i - 1;
622444c061aSmrg	else if (signature > modifiers[i].signature)
623444c061aSmrg	    left = i + 1;
624444c061aSmrg	else {
625444c061aSmrg	    previous = i;
626444c061aSmrg	    if (constMask)  *valueP = modifiers[i].value;
627444c061aSmrg	    else /* if (modifiers[i].modifierParseProc) always true */
628444c061aSmrg		(*modifiers[i].modifierParseProc)
629444c061aSmrg		    (modifiers[i].value, lateBindings, notFlag, valueP);
630444c061aSmrg	    UNLOCK_PROCESS;
631444c061aSmrg	    return TRUE;
632444c061aSmrg	}
633444c061aSmrg    }
634444c061aSmrg    UNLOCK_PROCESS;
635444c061aSmrg    return FALSE;
636444c061aSmrg}
637444c061aSmrg
638444c061aSmrg
639444c061aSmrgstatic String ScanIdent(
640444c061aSmrg    register String str)
641444c061aSmrg{
642444c061aSmrg    ScanAlphanumeric(str);
643444c061aSmrg    while (
644444c061aSmrg	   ('A' <= *str && *str <= 'Z')
645444c061aSmrg	|| ('a' <= *str && *str <= 'z')
646444c061aSmrg	|| ('0' <= *str && *str <= '9')
647444c061aSmrg	|| (*str == '-')
648444c061aSmrg	|| (*str == '_')
649444c061aSmrg	|| (*str == '$')
650444c061aSmrg	) str++;
651444c061aSmrg    return str;
652444c061aSmrg}
653444c061aSmrg
654444c061aSmrgstatic String FetchModifierToken(
655444c061aSmrg    String str,
656444c061aSmrg    XrmQuark *token_return)
657444c061aSmrg{
658444c061aSmrg    String start = str;
659444c061aSmrg
660444c061aSmrg    if (*str == '$') {
661444c061aSmrg        *token_return = QMeta;
662444c061aSmrg        str++;
663444c061aSmrg        return str;
664444c061aSmrg    }
665444c061aSmrg    if (*str == '^') {
666444c061aSmrg        *token_return = QCtrl;
667444c061aSmrg        str++;
668444c061aSmrg        return str;
669444c061aSmrg    }
670444c061aSmrg    str = ScanIdent(str);
671444c061aSmrg    if (start != str) {
672444c061aSmrg	char modStrbuf[100];
673444c061aSmrg	char* modStr;
674444c061aSmrg
675444c061aSmrg	modStr = XtStackAlloc ((size_t)(str - start + 1), modStrbuf);
676444c061aSmrg	if (modStr == NULL) _XtAllocError (NULL);
677444c061aSmrg	(void) memmove(modStr, start, str-start);
678444c061aSmrg	modStr[str-start] = '\0';
679444c061aSmrg	*token_return = XrmStringToQuark(modStr);
680444c061aSmrg	XtStackFree (modStr, modStrbuf);
681444c061aSmrg	return str;
682444c061aSmrg    }
683444c061aSmrg    return str;
684444c061aSmrg}
685444c061aSmrg
686444c061aSmrgstatic String ParseModifiers(
687444c061aSmrg    register String str,
688444c061aSmrg    EventPtr event,
689444c061aSmrg    Boolean* error)
690444c061aSmrg{
691444c061aSmrg    register String start;
692444c061aSmrg    Boolean notFlag, exclusive, keysymAsMod;
693444c061aSmrg    Value maskBit;
694444c061aSmrg    XrmQuark Qmod;
695444c061aSmrg
696444c061aSmrg    ScanWhitespace(str);
697444c061aSmrg    start = str;
698444c061aSmrg    str = FetchModifierToken(str, &Qmod);
699444c061aSmrg    exclusive = FALSE;
700444c061aSmrg    if (start != str) {
701444c061aSmrg	if (Qmod == QNone) {
702444c061aSmrg	    event->event.modifierMask = ~0;
703444c061aSmrg	    event->event.modifiers = 0;
704444c061aSmrg	    ScanWhitespace(str);
705444c061aSmrg	    return str;
706444c061aSmrg	} else if (Qmod == QAny) { /*backward compatability*/
707444c061aSmrg	    event->event.modifierMask = 0;
708444c061aSmrg	    event->event.modifiers = AnyModifier;
709444c061aSmrg	    ScanWhitespace(str);
710444c061aSmrg	    return str;
711444c061aSmrg	}
712444c061aSmrg	str = start; /*if plain modifier, reset to beginning */
713444c061aSmrg    }
714444c061aSmrg    else while (*str == '!' || *str == ':') {
715444c061aSmrg        if (*str == '!') {
716444c061aSmrg             exclusive = TRUE;
717444c061aSmrg             str++;
718444c061aSmrg             ScanWhitespace(str);
719444c061aSmrg        }
720444c061aSmrg        if (*str == ':') {
721444c061aSmrg             event->event.standard = TRUE;
722444c061aSmrg             str++;
723444c061aSmrg             ScanWhitespace(str);
724444c061aSmrg        }
725444c061aSmrg    }
726444c061aSmrg
727444c061aSmrg    while (*str != '<') {
728444c061aSmrg        if (*str == '~') {
729444c061aSmrg             notFlag = TRUE;
730444c061aSmrg             str++;
731444c061aSmrg          } else
732444c061aSmrg              notFlag = FALSE;
733444c061aSmrg        if (*str == '@') {
734444c061aSmrg            keysymAsMod = TRUE;
735444c061aSmrg            str++;
736444c061aSmrg        }
737444c061aSmrg        else keysymAsMod = FALSE;
738444c061aSmrg	start = str;
739444c061aSmrg        str = FetchModifierToken(str, &Qmod);
740444c061aSmrg        if (start == str) {
741444c061aSmrg            Syntax("Modifier or '<' expected","");
742444c061aSmrg            *error = TRUE;
743444c061aSmrg            return PanicModeRecovery(str);
744444c061aSmrg        }
745444c061aSmrg         if (keysymAsMod) {
746444c061aSmrg             _XtParseKeysymMod(XrmQuarkToString(Qmod),
747444c061aSmrg			       &event->event.lateModifiers,
748444c061aSmrg			       notFlag,&maskBit, error);
749444c061aSmrg	     if (*error)
750444c061aSmrg                 return PanicModeRecovery(str);
751444c061aSmrg
752444c061aSmrg         } else
753444c061aSmrg  	     if (!_XtLookupModifier(Qmod, &event->event.lateModifiers,
754444c061aSmrg				    notFlag, &maskBit, FALSE)) {
755444c061aSmrg	         Syntax("Unknown modifier name:  ", XrmQuarkToString(Qmod));
756444c061aSmrg                 *error = TRUE;
757444c061aSmrg                 return PanicModeRecovery(str);
758444c061aSmrg             }
759444c061aSmrg        event->event.modifierMask |= maskBit;
760444c061aSmrg	if (notFlag) event->event.modifiers &= ~maskBit;
761444c061aSmrg	else event->event.modifiers |= maskBit;
762444c061aSmrg        ScanWhitespace(str);
763444c061aSmrg    }
764444c061aSmrg    if (exclusive) event->event.modifierMask = ~0;
765444c061aSmrg    return str;
766444c061aSmrg}
767444c061aSmrg
768444c061aSmrgstatic String ParseXtEventType(
769444c061aSmrg    register String str,
770444c061aSmrg    EventPtr event,
771444c061aSmrg    Cardinal *tmEventP,
772444c061aSmrg    Boolean* error)
773444c061aSmrg{
774444c061aSmrg    String start = str;
775444c061aSmrg    char eventTypeStrbuf[100];
776444c061aSmrg    char* eventTypeStr;
777444c061aSmrg
778444c061aSmrg    ScanAlphanumeric(str);
779444c061aSmrg    eventTypeStr = XtStackAlloc ((size_t)(str - start + 1), eventTypeStrbuf);
780444c061aSmrg    if (eventTypeStr == NULL) _XtAllocError (NULL);
781444c061aSmrg    (void) memmove(eventTypeStr, start, str-start);
782444c061aSmrg    eventTypeStr[str-start] = '\0';
783444c061aSmrg    *tmEventP = LookupTMEventType(eventTypeStr,error);
784444c061aSmrg    XtStackFree (eventTypeStr, eventTypeStrbuf);
785444c061aSmrg    if (*error)
786444c061aSmrg        return PanicModeRecovery(str);
787444c061aSmrg    event->event.eventType = events[*tmEventP].eventType;
788444c061aSmrg    return str;
789444c061aSmrg}
790444c061aSmrg
791444c061aSmrgstatic unsigned long StrToHex(
792444c061aSmrg    String str)
793444c061aSmrg{
794444c061aSmrg    register char   c;
795444c061aSmrg    register unsigned long    val = 0;
796444c061aSmrg
797444c061aSmrg    while ((c = *str)) {
798444c061aSmrg	if ('0' <= c && c <= '9') val = val*16+c-'0';
799444c061aSmrg	else if ('a' <= c && c <= 'z') val = val*16+c-'a'+10;
800444c061aSmrg	else if ('A' <= c && c <= 'Z') val = val*16+c-'A'+10;
801444c061aSmrg	else return 0;
802444c061aSmrg	str++;
803444c061aSmrg    }
804444c061aSmrg
805444c061aSmrg    return val;
806444c061aSmrg}
807444c061aSmrg
808444c061aSmrgstatic unsigned long StrToOct(
809444c061aSmrg    String str)
810444c061aSmrg{
811444c061aSmrg    register char c;
812444c061aSmrg    register unsigned long  val = 0;
813444c061aSmrg
814444c061aSmrg    while ((c = *str)) {
815444c061aSmrg        if ('0' <= c && c <= '7') val = val*8+c-'0'; else return 0;
816444c061aSmrg	str++;
817444c061aSmrg    }
818444c061aSmrg
819444c061aSmrg    return val;
820444c061aSmrg}
821444c061aSmrg
822444c061aSmrgstatic unsigned long StrToNum(
823444c061aSmrg    String str)
824444c061aSmrg{
825444c061aSmrg    register char c;
826444c061aSmrg    register unsigned long val = 0;
827444c061aSmrg
828444c061aSmrg    if (*str == '0') {
829444c061aSmrg	str++;
830444c061aSmrg	if (*str == 'x' || *str == 'X') return StrToHex(++str);
831444c061aSmrg	else return StrToOct(str);
832444c061aSmrg    }
833444c061aSmrg
834444c061aSmrg    while ((c = *str)) {
835444c061aSmrg	if ('0' <= c && c <= '9') val = val*10+c-'0';
836444c061aSmrg	else return 0;
837444c061aSmrg	str++;
838444c061aSmrg    }
839444c061aSmrg
840444c061aSmrg    return val;
841444c061aSmrg}
842444c061aSmrg
843444c061aSmrgstatic KeySym StringToKeySym(
844444c061aSmrg    String str,
845444c061aSmrg    Boolean *error)
846444c061aSmrg{
847444c061aSmrg    KeySym k;
848444c061aSmrg
849444c061aSmrg    if (str == NULL || *str == '\0') return (KeySym) 0;
850444c061aSmrg
851444c061aSmrg#ifndef NOTASCII
852444c061aSmrg    /* special case single character ASCII, for speed */
853444c061aSmrg    if (*(str+1) == '\0') {
854444c061aSmrg	if (' ' <= *str && *str <= '~') return XK_space + (*str - ' ');
855444c061aSmrg    }
856444c061aSmrg#endif
857444c061aSmrg
858444c061aSmrg    if ('0' <= *str && *str <= '9') return (KeySym) StrToNum(str);
859444c061aSmrg    k = XStringToKeysym(str);
860444c061aSmrg    if (k != NoSymbol) return k;
861444c061aSmrg
862444c061aSmrg#ifdef NOTASCII
863444c061aSmrg    /* fall-back case to preserve backwards compatibility; no-one
864444c061aSmrg     * should be relying upon this!
865444c061aSmrg     */
866444c061aSmrg    if (*(str+1) == '\0') return (KeySym) *str;
867444c061aSmrg#endif
868444c061aSmrg
869444c061aSmrg    Syntax("Unknown keysym name: ", str);
870444c061aSmrg    *error = TRUE;
871444c061aSmrg    return NoSymbol;
872444c061aSmrg}
873444c061aSmrg/* ARGSUSED */
874444c061aSmrgstatic void ParseModImmed(
875444c061aSmrg    Value value,
876444c061aSmrg    LateBindingsPtr* lateBindings,
877444c061aSmrg    Boolean notFlag,
878444c061aSmrg    Value* valueP)
879444c061aSmrg{
880444c061aSmrg    *valueP = value;
881444c061aSmrg}
882444c061aSmrg
883444c061aSmrg /* is only valid with keysyms that have an _L and _R in their name;
884444c061aSmrg  * and ignores keysym lookup errors (i.e. assumes only valid keysyms)
885444c061aSmrg  */
886444c061aSmrgstatic void ParseModSym(
887444c061aSmrg    Value value,
888444c061aSmrg    LateBindingsPtr* lateBindings,
889444c061aSmrg    Boolean notFlag,
890444c061aSmrg    Value* valueP)
891444c061aSmrg{
892444c061aSmrg    register KeySym keysymL = (KeySym)value;
893444c061aSmrg    register KeySym keysymR = keysymL + 1; /* valid for supported keysyms */
894444c061aSmrg    StoreLateBindings(keysymL,notFlag,keysymR,notFlag,lateBindings);
895444c061aSmrg    *valueP = 0;
896444c061aSmrg}
897444c061aSmrg
898444c061aSmrg#ifdef sparc
899444c061aSmrg/*
900444c061aSmrg * The stupid optimizer in SunOS 4.0.3 and below generates bogus code that
901444c061aSmrg * causes the value of the most recently used variable to be returned instead
902444c061aSmrg * of the value passed in.
903444c061aSmrg */
904444c061aSmrgstatic String stupid_optimizer_kludge;
905444c061aSmrg#define BROKEN_OPTIMIZER_HACK(val) stupid_optimizer_kludge = (val)
906444c061aSmrg#else
907444c061aSmrg#define BROKEN_OPTIMIZER_HACK(val) val
908444c061aSmrg#endif
909444c061aSmrg
910444c061aSmrg/* ARGSUSED */
911444c061aSmrgstatic String ParseImmed(
912444c061aSmrg    register String str,
913444c061aSmrg    register Opaque closure,
914444c061aSmrg    register EventPtr event,
915444c061aSmrg    Boolean* error)
916444c061aSmrg{
917444c061aSmrg    event->event.eventCode = (unsigned long)closure;
918444c061aSmrg    event->event.eventCodeMask = ~0UL;
919444c061aSmrg
920444c061aSmrg    return BROKEN_OPTIMIZER_HACK(str);
921444c061aSmrg}
922444c061aSmrg
923444c061aSmrg/* ARGSUSED */
924444c061aSmrgstatic String ParseAddModifier(
925444c061aSmrg    register String str,
926444c061aSmrg    register Opaque closure,
927444c061aSmrg    register EventPtr event,
928444c061aSmrg    Boolean* error)
929444c061aSmrg{
930444c061aSmrg    register unsigned long modval = (unsigned long)closure;
931444c061aSmrg    event->event.modifiers |= modval;
932444c061aSmrg    if (modval != AnyButtonMask) /* AnyButtonMask is don't-care mask */
933444c061aSmrg	event->event.modifierMask |= modval;
934444c061aSmrg
935444c061aSmrg    return BROKEN_OPTIMIZER_HACK(str);
936444c061aSmrg}
937444c061aSmrg
938444c061aSmrg
939444c061aSmrgstatic String ParseKeyAndModifiers(
940444c061aSmrg    String str,
941444c061aSmrg    Opaque closure,
942444c061aSmrg    EventPtr event,
943444c061aSmrg    Boolean* error)
944444c061aSmrg{
945444c061aSmrg    str = ParseKeySym(str, closure, event,error);
946444c061aSmrg    if ((unsigned long) closure == 0) {
947444c061aSmrg	Value metaMask; /* unused */
948444c061aSmrg	(void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE,
949444c061aSmrg				 &metaMask, FALSE);
950444c061aSmrg    } else {
951444c061aSmrg	event->event.modifiers |= (unsigned long) closure;
952444c061aSmrg	event->event.modifierMask |= (unsigned long) closure;
953444c061aSmrg    }
954444c061aSmrg    return str;
955444c061aSmrg}
956444c061aSmrg
957444c061aSmrg/*ARGSUSED*/
958444c061aSmrgstatic String ParseKeySym(
959444c061aSmrg    register String str,
960444c061aSmrg    Opaque closure,
961444c061aSmrg    EventPtr event,
962444c061aSmrg    Boolean* error)
963444c061aSmrg{
964444c061aSmrg    char *start;
965444c061aSmrg    char keySymNamebuf[100];
966444c061aSmrg    char* keySymName;
967444c061aSmrg
968444c061aSmrg    ScanWhitespace(str);
969444c061aSmrg
970444c061aSmrg    if (*str == '\\') {
971444c061aSmrg	keySymName = keySymNamebuf;
972444c061aSmrg	str++;
973444c061aSmrg	keySymName[0] = *str;
974444c061aSmrg	if (*str != '\0' && !IsNewline(*str)) str++;
975444c061aSmrg	keySymName[1] = '\0';
976444c061aSmrg	event->event.eventCode = StringToKeySym(keySymName, error);
977444c061aSmrg	event->event.eventCodeMask = ~0L;
978444c061aSmrg    } else if (*str == ',' || *str == ':' ||
979444c061aSmrg             /* allow leftparen to be single char symbol,
980444c061aSmrg              * for backwards compatibility
981444c061aSmrg              */
982444c061aSmrg             (*str == '(' && *(str+1) >= '0' && *(str+1) <= '9')) {
983444c061aSmrg	keySymName = keySymNamebuf; /* just so we can stackfree it later */
984444c061aSmrg	/* no detail */
985444c061aSmrg	event->event.eventCode = 0L;
986444c061aSmrg        event->event.eventCodeMask = 0L;
987444c061aSmrg    } else {
988444c061aSmrg	start = str;
989444c061aSmrg	while (
990444c061aSmrg		*str != ','
991444c061aSmrg		&& *str != ':'
992444c061aSmrg		&& *str != ' '
993444c061aSmrg		&& *str != '\t'
994444c061aSmrg                && !IsNewline(*str)
995444c061aSmrg                && (*str != '(' || *(str+1) <= '0' || *(str+1) >= '9')
996444c061aSmrg		&& *str != '\0') str++;
997444c061aSmrg	keySymName = XtStackAlloc ((size_t)(str - start + 1), keySymNamebuf);
998444c061aSmrg	(void) memmove(keySymName, start, str-start);
999444c061aSmrg	keySymName[str-start] = '\0';
1000444c061aSmrg	event->event.eventCode = StringToKeySym(keySymName, error);
1001444c061aSmrg	event->event.eventCodeMask = ~0L;
1002444c061aSmrg    }
1003444c061aSmrg    if (*error) {
1004444c061aSmrg	/* We never get here when keySymName hasn't been allocated */
1005444c061aSmrg	if (keySymName[0] == '<') {
1006444c061aSmrg	    /* special case for common error */
1007444c061aSmrg	    XtWarningMsg(XtNtranslationParseError, "missingComma",
1008444c061aSmrg			 XtCXtToolkitError,
1009444c061aSmrg		     "... possibly due to missing ',' in event sequence.",
1010444c061aSmrg		     (String*)NULL, (Cardinal*)NULL);
1011444c061aSmrg	}
1012444c061aSmrg	XtStackFree (keySymName, keySymNamebuf);
1013444c061aSmrg	return PanicModeRecovery(str);
1014444c061aSmrg    }
1015444c061aSmrg    if (event->event.standard)
1016444c061aSmrg	event->event.matchEvent = _XtMatchUsingStandardMods;
1017444c061aSmrg    else
1018444c061aSmrg	event->event.matchEvent = _XtMatchUsingDontCareMods;
1019444c061aSmrg
1020444c061aSmrg    XtStackFree (keySymName, keySymNamebuf);
1021444c061aSmrg
1022444c061aSmrg    return str;
1023444c061aSmrg}
1024444c061aSmrg
1025444c061aSmrgstatic String ParseTable(
1026444c061aSmrg    register String str,
1027444c061aSmrg    Opaque closure,
1028444c061aSmrg    EventPtr event,
1029444c061aSmrg    Boolean* error)
1030444c061aSmrg{
1031444c061aSmrg    register String start = str;
1032444c061aSmrg    register XrmQuark signature;
1033444c061aSmrg    NameValueTable table = (NameValueTable) closure;
1034444c061aSmrg    char tableSymName[100];
1035444c061aSmrg
1036444c061aSmrg    event->event.eventCode = 0L;
1037444c061aSmrg    ScanAlphanumeric(str);
1038444c061aSmrg    if (str == start) {event->event.eventCodeMask = 0L; return str; }
1039444c061aSmrg    if (str-start >= 99) {
1040444c061aSmrg	Syntax("Invalid Detail Type (string is too long).", "");
1041444c061aSmrg	*error = TRUE;
1042444c061aSmrg	return str;
1043444c061aSmrg    }
1044444c061aSmrg    (void) memmove(tableSymName, start, str-start);
1045444c061aSmrg    tableSymName[str-start] = '\0';
1046444c061aSmrg    signature = StringToQuark(tableSymName);
1047444c061aSmrg    for (; table->signature != NULLQUARK; table++)
1048444c061aSmrg	if (table->signature == signature) {
1049444c061aSmrg	    event->event.eventCode = table->value;
1050444c061aSmrg	    event->event.eventCodeMask = ~0L;
1051444c061aSmrg	    return str;
1052444c061aSmrg	}
1053444c061aSmrg
1054444c061aSmrg    Syntax("Unknown Detail Type:  ", tableSymName);
1055444c061aSmrg    *error = TRUE;
1056444c061aSmrg    return PanicModeRecovery(str);
1057444c061aSmrg}
1058444c061aSmrg
1059444c061aSmrg/*ARGSUSED*/
1060444c061aSmrgstatic String ParseNone(
1061444c061aSmrg    String str,
1062444c061aSmrg    Opaque closure,
1063444c061aSmrg    EventPtr event,
1064444c061aSmrg    Boolean* error)
1065444c061aSmrg{
1066444c061aSmrg    event->event.eventCode = 0;
1067444c061aSmrg    event->event.eventCodeMask = 0;
1068444c061aSmrg
1069444c061aSmrg    return BROKEN_OPTIMIZER_HACK(str);
1070444c061aSmrg}
1071444c061aSmrg
1072444c061aSmrg/*ARGSUSED*/
1073444c061aSmrgstatic String ParseAtom(
1074444c061aSmrg    String str,
1075444c061aSmrg    Opaque closure,
1076444c061aSmrg    EventPtr event,
1077444c061aSmrg    Boolean* error)
1078444c061aSmrg{
1079444c061aSmrg    ScanWhitespace(str);
1080444c061aSmrg
1081444c061aSmrg    if (*str == ',' || *str == ':') {
1082444c061aSmrg	/* no detail */
1083444c061aSmrg	event->event.eventCode = 0L;
1084444c061aSmrg        event->event.eventCodeMask = 0L;
1085444c061aSmrg    } else {
1086444c061aSmrg	char *start, atomName[1000];
1087444c061aSmrg	start = str;
1088444c061aSmrg	while (
1089444c061aSmrg		*str != ','
1090444c061aSmrg		&& *str != ':'
1091444c061aSmrg		&& *str != ' '
1092444c061aSmrg		&& *str != '\t'
1093444c061aSmrg                && !IsNewline(*str)
1094444c061aSmrg		&& *str != '\0') str++;
1095444c061aSmrg	if (str-start >= 999) {
1096444c061aSmrg	    Syntax( "Atom name must be less than 1000 characters long.", "" );
1097444c061aSmrg	    *error = TRUE;
1098444c061aSmrg	    return str;
1099444c061aSmrg	}
1100444c061aSmrg	(void) memmove(atomName, start, str-start);
1101444c061aSmrg	atomName[str-start] = '\0';
1102444c061aSmrg	event->event.eventCode = XrmStringToQuark(atomName);
1103444c061aSmrg	event->event.matchEvent = _XtMatchAtom;
1104444c061aSmrg    }
1105444c061aSmrg    return str;
1106444c061aSmrg}
1107444c061aSmrg
1108444c061aSmrgstatic ModifierMask buttonModifierMasks[] = {
1109444c061aSmrg    0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask
1110444c061aSmrg};
1111444c061aSmrgstatic String ParseRepeat(String, int *, Boolean *, Boolean *);
1112444c061aSmrg
1113444c061aSmrgstatic String ParseEvent(
1114444c061aSmrg    register String str,
1115444c061aSmrg    EventPtr	event,
1116444c061aSmrg    int*	reps,
1117444c061aSmrg    Boolean*	plus,
1118444c061aSmrg    Boolean* error)
1119444c061aSmrg{
1120444c061aSmrg    Cardinal	tmEvent;
1121444c061aSmrg
1122444c061aSmrg    str = ParseModifiers(str, event,error);
1123444c061aSmrg    if (*error) return str;
1124444c061aSmrg    if (*str != '<') {
1125444c061aSmrg         Syntax("Missing '<' while parsing event type.","");
1126444c061aSmrg         *error = TRUE;
1127444c061aSmrg         return PanicModeRecovery(str);
1128444c061aSmrg    }
1129444c061aSmrg    else str++;
1130444c061aSmrg    str = ParseXtEventType(str, event, &tmEvent,error);
1131444c061aSmrg    if (*error) return str;
1132444c061aSmrg    if (*str != '>'){
1133444c061aSmrg         Syntax("Missing '>' while parsing event type","");
1134444c061aSmrg         *error = TRUE;
1135444c061aSmrg         return PanicModeRecovery(str);
1136444c061aSmrg    }
1137444c061aSmrg    else str++;
1138444c061aSmrg    if (*str == '(') {
1139444c061aSmrg	str = ParseRepeat(str, reps, plus, error);
1140444c061aSmrg	if (*error) return str;
1141444c061aSmrg    }
1142444c061aSmrg    str = (*(events[tmEvent].parseDetail))(
1143444c061aSmrg        str, events[tmEvent].closure, event,error);
1144444c061aSmrg    if (*error) return str;
1145444c061aSmrg
1146444c061aSmrg/* gross hack! ||| this kludge is related to the X11 protocol deficiency w.r.t.
1147444c061aSmrg * modifiers in grabs.
1148444c061aSmrg */
1149444c061aSmrg    if ((event->event.eventType == ButtonRelease)
1150444c061aSmrg	&& (event->event.modifiers | event->event.modifierMask) /* any */
1151444c061aSmrg        && (event->event.modifiers != AnyModifier))
1152444c061aSmrg    {
1153444c061aSmrg	event->event.modifiers
1154444c061aSmrg	    |= buttonModifierMasks[event->event.eventCode];
1155444c061aSmrg	/* the button that is going up will always be in the modifiers... */
1156444c061aSmrg    }
1157444c061aSmrg
1158444c061aSmrg    return str;
1159444c061aSmrg}
1160444c061aSmrg
1161444c061aSmrgstatic String ParseQuotedStringEvent(
1162444c061aSmrg    register String str,
1163444c061aSmrg    register EventPtr event,
1164444c061aSmrg    Boolean *error)
1165444c061aSmrg{
1166444c061aSmrg    Value metaMask;
1167444c061aSmrg    char	s[2];
1168444c061aSmrg
1169444c061aSmrg    if (*str=='^') {
1170444c061aSmrg	str++;
1171444c061aSmrg	event->event.modifiers = ControlMask;
1172444c061aSmrg    } else if (*str == '$') {
1173444c061aSmrg	str++;
1174444c061aSmrg	(void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE,
1175444c061aSmrg				 &metaMask, FALSE);
1176444c061aSmrg    }
1177444c061aSmrg    if (*str == '\\')
1178444c061aSmrg	str++;
1179444c061aSmrg    s[0] = *str;
1180444c061aSmrg    s[1] = '\0';
1181444c061aSmrg    if (*str != '\0' && !IsNewline(*str)) str++;
1182444c061aSmrg    event->event.eventType = KeyPress;
1183444c061aSmrg    event->event.eventCode = StringToKeySym(s, error);
1184444c061aSmrg    if (*error) return PanicModeRecovery(str);
1185444c061aSmrg    event->event.eventCodeMask = ~0L;
1186444c061aSmrg    event->event.matchEvent = _XtMatchUsingStandardMods;
1187444c061aSmrg    event->event.standard = TRUE;
1188444c061aSmrg
1189444c061aSmrg    return str;
1190444c061aSmrg}
1191444c061aSmrg
1192444c061aSmrg
1193444c061aSmrgstatic EventSeqRec timerEventRec = {
1194444c061aSmrg    {0, 0, NULL, _XtEventTimerEventType, 0L, 0L, NULL, False},
1195444c061aSmrg    /* (StatePtr) -1 */ NULL,
1196444c061aSmrg    NULL,
1197444c061aSmrg    NULL
1198444c061aSmrg};
1199444c061aSmrg
1200444c061aSmrgstatic void RepeatDown(
1201444c061aSmrg    EventPtr *eventP,
1202444c061aSmrg    int reps,
1203444c061aSmrg    ActionPtr **actionsP)
1204444c061aSmrg{
1205444c061aSmrg    EventRec upEventRec;
1206444c061aSmrg    register EventPtr event, downEvent;
1207444c061aSmrg    EventPtr upEvent = &upEventRec;
1208444c061aSmrg    register int i;
1209444c061aSmrg
1210444c061aSmrg    downEvent = event = *eventP;
1211444c061aSmrg    *upEvent = *downEvent;
1212444c061aSmrg    upEvent->event.eventType = ((event->event.eventType == ButtonPress) ?
1213444c061aSmrg	ButtonRelease : KeyRelease);
1214444c061aSmrg    if ((upEvent->event.eventType == ButtonRelease)
1215444c061aSmrg	&& (upEvent->event.modifiers != AnyModifier)
1216444c061aSmrg        && (upEvent->event.modifiers | upEvent->event.modifierMask))
1217444c061aSmrg	upEvent->event.modifiers
1218444c061aSmrg	    |= buttonModifierMasks[event->event.eventCode];
1219444c061aSmrg
1220444c061aSmrg    if (event->event.lateModifiers)
1221444c061aSmrg	event->event.lateModifiers->ref_count += (reps - 1) * 2;
1222444c061aSmrg
1223444c061aSmrg    for (i=1; i<reps; i++) {
1224444c061aSmrg
1225444c061aSmrg	/* up */
1226444c061aSmrg	event->next = XtNew(EventSeqRec);
1227444c061aSmrg	event = event->next;
1228444c061aSmrg	*event = *upEvent;
1229444c061aSmrg
1230444c061aSmrg	/* timer */
1231444c061aSmrg	event->next = XtNew(EventSeqRec);
1232444c061aSmrg	event = event->next;
1233444c061aSmrg	*event = timerEventRec;
1234444c061aSmrg
1235444c061aSmrg	/* down */
1236444c061aSmrg	event->next = XtNew(EventSeqRec);
1237444c061aSmrg	event = event->next;
1238444c061aSmrg	*event = *downEvent;
1239444c061aSmrg
1240444c061aSmrg    }
1241444c061aSmrg
1242444c061aSmrg    event->next = NULL;
1243444c061aSmrg    *eventP = event;
1244444c061aSmrg    *actionsP = &event->actions;
1245444c061aSmrg}
1246444c061aSmrg
1247444c061aSmrgstatic void RepeatDownPlus(
1248444c061aSmrg    EventPtr *eventP,
1249444c061aSmrg    int reps,
1250444c061aSmrg    ActionPtr **actionsP)
1251444c061aSmrg{
1252444c061aSmrg    EventRec upEventRec;
1253444c061aSmrg    register EventPtr event, downEvent, lastDownEvent = NULL;
1254444c061aSmrg    EventPtr upEvent = &upEventRec;
1255444c061aSmrg    register int i;
1256444c061aSmrg
1257444c061aSmrg    downEvent = event = *eventP;
1258444c061aSmrg    *upEvent = *downEvent;
1259444c061aSmrg    upEvent->event.eventType = ((event->event.eventType == ButtonPress) ?
1260444c061aSmrg	ButtonRelease : KeyRelease);
1261444c061aSmrg    if ((upEvent->event.eventType == ButtonRelease)
1262444c061aSmrg	&& (upEvent->event.modifiers != AnyModifier)
1263444c061aSmrg        && (upEvent->event.modifiers | upEvent->event.modifierMask))
1264444c061aSmrg	upEvent->event.modifiers
1265444c061aSmrg	    |= buttonModifierMasks[event->event.eventCode];
1266444c061aSmrg
1267444c061aSmrg    if (event->event.lateModifiers)
1268444c061aSmrg	event->event.lateModifiers->ref_count += reps * 2 - 1;
1269444c061aSmrg
1270444c061aSmrg    for (i=0; i<reps; i++) {
1271444c061aSmrg
1272444c061aSmrg	if (i > 0) {
1273444c061aSmrg	/* down */
1274444c061aSmrg	event->next = XtNew(EventSeqRec);
1275444c061aSmrg	event = event->next;
1276444c061aSmrg	*event = *downEvent;
1277444c061aSmrg	}
1278444c061aSmrg	lastDownEvent = event;
1279444c061aSmrg
1280444c061aSmrg	/* up */
1281444c061aSmrg	event->next = XtNew(EventSeqRec);
1282444c061aSmrg	event = event->next;
1283444c061aSmrg	*event = *upEvent;
1284444c061aSmrg
1285444c061aSmrg	/* timer */
1286444c061aSmrg	event->next = XtNew(EventSeqRec);
1287444c061aSmrg	event = event->next;
1288444c061aSmrg	*event = timerEventRec;
1289444c061aSmrg
1290444c061aSmrg    }
1291444c061aSmrg
1292444c061aSmrg    event->next = lastDownEvent;
1293444c061aSmrg    *eventP = event;
1294444c061aSmrg    *actionsP = &lastDownEvent->actions;
1295444c061aSmrg}
1296444c061aSmrg
1297444c061aSmrgstatic void RepeatUp(
1298444c061aSmrg    EventPtr *eventP,
1299444c061aSmrg    int reps,
1300444c061aSmrg    ActionPtr **actionsP)
1301444c061aSmrg{
1302444c061aSmrg    EventRec upEventRec;
1303444c061aSmrg    register EventPtr event, downEvent;
1304444c061aSmrg    EventPtr upEvent = &upEventRec;
1305444c061aSmrg    register int i;
1306444c061aSmrg
1307444c061aSmrg    /* the event currently sitting in *eventP is an "up" event */
1308444c061aSmrg    /* we want to make it a "down" event followed by an "up" event, */
1309444c061aSmrg    /* so that sequence matching on the "state" side works correctly. */
1310444c061aSmrg
1311444c061aSmrg    downEvent = event = *eventP;
1312444c061aSmrg    *upEvent = *downEvent;
1313444c061aSmrg    downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ?
1314444c061aSmrg	ButtonPress : KeyPress);
1315444c061aSmrg    if ((downEvent->event.eventType == ButtonPress)
1316444c061aSmrg	&& (downEvent->event.modifiers != AnyModifier)
1317444c061aSmrg        && (downEvent->event.modifiers | downEvent->event.modifierMask))
1318444c061aSmrg	downEvent->event.modifiers
1319444c061aSmrg	    &= ~buttonModifierMasks[event->event.eventCode];
1320444c061aSmrg
1321444c061aSmrg    if (event->event.lateModifiers)
1322444c061aSmrg	event->event.lateModifiers->ref_count += reps * 2 - 1;
1323444c061aSmrg
1324444c061aSmrg    /* up */
1325444c061aSmrg    event->next = XtNew(EventSeqRec);
1326444c061aSmrg    event = event->next;
1327444c061aSmrg    *event = *upEvent;
1328444c061aSmrg
1329444c061aSmrg    for (i=1; i<reps; i++) {
1330444c061aSmrg
1331444c061aSmrg	/* timer */
1332444c061aSmrg	event->next = XtNew(EventSeqRec);
1333444c061aSmrg	event = event->next;
1334444c061aSmrg	*event = timerEventRec;
1335444c061aSmrg
1336444c061aSmrg	/* down */
1337444c061aSmrg	event->next = XtNew(EventSeqRec);
1338444c061aSmrg	event = event->next;
1339444c061aSmrg	*event = *downEvent;
1340444c061aSmrg
1341444c061aSmrg	/* up */
1342444c061aSmrg	event->next = XtNew(EventSeqRec);
1343444c061aSmrg	event = event->next;
1344444c061aSmrg	*event = *upEvent;
1345444c061aSmrg
1346444c061aSmrg	}
1347444c061aSmrg
1348444c061aSmrg    event->next = NULL;
1349444c061aSmrg    *eventP = event;
1350444c061aSmrg    *actionsP = &event->actions;
1351444c061aSmrg}
1352444c061aSmrg
1353444c061aSmrgstatic void RepeatUpPlus(
1354444c061aSmrg    EventPtr *eventP,
1355444c061aSmrg    int reps,
1356444c061aSmrg    ActionPtr **actionsP)
1357444c061aSmrg{
1358444c061aSmrg    EventRec upEventRec;
1359444c061aSmrg    register EventPtr event, downEvent, lastUpEvent = NULL;
1360444c061aSmrg    EventPtr upEvent = &upEventRec;
1361444c061aSmrg    register int i;
1362444c061aSmrg
1363444c061aSmrg    /* the event currently sitting in *eventP is an "up" event */
1364444c061aSmrg    /* we want to make it a "down" event followed by an "up" event, */
1365444c061aSmrg    /* so that sequence matching on the "state" side works correctly. */
1366444c061aSmrg
1367444c061aSmrg    downEvent = event = *eventP;
1368444c061aSmrg    *upEvent = *downEvent;
1369444c061aSmrg    downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ?
1370444c061aSmrg	ButtonPress : KeyPress);
1371444c061aSmrg    if ((downEvent->event.eventType == ButtonPress)
1372444c061aSmrg	&& (downEvent->event.modifiers != AnyModifier)
1373444c061aSmrg        && (downEvent->event.modifiers | downEvent->event.modifierMask))
1374444c061aSmrg	downEvent->event.modifiers
1375444c061aSmrg	    &= ~buttonModifierMasks[event->event.eventCode];
1376444c061aSmrg
1377444c061aSmrg    if (event->event.lateModifiers)
1378444c061aSmrg	event->event.lateModifiers->ref_count += reps * 2;
1379444c061aSmrg
1380444c061aSmrg    for (i=0; i<reps; i++) {
1381444c061aSmrg
1382444c061aSmrg	/* up */
1383444c061aSmrg	event->next = XtNew(EventSeqRec);
1384444c061aSmrg	lastUpEvent = event = event->next;
1385444c061aSmrg	*event = *upEvent;
1386444c061aSmrg
1387444c061aSmrg	/* timer */
1388444c061aSmrg	event->next = XtNew(EventSeqRec);
1389444c061aSmrg	event = event->next;
1390444c061aSmrg	*event = timerEventRec;
1391444c061aSmrg
1392444c061aSmrg	/* down */
1393444c061aSmrg	event->next = XtNew(EventSeqRec);
1394444c061aSmrg        event = event->next;
1395444c061aSmrg	*event = *downEvent;
1396444c061aSmrg
1397444c061aSmrg	}
1398444c061aSmrg
1399444c061aSmrg    event->next = lastUpEvent;
1400444c061aSmrg    *eventP = event;
1401444c061aSmrg    *actionsP = &lastUpEvent->actions;
1402444c061aSmrg}
1403444c061aSmrg
1404444c061aSmrgstatic void RepeatOther(
1405444c061aSmrg    EventPtr *eventP,
1406444c061aSmrg    int reps,
1407444c061aSmrg    ActionPtr **actionsP)
1408444c061aSmrg{
1409444c061aSmrg    register EventPtr event, tempEvent;
1410444c061aSmrg    register int i;
1411444c061aSmrg
1412444c061aSmrg    tempEvent = event = *eventP;
1413444c061aSmrg
1414444c061aSmrg    if (event->event.lateModifiers)
1415444c061aSmrg	event->event.lateModifiers->ref_count += reps - 1;
1416444c061aSmrg
1417444c061aSmrg    for (i=1; i<reps; i++) {
1418444c061aSmrg	event->next = XtNew(EventSeqRec);
1419444c061aSmrg	event = event->next;
1420444c061aSmrg	*event = *tempEvent;
1421444c061aSmrg    }
1422444c061aSmrg
1423444c061aSmrg    *eventP = event;
1424444c061aSmrg    *actionsP = &event->actions;
1425444c061aSmrg}
1426444c061aSmrg
1427444c061aSmrgstatic void RepeatOtherPlus(
1428444c061aSmrg    EventPtr *eventP,
1429444c061aSmrg    int reps,
1430444c061aSmrg    ActionPtr **actionsP)
1431444c061aSmrg{
1432444c061aSmrg    register EventPtr event, tempEvent;
1433444c061aSmrg    register int i;
1434444c061aSmrg
1435444c061aSmrg    tempEvent = event = *eventP;
1436444c061aSmrg
1437444c061aSmrg    if (event->event.lateModifiers)
1438444c061aSmrg	event->event.lateModifiers->ref_count += reps - 1;
1439444c061aSmrg
1440444c061aSmrg    for (i=1; i<reps; i++) {
1441444c061aSmrg	event->next = XtNew(EventSeqRec);
1442444c061aSmrg	event = event->next;
1443444c061aSmrg	*event = *tempEvent;
1444444c061aSmrg    }
1445444c061aSmrg
1446444c061aSmrg    event->next = event;
1447444c061aSmrg    *eventP = event;
1448444c061aSmrg    *actionsP = &event->actions;
1449444c061aSmrg}
1450444c061aSmrg
1451444c061aSmrgstatic void RepeatEvent(
1452444c061aSmrg    EventPtr *eventP,
1453444c061aSmrg    int reps,
1454444c061aSmrg    Boolean plus,
1455444c061aSmrg    ActionPtr **actionsP)
1456444c061aSmrg{
1457444c061aSmrg    switch ((*eventP)->event.eventType) {
1458444c061aSmrg
1459444c061aSmrg	case ButtonPress:
1460444c061aSmrg	case KeyPress:
1461444c061aSmrg	    if (plus) RepeatDownPlus(eventP, reps, actionsP);
1462444c061aSmrg	    else RepeatDown(eventP, reps, actionsP);
1463444c061aSmrg	    break;
1464444c061aSmrg
1465444c061aSmrg	case ButtonRelease:
1466444c061aSmrg	case KeyRelease:
1467444c061aSmrg	    if (plus) RepeatUpPlus(eventP, reps, actionsP);
1468444c061aSmrg	    else RepeatUp(eventP, reps, actionsP);
1469444c061aSmrg	    break;
1470444c061aSmrg
1471444c061aSmrg	default:
1472444c061aSmrg	    if (plus) RepeatOtherPlus(eventP, reps, actionsP);
1473444c061aSmrg	    else RepeatOther(eventP, reps, actionsP);
1474444c061aSmrg    }
1475444c061aSmrg}
1476444c061aSmrg
1477444c061aSmrgstatic String ParseRepeat(
1478444c061aSmrg    register String str,
1479444c061aSmrg    int	*reps,
1480444c061aSmrg    Boolean *plus, Boolean *error)
1481444c061aSmrg{
1482444c061aSmrg
1483444c061aSmrg    /*** Parse the repetitions, for double click etc... ***/
1484444c061aSmrg    if (*str != '(' || !(isdigit(str[1]) || str[1] == '+' || str[1] == ')'))
1485444c061aSmrg	return str;
1486444c061aSmrg    str++;
1487444c061aSmrg    if (isdigit(*str)) {
1488444c061aSmrg	String start = str;
1489444c061aSmrg	char repStr[7];
1490444c061aSmrg	size_t len;
1491444c061aSmrg
1492444c061aSmrg	ScanNumeric(str);
1493444c061aSmrg	len = (str - start);
1494444c061aSmrg	if (len < sizeof repStr) {
1495444c061aSmrg	    (void) memmove(repStr, start, len);
1496444c061aSmrg	    repStr[len] = '\0';
1497444c061aSmrg	    *reps = StrToNum(repStr);
1498444c061aSmrg	} else {
1499444c061aSmrg	    Syntax("Repeat count too large.", "");
1500444c061aSmrg	    *error = TRUE;
1501444c061aSmrg	    return str;
1502444c061aSmrg	}
1503444c061aSmrg    }
1504444c061aSmrg    if (*reps == 0) {
1505444c061aSmrg	Syntax("Missing repeat count.","");
1506444c061aSmrg	*error = True;
1507444c061aSmrg	return str;
1508444c061aSmrg    }
1509444c061aSmrg
1510444c061aSmrg    if (*str == '+') {
1511444c061aSmrg	*plus = TRUE;
1512444c061aSmrg	str++;
1513444c061aSmrg    }
1514444c061aSmrg    if (*str == ')')
1515444c061aSmrg	str++;
1516444c061aSmrg    else {
1517444c061aSmrg	Syntax("Missing ')'.","");
1518444c061aSmrg	*error = TRUE;
1519444c061aSmrg    }
1520444c061aSmrg
1521444c061aSmrg    return str;
1522444c061aSmrg}
1523444c061aSmrg
1524444c061aSmrg/***********************************************************************
1525444c061aSmrg * ParseEventSeq
1526444c061aSmrg * Parses the left hand side of a translation table production
1527444c061aSmrg * up to, and consuming the ":".
1528444c061aSmrg * Takes a pointer to a char* (where to start parsing) and returns an
1529444c061aSmrg * event seq (in a passed in variable), having updated the String
1530444c061aSmrg **********************************************************************/
1531444c061aSmrg
1532444c061aSmrgstatic String ParseEventSeq(
1533444c061aSmrg    register String str,
1534444c061aSmrg    EventSeqPtr *eventSeqP,
1535444c061aSmrg    ActionPtr	**actionsP,
1536444c061aSmrg    Boolean *error)
1537444c061aSmrg{
1538444c061aSmrg    EventSeqPtr *nextEvent = eventSeqP;
1539444c061aSmrg
1540444c061aSmrg    *eventSeqP = NULL;
1541444c061aSmrg
1542444c061aSmrg    while ( *str != '\0' && !IsNewline(*str)) {
1543444c061aSmrg	static Event	nullEvent =
15442265a131Smrg             {0, 0,NULL, 0, 0L, 0L,_XtRegularMatch,FALSE};
1545444c061aSmrg	EventPtr	event;
1546444c061aSmrg
1547444c061aSmrg	ScanWhitespace(str);
1548444c061aSmrg
1549444c061aSmrg	if (*str == '"') {
1550444c061aSmrg	    str++;
1551444c061aSmrg	    while (*str != '"' && *str != '\0' && !IsNewline(*str)) {
1552444c061aSmrg                event = XtNew(EventRec);
1553444c061aSmrg                event->event = nullEvent;
1554444c061aSmrg                event->state = /* (StatePtr) -1 */ NULL;
1555444c061aSmrg                event->next = NULL;
1556444c061aSmrg                event->actions = NULL;
1557444c061aSmrg		str = ParseQuotedStringEvent(str, event,error);
1558444c061aSmrg		if (*error) {
1559444c061aSmrg		    XtWarningMsg(XtNtranslationParseError, "nonLatin1",
1560444c061aSmrg			XtCXtToolkitError,
1561444c061aSmrg			"... probably due to non-Latin1 character in quoted string",
1562444c061aSmrg			(String*)NULL, (Cardinal*)NULL);
1563444c061aSmrg		    return PanicModeRecovery(str);
1564444c061aSmrg		}
1565444c061aSmrg		*nextEvent = event;
1566444c061aSmrg		*actionsP = &event->actions;
1567444c061aSmrg		nextEvent = &event->next;
1568444c061aSmrg	    }
1569444c061aSmrg	    if (*str != '"') {
1570444c061aSmrg                Syntax("Missing '\"'.","");
1571444c061aSmrg                *error = TRUE;
1572444c061aSmrg                return PanicModeRecovery(str);
1573444c061aSmrg             }
1574444c061aSmrg             else str++;
1575444c061aSmrg	} else {
1576444c061aSmrg	    int reps = 0;
1577444c061aSmrg	    Boolean plus = FALSE;
1578444c061aSmrg
1579444c061aSmrg            event = XtNew(EventRec);
1580444c061aSmrg            event->event = nullEvent;
1581444c061aSmrg            event->state = /* (StatePtr) -1 */ NULL;
1582444c061aSmrg            event->next = NULL;
1583444c061aSmrg            event->actions = NULL;
1584444c061aSmrg
1585444c061aSmrg	    str = ParseEvent(str, event, &reps, &plus, error);
1586444c061aSmrg            if (*error) return str;
1587444c061aSmrg	    *nextEvent = event;
1588444c061aSmrg	    *actionsP = &event->actions;
1589444c061aSmrg	    if (reps > 1 || plus)
1590444c061aSmrg		RepeatEvent(&event, reps, plus, actionsP);
1591444c061aSmrg	    nextEvent = &event->next;
1592444c061aSmrg	}
1593444c061aSmrg	ScanWhitespace(str);
1594444c061aSmrg        if (*str == ':') break;
1595444c061aSmrg        else {
1596444c061aSmrg            if (*str != ',') {
1597444c061aSmrg                Syntax("',' or ':' expected while parsing event sequence.","");
1598444c061aSmrg                *error = TRUE;
1599444c061aSmrg                return PanicModeRecovery(str);
1600444c061aSmrg	    } else str++;
1601444c061aSmrg        }
1602444c061aSmrg    }
1603444c061aSmrg
1604444c061aSmrg    if (*str != ':') {
1605444c061aSmrg        Syntax("Missing ':'after event sequence.","");
1606444c061aSmrg        *error = TRUE;
1607444c061aSmrg        return PanicModeRecovery(str);
1608444c061aSmrg    } else str++;
1609444c061aSmrg
1610444c061aSmrg    return str;
1611444c061aSmrg}
1612444c061aSmrg
1613444c061aSmrg
1614444c061aSmrgstatic String ParseActionProc(
1615444c061aSmrg    register String str,
1616444c061aSmrg    XrmQuark *actionProcNameP,
1617444c061aSmrg    Boolean *error)
1618444c061aSmrg{
1619444c061aSmrg    register String start = str;
1620444c061aSmrg    char procName[200];
1621444c061aSmrg
1622444c061aSmrg    str = ScanIdent(str);
1623444c061aSmrg    if (str-start >= 199) {
1624444c061aSmrg	Syntax("Action procedure name is longer than 199 chars","");
1625444c061aSmrg	*error = TRUE;
1626444c061aSmrg	return str;
1627444c061aSmrg    }
1628444c061aSmrg    (void) memmove(procName, start, str-start);
1629444c061aSmrg    procName[str-start] = '\0';
1630444c061aSmrg    *actionProcNameP = XrmStringToQuark( procName );
1631444c061aSmrg    return str;
1632444c061aSmrg}
1633444c061aSmrg
1634444c061aSmrg
1635444c061aSmrgstatic String ParseString(
1636444c061aSmrg    register String str,
1637444c061aSmrg    String *strP)
1638444c061aSmrg{
1639444c061aSmrg    register String start;
1640444c061aSmrg
1641444c061aSmrg    if (*str == '"') {
1642444c061aSmrg	register unsigned prev_len, len;
1643444c061aSmrg	str++;
1644444c061aSmrg	start = str;
1645444c061aSmrg	*strP = NULL;
1646444c061aSmrg	prev_len = 0;
1647444c061aSmrg
1648444c061aSmrg	while (*str != '"' && *str != '\0') {
1649444c061aSmrg	    /* \"  produces double quote embedded in a quoted parameter
1650444c061aSmrg	     * \\" produces backslash as last character of a quoted parameter
1651444c061aSmrg	     */
1652444c061aSmrg	    if (*str == '\\' &&
1653444c061aSmrg		(*(str+1) == '"' || (*(str+1) == '\\' && *(str+2) == '"'))) {
1654444c061aSmrg		len = prev_len + (str-start+2);
1655444c061aSmrg		*strP = XtRealloc(*strP, len);
1656444c061aSmrg		(void) memmove(*strP + prev_len, start, str-start);
1657444c061aSmrg		prev_len = len-1;
1658444c061aSmrg		str++;
1659444c061aSmrg		(*strP)[prev_len-1] = *str;
1660444c061aSmrg		(*strP)[prev_len] = '\0';
1661444c061aSmrg		start = str+1;
1662444c061aSmrg	    }
1663444c061aSmrg	    str++;
1664444c061aSmrg	}
1665444c061aSmrg	len = prev_len + (str-start+1);
1666444c061aSmrg	*strP = XtRealloc(*strP, len);
1667444c061aSmrg	(void) memmove( *strP + prev_len, start, str-start);
1668444c061aSmrg	(*strP)[len-1] = '\0';
1669444c061aSmrg	if (*str == '"') str++; else
1670444c061aSmrg            XtWarningMsg(XtNtranslationParseError,"parseString",
1671444c061aSmrg                      XtCXtToolkitError,"Missing '\"'.",
1672444c061aSmrg		      (String *)NULL, (Cardinal *)NULL);
1673444c061aSmrg    } else {
1674444c061aSmrg	/* scan non-quoted string, stop on whitespace, ',' or ')' */
1675444c061aSmrg	start = str;
1676444c061aSmrg	while (*str != ' '
1677444c061aSmrg		&& *str != '\t'
1678444c061aSmrg		&& *str != ','
1679444c061aSmrg		&& *str != ')'
1680444c061aSmrg                && !IsNewline(*str)
1681444c061aSmrg		&& *str != '\0') str++;
1682444c061aSmrg	*strP = __XtMalloc((unsigned)(str-start+1));
1683444c061aSmrg	(void) memmove(*strP, start, str-start);
1684444c061aSmrg	(*strP)[str-start] = '\0';
1685444c061aSmrg    }
1686444c061aSmrg    return str;
1687444c061aSmrg}
1688444c061aSmrg
1689444c061aSmrg
1690444c061aSmrgstatic String ParseParamSeq(
1691444c061aSmrg    register String str,
1692444c061aSmrg    String **paramSeqP,
1693444c061aSmrg    Cardinal *paramNumP)
1694444c061aSmrg{
1695444c061aSmrg    typedef struct _ParamRec *ParamPtr;
1696444c061aSmrg    typedef struct _ParamRec {
1697444c061aSmrg	ParamPtr next;
1698444c061aSmrg	String	param;
1699444c061aSmrg    } ParamRec;
1700444c061aSmrg
1701444c061aSmrg    ParamPtr params = NULL;
1702444c061aSmrg    register Cardinal num_params = 0;
1703444c061aSmrg    register Cardinal i;
1704444c061aSmrg
1705444c061aSmrg    ScanWhitespace(str);
1706444c061aSmrg    while (*str != ')' && *str != '\0' && !IsNewline(*str)) {
1707444c061aSmrg	String newStr;
1708444c061aSmrg	str = ParseString(str, &newStr);
1709444c061aSmrg	if (newStr != NULL) {
1710444c061aSmrg	    ParamPtr temp = (ParamRec*)
1711444c061aSmrg		ALLOCATE_LOCAL( (unsigned)sizeof(ParamRec) );
1712444c061aSmrg	    if (temp == NULL) _XtAllocError (NULL);
1713444c061aSmrg
1714444c061aSmrg	    num_params++;
1715444c061aSmrg	    temp->next = params;
1716444c061aSmrg	    params = temp;
1717444c061aSmrg	    temp->param = newStr;
1718444c061aSmrg	    ScanWhitespace(str);
1719444c061aSmrg	    if (*str == ',') {
1720444c061aSmrg		str++;
1721444c061aSmrg		ScanWhitespace(str);
1722444c061aSmrg	    }
1723444c061aSmrg	}
1724444c061aSmrg    }
1725444c061aSmrg
1726444c061aSmrg    if (num_params != 0) {
1727444c061aSmrg	String *paramP = (String *)
1728444c061aSmrg		__XtMalloc( (unsigned)(num_params+1) * sizeof(String) );
1729444c061aSmrg	*paramSeqP = paramP;
1730444c061aSmrg	*paramNumP = num_params;
1731444c061aSmrg	paramP += num_params; /* list is LIFO right now */
1732444c061aSmrg	*paramP-- = NULL;
1733444c061aSmrg	for (i=0; i < num_params; i++) {
1734444c061aSmrg	    ParamPtr next = params->next;
1735444c061aSmrg	    *paramP-- = params->param;
1736444c061aSmrg	    DEALLOCATE_LOCAL( (char *)params );
1737444c061aSmrg	    params = next;
1738444c061aSmrg	}
1739444c061aSmrg    } else {
1740444c061aSmrg	*paramSeqP = NULL;
1741444c061aSmrg	*paramNumP = 0;
1742444c061aSmrg    }
1743444c061aSmrg
1744444c061aSmrg    return str;
1745444c061aSmrg}
1746444c061aSmrg
1747444c061aSmrgstatic String ParseAction(
1748444c061aSmrg    String str,
1749444c061aSmrg    ActionPtr actionP,
1750444c061aSmrg    XrmQuark* quarkP,
1751444c061aSmrg    Boolean* error)
1752444c061aSmrg{
1753444c061aSmrg    str = ParseActionProc(str, quarkP, error);
1754444c061aSmrg    if (*error) return str;
1755444c061aSmrg
1756444c061aSmrg    if (*str == '(') {
1757444c061aSmrg	str++;
1758444c061aSmrg	str = ParseParamSeq(str, &actionP->params, &actionP->num_params);
1759444c061aSmrg    } else {
1760444c061aSmrg        Syntax("Missing '(' while parsing action sequence","");
1761444c061aSmrg        *error = TRUE;
1762444c061aSmrg        return str;
1763444c061aSmrg    }
1764444c061aSmrg    if (*str == ')') str++;
1765444c061aSmrg    else{
1766444c061aSmrg        Syntax("Missing ')' while parsing action sequence","");
1767444c061aSmrg        *error = TRUE;
1768444c061aSmrg        return str;
1769444c061aSmrg    }
1770444c061aSmrg    return str;
1771444c061aSmrg}
1772444c061aSmrg
1773444c061aSmrg
1774444c061aSmrgstatic String ParseActionSeq(
1775444c061aSmrg    TMParseStateTree   	parseTree,
1776444c061aSmrg    String 		str,
1777444c061aSmrg    ActionPtr 		*actionsP,
1778444c061aSmrg    Boolean		*error)
1779444c061aSmrg{
1780444c061aSmrg    ActionPtr *nextActionP = actionsP;
1781444c061aSmrg
1782444c061aSmrg    *actionsP = NULL;
1783444c061aSmrg    while (*str != '\0' && !IsNewline(*str)) {
1784444c061aSmrg	register ActionPtr	action;
1785444c061aSmrg	XrmQuark quark;
1786444c061aSmrg
1787444c061aSmrg	action = XtNew(ActionRec);
1788444c061aSmrg        action->params = NULL;
1789444c061aSmrg        action->num_params = 0;
1790444c061aSmrg        action->next = NULL;
1791444c061aSmrg
1792444c061aSmrg	str = ParseAction(str, action, &quark, error);
1793444c061aSmrg	if (*error) return PanicModeRecovery(str);
1794444c061aSmrg
1795444c061aSmrg	action->idx = _XtGetQuarkIndex(parseTree, quark);
1796444c061aSmrg	ScanWhitespace(str);
1797444c061aSmrg	*nextActionP = action;
1798444c061aSmrg	nextActionP = &action->next;
1799444c061aSmrg    }
1800444c061aSmrg    if (IsNewline(*str)) str++;
1801444c061aSmrg    ScanWhitespace(str);
1802444c061aSmrg    return str;
1803444c061aSmrg}
1804444c061aSmrg
1805444c061aSmrg
1806444c061aSmrgstatic void ShowProduction(
1807444c061aSmrg  String currentProduction)
1808444c061aSmrg{
1809444c061aSmrg    Cardinal num_params = 1;
1810444c061aSmrg    String params[1];
1811444c061aSmrg    size_t len;
1812444c061aSmrg    char *eol, *production, productionbuf[500];
1813444c061aSmrg
1814444c061aSmrg#ifdef __UNIXOS2__
1815444c061aSmrg    eol = strchr(currentProduction, '\r');
1816444c061aSmrg    if (!eol) /* try '\n' as well below */
1817444c061aSmrg#endif
1818444c061aSmrg        eol = strchr(currentProduction, '\n');
1819444c061aSmrg    if (eol) len = eol - currentProduction;
1820444c061aSmrg    else len = strlen (currentProduction);
1821444c061aSmrg    production = XtStackAlloc (len + 1, productionbuf);
1822444c061aSmrg    if (production == NULL) _XtAllocError (NULL);
1823444c061aSmrg    (void) memmove(production, currentProduction, len);
1824444c061aSmrg    production[len] = '\0';
1825444c061aSmrg
1826444c061aSmrg    params[0] = production;
1827444c061aSmrg    XtWarningMsg(XtNtranslationParseError, "showLine", XtCXtToolkitError,
1828444c061aSmrg		 "... found while parsing '%s'", params, &num_params);
1829444c061aSmrg
1830444c061aSmrg    XtStackFree (production, productionbuf);
1831444c061aSmrg}
1832444c061aSmrg
1833444c061aSmrg/***********************************************************************
1834444c061aSmrg * ParseTranslationTableProduction
1835444c061aSmrg * Parses one line of event bindings.
1836444c061aSmrg ***********************************************************************/
1837444c061aSmrg
1838444c061aSmrgstatic String ParseTranslationTableProduction(
1839444c061aSmrg    TMParseStateTree	 parseTree,
1840444c061aSmrg    register String str,
1841444c061aSmrg    Boolean* error)
1842444c061aSmrg{
1843444c061aSmrg    EventSeqPtr	eventSeq = NULL;
1844444c061aSmrg    ActionPtr	*actionsP;
1845444c061aSmrg    String	production = str;
1846444c061aSmrg
18472265a131Smrg    actionsP = NULL;
1848444c061aSmrg    str = ParseEventSeq(str, &eventSeq, &actionsP,error);
1849444c061aSmrg    if (*error == TRUE) {
1850444c061aSmrg	ShowProduction(production);
1851444c061aSmrg        FreeEventSeq(eventSeq);
1852444c061aSmrg        return (str);
1853444c061aSmrg    }
1854444c061aSmrg    ScanWhitespace(str);
1855444c061aSmrg    str = ParseActionSeq(parseTree, str, actionsP, error);
1856444c061aSmrg    if (*error == TRUE) {
1857444c061aSmrg	ShowProduction(production);
1858444c061aSmrg        FreeEventSeq(eventSeq);
1859444c061aSmrg        return (str);
1860444c061aSmrg    }
1861444c061aSmrg
1862444c061aSmrg    _XtAddEventSeqToStateTree(eventSeq, parseTree);
1863444c061aSmrg    FreeEventSeq(eventSeq);
1864444c061aSmrg    return (str);
1865444c061aSmrg}
1866444c061aSmrg
1867444c061aSmrgstatic String CheckForPoundSign(
1868444c061aSmrg    String str,
1869444c061aSmrg    _XtTranslateOp defaultOp,
1870444c061aSmrg    _XtTranslateOp *actualOpRtn)
1871444c061aSmrg{
1872444c061aSmrg    String start;
1873444c061aSmrg    char operation[20];
1874444c061aSmrg    _XtTranslateOp opType;
1875444c061aSmrg
1876444c061aSmrg    opType = defaultOp;
1877444c061aSmrg    ScanWhitespace(str);
1878444c061aSmrg    if (*str == '#') {
1879444c061aSmrg	int len;
1880444c061aSmrg	str++;
1881444c061aSmrg	start = str;
1882444c061aSmrg	str = ScanIdent(str);
1883444c061aSmrg	len = MIN(19, str-start);
1884444c061aSmrg	(void) memmove(operation, start, len);
1885444c061aSmrg	operation[len] = '\0';
1886444c061aSmrg	if (!strcmp(operation,"replace"))
1887444c061aSmrg	  opType = XtTableReplace;
1888444c061aSmrg	else if (!strcmp(operation,"augment"))
1889444c061aSmrg	  opType = XtTableAugment;
1890444c061aSmrg	else if (!strcmp(operation,"override"))
1891444c061aSmrg	  opType = XtTableOverride;
1892444c061aSmrg	ScanWhitespace(str);
1893444c061aSmrg	if (IsNewline(*str)) {
1894444c061aSmrg	    str++;
1895444c061aSmrg	    ScanWhitespace(str);
1896444c061aSmrg	}
1897444c061aSmrg    }
1898444c061aSmrg    *actualOpRtn = opType;
1899444c061aSmrg    return str;
1900444c061aSmrg}
1901444c061aSmrg
1902444c061aSmrgstatic XtTranslations ParseTranslationTable(
1903444c061aSmrg    String 	source,
1904444c061aSmrg    Boolean	isAccelerator,
1905444c061aSmrg    _XtTranslateOp defaultOp,
1906444c061aSmrg    Boolean*	error)
1907444c061aSmrg{
1908444c061aSmrg    XtTranslations		xlations;
1909444c061aSmrg    TMStateTree			stateTrees[8];
1910444c061aSmrg    TMParseStateTreeRec		parseTreeRec, *parseTree = &parseTreeRec;
1911444c061aSmrg    XrmQuark			stackQuarks[200];
1912444c061aSmrg    TMBranchHeadRec		stackBranchHeads[200];
1913444c061aSmrg    StatePtr			stackComplexBranchHeads[200];
1914444c061aSmrg    _XtTranslateOp		actualOp;
1915444c061aSmrg
1916444c061aSmrg    if (source == NULL)
1917444c061aSmrg      return (XtTranslations)NULL;
1918444c061aSmrg
1919444c061aSmrg    source = CheckForPoundSign(source, defaultOp, &actualOp);
1920444c061aSmrg    if (isAccelerator && actualOp == XtTableReplace)
1921444c061aSmrg	actualOp = defaultOp;
1922444c061aSmrg
1923444c061aSmrg    parseTree->isSimple = TRUE;
1924444c061aSmrg    parseTree->mappingNotifyInterest = FALSE;
1925444c061aSmrg    parseTree->isAccelerator = isAccelerator;
1926444c061aSmrg    parseTree->isStackBranchHeads =
1927444c061aSmrg      parseTree->isStackQuarks =
1928444c061aSmrg	parseTree->isStackComplexBranchHeads = TRUE;
1929444c061aSmrg
1930444c061aSmrg    parseTree->numQuarks =
1931444c061aSmrg      parseTree->numBranchHeads =
1932444c061aSmrg	parseTree->numComplexBranchHeads = 0;
1933444c061aSmrg
1934444c061aSmrg    parseTree->quarkTblSize =
1935444c061aSmrg      parseTree->branchHeadTblSize =
1936444c061aSmrg	parseTree->complexBranchHeadTblSize = 200;
1937444c061aSmrg
1938444c061aSmrg    parseTree->quarkTbl = stackQuarks;
1939444c061aSmrg    parseTree->branchHeadTbl = stackBranchHeads;
1940444c061aSmrg    parseTree->complexBranchHeadTbl = stackComplexBranchHeads;
1941444c061aSmrg
1942444c061aSmrg    while (source != NULL && *source != '\0') {
1943444c061aSmrg	source =  ParseTranslationTableProduction(parseTree, source, error);
1944444c061aSmrg	if (*error == TRUE) break;
1945444c061aSmrg    }
1946444c061aSmrg    stateTrees[0] = _XtParseTreeToStateTree(parseTree);
1947444c061aSmrg
1948444c061aSmrg    if (!parseTree->isStackQuarks)
1949444c061aSmrg      XtFree((char *)parseTree->quarkTbl);
1950444c061aSmrg    if (!parseTree->isStackBranchHeads)
1951444c061aSmrg      XtFree((char *)parseTree->branchHeadTbl);
1952444c061aSmrg    if (!parseTree->isStackComplexBranchHeads)
1953444c061aSmrg      XtFree((char *)parseTree->complexBranchHeadTbl);
1954444c061aSmrg
1955444c061aSmrg    xlations = _XtCreateXlations(stateTrees, 1, NULL, NULL);
1956444c061aSmrg    xlations->operation = actualOp;
1957444c061aSmrg
1958444c061aSmrg#ifdef notdef
1959444c061aSmrg    XtFree(stateTrees);
1960444c061aSmrg#endif /* notdef */
1961444c061aSmrg    return xlations;
1962444c061aSmrg}
1963444c061aSmrg
1964444c061aSmrg/*** public procedures ***/
1965444c061aSmrg
1966444c061aSmrg/*ARGSUSED*/
1967444c061aSmrgBoolean XtCvtStringToAcceleratorTable(
1968444c061aSmrg    Display*	dpy,
1969444c061aSmrg    XrmValuePtr args,
1970444c061aSmrg    Cardinal    *num_args,
1971444c061aSmrg    XrmValuePtr from,
1972444c061aSmrg    XrmValuePtr to,
1973444c061aSmrg    XtPointer	*closure)
1974444c061aSmrg{
1975444c061aSmrg    String str;
1976444c061aSmrg    Boolean error = FALSE;
1977444c061aSmrg
1978444c061aSmrg    if (*num_args != 0)
1979444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
1980444c061aSmrg	  "wrongParameters","cvtStringToAcceleratorTable",XtCXtToolkitError,
1981444c061aSmrg          "String to AcceleratorTable conversion needs no extra arguments",
1982444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
1983444c061aSmrg    str = (String)(from->addr);
1984444c061aSmrg    if (str == NULL) {
1985444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
1986444c061aSmrg	  "badParameters","cvtStringToAcceleratorTable",XtCXtToolkitError,
1987444c061aSmrg          "String to AcceleratorTable conversion needs string",
1988444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
1989444c061aSmrg	return FALSE;
1990444c061aSmrg    }
1991444c061aSmrg    if (to->addr != NULL) {
1992444c061aSmrg	if (to->size < sizeof(XtAccelerators)) {
1993444c061aSmrg	    to->size = sizeof(XtAccelerators);
1994444c061aSmrg	    return FALSE;
1995444c061aSmrg	}
1996444c061aSmrg	*(XtAccelerators*)to->addr =
1997444c061aSmrg	    (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, &error);
1998444c061aSmrg    }
1999444c061aSmrg    else {
2000444c061aSmrg	static XtAccelerators staticStateTable;
2001444c061aSmrg	staticStateTable =
2002444c061aSmrg	    (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, &error);
2003444c061aSmrg	to->addr = (XPointer) &staticStateTable;
2004444c061aSmrg	to->size = sizeof(XtAccelerators);
2005444c061aSmrg    }
2006444c061aSmrg    if (error == TRUE)
2007444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2008444c061aSmrg	  "parseError","cvtStringToAcceleratorTable",XtCXtToolkitError,
2009444c061aSmrg          "String to AcceleratorTable conversion encountered errors",
2010444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2011444c061aSmrg    return (error != TRUE);
2012444c061aSmrg}
2013444c061aSmrg
2014444c061aSmrg
2015444c061aSmrg/*ARGSUSED*/
2016444c061aSmrgBoolean
2017444c061aSmrgXtCvtStringToTranslationTable(
2018444c061aSmrg    Display	*dpy,
2019444c061aSmrg    XrmValuePtr args,
2020444c061aSmrg    Cardinal    *num_args,
2021444c061aSmrg    XrmValuePtr from,
2022444c061aSmrg    XrmValuePtr to,
2023444c061aSmrg    XtPointer	*closure_ret)
2024444c061aSmrg{
2025444c061aSmrg    String str;
2026444c061aSmrg    Boolean error = FALSE;
2027444c061aSmrg
2028444c061aSmrg    if (*num_args != 0)
2029444c061aSmrg      XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2030444c061aSmrg	    "wrongParameters","cvtStringToTranslationTable",XtCXtToolkitError,
2031444c061aSmrg	    "String to TranslationTable conversion needs no extra arguments",
2032444c061aSmrg	    (String *)NULL, (Cardinal *)NULL);
2033444c061aSmrg    str = (String)(from->addr);
2034444c061aSmrg    if (str == NULL) {
2035444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2036444c061aSmrg	  "badParameters","cvtStringToTranslation",XtCXtToolkitError,
2037444c061aSmrg          "String to TranslationTable conversion needs string",
2038444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2039444c061aSmrg	return FALSE;
2040444c061aSmrg    }
2041444c061aSmrg    if (to->addr != NULL) {
2042444c061aSmrg	if (to->size < sizeof(XtTranslations)) {
2043444c061aSmrg	    to->size = sizeof(XtTranslations);
2044444c061aSmrg	    return FALSE;
2045444c061aSmrg	}
2046444c061aSmrg	*(XtTranslations*)to->addr =
2047444c061aSmrg	    ParseTranslationTable(str, FALSE, XtTableReplace, &error);
2048444c061aSmrg    }
2049444c061aSmrg    else {
2050444c061aSmrg	static XtTranslations staticStateTable;
2051444c061aSmrg	staticStateTable =
2052444c061aSmrg	    ParseTranslationTable(str, FALSE, XtTableReplace, &error);
2053444c061aSmrg	to->addr = (XPointer) &staticStateTable;
2054444c061aSmrg	to->size = sizeof(XtTranslations);
2055444c061aSmrg    }
2056444c061aSmrg    if (error == TRUE)
2057444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2058444c061aSmrg	  "parseError","cvtStringToTranslationTable",XtCXtToolkitError,
2059444c061aSmrg          "String to TranslationTable conversion encountered errors",
2060444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2061444c061aSmrg    return (error != TRUE);
2062444c061aSmrg}
2063444c061aSmrg
2064444c061aSmrg
2065444c061aSmrg/*
2066444c061aSmrg * Parses a user's or applications translation table
2067444c061aSmrg */
2068444c061aSmrgXtAccelerators XtParseAcceleratorTable(
2069444c061aSmrg    _Xconst char* source)
2070444c061aSmrg{
2071444c061aSmrg    Boolean error = FALSE;
2072444c061aSmrg    XtAccelerators ret =
2073444c061aSmrg	(XtAccelerators) ParseTranslationTable ((char *)source, TRUE, XtTableAugment, &error);
2074444c061aSmrg    if (error == TRUE)
2075444c061aSmrg        XtWarningMsg ("parseError", "cvtStringToAcceleratorTable",
2076444c061aSmrg	  XtCXtToolkitError,
2077444c061aSmrg          "String to AcceleratorTable conversion encountered errors",
2078444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2079444c061aSmrg    return ret;
2080444c061aSmrg}
2081444c061aSmrg
2082444c061aSmrgXtTranslations XtParseTranslationTable(
2083444c061aSmrg    _Xconst char* source)
2084444c061aSmrg{
2085444c061aSmrg    Boolean error = FALSE;
2086444c061aSmrg    XtTranslations ret = ParseTranslationTable((char *)source, FALSE, XtTableReplace, &error);
2087444c061aSmrg    if (error == TRUE)
2088444c061aSmrg        XtWarningMsg ("parseError",
2089444c061aSmrg	  "cvtStringToTranslationTable", XtCXtToolkitError,
2090444c061aSmrg          "String to TranslationTable conversion encountered errors",
2091444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2092444c061aSmrg    return ret;
2093444c061aSmrg}
2094444c061aSmrg
2095444c061aSmrgvoid _XtTranslateInitialize(void)
2096444c061aSmrg{
2097444c061aSmrg    LOCK_PROCESS;
2098444c061aSmrg    if (initialized) {
2099444c061aSmrg	XtWarningMsg("translationError","xtTranslateInitialize",
2100444c061aSmrg                  XtCXtToolkitError,"Initializing Translation manager twice.",
2101444c061aSmrg                    (String *)NULL, (Cardinal *)NULL);
2102444c061aSmrg	UNLOCK_PROCESS;
2103444c061aSmrg	return;
2104444c061aSmrg    }
2105444c061aSmrg
2106444c061aSmrg    initialized = TRUE;
2107444c061aSmrg    UNLOCK_PROCESS;
2108444c061aSmrg    QMeta = XrmPermStringToQuark("Meta");
2109444c061aSmrg    QCtrl = XrmPermStringToQuark("Ctrl");
2110444c061aSmrg    QNone = XrmPermStringToQuark("None");
2111444c061aSmrg    QAny  = XrmPermStringToQuark("Any");
2112444c061aSmrg
2113444c061aSmrg    Compile_XtEventTable( events, XtNumber(events) );
2114444c061aSmrg    Compile_XtModifierTable( modifiers, XtNumber(modifiers) );
2115444c061aSmrg    CompileNameValueTable( buttonNames );
2116444c061aSmrg    CompileNameValueTable( notifyModes );
2117444c061aSmrg    CompileNameValueTable( motionDetails );
2118444c061aSmrg#if 0
2119444c061aSmrg    CompileNameValueTable( notifyDetail );
2120444c061aSmrg    CompileNameValueTable( visibilityNotify );
2121444c061aSmrg    CompileNameValueTable( circulation );
2122444c061aSmrg    CompileNameValueTable( propertyChanged );
2123444c061aSmrg#endif
2124444c061aSmrg    CompileNameValueTable( mappingNotify );
2125444c061aSmrg}
2126444c061aSmrg
2127444c061aSmrgvoid _XtAddTMConverters(
2128444c061aSmrg    ConverterTable table)
2129444c061aSmrg{
2130444c061aSmrg     _XtTableAddConverter(table,
2131444c061aSmrg	     _XtQString,
2132444c061aSmrg	     XrmPermStringToQuark(XtRTranslationTable),
2133444c061aSmrg 	     XtCvtStringToTranslationTable, (XtConvertArgList) NULL,
2134444c061aSmrg	     (Cardinal)0, True, CACHED, _XtFreeTranslations, True);
2135444c061aSmrg     _XtTableAddConverter(table, _XtQString,
2136444c061aSmrg	     XrmPermStringToQuark(XtRAcceleratorTable),
2137444c061aSmrg 	     XtCvtStringToAcceleratorTable, (XtConvertArgList) NULL,
2138444c061aSmrg	     (Cardinal)0, True, CACHED, _XtFreeTranslations, True);
2139444c061aSmrg     _XtTableAddConverter(table,
2140444c061aSmrg	     XrmPermStringToQuark( _XtRStateTablePair ),
2141444c061aSmrg	     XrmPermStringToQuark(XtRTranslationTable),
2142444c061aSmrg 	     _XtCvtMergeTranslations, (XtConvertArgList) NULL,
2143444c061aSmrg	     (Cardinal)0, True, CACHED, _XtFreeTranslations, True);
2144444c061aSmrg}
2145