1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates.
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#ifdef HAVE_CONFIG_H
72#include <config.h>
73#endif
74#include "IntrinsicI.h"
75#include <stdio.h>
76
77typedef struct _TMStringBufRec {
78    _XtString start;
79    _XtString current;
80    Cardinal max;
81} TMStringBufRec, *TMStringBuf;
82
83#define STR_THRESHOLD 25
84#define STR_INCAMOUNT 100
85
86#define CHECK_STR_OVERFLOW(sb) \
87    if (sb->current - sb->start > (int)sb->max - STR_THRESHOLD)           \
88    {                                                                     \
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
109PrintModifiers(TMStringBuf sb, unsigned long mask, unsigned long mod)
110{
111    Boolean notfirst = False;
112
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
156PrintEventType(TMStringBuf sb, 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
204PrintCode(TMStringBuf sb, unsigned long mask, unsigned long code)
205{
206    CHECK_STR_OVERFLOW(sb);
207    if (mask != 0) {
208        if (mask != ~0UL)
209            (void) sprintf(sb->current, "0x%lx:0x%lx", mask, code);
210        else
211            (void) sprintf(sb->current, /*"0x%lx" */ "%u", (unsigned) code);
212        sb->current += strlen(sb->current);
213    }
214}
215
216static void
217PrintKeysym(TMStringBuf sb, KeySym keysym)
218{
219    String keysymName;
220
221    if (keysym == 0)
222        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
236PrintAtom(TMStringBuf sb, Display *dpy, Atom atom)
237{
238    _XtString atomName;
239
240    if (atom == 0)
241        return;
242
243    atomName = (dpy ? XGetAtomName(dpy, atom) : NULL);
244
245    if (!atomName)
246        PrintCode(sb, ~0UL, (unsigned long) atom);
247    else {
248        ExpandToFit(sb, atomName);
249        strcpy(sb->current, atomName);
250        sb->current += strlen(sb->current);
251        XFree(atomName);
252    }
253}
254
255static void
256PrintLateModifiers(TMStringBuf sb, LateBindingsPtr lateModifiers)
257{
258    for (; lateModifiers->keysym; lateModifiers++) {
259        CHECK_STR_OVERFLOW(sb);
260        if (lateModifiers->knot) {
261            *sb->current++ = '~';
262        }
263        else {
264            *sb->current++ = ' ';
265        }
266        strcpy(sb->current, XKeysymToString(lateModifiers->keysym));
267        sb->current += strlen(sb->current);
268        if (lateModifiers->pair) {
269            *(sb->current -= 2) = '\0'; /* strip "_L" */
270            lateModifiers++;    /* skip _R keysym */
271        }
272    }
273}
274
275static void
276PrintEvent(TMStringBuf sb,
277           register TMTypeMatch typeMatch,
278           register TMModifierMatch modMatch,
279           Display *dpy)
280{
281    if (modMatch->standard)
282        *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
308PrintParams(TMStringBuf sb, String *params, Cardinal num_params)
309{
310    register Cardinal i;
311
312    for (i = 0; i < num_params; i++) {
313        ExpandToFit(sb, params[i]);
314        if (i != 0) {
315            *sb->current++ = ',';
316            *sb->current++ = ' ';
317        }
318        *sb->current++ = '"';
319        strcpy(sb->current, params[i]);
320        sb->current += strlen(sb->current);
321        *sb->current++ = '"';
322    }
323    *sb->current = '\0';
324}
325
326static void
327PrintActions(TMStringBuf sb,
328             register ActionPtr actions,
329             XrmQuark *quarkTbl,
330             Widget accelWidget)
331{
332    while (actions != NULL) {
333        String proc;
334
335        *sb->current++ = ' ';
336
337        if (accelWidget) {
338            /* accelerator */
339            String name = XtName(accelWidget);
340            int nameLen = (int) strlen(name);
341
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
360LookAheadForCycleOrMulticlick(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
400            unsigned int type = (unsigned) sTypeMatch->eventType;
401            unsigned int t = (unsigned) typeMatch->eventType;
402
403            if ((type == ButtonPress && t != ButtonRelease)
404                || (type == ButtonRelease && t != ButtonPress)
405                || (type == KeyPress && t != KeyRelease)
406                || (type == KeyRelease && t != KeyPress)
407                || typeMatch->eventCode != sTypeMatch->eventCode
408                || modMatch->modifiers != sModMatch->modifiers
409                || modMatch->modifierMask != sModMatch->modifierMask
410                || modMatch->lateModifiers != sModMatch->lateModifiers
411                || typeMatch->eventCodeMask != sTypeMatch->eventCodeMask
412                || typeMatch->matchEvent != sTypeMatch->matchEvent
413                || modMatch->standard != sModMatch->standard)
414                /* not inverse of starting event, either */
415                break;
416        }
417    }
418    *countP = repeatCount;
419    UNLOCK_PROCESS;
420    return isCycle;
421}
422
423static void
424PrintComplexState(TMStringBuf sb,
425                  Boolean includeRHS,
426                  StatePtr state,
427                  TMStateTree stateTree,
428                  Widget accelWidget,
429                  Display *dpy)
430{
431    int clickCount = 0;
432    Boolean cycle;
433    StatePtr nextLevel = NULL;
434    StatePtr triggerState = NULL;
435
436    /* print the current state */
437    if (!state)
438        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
493FindNextMatch(PrintRec *printData,
494              TMShortCard numPrints,
495              XtTranslations xlations,
496              TMBranchHead branchHead,
497              StatePtr nextLevel,
498              TMShortCard startIndex)
499{
500    TMShortCard i;
501    StatePtr currState, candState;
502    Boolean noMatch = True;
503
504    for (i = startIndex; noMatch && i < numPrints; i++) {
505        TMBranchHead prBranchHead;
506        TMComplexStateTree stateTree;
507
508        stateTree = (TMComplexStateTree)
509            xlations->stateTreeTbl[printData[i].tIndex];
510        prBranchHead = &(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
541ProcessLaterMatches(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
558            j = 0;
559        for (branchHead = &stateTree->branchHeadTbl[j];
560             j < (int) stateTree->numBranchHeads; j++, branchHead++) {
561            if ((branchHead->typeIndex == matchBranch->typeIndex) &&
562                (branchHead->modIndex == matchBranch->modIndex)) {
563                StatePtr state;
564
565                if (!branchHead->isSimple)
566                    state = TMComplexBranchHead(stateTree, branchHead);
567                else
568                    state = NULL;
569                if ((!branchHead->isSimple || branchHead->hasActions) &&
570                    (FindNextMatch(printData,
571                                   *numPrintsRtn,
572                                   xlations,
573                                   branchHead,
574                                   (state ? state->nextLevel : NULL),
575                                   0) == TM_NO_MATCH)) {
576                    printData[*numPrintsRtn].tIndex = (TMShortCard) i;
577                    printData[*numPrintsRtn].bIndex = (TMShortCard) j;
578                    (*numPrintsRtn)++;
579                }
580            }
581        }
582    }
583}
584
585static void
586ProcessStateTree(PrintRec *printData,
587                 XtTranslations xlations,
588                 TMShortCard tIndex,
589                 TMShortCard *numPrintsRtn)
590{
591    TMComplexStateTree stateTree;
592    int i;
593    TMBranchHead branchHead;
594
595    stateTree = (TMComplexStateTree) xlations->stateTreeTbl[tIndex];
596
597    for (i = 0, branchHead = stateTree->branchHeadTbl;
598         i < (int) stateTree->numBranchHeads; i++, branchHead++) {
599        StatePtr state;
600
601        if (!branchHead->isSimple)
602            state = TMComplexBranchHead(stateTree, branchHead);
603        else
604            state = NULL;
605        if (FindNextMatch(printData, *numPrintsRtn, xlations, branchHead,
606                          (state ? state->nextLevel : NULL), 0)
607            == TM_NO_MATCH) {
608            if (!branchHead->isSimple || branchHead->hasActions) {
609                printData[*numPrintsRtn].tIndex = tIndex;
610                printData[*numPrintsRtn].bIndex = (TMShortCard) i;
611                (*numPrintsRtn)++;
612            }
613            LOCK_PROCESS;
614            if (_XtGlobalTM.newMatchSemantics == False)
615                ProcessLaterMatches(printData,
616                                    xlations, tIndex, i, numPrintsRtn);
617            UNLOCK_PROCESS;
618        }
619    }
620}
621
622static void
623PrintState(TMStringBuf sb,
624           TMStateTree tree,
625           TMBranchHead branchHead,
626           Boolean includeRHS,
627           Widget accelWidget,
628           Display *dpy)
629{
630    TMComplexStateTree stateTree = (TMComplexStateTree) tree;
631
632    LOCK_PROCESS;
633    if (branchHead->isSimple) {
634        PrintEvent(sb,
635                   TMGetTypeMatch(branchHead->typeIndex),
636                   TMGetModifierMatch(branchHead->modIndex), dpy);
637        if (includeRHS) {
638            ActionRec actRec;
639
640            CHECK_STR_OVERFLOW(sb);
641            *sb->current++ = ':';
642            actRec.idx = TMBranchMore(branchHead);
643            actRec.num_params = 0;
644            actRec.params = NULL;
645            actRec.next = NULL;
646            PrintActions(sb, &actRec, stateTree->quarkTbl, accelWidget);
647            *sb->current++ = '\n';
648        }
649        else
650            *sb->current++ = ',';
651#ifdef TRACE_TM
652        if (!branchHead->hasActions)
653            printf(" !! no actions !! ");
654#endif
655    }
656    else {                      /* it's a complex branchHead */
657        StatePtr state = TMComplexBranchHead(stateTree, branchHead);
658
659        PrintComplexState(sb,
660                          includeRHS,
661                          state, tree, accelWidget, (Display *) NULL);
662    }
663    *sb->current = '\0';
664    UNLOCK_PROCESS;
665}
666
667_XtString
668_XtPrintXlations(Widget w,
669                 XtTranslations xlations,
670                 Widget accelWidget,
671                 _XtBoolean includeRHS)
672{
673    register Cardinal i;
674
675#define STACKPRINTSIZE 250
676    PrintRec stackPrints[STACKPRINTSIZE];
677    PrintRec *prints;
678    TMStringBufRec sbRec, *sb = &sbRec;
679    TMShortCard numPrints, maxPrints;
680
681#ifdef TRACE_TM
682    TMBindData bindData = (TMBindData) w->core.tm.proc_table;
683    Boolean hasAccel = (accelWidget ? True : False);
684#endif                          /* TRACE_TM */
685    if (xlations == NULL)
686        return NULL;
687
688    sb->current = sb->start = __XtMalloc((Cardinal) 1000);
689    sb->max = 1000;
690    maxPrints = 0;
691    for (i = 0; i < xlations->numStateTrees; i++)
692        maxPrints = (TMShortCard) (maxPrints +
693                                   ((TMSimpleStateTree)
694                                    (xlations->stateTreeTbl[i]))->
695                                   numBranchHeads);
696    prints = (PrintRec *)
697        XtStackAlloc(maxPrints * sizeof(PrintRec), stackPrints);
698
699    numPrints = 0;
700    for (i = 0; i < xlations->numStateTrees; i++)
701        ProcessStateTree(prints, xlations, (TMShortCard) i, &numPrints);
702
703    for (i = 0; i < numPrints; i++) {
704        TMSimpleStateTree stateTree = (TMSimpleStateTree)
705            xlations->stateTreeTbl[prints[i].tIndex];
706        TMBranchHead branchHead = &stateTree->branchHeadTbl[prints[i].bIndex];
707
708#ifdef TRACE_TM
709        TMComplexBindProcs complexBindProcs;
710
711        if (hasAccel == False) {
712            accelWidget = NULL;
713            if (bindData->simple.isComplex) {
714                complexBindProcs = TMGetComplexBindEntry(bindData, 0);
715                accelWidget = complexBindProcs[prints[i].tIndex].widget;
716            }
717        }
718#endif                          /* TRACE_TM */
719        PrintState(sb, (TMStateTree) stateTree, branchHead,
720                   (Boolean) includeRHS, accelWidget, XtDisplay(w));
721    }
722    XtStackFree((XtPointer) prints, (XtPointer) stackPrints);
723    return (sb->start);
724}
725
726#ifndef NO_MIT_HACKS
727void
728_XtDisplayTranslations(Widget widget,
729                       XEvent *event _X_UNUSED,
730                       String *params _X_UNUSED,
731                       Cardinal *num_params _X_UNUSED)
732{
733    _XtString xString;
734
735    xString = _XtPrintXlations(widget,
736                               widget->core.tm.translations, NULL, True);
737    if (xString) {
738        printf("%s\n", xString);
739        XtFree(xString);
740    }
741}
742
743void
744_XtDisplayAccelerators(Widget widget,
745                       XEvent *event _X_UNUSED,
746                       String *params _X_UNUSED,
747                       Cardinal *num_params _X_UNUSED)
748{
749    _XtString xString;
750
751    xString = _XtPrintXlations(widget, widget->core.accelerators, NULL, True);
752    if (xString) {
753        printf("%s\n", xString);
754        XtFree(xString);
755    }
756}
757
758void
759_XtDisplayInstalledAccelerators(Widget widget,
760                                XEvent *event,
761                                String *params _X_UNUSED,
762                                Cardinal *num_params _X_UNUSED)
763{
764    Widget eventWidget
765        = XtWindowToWidget(event->xany.display, event->xany.window);
766    register Cardinal i;
767    TMStringBufRec sbRec, *sb = &sbRec;
768    XtTranslations xlations;
769
770#define STACKPRINTSIZE 250
771    PrintRec stackPrints[STACKPRINTSIZE];
772    PrintRec *prints;
773    TMShortCard numPrints, maxPrints;
774    TMBindData bindData;
775    TMComplexBindProcs complexBindProcs;
776
777    if ((eventWidget == NULL) || (eventWidget->core.tm.translations == NULL))
778        return;
779
780    xlations = eventWidget->core.tm.translations;
781    bindData = (TMBindData) eventWidget->core.tm.proc_table;
782    if (bindData->simple.isComplex == False)
783        return;
784
785    sb->current = sb->start = __XtMalloc((Cardinal) 1000);
786    sb->start[0] = '\0';
787    sb->max = 1000;
788    maxPrints = 0;
789    for (i = 0; i < xlations->numStateTrees; i++)
790        maxPrints = (TMShortCard) (maxPrints +
791                                   ((TMSimpleStateTree) xlations->
792                                    stateTreeTbl[i])->numBranchHeads);
793    prints = (PrintRec *)
794        XtStackAlloc(maxPrints * sizeof(PrintRec), stackPrints);
795
796    numPrints = 0;
797
798    complexBindProcs = TMGetComplexBindEntry(bindData, 0);
799    for (i = 0; i < xlations->numStateTrees; i++, complexBindProcs++) {
800        if (complexBindProcs->widget) {
801            ProcessStateTree(prints, xlations, (TMShortCard) i, &numPrints);
802        }
803    }
804    for (i = 0; i < numPrints; i++) {
805        TMSimpleStateTree stateTree = (TMSimpleStateTree)
806            xlations->stateTreeTbl[prints[i].tIndex];
807        TMBranchHead branchHead = &stateTree->branchHeadTbl[prints[i].bIndex];
808
809        complexBindProcs = TMGetComplexBindEntry(bindData, 0);
810
811        PrintState(sb, (TMStateTree) stateTree, branchHead, True,
812                   complexBindProcs[prints[i].tIndex].widget,
813                   XtDisplay(widget));
814    }
815    XtStackFree((XtPointer) prints, (XtPointer) stackPrints);
816    printf("%s\n", sb->start);
817    XtFree(sb->start);
818}
819#endif                          /*NO_MIT_HACKS */
820
821String
822_XtPrintActions(register ActionRec *actions, XrmQuark *quarkTbl)
823{
824    TMStringBufRec sbRec, *sb = &sbRec;
825
826    sb->max = 1000;
827    sb->current = sb->start = __XtMalloc((Cardinal) 1000);
828    PrintActions(sb, actions, quarkTbl, (Widget) NULL);
829    return sb->start;
830}
831
832String
833_XtPrintState(TMStateTree stateTree, TMBranchHead branchHead)
834{
835    TMStringBufRec sbRec, *sb = &sbRec;
836
837    sb->current = sb->start = __XtMalloc((Cardinal) 1000);
838    sb->max = 1000;
839    PrintState(sb, stateTree, branchHead,
840               True, (Widget) NULL, (Display *) NULL);
841    return sb->start;
842}
843
844String
845_XtPrintEventSeq(register EventSeqPtr eventSeq, Display *dpy)
846{
847    TMStringBufRec sbRec, *sb = &sbRec;
848
849#define MAXSEQS 100
850    EventSeqPtr eventSeqs[MAXSEQS];
851    TMShortCard i, j;
852    Boolean cycle = False;
853
854    sb->current = sb->start = __XtMalloc((Cardinal) 1000);
855    sb->max = 1000;
856    for (i = 0;
857         i < MAXSEQS && eventSeq != NULL && !cycle;
858         eventSeq = eventSeq->next, i++) {
859        eventSeqs[i] = eventSeq;
860        for (j = 0; j < i && !cycle; j++)
861            if (eventSeqs[j] == eventSeq)
862                cycle = True;
863    }
864    LOCK_PROCESS;
865    for (j = 0; j < i; j++) {
866        TMTypeMatch typeMatch;
867        TMModifierMatch modMatch;
868
869        typeMatch = TMGetTypeMatch(_XtGetTypeIndex(&eventSeqs[j]->event));
870        modMatch =
871            TMGetModifierMatch(_XtGetModifierIndex(&eventSeqs[j]->event));
872        PrintEvent(sb, typeMatch, modMatch, dpy);
873        *sb->current++ = ',';
874    }
875    UNLOCK_PROCESS;
876    return sb->start;
877}
878