TMprint.c revision 0568f49b
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    _XtString	start;
80    _XtString	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{ _XtString 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 - (Cardinal) nchars)) { \
96	_XtString old = sb->start;				\
97	sb->start = XtRealloc(old,				\
98	    (Cardinal)(sb->max = (Cardinal)(sb->max + STR_INCAMOUNT + (Cardinal) 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    (void) notfirst;
151
152#undef PRINTMOD
153}
154
155static void PrintEventType(
156    TMStringBuf	sb,
157    unsigned long event)
158{
159    CHECK_STR_OVERFLOW(sb);
160    switch (event) {
161#define PRINTEVENT(event, name) case event: (void) strcpy(sb->current, name); break;
162	PRINTEVENT(KeyPress, "<KeyPress>")
163	PRINTEVENT(KeyRelease, "<KeyRelease>")
164	PRINTEVENT(ButtonPress, "<ButtonPress>")
165	PRINTEVENT(ButtonRelease, "<ButtonRelease>")
166	PRINTEVENT(MotionNotify, "<MotionNotify>")
167	PRINTEVENT(EnterNotify, "<EnterNotify>")
168	PRINTEVENT(LeaveNotify, "<LeaveNotify>")
169	PRINTEVENT(FocusIn, "<FocusIn>")
170	PRINTEVENT(FocusOut, "<FocusOut>")
171	PRINTEVENT(KeymapNotify, "<KeymapNotify>")
172	PRINTEVENT(Expose, "<Expose>")
173	PRINTEVENT(GraphicsExpose, "<GraphicsExpose>")
174	PRINTEVENT(NoExpose, "<NoExpose>")
175	PRINTEVENT(VisibilityNotify, "<VisibilityNotify>")
176	PRINTEVENT(CreateNotify, "<CreateNotify>")
177	PRINTEVENT(DestroyNotify, "<DestroyNotify>")
178	PRINTEVENT(UnmapNotify, "<UnmapNotify>")
179	PRINTEVENT(MapNotify, "<MapNotify>")
180	PRINTEVENT(MapRequest, "<MapRequest>")
181	PRINTEVENT(ReparentNotify, "<ReparentNotify>")
182	PRINTEVENT(ConfigureNotify, "<ConfigureNotify>")
183	PRINTEVENT(ConfigureRequest, "<ConfigureRequest>")
184	PRINTEVENT(GravityNotify, "<GravityNotify>")
185	PRINTEVENT(ResizeRequest, "<ResizeRequest>")
186	PRINTEVENT(CirculateNotify, "<CirculateNotify>")
187	PRINTEVENT(CirculateRequest, "<CirculateRequest>")
188	PRINTEVENT(PropertyNotify, "<PropertyNotify>")
189	PRINTEVENT(SelectionClear, "<SelectionClear>")
190	PRINTEVENT(SelectionRequest, "<SelectionRequest>")
191	PRINTEVENT(SelectionNotify, "<SelectionNotify>")
192	PRINTEVENT(ColormapNotify, "<ColormapNotify>")
193	PRINTEVENT(ClientMessage, "<ClientMessage>")
194	case _XtEventTimerEventType:
195	    (void) strcpy(sb->current,"<EventTimer>");
196	    break;
197	default:
198	    (void) sprintf(sb->current, "<0x%x>", (int) event);
199#undef PRINTEVENT
200    }
201    sb->current += strlen(sb->current);
202}
203
204static void PrintCode(
205    TMStringBuf sb,
206    unsigned long mask, unsigned long code)
207{
208    CHECK_STR_OVERFLOW(sb);
209    if (mask != 0) {
210	if (mask != ~0UL)
211	    (void) sprintf(sb->current, "0x%lx:0x%lx", mask, code);
212	else (void) sprintf(sb->current, /*"0x%lx"*/ "%u", (unsigned)code);
213	sb->current += strlen(sb->current);
214    }
215}
216
217static void PrintKeysym(
218    TMStringBuf sb,
219    KeySym keysym)
220{
221    String keysymName;
222
223    if (keysym == 0) return;
224
225    CHECK_STR_OVERFLOW(sb);
226    keysymName = XKeysymToString(keysym);
227    if (keysymName == NULL)
228      PrintCode(sb,~0UL,(unsigned long)keysym);
229    else {
230      ExpandToFit(sb, keysymName);
231      strcpy(sb->current, keysymName);
232      sb->current += strlen(sb->current);
233    }
234}
235
236static void PrintAtom(
237    TMStringBuf sb,
238    Display *dpy,
239    Atom atom)
240{
241    _XtString atomName;
242
243    if (atom == 0) return;
244
245    atomName = (dpy ? XGetAtomName(dpy, atom) : NULL);
246
247    if (! atomName)
248      PrintCode(sb,~0UL,(unsigned long)atom);
249    else {
250      ExpandToFit( sb, atomName );
251      strcpy(sb->current, atomName);
252      sb->current += strlen(sb->current);
253      XFree(atomName);
254    }
255}
256
257static	void PrintLateModifiers(
258    TMStringBuf	sb,
259    LateBindingsPtr lateModifiers)
260{
261    for (; lateModifiers->keysym; lateModifiers++) {
262	CHECK_STR_OVERFLOW(sb);
263	if (lateModifiers->knot) {
264	    *sb->current++ = '~';
265	} else {
266	    *sb->current++ = ' ';
267	}
268	strcpy(sb->current, XKeysymToString(lateModifiers->keysym));
269	sb->current += strlen(sb->current);
270	if (lateModifiers->pair) {
271	    *(sb->current -= 2) = '\0';	/* strip "_L" */
272	    lateModifiers++;	/* skip _R keysym */
273	}
274    }
275}
276
277static void PrintEvent(
278    TMStringBuf sb,
279    register TMTypeMatch typeMatch,
280    register TMModifierMatch modMatch,
281    Display *dpy)
282{
283    if (modMatch->standard) *sb->current++ = ':';
284
285    PrintModifiers(sb, modMatch->modifierMask, modMatch->modifiers);
286    if (modMatch->lateModifiers != NULL)
287      PrintLateModifiers(sb, modMatch->lateModifiers);
288    PrintEventType(sb, typeMatch->eventType);
289    switch (typeMatch->eventType) {
290      case KeyPress:
291      case KeyRelease:
292	PrintKeysym(sb, (KeySym)typeMatch->eventCode);
293	break;
294
295      case PropertyNotify:
296      case SelectionClear:
297      case SelectionRequest:
298      case SelectionNotify:
299      case ClientMessage:
300	PrintAtom(sb, dpy, (Atom)typeMatch->eventCode);
301	break;
302
303      default:
304	PrintCode(sb, typeMatch->eventCodeMask, typeMatch->eventCode);
305    }
306}
307
308static void PrintParams(
309    TMStringBuf	sb,
310    String	*params,
311    Cardinal num_params)
312{
313    register Cardinal i;
314    for (i = 0; i<num_params; i++) {
315	ExpandToFit( sb, params[i] );
316	if (i != 0) {
317	    *sb->current++ = ',';
318	    *sb->current++ = ' ';
319	}
320	*sb->current++ = '"';
321	strcpy(sb->current, params[i]);
322	sb->current += strlen(sb->current);
323	*sb->current++ = '"';
324    }
325    *sb->current = '\0';
326}
327
328static void PrintActions(
329    TMStringBuf	sb,
330    register ActionPtr actions,
331    XrmQuark *quarkTbl,
332    Widget   accelWidget)
333{
334    while (actions != NULL) {
335	String proc;
336
337	*sb->current++ = ' ';
338
339	if (accelWidget) {
340	    /* accelerator */
341	    String name = XtName(accelWidget);
342	    int nameLen = (int) strlen(name);
343	    ExpandForChars(sb,  nameLen );
344	    XtMemmove(sb->current, name, nameLen );
345	    sb->current += nameLen;
346	    *sb->current++ = '`';
347	}
348	proc = XrmQuarkToString(quarkTbl[actions->idx]);
349	ExpandToFit( sb, proc );
350	strcpy(sb->current, proc);
351	sb->current += strlen(proc);
352	*sb->current++ = '(';
353	PrintParams(sb, actions->params, actions->num_params);
354	*sb->current++ = ')';
355	actions = actions->next;
356    }
357    *sb->current = '\0';
358}
359
360static Boolean LookAheadForCycleOrMulticlick(
361    register StatePtr state,
362    StatePtr *state_return,	/* state to print, usually startState */
363    int *countP,
364    StatePtr *nextLevelP)
365{
366    int repeatCount = 0;
367    StatePtr	startState = state;
368    Boolean	isCycle = startState->isCycleEnd;
369    TMTypeMatch sTypeMatch;
370    TMModifierMatch sModMatch;
371
372    LOCK_PROCESS;
373    sTypeMatch = TMGetTypeMatch(startState->typeIndex);
374    sModMatch = TMGetModifierMatch(startState->modIndex);
375
376    *state_return = startState;
377
378    for (state = state->nextLevel; state != NULL; state = state->nextLevel) {
379	TMTypeMatch typeMatch = TMGetTypeMatch(state->typeIndex);
380	TMModifierMatch modMatch = TMGetModifierMatch(state->modIndex);
381
382	/* try to pick up the correct state with actions, to be printed */
383	/* This is to accommodate <ButtonUp>(2+), for example */
384	if (state->isCycleStart)
385	    *state_return = state;
386
387	if (state->isCycleEnd) {
388	    *countP = repeatCount;
389	    UNLOCK_PROCESS;
390	    return True;
391	}
392	if ((startState->typeIndex == state->typeIndex) &&
393	    (startState->modIndex == state->modIndex)) {
394	    repeatCount++;
395	    *nextLevelP = state;
396	}
397	else if (typeMatch->eventType == _XtEventTimerEventType)
398	  continue;
399	else /* not same event as starting event and not timer */ {
400	    unsigned int type = (unsigned) sTypeMatch->eventType;
401	    unsigned int t = (unsigned) typeMatch->eventType;
402	    if (   (type == ButtonPress	  && t != ButtonRelease)
403		|| (type == ButtonRelease && t != ButtonPress)
404		|| (type == KeyPress	  && t != KeyRelease)
405		|| (type == KeyRelease	  && t != KeyPress)
406		|| typeMatch->eventCode != sTypeMatch->eventCode
407		|| modMatch->modifiers != sModMatch->modifiers
408		|| modMatch->modifierMask != sModMatch->modifierMask
409		|| modMatch->lateModifiers != sModMatch->lateModifiers
410		|| typeMatch->eventCodeMask != sTypeMatch->eventCodeMask
411		|| typeMatch->matchEvent != sTypeMatch->matchEvent
412		|| modMatch->standard != sModMatch->standard)
413		/* not inverse of starting event, either */
414		break;
415	}
416    }
417    *countP = repeatCount;
418    UNLOCK_PROCESS;
419    return isCycle;
420}
421
422static void PrintComplexState(
423    TMStringBuf	sb,
424    Boolean	includeRHS,
425    StatePtr 	state,
426    TMStateTree stateTree,
427    Widget	accelWidget,
428    Display 	*dpy)
429{
430    int 		clickCount = 0;
431    Boolean 		cycle;
432    StatePtr 		nextLevel = NULL;
433    StatePtr		triggerState = NULL;
434
435    /* print the current state */
436    if (! state) return;
437    LOCK_PROCESS;
438    cycle = LookAheadForCycleOrMulticlick(state, &triggerState, &clickCount,
439					  &nextLevel);
440
441    PrintEvent(sb, TMGetTypeMatch(triggerState->typeIndex),
442	       TMGetModifierMatch(triggerState->modIndex), dpy);
443
444    if (cycle || clickCount) {
445	if (clickCount)
446	    sprintf(sb->current, "(%d%s)", clickCount+1, cycle ? "+" : "");
447	else
448	    (void) strncpy(sb->current, "(+)", 4);
449	sb->current += strlen(sb->current);
450	if (! state->actions && nextLevel)
451	    state = nextLevel;
452	while (! state->actions && ! state->isCycleEnd)
453	    state = state->nextLevel;	/* should be trigger state */
454    }
455
456    if (state->actions) {
457	if (includeRHS) {
458	    CHECK_STR_OVERFLOW(sb);
459	    *sb->current++ = ':';
460	    PrintActions(sb,
461			 state->actions,
462			 ((TMSimpleStateTree)stateTree)->quarkTbl,
463			 accelWidget);
464	    *sb->current++ = '\n';
465	}
466    }
467    else {
468	if (state->nextLevel && !cycle && !clickCount)
469	    *sb->current++ = ',';
470	else {
471	    /* no actions are attached to this production */
472	    *sb->current++ = ':';
473	    *sb->current++ = '\n';
474	}
475    }
476    *sb->current = '\0';
477
478    /* print succeeding states */
479    if (state->nextLevel && !cycle && !clickCount)
480	PrintComplexState(sb, includeRHS, state->nextLevel,
481			  stateTree, accelWidget, dpy);
482    UNLOCK_PROCESS;
483}
484
485typedef struct{
486    TMShortCard	tIndex;
487    TMShortCard	bIndex;
488}PrintRec, *Print;
489
490static int FindNextMatch(
491    PrintRec		*printData,
492    TMShortCard		numPrints,
493    XtTranslations 	xlations,
494    TMBranchHead	branchHead,
495    StatePtr 		nextLevel,
496    TMShortCard		startIndex)
497{
498    TMShortCard		i;
499    StatePtr		currState, candState;
500    Boolean		noMatch = True;
501
502    for (i = startIndex; noMatch && i < numPrints; i++) {
503	TMBranchHead prBranchHead;
504	TMComplexStateTree stateTree;
505
506	stateTree = (TMComplexStateTree)
507	  xlations->stateTreeTbl[printData[i].tIndex];
508	prBranchHead =
509	  &(stateTree->branchHeadTbl[printData[i].bIndex]);
510
511	if ((prBranchHead->typeIndex == branchHead->typeIndex) &&
512	    (prBranchHead->modIndex == branchHead->modIndex)) {
513	    if (prBranchHead->isSimple) {
514		if (!nextLevel)
515		  return i;
516	    }
517	    else {
518		currState = TMComplexBranchHead(stateTree, prBranchHead);
519		currState = currState->nextLevel;
520		candState = nextLevel;
521		for (;
522		     ((currState && !currState->isCycleEnd) &&
523		      (candState && !candState->isCycleEnd));
524		     currState = currState->nextLevel,
525		     candState = candState->nextLevel) {
526		    if ((currState->typeIndex != candState->typeIndex) ||
527			(currState->modIndex != candState->modIndex))
528		      break;
529		}
530		if (candState == currState) {
531		    return i;
532		}
533	    }
534	}
535    }
536    return TM_NO_MATCH;
537}
538
539static void ProcessLaterMatches(
540    PrintRec	*printData,
541    XtTranslations xlations,
542    TMShortCard	tIndex,
543    int bIndex,
544    TMShortCard	*numPrintsRtn)
545{
546    TMComplexStateTree 	stateTree;
547    int			i, j;
548    TMBranchHead	branchHead, matchBranch = NULL;
549
550    for (i = tIndex; i < (int)xlations->numStateTrees; i++) {
551	stateTree = (TMComplexStateTree)xlations->stateTreeTbl[i];
552	if (i == tIndex) {
553	    matchBranch = &stateTree->branchHeadTbl[bIndex];
554	    j = bIndex+1;
555	}
556	else j = 0;
557	for (branchHead = &stateTree->branchHeadTbl[j];
558	     j < (int)stateTree->numBranchHeads;
559	     j++, branchHead++) {
560	    if ((branchHead->typeIndex == matchBranch->typeIndex) &&
561		(branchHead->modIndex == matchBranch->modIndex)) {
562		StatePtr state;
563		if (!branchHead->isSimple)
564		  state = TMComplexBranchHead(stateTree, branchHead);
565		else
566		  state = NULL;
567		if ((!branchHead->isSimple || branchHead->hasActions) &&
568		    (FindNextMatch(printData,
569				   *numPrintsRtn,
570				   xlations,
571				   branchHead,
572				   (state ? state->nextLevel : NULL),
573				   0) == TM_NO_MATCH)) {
574		    printData[*numPrintsRtn].tIndex = (TMShortCard) i;
575		    printData[*numPrintsRtn].bIndex = (TMShortCard) j;
576		    (*numPrintsRtn)++;
577		}
578	    }
579	}
580    }
581}
582
583static void ProcessStateTree(
584    PrintRec	*printData,
585    XtTranslations xlations,
586    TMShortCard	tIndex,
587    TMShortCard	*numPrintsRtn)
588{
589    TMComplexStateTree stateTree;
590    int			i;
591    TMBranchHead	branchHead;
592
593    stateTree = (TMComplexStateTree)xlations->stateTreeTbl[tIndex];
594
595    for (i = 0, branchHead = stateTree->branchHeadTbl;
596	 i < (int)stateTree->numBranchHeads;
597	 i++, branchHead++) {
598	StatePtr state;
599	if (!branchHead->isSimple)
600	  state = TMComplexBranchHead(stateTree, branchHead);
601	else
602	  state = NULL;
603	if (FindNextMatch(printData, *numPrintsRtn, xlations, branchHead,
604			  (state ? state->nextLevel : NULL), 0)
605	    == TM_NO_MATCH) {
606	    if (!branchHead->isSimple || branchHead->hasActions) {
607		printData[*numPrintsRtn].tIndex = tIndex;
608		printData[*numPrintsRtn].bIndex = (TMShortCard) i;
609		(*numPrintsRtn)++;
610	    }
611	    LOCK_PROCESS;
612	    if (_XtGlobalTM.newMatchSemantics == False)
613	      ProcessLaterMatches(printData,
614				  xlations,
615				  tIndex,
616				  i,
617				  numPrintsRtn);
618	    UNLOCK_PROCESS;
619	}
620    }
621}
622
623static void PrintState(
624    TMStringBuf	sb,
625    TMStateTree	tree,
626    TMBranchHead branchHead,
627    Boolean	includeRHS,
628    Widget	accelWidget,
629    Display 	*dpy)
630{
631    TMComplexStateTree stateTree = (TMComplexStateTree)tree;
632    LOCK_PROCESS;
633    if (branchHead->isSimple) {
634	PrintEvent(sb,
635		   TMGetTypeMatch(branchHead->typeIndex),
636		   TMGetModifierMatch(branchHead->modIndex),
637		   dpy);
638	if (includeRHS) {
639	    ActionRec	actRec;
640
641	    CHECK_STR_OVERFLOW(sb);
642	    *sb->current++ = ':';
643	    actRec.idx = TMBranchMore(branchHead);
644	    actRec.num_params = 0;
645	    actRec.params = NULL;
646	    actRec.next = NULL;
647	    PrintActions(sb,
648			 &actRec,
649			 stateTree->quarkTbl,
650			 accelWidget);
651	    *sb->current++ = '\n';
652	}
653	else
654	  *sb->current++ = ',';
655#ifdef TRACE_TM
656	if (!branchHead->hasActions)
657	  printf(" !! no actions !! ");
658#endif
659    }
660	else { /* it's a complex branchHead */
661	    StatePtr state = TMComplexBranchHead(stateTree, branchHead);
662	    PrintComplexState(sb,
663			      includeRHS,
664			      state,
665			      tree,
666			      accelWidget,
667			      (Display *)NULL);
668	}
669    *sb->current = '\0';
670    UNLOCK_PROCESS;
671}
672
673_XtString _XtPrintXlations(
674    Widget		w,
675    XtTranslations 	xlations,
676    Widget		accelWidget,
677    _XtBoolean		includeRHS)
678{
679    register Cardinal 	i;
680#define STACKPRINTSIZE 250
681    PrintRec		stackPrints[STACKPRINTSIZE];
682    PrintRec		*prints;
683    TMStringBufRec	sbRec, *sb = &sbRec;
684    TMShortCard		numPrints, maxPrints;
685#ifdef TRACE_TM
686    TMBindData		bindData = (TMBindData)w->core.tm.proc_table;
687    Boolean		hasAccel = (accelWidget ? True : False);
688#endif /* TRACE_TM */
689    if (xlations == NULL) return NULL;
690
691    sb->current = sb->start = __XtMalloc((Cardinal)1000);
692    sb->max = 1000;
693    maxPrints = 0;
694    for (i = 0; i < xlations->numStateTrees; i++)
695	maxPrints = (TMShortCard) (maxPrints +
696	  ((TMSimpleStateTree)(xlations->stateTreeTbl[i]))->numBranchHeads);
697    prints = (PrintRec *)
698      XtStackAlloc(maxPrints * sizeof(PrintRec), stackPrints);
699
700    numPrints = 0;
701    for (i = 0; i < xlations->numStateTrees; i++)
702      ProcessStateTree(prints, xlations, (TMShortCard) i, &numPrints);
703
704    for (i = 0; i < numPrints; i++) {
705	TMSimpleStateTree stateTree = (TMSimpleStateTree)
706	  xlations->stateTreeTbl[prints[i].tIndex];
707	TMBranchHead branchHead =
708	  &stateTree->branchHeadTbl[prints[i].bIndex];
709#ifdef TRACE_TM
710	TMComplexBindProcs	complexBindProcs;
711
712	if (hasAccel == False) {
713	    accelWidget = NULL;
714	    if (bindData->simple.isComplex) {
715		complexBindProcs = TMGetComplexBindEntry(bindData, 0);
716		accelWidget = complexBindProcs[prints[i].tIndex].widget;
717	    }
718	}
719#endif /* TRACE_TM */
720	PrintState(sb, (TMStateTree)stateTree, branchHead,
721		   (Boolean) includeRHS, accelWidget, XtDisplay(w));
722    }
723    XtStackFree((XtPointer)prints, (XtPointer)stackPrints);
724    return (sb->start);
725}
726
727
728#ifndef NO_MIT_HACKS
729/*ARGSUSED*/
730void _XtDisplayTranslations(
731    Widget widget,
732    XEvent *event,
733    String *params,
734    Cardinal *num_params)
735{
736    _XtString 	xString;
737
738    xString =  _XtPrintXlations(widget,
739				widget->core.tm.translations,
740				NULL,
741				True);
742    if (xString) {
743	printf("%s\n",xString);
744	XtFree(xString);
745    }
746}
747
748/*ARGSUSED*/
749void _XtDisplayAccelerators(
750    Widget widget,
751    XEvent *event,
752    String *params,
753    Cardinal *num_params)
754{
755    _XtString 	xString;
756
757
758    xString =  _XtPrintXlations(widget,
759				widget->core.accelerators,
760				NULL,
761				True);
762    if (xString) {
763	printf("%s\n",xString);
764	XtFree(xString);
765    }
766}
767
768/*ARGSUSED*/
769void _XtDisplayInstalledAccelerators(
770    Widget widget,
771    XEvent *event,
772    String *params,
773    Cardinal *num_params)
774{
775    Widget eventWidget
776	= XtWindowToWidget(event->xany.display, event->xany.window);
777    register Cardinal 	i;
778    TMStringBufRec	sbRec, *sb = &sbRec;
779    XtTranslations	xlations;
780#define STACKPRINTSIZE 250
781    PrintRec		stackPrints[STACKPRINTSIZE];
782    PrintRec		*prints;
783    TMShortCard		numPrints, maxPrints;
784    TMBindData	bindData ;
785    TMComplexBindProcs	complexBindProcs;
786
787    if ((eventWidget == NULL) ||
788	(eventWidget->core.tm.translations == NULL) )
789      return;
790
791    xlations = eventWidget->core.tm.translations;
792    bindData = (TMBindData) eventWidget->core.tm.proc_table;
793    if (bindData->simple.isComplex == False)
794      return;
795
796    sb->current = sb->start = __XtMalloc((Cardinal)1000);
797    sb->start[0] = '\0';
798    sb->max = 1000;
799    maxPrints = 0;
800    for (i = 0; i < xlations->numStateTrees; i++)
801	maxPrints = (TMShortCard) (maxPrints +
802	  ((TMSimpleStateTree)xlations->stateTreeTbl[i])->numBranchHeads);
803    prints = (PrintRec *)
804      XtStackAlloc(maxPrints * sizeof(PrintRec), stackPrints);
805
806    numPrints = 0;
807
808    complexBindProcs = TMGetComplexBindEntry(bindData, 0);
809    for (i = 0;
810	 i < xlations->numStateTrees;
811	 i++, complexBindProcs++) {
812	if (complexBindProcs->widget)
813	  {
814	      ProcessStateTree(prints, xlations, (TMShortCard) i, &numPrints);
815	  }
816    }
817    for (i = 0; i < numPrints; i++) {
818	TMSimpleStateTree stateTree = (TMSimpleStateTree)
819	  xlations->stateTreeTbl[prints[i].tIndex];
820	TMBranchHead branchHead =
821	  &stateTree->branchHeadTbl[prints[i].bIndex];
822
823	complexBindProcs = TMGetComplexBindEntry(bindData, 0);
824
825	PrintState(sb, (TMStateTree)stateTree, branchHead, True,
826		   complexBindProcs[prints[i].tIndex].widget,
827		   XtDisplay(widget));
828    }
829    XtStackFree((XtPointer)prints, (XtPointer)stackPrints);
830    printf("%s\n", sb->start);
831    XtFree(sb->start);
832}
833#endif /*NO_MIT_HACKS*/
834
835String _XtPrintActions(
836    register ActionRec *actions,
837    XrmQuark		*quarkTbl)
838{
839    TMStringBufRec	sbRec, *sb = &sbRec;
840
841    sb->max = 1000;
842    sb->current = sb->start = __XtMalloc((Cardinal)1000);
843    PrintActions(sb,
844		 actions,
845		 quarkTbl,
846		 (Widget)NULL);
847    return sb->start;
848}
849
850String _XtPrintState(
851    TMStateTree		stateTree,
852    TMBranchHead	branchHead)
853{
854    TMStringBufRec	sbRec, *sb = &sbRec;
855
856    sb->current = sb->start = __XtMalloc((Cardinal)1000);
857    sb->max = 1000;
858    PrintState(sb, stateTree, branchHead,
859	       True, (Widget)NULL, (Display *)NULL);
860    return sb->start;
861}
862
863
864String _XtPrintEventSeq(
865    register EventSeqPtr eventSeq,
866    Display *dpy)
867{
868    TMStringBufRec	sbRec, *sb = &sbRec;
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	TMTypeMatch typeMatch;
888	TMModifierMatch modMatch;
889
890	typeMatch =
891	  TMGetTypeMatch(_XtGetTypeIndex(&eventSeqs[j]->event));
892	modMatch =
893	  TMGetModifierMatch(_XtGetModifierIndex(&eventSeqs[j]->event));
894	PrintEvent(sb, typeMatch, modMatch, dpy);
895	if (j < i)
896	  *sb->current++ = ',';
897    }
898    UNLOCK_PROCESS;
899    return sb->start;
900}
901