TMprint.c revision 444c061a
1/* $Xorg: TMprint.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */
2
3/***********************************************************
4Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts
5Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA.
6
7                        All Rights Reserved
8
9Permission to use, copy, modify, and distribute this software and its
10documentation for any purpose and without fee is hereby granted,
11provided that the above copyright notice appear in all copies and that
12both that copyright notice and this permission notice appear in
13supporting documentation, and that the names of Digital or Sun not be
14used in advertising or publicity pertaining to distribution of the
15software without specific, written prior permission.
16
17DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
18ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
19DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
20ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23SOFTWARE.
24
25SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
26INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
27NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
28ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
29ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
30PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
31OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
32THE USE OR PERFORMANCE OF THIS SOFTWARE.
33
34******************************************************************/
35
36/*
37
38Copyright 1987, 1988, 1998  The Open Group
39
40Permission to use, copy, modify, distribute, and sell this software and its
41documentation for any purpose is hereby granted without fee, provided that
42the above copyright notice appear in all copies and that both that
43copyright notice and this permission notice appear in supporting
44documentation.
45
46The above copyright notice and this permission notice shall be included in
47all copies or substantial portions of the Software.
48
49THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
52OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
53AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
54CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
55
56Except as contained in this notice, the name of The Open Group shall not be
57used in advertising or otherwise to promote the sale, use or other dealings
58in this Software without prior written authorization from The Open Group.
59
60*/
61/* $XFree86: xc/lib/Xt/TMprint.c,v 1.6 2001/12/14 19:56:31 dawes Exp $ */
62
63/*LINTLIBRARY*/
64#ifdef HAVE_CONFIG_H
65#include <config.h>
66#endif
67#include "IntrinsicI.h"
68#include <stdio.h>
69
70typedef struct _TMStringBufRec{
71    String	start;
72    String	current;
73    Cardinal	max;
74}TMStringBufRec, *TMStringBuf;
75
76
77#define STR_THRESHOLD 25
78#define STR_INCAMOUNT 100
79#define CHECK_STR_OVERFLOW(sb) \
80if (sb->current - sb->start > (int)sb->max - STR_THRESHOLD) 	\
81{ String old = sb->start; \
82  sb->start = XtRealloc(old, (Cardinal)(sb->max += STR_INCAMOUNT)); \
83  sb->current = sb->current - old + sb->start; \
84}
85
86#define ExpandForChars(sb, nchars ) \
87    if ((unsigned)(sb->current - sb->start) > sb->max - STR_THRESHOLD - nchars) { \
88	String old = sb->start;					\
89	sb->start = XtRealloc(old,				\
90	    (Cardinal)(sb->max += STR_INCAMOUNT + nchars));	\
91	sb->current = sb->current - old + sb->start;		\
92    }
93
94#define ExpandToFit(sb, more) \
95{								\
96	size_t l = strlen(more);				\
97	ExpandForChars(sb, l);					\
98      }
99
100static void PrintModifiers(
101    TMStringBuf	sb,
102    unsigned long mask, unsigned long mod)
103{
104    Boolean notfirst = False;
105    CHECK_STR_OVERFLOW(sb);
106
107    if (mask == ~0UL && mod == 0) {
108	*sb->current++ = '!';
109	*sb->current = '\0';
110	return;
111    }
112
113#define PRINTMOD(modmask,modstring) \
114    if (mask & modmask) {		 \
115	if (! (mod & modmask)) {	 \
116	    *sb->current++ = '~';		 \
117	    notfirst = True;		 \
118	}				 \
119	else if (notfirst)		 \
120	    *sb->current++ = ' ';		 \
121	else notfirst = True;		 \
122	strcpy(sb->current, modstring);		 \
123	sb->current += strlen(sb->current);		 \
124    }
125
126    PRINTMOD(ShiftMask, "Shift");
127    PRINTMOD(ControlMask, "Ctrl");	/* name is not CtrlMask... */
128    PRINTMOD(LockMask, "Lock");
129    PRINTMOD(Mod1Mask, "Mod1");
130    CHECK_STR_OVERFLOW(sb);
131    PRINTMOD(Mod2Mask, "Mod2");
132    PRINTMOD(Mod3Mask, "Mod3");
133    PRINTMOD(Mod4Mask, "Mod4");
134    PRINTMOD(Mod5Mask, "Mod5");
135    CHECK_STR_OVERFLOW(sb);
136    PRINTMOD(Button1Mask, "Button1");
137    PRINTMOD(Button2Mask, "Button2");
138    PRINTMOD(Button3Mask, "Button3");
139    CHECK_STR_OVERFLOW(sb);
140    PRINTMOD(Button4Mask, "Button4");
141    PRINTMOD(Button5Mask, "Button5");
142
143#undef PRINTMOD
144}
145
146static void PrintEventType(
147    TMStringBuf	sb,
148    unsigned long event)
149{
150    CHECK_STR_OVERFLOW(sb);
151    switch (event) {
152#define PRINTEVENT(event, name) case event: (void) strcpy(sb->current, name); break;
153	PRINTEVENT(KeyPress, "<KeyPress>")
154	PRINTEVENT(KeyRelease, "<KeyRelease>")
155	PRINTEVENT(ButtonPress, "<ButtonPress>")
156	PRINTEVENT(ButtonRelease, "<ButtonRelease>")
157	PRINTEVENT(MotionNotify, "<MotionNotify>")
158	PRINTEVENT(EnterNotify, "<EnterNotify>")
159	PRINTEVENT(LeaveNotify, "<LeaveNotify>")
160	PRINTEVENT(FocusIn, "<FocusIn>")
161	PRINTEVENT(FocusOut, "<FocusOut>")
162	PRINTEVENT(KeymapNotify, "<KeymapNotify>")
163	PRINTEVENT(Expose, "<Expose>")
164	PRINTEVENT(GraphicsExpose, "<GraphicsExpose>")
165	PRINTEVENT(NoExpose, "<NoExpose>")
166	PRINTEVENT(VisibilityNotify, "<VisibilityNotify>")
167	PRINTEVENT(CreateNotify, "<CreateNotify>")
168	PRINTEVENT(DestroyNotify, "<DestroyNotify>")
169	PRINTEVENT(UnmapNotify, "<UnmapNotify>")
170	PRINTEVENT(MapNotify, "<MapNotify>")
171	PRINTEVENT(MapRequest, "<MapRequest>")
172	PRINTEVENT(ReparentNotify, "<ReparentNotify>")
173	PRINTEVENT(ConfigureNotify, "<ConfigureNotify>")
174	PRINTEVENT(ConfigureRequest, "<ConfigureRequest>")
175	PRINTEVENT(GravityNotify, "<GravityNotify>")
176	PRINTEVENT(ResizeRequest, "<ResizeRequest>")
177	PRINTEVENT(CirculateNotify, "<CirculateNotify>")
178	PRINTEVENT(CirculateRequest, "<CirculateRequest>")
179	PRINTEVENT(PropertyNotify, "<PropertyNotify>")
180	PRINTEVENT(SelectionClear, "<SelectionClear>")
181	PRINTEVENT(SelectionRequest, "<SelectionRequest>")
182	PRINTEVENT(SelectionNotify, "<SelectionNotify>")
183	PRINTEVENT(ColormapNotify, "<ColormapNotify>")
184	PRINTEVENT(ClientMessage, "<ClientMessage>")
185	case _XtEventTimerEventType:
186	    (void) strcpy(sb->current,"<EventTimer>");
187	    break;
188	default:
189	    (void) sprintf(sb->current, "<0x%x>", (int) event);
190#undef PRINTEVENT
191    }
192    sb->current += strlen(sb->current);
193}
194
195static void PrintCode(
196    TMStringBuf sb,
197    unsigned long mask, unsigned long code)
198{
199    CHECK_STR_OVERFLOW(sb);
200    if (mask != 0) {
201	if (mask != ~0UL)
202	    (void) sprintf(sb->current, "0x%lx:0x%lx", mask, code);
203	else (void) sprintf(sb->current, /*"0x%lx"*/ "%d", (unsigned)code);
204	sb->current += strlen(sb->current);
205    }
206}
207
208static void PrintKeysym(
209    TMStringBuf sb,
210    KeySym keysym)
211{
212    String keysymName;
213
214    if (keysym == 0) return;
215
216    CHECK_STR_OVERFLOW(sb);
217    keysymName = XKeysymToString(keysym);
218    if (keysymName == NULL)
219      PrintCode(sb,~0UL,(unsigned long)keysym);
220    else {
221      ExpandToFit(sb, keysymName);
222      strcpy(sb->current, keysymName);
223      sb->current += strlen(sb->current);
224    }
225}
226
227static void PrintAtom(
228    TMStringBuf sb,
229    Display *dpy,
230    Atom atom)
231{
232    String atomName;
233
234    if (atom == 0) return;
235
236    atomName = (dpy ? XGetAtomName(dpy, atom) : NULL);
237
238    if (! atomName)
239      PrintCode(sb,~0UL,(unsigned long)atom);
240    else {
241      ExpandToFit( sb, atomName );
242      strcpy(sb->current, atomName);
243      sb->current += strlen(sb->current);
244      XFree(atomName);
245    }
246}
247
248static	void PrintLateModifiers(
249    TMStringBuf	sb,
250    LateBindingsPtr lateModifiers)
251{
252    for (; lateModifiers->keysym; lateModifiers++) {
253	CHECK_STR_OVERFLOW(sb);
254	if (lateModifiers->knot) {
255	    *sb->current++ = '~';
256	} else {
257	    *sb->current++ = ' ';
258	}
259	strcpy(sb->current, XKeysymToString(lateModifiers->keysym));
260	sb->current += strlen(sb->current);
261	if (lateModifiers->pair) {
262	    *(sb->current -= 2) = '\0';	/* strip "_L" */
263	    lateModifiers++;	/* skip _R keysym */
264	}
265    }
266}
267
268static void PrintEvent(
269    TMStringBuf sb,
270    register TMTypeMatch typeMatch,
271    register TMModifierMatch modMatch,
272    Display *dpy)
273{
274    if (modMatch->standard) *sb->current++ = ':';
275
276    PrintModifiers(sb, modMatch->modifierMask, modMatch->modifiers);
277    if (modMatch->lateModifiers != NULL)
278      PrintLateModifiers(sb, modMatch->lateModifiers);
279    PrintEventType(sb, typeMatch->eventType);
280    switch (typeMatch->eventType) {
281      case KeyPress:
282      case KeyRelease:
283	PrintKeysym(sb, (KeySym)typeMatch->eventCode);
284	break;
285
286      case PropertyNotify:
287      case SelectionClear:
288      case SelectionRequest:
289      case SelectionNotify:
290      case ClientMessage:
291	PrintAtom(sb, dpy, (Atom)typeMatch->eventCode);
292	break;
293
294      default:
295	PrintCode(sb, typeMatch->eventCodeMask, typeMatch->eventCode);
296    }
297}
298
299static void PrintParams(
300    TMStringBuf	sb,
301    String	*params,
302    Cardinal num_params)
303{
304    register Cardinal i;
305    for (i = 0; i<num_params; i++) {
306	ExpandToFit( sb, params[i] );
307	if (i != 0) {
308	    *sb->current++ = ',';
309	    *sb->current++ = ' ';
310	}
311	*sb->current++ = '"';
312	strcpy(sb->current, params[i]);
313	sb->current += strlen(sb->current);
314	*sb->current++ = '"';
315    }
316    *sb->current = '\0';
317}
318
319static void PrintActions(
320    TMStringBuf	sb,
321    register ActionPtr actions,
322    XrmQuark *quarkTbl,
323    Widget   accelWidget)
324{
325    while (actions != NULL) {
326	String proc;
327
328	*sb->current++ = ' ';
329
330	if (accelWidget) {
331	    /* accelerator */
332	    String name = XtName(accelWidget);
333	    int nameLen = strlen(name);
334	    ExpandForChars(sb,  nameLen );
335	    XtMemmove(sb->current, name, nameLen );
336	    sb->current += nameLen;
337	    *sb->current++ = '`';
338	}
339	proc = XrmQuarkToString(quarkTbl[actions->idx]);
340	ExpandToFit( sb, proc );
341	strcpy(sb->current, proc);
342	sb->current += strlen(proc);
343	*sb->current++ = '(';
344	PrintParams(sb, actions->params, actions->num_params);
345	*sb->current++ = ')';
346	actions = actions->next;
347    }
348    *sb->current = '\0';
349}
350
351static Boolean LookAheadForCycleOrMulticlick(
352    register StatePtr state,
353    StatePtr *state_return,	/* state to print, usually startState */
354    int *countP,
355    StatePtr *nextLevelP)
356{
357    int repeatCount = 0;
358    StatePtr	startState = state;
359    Boolean	isCycle = startState->isCycleEnd;
360    TMTypeMatch sTypeMatch;
361    TMModifierMatch sModMatch;
362
363    LOCK_PROCESS;
364    sTypeMatch = TMGetTypeMatch(startState->typeIndex);
365    sModMatch = TMGetModifierMatch(startState->modIndex);
366
367    *state_return = startState;
368
369    for (state = state->nextLevel; state != NULL; state = state->nextLevel) {
370	TMTypeMatch typeMatch = TMGetTypeMatch(state->typeIndex);
371	TMModifierMatch modMatch = TMGetModifierMatch(state->modIndex);
372
373	/* try to pick up the correct state with actions, to be printed */
374	/* This is to accommodate <ButtonUp>(2+), for example */
375	if (state->isCycleStart)
376	    *state_return = state;
377
378	if (state->isCycleEnd) {
379	    *countP = repeatCount;
380	    UNLOCK_PROCESS;
381	    return True;
382	}
383	if ((startState->typeIndex == state->typeIndex) &&
384	    (startState->modIndex == state->modIndex)) {
385	    repeatCount++;
386	    *nextLevelP = state;
387	}
388	else if (typeMatch->eventType == _XtEventTimerEventType)
389	  continue;
390	else /* not same event as starting event and not timer */ {
391	    unsigned int type = sTypeMatch->eventType;
392	    unsigned int t = typeMatch->eventType;
393	    if (   (type == ButtonPress	  && t != ButtonRelease)
394		|| (type == ButtonRelease && t != ButtonPress)
395		|| (type == KeyPress	  && t != KeyRelease)
396		|| (type == KeyRelease	  && t != KeyPress)
397		|| typeMatch->eventCode != sTypeMatch->eventCode
398		|| modMatch->modifiers != sModMatch->modifiers
399		|| modMatch->modifierMask != sModMatch->modifierMask
400		|| modMatch->lateModifiers != sModMatch->lateModifiers
401		|| typeMatch->eventCodeMask != sTypeMatch->eventCodeMask
402		|| typeMatch->matchEvent != sTypeMatch->matchEvent
403		|| modMatch->standard != sModMatch->standard)
404		/* not inverse of starting event, either */
405		break;
406	}
407    }
408    *countP = repeatCount;
409    UNLOCK_PROCESS;
410    return isCycle;
411}
412
413static void PrintComplexState(
414    TMStringBuf	sb,
415    Boolean	includeRHS,
416    StatePtr 	state,
417    TMStateTree stateTree,
418    Widget	accelWidget,
419    Display 	*dpy)
420{
421    int 		clickCount = 0;
422    Boolean 		cycle;
423    StatePtr 		nextLevel = NULL;
424    StatePtr		triggerState = NULL;
425
426    /* print the current state */
427    if (! state) return;
428    LOCK_PROCESS;
429    cycle = LookAheadForCycleOrMulticlick(state, &triggerState, &clickCount,
430					  &nextLevel);
431
432    PrintEvent(sb, TMGetTypeMatch(triggerState->typeIndex),
433	       TMGetModifierMatch(triggerState->modIndex), dpy);
434
435    if (cycle || clickCount) {
436	if (clickCount)
437	    sprintf(sb->current, "(%d%s)", clickCount+1, cycle ? "+" : "");
438	else
439	    (void) strncpy(sb->current, "(+)", 4);
440	sb->current += strlen(sb->current);
441	if (! state->actions && nextLevel)
442	    state = nextLevel;
443	while (! state->actions && ! state->isCycleEnd)
444	    state = state->nextLevel;	/* should be trigger state */
445    }
446
447    if (state->actions) {
448	if (includeRHS) {
449	    CHECK_STR_OVERFLOW(sb);
450	    *sb->current++ = ':';
451	    PrintActions(sb,
452			 state->actions,
453			 ((TMSimpleStateTree)stateTree)->quarkTbl,
454			 accelWidget);
455	    *sb->current++ = '\n';
456	}
457    }
458    else {
459	if (state->nextLevel && !cycle && !clickCount)
460	    *sb->current++ = ',';
461	else {
462	    /* no actions are attached to this production */
463	    *sb->current++ = ':';
464	    *sb->current++ = '\n';
465	}
466    }
467    *sb->current = '\0';
468
469    /* print succeeding states */
470    if (state->nextLevel && !cycle && !clickCount)
471	PrintComplexState(sb, includeRHS, state->nextLevel,
472			  stateTree, accelWidget, dpy);
473    UNLOCK_PROCESS;
474}
475
476typedef struct{
477    TMShortCard	tIndex;
478    TMShortCard	bIndex;
479}PrintRec, *Print;
480
481static int FindNextMatch(
482    PrintRec		*printData,
483    TMShortCard		numPrints,
484    XtTranslations 	xlations,
485    TMBranchHead	branchHead,
486    StatePtr 		nextLevel,
487    TMShortCard		startIndex)
488{
489    TMShortCard		i;
490    TMComplexStateTree 	stateTree;
491    StatePtr		currState, candState;
492    Boolean		noMatch = True;
493    TMBranchHead	prBranchHead;
494
495    for (i = startIndex; noMatch && i < numPrints; i++) {
496	stateTree = (TMComplexStateTree)
497	  xlations->stateTreeTbl[printData[i].tIndex];
498	prBranchHead =
499	  &(stateTree->branchHeadTbl[printData[i].bIndex]);
500
501	if ((prBranchHead->typeIndex == branchHead->typeIndex) &&
502	    (prBranchHead->modIndex == branchHead->modIndex)) {
503	    if (prBranchHead->isSimple) {
504		if (!nextLevel)
505		  return i;
506	    }
507	    else {
508		currState = TMComplexBranchHead(stateTree, prBranchHead);
509		currState = currState->nextLevel;
510		candState = nextLevel;
511		for (;
512		     ((currState && !currState->isCycleEnd) &&
513		      (candState && !candState->isCycleEnd));
514		     currState = currState->nextLevel,
515		     candState = candState->nextLevel) {
516		    if ((currState->typeIndex != candState->typeIndex) ||
517			(currState->modIndex != candState->modIndex))
518		      break;
519		}
520		if (candState == currState) {
521		    return i;
522		}
523	    }
524	}
525    }
526    return TM_NO_MATCH;
527}
528
529static void ProcessLaterMatches(
530    PrintRec	*printData,
531    XtTranslations xlations,
532    TMShortCard	tIndex,
533    int bIndex,
534    TMShortCard	*numPrintsRtn)
535{
536    TMComplexStateTree 	stateTree;
537    int			i, j;
538    TMBranchHead	branchHead, matchBranch = NULL;
539
540    for (i = tIndex; i < (int)xlations->numStateTrees; i++) {
541	stateTree = (TMComplexStateTree)xlations->stateTreeTbl[i];
542	if (i == tIndex) {
543	    matchBranch = &stateTree->branchHeadTbl[bIndex];
544	    j = bIndex+1;
545	}
546	else j = 0;
547	for (branchHead = &stateTree->branchHeadTbl[j];
548	     j < (int)stateTree->numBranchHeads;
549	     j++, branchHead++) {
550	    if ((branchHead->typeIndex == matchBranch->typeIndex) &&
551		(branchHead->modIndex == matchBranch->modIndex)) {
552		StatePtr state;
553		if (!branchHead->isSimple)
554		  state = TMComplexBranchHead(stateTree, branchHead);
555		else
556		  state = NULL;
557		if ((!branchHead->isSimple || branchHead->hasActions) &&
558		    (FindNextMatch(printData,
559				   *numPrintsRtn,
560				   xlations,
561				   branchHead,
562				   (state ? state->nextLevel : NULL),
563				   0) == TM_NO_MATCH)) {
564		    printData[*numPrintsRtn].tIndex = i;
565		    printData[*numPrintsRtn].bIndex = j;
566		    (*numPrintsRtn)++;
567		}
568	    }
569	}
570    }
571}
572
573static void ProcessStateTree(
574    PrintRec	*printData,
575    XtTranslations xlations,
576    TMShortCard	tIndex,
577    TMShortCard	*numPrintsRtn)
578{
579    TMComplexStateTree stateTree;
580    int			i;
581    TMBranchHead	branchHead;
582
583    stateTree = (TMComplexStateTree)xlations->stateTreeTbl[tIndex];
584
585    for (i = 0, branchHead = stateTree->branchHeadTbl;
586	 i < (int)stateTree->numBranchHeads;
587	 i++, branchHead++) {
588	StatePtr state;
589	if (!branchHead->isSimple)
590	  state = TMComplexBranchHead(stateTree, branchHead);
591	else
592	  state = NULL;
593	if (FindNextMatch(printData, *numPrintsRtn, xlations, branchHead,
594			  (state ? state->nextLevel : NULL), 0)
595	    == TM_NO_MATCH) {
596	    if (!branchHead->isSimple || branchHead->hasActions) {
597		printData[*numPrintsRtn].tIndex = tIndex;
598		printData[*numPrintsRtn].bIndex = i;
599		(*numPrintsRtn)++;
600	    }
601	    LOCK_PROCESS;
602	    if (_XtGlobalTM.newMatchSemantics == False)
603	      ProcessLaterMatches(printData,
604				  xlations,
605				  tIndex,
606				  i,
607				  numPrintsRtn);
608	    UNLOCK_PROCESS;
609	}
610    }
611}
612
613static void PrintState(
614    TMStringBuf	sb,
615    TMStateTree	tree,
616    TMBranchHead branchHead,
617    Boolean	includeRHS,
618    Widget	accelWidget,
619    Display 	*dpy)
620{
621    TMComplexStateTree stateTree = (TMComplexStateTree)tree;
622    LOCK_PROCESS;
623    if (branchHead->isSimple) {
624	PrintEvent(sb,
625		   TMGetTypeMatch(branchHead->typeIndex),
626		   TMGetModifierMatch(branchHead->modIndex),
627		   dpy);
628	if (includeRHS) {
629	    ActionRec	actRec;
630
631	    CHECK_STR_OVERFLOW(sb);
632	    *sb->current++ = ':';
633	    actRec.idx = TMBranchMore(branchHead);
634	    actRec.num_params = 0;
635	    actRec.params = NULL;
636	    actRec.next = NULL;
637	    PrintActions(sb,
638			 &actRec,
639			 stateTree->quarkTbl,
640			 accelWidget);
641	    *sb->current++ = '\n';
642	}
643	else
644	  *sb->current++ = ',';
645#ifdef TRACE_TM
646	if (!branchHead->hasActions)
647	  printf(" !! no actions !! ");
648#endif
649    }
650	else { /* it's a complex branchHead */
651	    StatePtr state = TMComplexBranchHead(stateTree, branchHead);
652	    PrintComplexState(sb,
653			      includeRHS,
654			      state,
655			      tree,
656			      accelWidget,
657			      (Display *)NULL);
658	}
659    *sb->current = '\0';
660    UNLOCK_PROCESS;
661}
662
663String _XtPrintXlations(
664    Widget		w,
665    XtTranslations 	xlations,
666    Widget		accelWidget,
667    _XtBoolean		includeRHS)
668{
669    register Cardinal 	i;
670#define STACKPRINTSIZE 250
671    PrintRec		stackPrints[STACKPRINTSIZE];
672    PrintRec		*prints;
673    TMStringBufRec	sbRec, *sb = &sbRec;
674    TMShortCard		numPrints, maxPrints;
675#ifdef TRACE_TM
676    TMBindData		bindData = (TMBindData)w->core.tm.proc_table;
677    Boolean		hasAccel = (accelWidget ? True : False);
678#endif /* TRACE_TM */
679    if (xlations == NULL) return NULL;
680
681    sb->current = sb->start = __XtMalloc((Cardinal)1000);
682    sb->max = 1000;
683    maxPrints = 0;
684    for (i = 0; i < xlations->numStateTrees; i++)
685	maxPrints +=
686	  ((TMSimpleStateTree)(xlations->stateTreeTbl[i]))->numBranchHeads;
687    prints = (PrintRec *)
688      XtStackAlloc(maxPrints * sizeof(PrintRec), stackPrints);
689
690    numPrints = 0;
691    for (i = 0; i < xlations->numStateTrees; i++)
692      ProcessStateTree(prints, xlations, i, &numPrints);
693
694    for (i = 0; i < numPrints; i++) {
695	TMSimpleStateTree stateTree = (TMSimpleStateTree)
696	  xlations->stateTreeTbl[prints[i].tIndex];
697	TMBranchHead branchHead =
698	  &stateTree->branchHeadTbl[prints[i].bIndex];
699#ifdef TRACE_TM
700	TMComplexBindProcs	complexBindProcs;
701
702	if (hasAccel == False) {
703	    accelWidget = NULL;
704	    if (bindData->simple.isComplex) {
705		complexBindProcs = TMGetComplexBindEntry(bindData, 0);
706		accelWidget = complexBindProcs[prints[i].tIndex].widget;
707	    }
708	}
709#endif /* TRACE_TM */
710	PrintState(sb, (TMStateTree)stateTree, branchHead,
711		   includeRHS, accelWidget, XtDisplay(w));
712    }
713    XtStackFree((XtPointer)prints, (XtPointer)stackPrints);
714    return (sb->start);
715}
716
717
718#ifndef NO_MIT_HACKS
719/*ARGSUSED*/
720void _XtDisplayTranslations(
721    Widget widget,
722    XEvent *event,
723    String *params,
724    Cardinal *num_params)
725{
726    String 	xString;
727
728    xString =  _XtPrintXlations(widget,
729				widget->core.tm.translations,
730				NULL,
731				True);
732    printf("%s\n",xString);
733    XtFree(xString);
734}
735
736/*ARGSUSED*/
737void _XtDisplayAccelerators(
738    Widget widget,
739    XEvent *event,
740    String *params,
741    Cardinal *num_params)
742{
743    String 	xString;
744
745
746    xString =  _XtPrintXlations(widget,
747				widget->core.accelerators,
748				NULL,
749				True);
750    printf("%s\n",xString);
751    XtFree(xString);
752}
753
754/*ARGSUSED*/
755void _XtDisplayInstalledAccelerators(
756    Widget widget,
757    XEvent *event,
758    String *params,
759    Cardinal *num_params)
760{
761    Widget eventWidget
762	= XtWindowToWidget(event->xany.display, event->xany.window);
763    register Cardinal 	i;
764    TMStringBufRec	sbRec, *sb = &sbRec;
765    XtTranslations	xlations;
766#define STACKPRINTSIZE 250
767    PrintRec		stackPrints[STACKPRINTSIZE];
768    PrintRec		*prints;
769    TMShortCard		numPrints, maxPrints;
770    TMBindData	bindData = (TMBindData) eventWidget->core.tm.proc_table;
771    TMComplexBindProcs	complexBindProcs;
772
773    if ((eventWidget == NULL) ||
774	((xlations = eventWidget->core.tm.translations) == NULL) ||
775	(bindData->simple.isComplex == False))
776      return;
777
778    sb->current = sb->start = __XtMalloc((Cardinal)1000);
779    sb->start[0] = '\0';
780    sb->max = 1000;
781    maxPrints = 0;
782    for (i = 0; i < xlations->numStateTrees; i++)
783	maxPrints +=
784	  ((TMSimpleStateTree)xlations->stateTreeTbl[i])->numBranchHeads;
785    prints = (PrintRec *)
786      XtStackAlloc(maxPrints * sizeof(PrintRec), stackPrints);
787
788    numPrints = 0;
789
790    complexBindProcs = TMGetComplexBindEntry(bindData, 0);
791    for (i = 0;
792	 i < xlations->numStateTrees;
793	 i++, complexBindProcs++) {
794	if (complexBindProcs->widget)
795	  {
796	      ProcessStateTree(prints, xlations, i, &numPrints);
797	  }
798    }
799    for (i = 0; i < numPrints; i++) {
800	TMSimpleStateTree stateTree = (TMSimpleStateTree)
801	  xlations->stateTreeTbl[prints[i].tIndex];
802	TMBranchHead branchHead =
803	  &stateTree->branchHeadTbl[prints[i].bIndex];
804
805	complexBindProcs = TMGetComplexBindEntry(bindData, 0);
806
807	PrintState(sb, (TMStateTree)stateTree, branchHead, True,
808		   complexBindProcs[prints[i].tIndex].widget,
809		   XtDisplay(widget));
810    }
811    XtStackFree((XtPointer)prints, (XtPointer)stackPrints);
812    printf("%s\n", sb->start);
813    XtFree(sb->start);
814}
815#endif /*NO_MIT_HACKS*/
816
817String _XtPrintActions(
818    register ActionRec *actions,
819    XrmQuark		*quarkTbl)
820{
821    TMStringBufRec	sbRec, *sb = &sbRec;
822
823    sb->max = 1000;
824    sb->current = sb->start = __XtMalloc((Cardinal)1000);
825    PrintActions(sb,
826		 actions,
827		 quarkTbl,
828		 (Widget)NULL);
829    return sb->start;
830}
831
832String _XtPrintState(
833    TMStateTree		stateTree,
834    TMBranchHead	branchHead)
835{
836    TMStringBufRec	sbRec, *sb = &sbRec;
837
838    sb->current = sb->start = __XtMalloc((Cardinal)1000);
839    sb->max = 1000;
840    PrintState(sb, stateTree, branchHead,
841	       True, (Widget)NULL, (Display *)NULL);
842    return sb->start;
843}
844
845
846String _XtPrintEventSeq(
847    register EventSeqPtr eventSeq,
848    Display *dpy)
849{
850    TMStringBufRec	sbRec, *sb = &sbRec;
851    TMTypeMatch		typeMatch;
852    TMModifierMatch	modMatch;
853#define MAXSEQS 100
854    EventSeqPtr		eventSeqs[MAXSEQS];
855    TMShortCard		i, j;
856    Boolean		cycle = False;
857
858    sb->current = sb->start = __XtMalloc((Cardinal)1000);
859    sb->max = 1000;
860    for (i = 0;
861	 i < MAXSEQS && eventSeq != NULL && !cycle;
862	 eventSeq = eventSeq->next, i++)
863      {
864	  eventSeqs[i] = eventSeq;
865	  for (j = 0; j < i && !cycle; j++)
866	    if (eventSeqs[j] == eventSeq)
867	      cycle = True;
868      }
869    LOCK_PROCESS;
870    for (j = 0; j < i; j++) {
871	typeMatch =
872	  TMGetTypeMatch(_XtGetTypeIndex(&eventSeqs[j]->event));
873	modMatch =
874	  TMGetModifierMatch(_XtGetModifierIndex(&eventSeqs[j]->event));
875	PrintEvent(sb, typeMatch, modMatch, dpy);
876	if (j < i)
877	  *sb->current++ = ',';
878    }
879    UNLOCK_PROCESS;
880    return sb->start;
881}
882