Home | History | Annotate | Line # | Download | only in src
      1 /***********************************************************
      2 Copyright (c) 1993, Oracle and/or its affiliates.
      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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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