1 /***********************************************************
2 Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3 
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice (including the next
12 paragraph) shall be included in all copies or substantial portions of the
13 Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 DEALINGS IN THE SOFTWARE.
22 
23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24 
25                         All Rights Reserved
26 
27 Permission to use, copy, modify, and distribute this software and its
28 documentation for any purpose and without fee is hereby granted,
29 provided that the above copyright notice appear in all copies and that
30 both that copyright notice and this permission notice appear in
31 supporting documentation, and that the name of Digital not be
32 used in advertising or publicity pertaining to distribution of the
33 software without specific, written prior permission.
34 
35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41 SOFTWARE.
42 
43 ******************************************************************/
44 
45 /*
46 
47 Copyright 1987, 1988, 1998  The Open Group
48 
49 Permission to use, copy, modify, distribute, and sell this software and its
50 documentation for any purpose is hereby granted without fee, provided that
51 the above copyright notice appear in all copies and that both that
52 copyright notice and this permission notice appear in supporting
53 documentation.
54 
55 The above copyright notice and this permission notice shall be included in
56 all copies or substantial portions of the Software.
57 
58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64 
65 Except as contained in this notice, the name of The Open Group shall not be
66 used in advertising or otherwise to promote the sale, use or other dealings
67 in 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 
77 typedef 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 
108 static void
PrintModifiers(TMStringBuf sb,unsigned long mask,unsigned long mod)109 PrintModifiers(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 
155 static void
PrintEventType(TMStringBuf sb,unsigned long event)156 PrintEventType(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 
203 static void
PrintCode(TMStringBuf sb,unsigned long mask,unsigned long code)204 PrintCode(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 
216 static void
PrintKeysym(TMStringBuf sb,KeySym keysym)217 PrintKeysym(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 
235 static void
PrintAtom(TMStringBuf sb,Display * dpy,Atom atom)236 PrintAtom(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 
255 static void
PrintLateModifiers(TMStringBuf sb,LateBindingsPtr lateModifiers)256 PrintLateModifiers(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 
275 static void
PrintEvent(TMStringBuf sb,register TMTypeMatch typeMatch,register TMModifierMatch modMatch,Display * dpy)276 PrintEvent(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 
307 static void
PrintParams(TMStringBuf sb,String * params,Cardinal num_params)308 PrintParams(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 
326 static void
PrintActions(TMStringBuf sb,register ActionPtr actions,XrmQuark * quarkTbl,Widget accelWidget)327 PrintActions(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 
359 static Boolean
LookAheadForCycleOrMulticlick(register StatePtr state,StatePtr * state_return,int * countP,StatePtr * nextLevelP)360 LookAheadForCycleOrMulticlick(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 
423 static void
PrintComplexState(TMStringBuf sb,Boolean includeRHS,StatePtr state,TMStateTree stateTree,Widget accelWidget,Display * dpy)424 PrintComplexState(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 
487 typedef struct {
488     TMShortCard tIndex;
489     TMShortCard bIndex;
490 } PrintRec, *Print;
491 
492 static int
FindNextMatch(PrintRec * printData,TMShortCard numPrints,XtTranslations xlations,TMBranchHead branchHead,StatePtr nextLevel,TMShortCard startIndex)493 FindNextMatch(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 
540 static void
ProcessLaterMatches(PrintRec * printData,XtTranslations xlations,TMShortCard tIndex,int bIndex,TMShortCard * numPrintsRtn)541 ProcessLaterMatches(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 
585 static void
ProcessStateTree(PrintRec * printData,XtTranslations xlations,TMShortCard tIndex,TMShortCard * numPrintsRtn)586 ProcessStateTree(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 
622 static void
PrintState(TMStringBuf sb,TMStateTree tree,TMBranchHead branchHead,Boolean includeRHS,Widget accelWidget,Display * dpy)623 PrintState(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
_XtPrintXlations(Widget w,XtTranslations xlations,Widget accelWidget,_XtBoolean includeRHS)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
727 void
_XtDisplayTranslations(Widget widget,XEvent * event _X_UNUSED,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)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 
743 void
_XtDisplayAccelerators(Widget widget,XEvent * event _X_UNUSED,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)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 
758 void
_XtDisplayInstalledAccelerators(Widget widget,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)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 
821 String
_XtPrintActions(register ActionRec * actions,XrmQuark * quarkTbl)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 
832 String
_XtPrintState(TMStateTree stateTree,TMBranchHead branchHead)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 
844 String
_XtPrintEventSeq(register EventSeqPtr eventSeq,Display * dpy)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         if (j < i)
874             *sb->current++ = ',';
875     }
876     UNLOCK_PROCESS;
877     return sb->start;
878 }
879