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