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