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