home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xt / TMparse.c.orig < prev    next >
Encoding:
Text File  |  1993-07-21  |  54.5 KB  |  2,048 lines

  1. /* $XConsortium: TMparse.c,v 1.128 92/03/05 18:48:55 converse Exp $ */
  2.  
  3. /***********************************************************
  4. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  5. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  6.  
  7.                         All Rights Reserved
  8.  
  9. Permission to use, copy, modify, and distribute this software and its 
  10. documentation for any purpose and without fee is hereby granted, 
  11. provided that the above copyright notice appear in all copies and that
  12. both that copyright notice and this permission notice appear in 
  13. supporting documentation, and that the names of Digital or MIT not be
  14. used in advertising or publicity pertaining to distribution of the
  15. software without specific, written prior permission.  
  16.  
  17. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  18. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  19. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  20. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  22. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  23. SOFTWARE.
  24.  
  25. ******************************************************************/
  26.  
  27. #include "IntrinsicI.h"
  28. #include "StringDefs.h"
  29. #include <ctype.h>
  30. #ifndef NOTASCII
  31. #define XK_LATIN1
  32. #endif
  33. #define XK_MISCELLANY
  34. #include <X11/keysymdef.h>
  35.  
  36. #ifdef CACHE_TRANSLATIONS
  37. # ifdef REFCNT_TRANSLATIONS
  38. #  define CACHED XtCacheAll | XtCacheRefCount
  39. # else
  40. #  define CACHED XtCacheAll
  41. # endif
  42. #else
  43. # define CACHED XtCacheNone
  44. #endif
  45.  
  46. static String XtNtranslationParseError = "translationParseError";
  47.  
  48. typedef int        EventType;
  49.  
  50. typedef String (*ParseProc)(); /* str, closure, event ,error */
  51.     /* String str; */
  52.     /* Opaque closure; */
  53.     /* EventPtr event; */
  54.     /* Boolean* error */
  55.  
  56. typedef void (*ModifierProc)(); 
  57. typedef TMShortCard    Value;
  58.  
  59. typedef struct _ModifierRec {
  60.     char*      name;
  61.     XrmQuark   signature;
  62.     ModifierProc modifierParseProc;
  63.     Value      value;
  64. } ModifierRec, *ModifierKeys;
  65.  
  66. typedef struct _EventKey {
  67.     char        *event;
  68.     XrmQuark    signature;
  69.     EventType    eventType;
  70.     ParseProc    parseDetail;
  71.     Opaque    closure;
  72. }EventKey, *EventKeys;
  73.  
  74. typedef struct {
  75.     char    *name;
  76.     XrmQuark    signature;
  77.     Value    value;
  78. } NameValueRec, *NameValueTable;
  79.  
  80. static void ParseModImmed();
  81. static void ParseModSym();
  82. static String PanicModeRecovery();
  83. static String CheckForPoundSign();
  84. static KeySym StringToKeySym();
  85. static ModifierRec modifiers[] = {
  86.     {"None",    0,      ParseModImmed,None},
  87.     {"Shift",    0,    ParseModImmed,ShiftMask},
  88.     {"Lock",    0,    ParseModImmed,LockMask},
  89.     {"Ctrl",    0,    ParseModImmed,ControlMask},
  90.     {"Mod1",    0,    ParseModImmed,Mod1Mask},
  91.     {"Mod2",    0,    ParseModImmed,Mod2Mask},
  92.     {"Mod3",    0,    ParseModImmed,Mod3Mask},
  93.     {"Mod4",    0,    ParseModImmed,Mod4Mask},
  94.     {"Mod5",    0,    ParseModImmed,Mod5Mask},
  95.     {"Meta",    0,    ParseModSym,  XK_Meta_L},
  96.     {"m",       0,      ParseModSym,  XK_Meta_L},
  97.     {"h",       0,      ParseModSym,  XK_Hyper_L},
  98.     {"su",      0,      ParseModSym,  XK_Super_L},
  99.     {"a",       0,      ParseModSym,  XK_Alt_L},
  100.     {"Hyper",   0,      ParseModSym,  XK_Hyper_L},
  101.     {"Super",   0,      ParseModSym,  XK_Super_L},
  102.     {"Alt",     0,      ParseModSym,  XK_Alt_L},
  103.     {"Button1",    0,    ParseModImmed,Button1Mask},
  104.     {"Button2",    0,    ParseModImmed,Button2Mask},
  105.     {"Button3",    0,    ParseModImmed,Button3Mask},
  106.     {"Button4",    0,    ParseModImmed,Button4Mask},
  107.     {"Button5",    0,    ParseModImmed,Button5Mask},
  108.  
  109.     {"Any",    0,    ParseModImmed,AnyModifier},
  110.  
  111.     {"c",    0,    ParseModImmed,ControlMask},
  112.     {"s",    0,    ParseModImmed,ShiftMask},
  113.     {"l",    0,    ParseModImmed,LockMask},
  114. };
  115.  
  116. static NameValueRec buttonNames[] = {
  117.     {"Button1",    0,    Button1},
  118.     {"Button2", 0,    Button2},
  119.     {"Button3", 0,    Button3},
  120.     {"Button4", 0,    Button4},
  121.     {"Button5", 0,    Button5},
  122.     {NULL, NULLQUARK, 0},
  123. };
  124.  
  125. static NameValueRec motionDetails[] = {
  126.     {"Normal",        0,    NotifyNormal},
  127.     {"Hint",        0,    NotifyHint},
  128.     {NULL, NULLQUARK, 0},
  129. };
  130.  
  131. static NameValueRec notifyModes[] = {
  132.     {"Normal",        0,    NotifyNormal},
  133.     {"Grab",        0,    NotifyGrab},
  134.     {"Ungrab",        0,    NotifyUngrab},
  135.     {"WhileGrabbed",    0,    NotifyWhileGrabbed},
  136.     {NULL, NULLQUARK, 0},
  137. };
  138.  
  139. #if 0
  140. static NameValueRec notifyDetail[] = {
  141.     {"Ancestor",        0,    NotifyAncestor},
  142.     {"Virtual",            0,    NotifyVirtual},
  143.     {"Inferior",        0,    NotifyInferior},
  144.     {"Nonlinear",        0,    NotifyNonlinear},
  145.     {"NonlinearVirtual",    0,    NotifyNonlinearVirtual},
  146.     {"Pointer",            0,    NotifyPointer},
  147.     {"PointerRoot",        0,    NotifyPointerRoot},
  148.     {"DetailNone",        0,    NotifyDetailNone},
  149.     {NULL, NULLQUARK, 0},
  150. };
  151.  
  152. static NameValueRec visibilityNotify[] = {
  153.     {"Unobscured",        0,    VisibilityUnobscured},
  154.     {"PartiallyObscured",   0,    VisibilityPartiallyObscured},
  155.     {"FullyObscured",       0,    VisibilityFullyObscured},
  156.     {NULL, NULLQUARK, 0},
  157. };
  158.  
  159. static NameValueRec circulation[] = {
  160.     {"OnTop",       0,    PlaceOnTop},
  161.     {"OnBottom",    0,    PlaceOnBottom},
  162.     {NULL, NULLQUARK, 0},
  163. };
  164.  
  165. static NameValueRec propertyChanged[] = {
  166.     {"NewValue",    0,    PropertyNewValue},
  167.     {"Delete",      0,    PropertyDelete},
  168.     {NULL, NULLQUARK, 0},
  169. };
  170. #endif /*0*/
  171.  
  172. static NameValueRec mappingNotify[] = {
  173.     {"Modifier",    0,    MappingModifier},
  174.     {"Keyboard",    0,    MappingKeyboard},
  175.     {"Pointer",    0,    MappingPointer},
  176.     {NULL, NULLQUARK, 0},
  177. };
  178.  
  179. static String ParseKeySym();
  180. static String ParseKeyAndModifiers();
  181. static String ParseTable();
  182. static String ParseImmed();
  183. static String ParseAddModifier();
  184. static String ParseNone();
  185. static String ParseAtom();
  186.  
  187. static EventKey events[] = {
  188.  
  189. /* Event Name,      Quark, Event Type,    Detail Parser, Closure */
  190.  
  191. {"KeyPress",        NULLQUARK, KeyPress,    ParseKeySym,    NULL},
  192. {"Key",         NULLQUARK, KeyPress,    ParseKeySym,    NULL},
  193. {"KeyDown",        NULLQUARK, KeyPress,    ParseKeySym,    NULL},
  194. {"Ctrl",            NULLQUARK, KeyPress, ParseKeyAndModifiers,(Opaque)ControlMask},
  195. {"Shift",           NULLQUARK, KeyPress, ParseKeyAndModifiers,(Opaque)ShiftMask},
  196. {"Meta",            NULLQUARK, KeyPress,   ParseKeyAndModifiers,(Opaque)NULL},
  197. {"KeyUp",        NULLQUARK, KeyRelease,    ParseKeySym,    NULL},
  198. {"KeyRelease",        NULLQUARK, KeyRelease,    ParseKeySym,    NULL},
  199.  
  200. {"ButtonPress",     NULLQUARK, ButtonPress,  ParseTable,(Opaque)buttonNames},
  201. {"BtnDown",        NULLQUARK, ButtonPress,  ParseTable,(Opaque)buttonNames},
  202. {"Btn1Down",        NULLQUARK, ButtonPress,    ParseImmed,(Opaque)Button1},
  203. {"Btn2Down",         NULLQUARK, ButtonPress,    ParseImmed,(Opaque)Button2},
  204. {"Btn3Down",         NULLQUARK, ButtonPress,    ParseImmed,(Opaque)Button3},
  205. {"Btn4Down",         NULLQUARK, ButtonPress,    ParseImmed,(Opaque)Button4},
  206. {"Btn5Down",         NULLQUARK, ButtonPress,    ParseImmed,(Opaque)Button5},
  207.  
  208. /* Event Name,      Quark, Event Type,    Detail Parser, Closure */
  209.  
  210. {"ButtonRelease",   NULLQUARK, ButtonRelease,  ParseTable,(Opaque)buttonNames},
  211. {"BtnUp",         NULLQUARK, ButtonRelease,  ParseTable,(Opaque)buttonNames},
  212. {"Btn1Up",         NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button1},
  213. {"Btn2Up",         NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button2},
  214. {"Btn3Up",         NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button3},
  215. {"Btn4Up",         NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button4},
  216. {"Btn5Up",         NULLQUARK, ButtonRelease,    ParseImmed,(Opaque)Button5},
  217.  
  218. {"MotionNotify",    NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails},
  219. {"PtrMoved",         NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails},
  220. {"Motion",         NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails},
  221. {"MouseMoved",         NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails},
  222. {"BtnMotion",  NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)AnyButtonMask},
  223. {"Btn1Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button1Mask},
  224. {"Btn2Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button2Mask},
  225. {"Btn3Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button3Mask},
  226. {"Btn4Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button4Mask},
  227. {"Btn5Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button5Mask},
  228.  
  229. {"EnterNotify",     NULLQUARK, EnterNotify,    ParseTable,(Opaque)notifyModes},
  230. {"Enter",        NULLQUARK, EnterNotify,    ParseTable,(Opaque)notifyModes},
  231. {"EnterWindow",     NULLQUARK, EnterNotify,    ParseTable,(Opaque)notifyModes},
  232.  
  233. {"LeaveNotify",     NULLQUARK, LeaveNotify,    ParseTable,(Opaque)notifyModes},
  234. {"LeaveWindow",     NULLQUARK, LeaveNotify,    ParseTable,(Opaque)notifyModes},
  235. {"Leave",        NULLQUARK, LeaveNotify,    ParseTable,(Opaque)notifyModes},
  236.  
  237. /* Event Name,      Quark, Event Type,    Detail Parser, Closure */
  238.  
  239. {"FocusIn",        NULLQUARK, FocusIn,      ParseTable,(Opaque)notifyModes},
  240.  
  241. {"FocusOut",        NULLQUARK, FocusOut,       ParseTable,(Opaque)notifyModes},
  242.  
  243. {"KeymapNotify",    NULLQUARK, KeymapNotify,    ParseNone,    NULL},
  244. {"Keymap",        NULLQUARK, KeymapNotify,    ParseNone,    NULL},
  245.  
  246. {"Expose",         NULLQUARK, Expose,        ParseNone,    NULL},
  247.  
  248. {"GraphicsExpose",  NULLQUARK, GraphicsExpose,    ParseNone,    NULL},
  249. {"GrExp",        NULLQUARK, GraphicsExpose,    ParseNone,    NULL},
  250.  
  251. {"NoExpose",        NULLQUARK, NoExpose,    ParseNone,    NULL},
  252. {"NoExp",        NULLQUARK, NoExpose,    ParseNone,    NULL},
  253.  
  254. {"VisibilityNotify",NULLQUARK, VisibilityNotify,ParseNone,    NULL},
  255. {"Visible",        NULLQUARK, VisibilityNotify,ParseNone,    NULL},
  256.  
  257. {"CreateNotify",    NULLQUARK, CreateNotify,    ParseNone,    NULL},
  258. {"Create",        NULLQUARK, CreateNotify,    ParseNone,    NULL},
  259.  
  260. /* Event Name,      Quark, Event Type,    Detail Parser, Closure */
  261.  
  262. {"DestroyNotify",   NULLQUARK, DestroyNotify,    ParseNone,    NULL},
  263. {"Destroy",        NULLQUARK, DestroyNotify,    ParseNone,    NULL},
  264.  
  265. {"UnmapNotify",     NULLQUARK, UnmapNotify,    ParseNone,    NULL},
  266. {"Unmap",        NULLQUARK, UnmapNotify,    ParseNone,    NULL},
  267.  
  268. {"MapNotify",        NULLQUARK, MapNotify,    ParseNone,    NULL},
  269. {"Map",            NULLQUARK, MapNotify,    ParseNone,    NULL},
  270.  
  271. {"MapRequest",        NULLQUARK, MapRequest,    ParseNone,    NULL},
  272. {"MapReq",        NULLQUARK, MapRequest,    ParseNone,    NULL},
  273.  
  274. {"ReparentNotify",  NULLQUARK, ReparentNotify,    ParseNone,    NULL},
  275. {"Reparent",        NULLQUARK, ReparentNotify,    ParseNone,    NULL},
  276.  
  277. {"ConfigureNotify", NULLQUARK, ConfigureNotify,    ParseNone,    NULL},
  278. {"Configure",        NULLQUARK, ConfigureNotify,    ParseNone,    NULL},
  279.  
  280. {"ConfigureRequest",NULLQUARK, ConfigureRequest,ParseNone,    NULL},
  281. {"ConfigureReq",    NULLQUARK, ConfigureRequest,ParseNone,    NULL},
  282.  
  283. /* Event Name,      Quark, Event Type,    Detail Parser, Closure */
  284.  
  285. {"GravityNotify",   NULLQUARK, GravityNotify,    ParseNone,    NULL},
  286. {"Grav",        NULLQUARK, GravityNotify,    ParseNone,    NULL},
  287.  
  288. {"ResizeRequest",   NULLQUARK, ResizeRequest,    ParseNone,    NULL},
  289. {"ResReq",        NULLQUARK, ResizeRequest,    ParseNone,    NULL},
  290.  
  291. {"CirculateNotify", NULLQUARK, CirculateNotify,    ParseNone,    NULL},
  292. {"Circ",        NULLQUARK, CirculateNotify,    ParseNone,    NULL},
  293.  
  294. {"CirculateRequest",NULLQUARK, CirculateRequest,ParseNone,    NULL},
  295. {"CircReq",        NULLQUARK, CirculateRequest,ParseNone,    NULL},
  296.  
  297. {"PropertyNotify",  NULLQUARK, PropertyNotify,    ParseAtom,    NULL},
  298. {"Prop",        NULLQUARK, PropertyNotify,    ParseAtom,    NULL},
  299.  
  300. {"SelectionClear",  NULLQUARK, SelectionClear,    ParseAtom,    NULL},
  301. {"SelClr",        NULLQUARK, SelectionClear,    ParseAtom,    NULL},
  302.  
  303. {"SelectionRequest",NULLQUARK, SelectionRequest,ParseAtom,    NULL},
  304. {"SelReq",        NULLQUARK, SelectionRequest,ParseAtom,    NULL},
  305.  
  306. /* Event Name,      Quark, Event Type,    Detail Parser, Closure */
  307.  
  308. {"SelectionNotify", NULLQUARK, SelectionNotify,    ParseAtom,    NULL},
  309. {"Select",        NULLQUARK, SelectionNotify,    ParseAtom,    NULL},
  310.  
  311. {"ColormapNotify",  NULLQUARK, ColormapNotify,    ParseNone,    NULL},
  312. {"Clrmap",        NULLQUARK, ColormapNotify,    ParseNone,    NULL},
  313.  
  314. {"ClientMessage",   NULLQUARK, ClientMessage,    ParseAtom,    NULL},
  315. {"Message",        NULLQUARK, ClientMessage,    ParseAtom,    NULL},
  316.  
  317. {"MappingNotify",   NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify},
  318. {"Mapping",        NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify},
  319.  
  320. #ifdef DEBUG
  321. # ifdef notdef
  322. {"Timer",        NULLQUARK, _XtTimerEventType,ParseNone,    NULL},
  323. # endif /* notdef */
  324. {"EventTimer",        NULLQUARK, _XtEventTimerEventType,ParseNone,NULL},
  325. #endif /* DEBUG */
  326.  
  327. /* Event Name,      Quark, Event Type,    Detail Parser, Closure */
  328.  
  329. };
  330.  
  331.  
  332. #define ScanFor(str, ch) \
  333.     while ((*(str) != (ch)) && (*(str) != '\0') && (*(str) != '\n')) (str)++
  334.  
  335. #define ScanNumeric(str)  while ('0' <= *(str) && *(str) <= '9') (str)++
  336.  
  337. #define ScanAlphanumeric(str) \
  338.     while (('A' <= *(str) && *(str) <= 'Z') || \
  339.            ('a' <= *(str) && *(str) <= 'z') || \
  340.            ('0' <= *(str) && *(str) <= '9')) (str)++
  341.  
  342. #define ScanWhitespace(str) \
  343.     while (*(str) == ' ' || *(str) == '\t') (str)++
  344.  
  345.  
  346. static Boolean initialized = FALSE;
  347.  
  348. static void FreeEventSeq(eventSeq)
  349.     EventSeqPtr eventSeq;
  350. {
  351.     register EventSeqPtr evs = eventSeq;
  352.  
  353.     while (evs != NULL) {
  354.     evs->state = (StatePtr) evs;
  355.     if (evs->next != NULL
  356.         && evs->next->state == (StatePtr) evs->next)
  357.         evs->next = NULL;
  358.     evs = evs->next;
  359.     }
  360.  
  361.     evs = eventSeq;
  362.     while (evs != NULL) {
  363.     register EventPtr event = evs;
  364.     evs = evs->next;
  365.     if (evs == event) evs = NULL;
  366.     XtFree((char *)event);
  367.     }
  368. }
  369.  
  370. static void CompileNameValueTable(table)
  371.     NameValueTable table;
  372. {
  373.     register int i;
  374.  
  375.     for (i=0; table[i].name; i++)
  376.         table[i].signature = XrmPermStringToQuark(table[i].name);
  377. }
  378.  
  379. static int OrderEvents(a, b)
  380.     EventKey    *a, *b;
  381. {
  382.     return ((a->signature < b->signature) ? -1 : 1);
  383. }
  384.  
  385. static void Compile_XtEventTable(table, count)
  386.     EventKeys    table;
  387.     Cardinal    count;
  388. {
  389.     register int i;
  390.     register EventKeys entry = table;
  391.  
  392.     for (i=count; --i >= 0; entry++)
  393.     entry->signature = XrmPermStringToQuark(entry->event);
  394.     qsort(table, count, sizeof(EventKey), OrderEvents);
  395. }
  396.  
  397. static int OrderModifiers(a, b)
  398.     ModifierRec *a, *b;
  399. {
  400.     return ((a->signature < b->signature) ? -1 : 1);
  401. }
  402.  
  403. static void Compile_XtModifierTable(table, count)
  404.     ModifierKeys table;
  405.     Cardinal count;
  406. {
  407.     register int i;
  408.     register ModifierKeys entry = table;
  409.  
  410.     for (i=count; --i >= 0; entry++)
  411.     entry->signature = XrmPermStringToQuark(entry->name);
  412.     qsort(table, count, sizeof(ModifierRec), OrderModifiers);
  413. }
  414.  
  415. static String PanicModeRecovery(str)
  416.     String str;
  417. {
  418.      ScanFor(str,'\n');
  419.      if (*str == '\n') str++;
  420.      return str;
  421.  
  422. }
  423.  
  424.  
  425. static Syntax(str,str1)
  426.     String str,str1;
  427. {
  428.     Cardinal numChars;
  429.     Cardinal num_params = 1;
  430.     String params[1];
  431.     char message[1000];
  432.  
  433.     (void)strcpy(message,str);
  434.     numChars = strlen(message);
  435.     (void) strcpy(&message[numChars], str1);
  436.     numChars += strlen(str1);
  437.     message[numChars] = '\0';
  438.     params[0] = message;
  439.     XtWarningMsg(XtNtranslationParseError,"parseError",XtCXtToolkitError,
  440.          "translation table syntax error: %s",params,&num_params);
  441. }
  442.  
  443.  
  444.  
  445. static Cardinal LookupTMEventType(eventStr,error)
  446.   String eventStr;
  447.   Boolean *error;
  448. {
  449.     register int   i, left, right;
  450.     register XrmQuark    signature;
  451.     static int     previous = 0;
  452.  
  453.     if ((signature = StringToQuark(eventStr)) == events[previous].signature)
  454.     return (Cardinal) previous;
  455.  
  456.     left = 0;
  457.     right = XtNumber(events) - 1;
  458.     while (left <= right) {
  459.     i = (left + right) >> 1;
  460.     if (signature < events[i].signature)
  461.         right = i - 1;
  462.     else if (signature > events[i].signature)
  463.         left = i + 1;
  464.     else {
  465.         previous = i;
  466.         return (Cardinal) i;
  467.     }
  468.     }
  469.  
  470.     Syntax("Unknown event type :  ",eventStr);
  471.     *error = TRUE;
  472.     return (Cardinal) i;
  473. }
  474.  
  475. /***********************************************************************
  476.  * _XtLookupTableSym
  477.  * Given a table and string, it fills in the value if found and returns
  478.  * status
  479.  ***********************************************************************/
  480.  
  481. static Boolean _XtLookupTableSym(table, name, valueP)
  482.     NameValueTable    table;
  483.     String name;
  484.     Value *valueP;
  485. {
  486. /* ||| should implement via hash or something else faster than linear search */
  487.  
  488.     register int i;
  489.     register XrmQuark signature = StringToQuark(name);
  490.  
  491.     for (i=0; table[i].name != NULL; i++)
  492.     if (table[i].signature == signature) {
  493.         *valueP = table[i].value;
  494.         return TRUE;
  495.     }
  496.  
  497.     return FALSE;
  498. }
  499.  
  500.  
  501.  
  502.  
  503. static void StoreLateBindings(keysymL,notL,keysymR,notR,lateBindings)
  504.  
  505.     KeySym  keysymL;
  506.     Boolean notL;
  507.     KeySym keysymR;
  508.     Boolean notR;
  509.     LateBindingsPtr* lateBindings;
  510. {
  511.     LateBindingsPtr temp;
  512.     Boolean pair = FALSE;
  513.     unsigned long count,number;
  514.     if (lateBindings != NULL){
  515.         temp = *lateBindings;
  516.         if (temp != NULL) {
  517.             for (count = 0; temp[count].keysym; count++){/*EMPTY*/}
  518.         }
  519.         else count = 0;
  520.         if (! keysymR){
  521.              number = 1;pair = FALSE;
  522.         } else{
  523.              number = 2;pair = TRUE;
  524.         }
  525.           
  526.         temp = (LateBindingsPtr)XtRealloc((char *)temp,
  527.             (unsigned)((count+number+1) * sizeof(LateBindings)) );
  528.         *lateBindings = temp;
  529.         temp[count].knot = notL;
  530.         temp[count].pair = pair;
  531.     if (count == 0)
  532.         temp[count].ref_count = 1;
  533.         temp[count++].keysym = keysymL;
  534.         if (keysymR){
  535.             temp[count].knot = notR;
  536.             temp[count].pair = FALSE;
  537.             temp[count++].keysym = keysymR;
  538.         }
  539.         temp[count].knot = FALSE;
  540.         temp[count].keysym = 0;
  541.     }
  542.  
  543. static _XtParseKeysymMod(name,lateBindings,notFlag,valueP,error)
  544.     String name;
  545.     LateBindingsPtr* lateBindings;
  546.     Boolean notFlag;
  547.     Value *valueP;
  548.     Boolean *error;
  549. {
  550.     KeySym keySym;
  551.     keySym = StringToKeySym(name, error);
  552.     *valueP = 0;
  553.     if (keySym != NoSymbol) {
  554.         StoreLateBindings(keySym,notFlag,(KeySym) NULL,FALSE,lateBindings);
  555.     }
  556. }
  557.  
  558. static Boolean _XtLookupModifier(name,lateBindings,notFlag,valueP,constMask)
  559.     String name;
  560.     LateBindingsPtr* lateBindings;
  561.     Boolean notFlag;
  562.     Value *valueP;
  563.     Bool constMask;
  564. {
  565.    register int i, left, right;
  566.    register XrmQuark signature = StringToQuark(name);
  567.    static int previous = 0;
  568.    
  569.    if (signature == modifiers[previous].signature) {
  570.        if (constMask)  *valueP = modifiers[previous].value;
  571.        else /* if (modifiers[previous].modifierParseProc) always true */
  572.        (*modifiers[previous].modifierParseProc)
  573.           (name, modifiers[previous].value, lateBindings, notFlag, valueP);
  574.        return TRUE;
  575.    }
  576.  
  577.    left = 0;
  578.    right = XtNumber(modifiers) - 1;
  579.    while (left <= right) {
  580.        i = (left + right) >> 1;
  581.        if (signature < modifiers[i].signature)
  582.        right = i - 1;
  583.        else if (signature > modifiers[i].signature)
  584.        left = i + 1;
  585.        else {
  586.        previous = i;
  587.        if (constMask)  *valueP = modifiers[i].value;
  588.        else /* if (modifiers[i].modifierParseProc) always true */
  589.            (*modifiers[i].modifierParseProc)
  590.            (name, modifiers[i].value, lateBindings, notFlag, valueP);
  591.        return TRUE;
  592.        }
  593.    }
  594.    return FALSE;
  595. }
  596.  
  597.  
  598. static String ScanIdent(str)
  599.     register String str;
  600. {
  601.     ScanAlphanumeric(str);
  602.     while (
  603.        ('A' <= *str && *str <= 'Z')
  604.     || ('a' <= *str && *str <= 'z')
  605.     || ('0' <= *str && *str <= '9')
  606.     || (*str == '-')
  607.     || (*str == '_')
  608.     || (*str == '$')
  609.     ) str++;
  610.     return str;
  611. }
  612.  
  613. static String FetchModifierToken(str,modStr)
  614.     String str,modStr;
  615. {
  616.     String start = str;
  617.     String metaString = "Meta";
  618.     String ctrlString = "Ctrl";
  619.     if (*str == '$') {
  620.         strcpy(modStr,metaString);
  621.         str++;
  622.         return str;
  623.     }
  624.     if (*str == '^') {
  625.         strcpy(modStr,ctrlString);
  626.         str++;
  627.         return str;
  628.     }
  629.     str = ScanIdent(str);
  630.     if (start != str) {
  631.      bcopy(start, modStr, str-start);
  632.           modStr[str-start] = '\0';
  633.           return str;
  634.     }
  635.     return str;
  636. }        
  637.     
  638. static String ParseModifiers(str, event,error)
  639.     register String str;
  640.     EventPtr event;
  641.     Boolean* error;
  642. {
  643.     register String start;
  644.     Boolean notFlag, exclusive, keysymAsMod;
  645.     Value maskBit;
  646.     char modStr[100];
  647.  
  648.     ScanWhitespace(str);
  649.     start = str;
  650.     str = FetchModifierToken(str,modStr);
  651.     exclusive = FALSE;
  652.     if (start != str) {
  653.           if (_XtLookupModifier(modStr,(LateBindingsPtr *) NULL,
  654.           FALSE,&maskBit,TRUE)) {
  655.           if (maskBit== None) {
  656.           event->event.modifierMask = ~0;
  657.           event->event.modifiers = 0;
  658.           ScanWhitespace(str);
  659.           return str;
  660.           }
  661.           if (maskBit == AnyModifier) {/*backward compatability*/
  662.           event->event.modifierMask = 0;
  663.           event->event.modifiers = 0;
  664.           ScanWhitespace(str);
  665.           return str;
  666.           }
  667.       }
  668.       str = start; /*if plain modifier, reset to beginning */
  669.     }
  670.     else while (*str == '!' || *str == ':') {
  671.         if (*str == '!') {
  672.              exclusive = TRUE;
  673.              str++;
  674.              ScanWhitespace(str);
  675.         }
  676.         if (*str == ':') {
  677.              event->event.standard = TRUE;
  678.              str++;
  679.              ScanWhitespace(str);
  680.         }
  681.     }
  682.    
  683.     while (*str != '<') {
  684.         if (*str == '~') {
  685.              notFlag = TRUE;
  686.              str++;
  687.           } else 
  688.               notFlag = FALSE;
  689.         if (*str == '@') {
  690.             keysymAsMod = TRUE;
  691.             str++;
  692.         }
  693.         else keysymAsMod = FALSE;
  694.     start = str;
  695.         str = FetchModifierToken(str,modStr);
  696.         if (start == str) {
  697.             Syntax("Modifier or '<' expected","");
  698.             *error = TRUE;
  699.             return PanicModeRecovery(str);
  700.         }
  701.          if (keysymAsMod) {
  702.              _XtParseKeysymMod(modStr,&event->event.lateModifiers,
  703.                    notFlag,&maskBit, error);
  704.          if (*error)
  705.                  return PanicModeRecovery(str);
  706.  
  707.          } else
  708.            if (!_XtLookupModifier( modStr,
  709.        &event->event.lateModifiers, notFlag, &maskBit,FALSE)) {
  710.              Syntax("Unknown modifier name:  ",modStr);
  711.                  *error = TRUE;
  712.                  return PanicModeRecovery(str);
  713.              }
  714.         event->event.modifierMask |= maskBit;
  715.     if (notFlag) event->event.modifiers &= ~maskBit;
  716.     else event->event.modifiers |= maskBit;
  717.         ScanWhitespace(str);
  718.     }
  719.     if (exclusive) event->event.modifierMask = ~0;
  720.     return str;
  721. }
  722.  
  723. static String ParseXtEventType(str, event, tmEventP,error)
  724.     register String str;
  725.     EventPtr event;
  726.     Cardinal *tmEventP;
  727.     Boolean* error;
  728. {
  729.     String start = str;
  730.     char eventTypeStr[100];
  731.  
  732.     ScanAlphanumeric(str);
  733.     bcopy(start, eventTypeStr, str-start);
  734.     eventTypeStr[str-start] = '\0';
  735.     *tmEventP = LookupTMEventType(eventTypeStr,error);
  736.     if (*error) 
  737.         return PanicModeRecovery(str);
  738.     event->event.eventType = events[*tmEventP].eventType;
  739.     return str;
  740. }
  741.  
  742. static unsigned long StrToHex(str)
  743.     String str;
  744. {
  745.     register char   c;
  746.     register unsigned long    val = 0;
  747.  
  748.     while (c = *str) {
  749.     if ('0' <= c && c <= '9') val = val*16+c-'0';
  750.     else if ('a' <= c && c <= 'z') val = val*16+c-'a'+10;
  751.     else if ('A' <= c && c <= 'Z') val = val*16+c-'A'+10;
  752.     else return 0;
  753.     str++;
  754.     }
  755.  
  756.     return val;
  757. }
  758.  
  759. static unsigned long StrToOct(str)
  760.     String str;
  761. {
  762.     register char c;
  763.     register unsigned long  val = 0;
  764.  
  765.     while (c = *str) {
  766.         if ('0' <= c && c <= '7') val = val*8+c-'0'; else return 0;
  767.     str++;
  768.     }
  769.  
  770.     return val;
  771. }
  772.  
  773. static unsigned long StrToNum(str)
  774.     String str;
  775. {
  776.     register char c;
  777.     register unsigned long val = 0;
  778.  
  779.     if (*str == '0') {
  780.     str++;
  781.     if (*str == 'x' || *str == 'X') return StrToHex(++str);
  782.     else return StrToOct(str);
  783.     }
  784.  
  785.     while (c = *str) {
  786.     if ('0' <= c && c <= '9') val = val*10+c-'0';
  787.     else return 0;
  788.     str++;
  789.     }
  790.  
  791.     return val;
  792. }
  793.  
  794. static KeySym StringToKeySym(str, error)
  795.     String str;
  796.     Boolean *error;
  797. {
  798.     KeySym k;
  799.  
  800.     if (str == NULL || *str == '\0') return (KeySym) 0;
  801.  
  802. #ifndef NOTASCII
  803.     /* special case single character ASCII, for speed */
  804.     if (*(str+1) == '\0') {
  805.     if (' ' <= *str && *str <= '~') return XK_space + (*str - ' ');
  806.     }
  807. #endif
  808.  
  809.     if ('0' <= *str && *str <= '9') return (KeySym) StrToNum(str);
  810.     k = XStringToKeysym(str);
  811.     if (k != NoSymbol) return k;
  812.  
  813. #ifdef NOTASCII
  814.     /* fall-back case to preserve backwards compatibility; no-one
  815.      * should be relying upon this!
  816.      */
  817.     if (*(str+1) == '\0') return (KeySym) *str;
  818. #endif
  819.  
  820.     Syntax("Unknown keysym name: ", str);
  821.     *error = True;
  822.     return NoSymbol;
  823. }
  824. /* ARGSUSED */
  825. static void ParseModImmed(name,value,lateBindings,notFlag,valueP)
  826.     String name;
  827.     Value value;
  828.     LateBindingsPtr* lateBindings;
  829.     Boolean notFlag;
  830.     Value* valueP;
  831. {
  832.     *valueP = value;
  833. }
  834. /* ARGSUSED */
  835. static void ParseModSym (name,value,lateBindings,notFlag,valueP)
  836.  /* is only valid with keysyms that have an _L and _R in their name;
  837.   * and ignores keysym lookup errors (i.e. assumes only valid keysyms)
  838.   */
  839.     String name;
  840.     Value value;
  841.     LateBindingsPtr* lateBindings;
  842.     Boolean notFlag;
  843.     Value* valueP;
  844. {
  845.     register KeySym keysymL = (KeySym)value;
  846.     register KeySym keysymR = keysymL + 1; /* valid for supported keysyms */
  847.     StoreLateBindings(keysymL,notFlag,keysymR,notFlag,lateBindings);
  848.     *valueP = 0;
  849. }
  850.  
  851. #ifdef sparc
  852. /*
  853.  * The stupid optimizer in SunOS 4.0.3 and below generates bogus code that
  854.  * causes the value of the most recently used variable to be returned instead
  855.  * of the value passed in.
  856.  */
  857. static String stupid_optimizer_kludge;
  858. #define BROKEN_OPTIMIZER_HACK(val) stupid_optimizer_kludge = (val)
  859. #else
  860. #define BROKEN_OPTIMIZER_HACK(val) val
  861. #endif
  862.  
  863. /* ARGSUSED */
  864. static String ParseImmed(str, closure, event,error)
  865.     register String str;
  866.     register Opaque closure;
  867.     register EventPtr event;
  868.     Boolean* error;
  869. {
  870.     event->event.eventCode = (unsigned long)closure;
  871.     event->event.eventCodeMask = (unsigned long)~0L;
  872.  
  873.     return BROKEN_OPTIMIZER_HACK(str);
  874. }
  875.  
  876. /* ARGSUSED */
  877. static String ParseAddModifier(str, closure, event, error)
  878.     register String str;
  879.     register Opaque closure;
  880.     register EventPtr event;
  881.     Boolean* error;
  882. {
  883.     register unsigned long modval = (unsigned long)closure;
  884.     event->event.modifiers |= modval;
  885.     if (modval != AnyButtonMask) /* AnyButtonMask is don't-care mask */
  886.     event->event.modifierMask |= modval;
  887.  
  888.     return BROKEN_OPTIMIZER_HACK(str);
  889. }
  890.  
  891.  
  892. static String ParseKeyAndModifiers(str, closure, event,error)
  893.     String str;
  894.     Opaque closure;
  895.     EventPtr event;
  896.     Boolean* error;
  897. {
  898.     str = ParseKeySym(str, closure, event,error);
  899.  
  900.     event->event.modifiers |= (unsigned long)closure;
  901.     event->event.modifierMask |= (unsigned long)closure;
  902.  
  903.     return str;
  904. }
  905.  
  906. /*ARGSUSED*/
  907. static String ParseKeySym(str, closure, event,error)
  908.     register String str;
  909.     Opaque closure;
  910.     EventPtr event;
  911.     Boolean* error;
  912. {
  913.     char *start;
  914.     char keySymName[100];
  915.  
  916.     ScanWhitespace(str);
  917.  
  918.     if (*str == '\\') {
  919.     str++;
  920.     keySymName[0] = *str;
  921.     if (*str != '\0' && *str != '\n') str++;
  922.     keySymName[1] = '\0';
  923.     event->event.eventCode = StringToKeySym(keySymName, error);
  924.     event->event.eventCodeMask = ~0L;
  925.     } else if (*str == ',' || *str == ':' ||
  926.              /* allow leftparen to be single char symbol,
  927.               * for backwards compatibility
  928.               */
  929.              (*str == '(' && *(str+1) >= '0' && *(str+1) <= '9')) {
  930.     /* no detail */
  931.     event->event.eventCode = 0L;
  932.         event->event.eventCodeMask = 0L;
  933.     } else {
  934.     start = str;
  935.     while (
  936.         *str != ','
  937.         && *str != ':'
  938.         && *str != ' '
  939.         && *str != '\t'
  940.                 && *str != '\n'
  941.                 && (*str != '(' || *(str+1) <= '0' || *(str+1) >= '9')
  942.         && *str != '\0') str++;
  943.     bcopy(start, keySymName, str-start);
  944.     keySymName[str-start] = '\0';
  945.     event->event.eventCode = StringToKeySym(keySymName, error);
  946.     event->event.eventCodeMask = ~0L;
  947.     }
  948.     if (*error) {
  949.     if (keySymName[0] == '<') {
  950.         /* special case for common error */
  951.         XtWarningMsg(XtNtranslationParseError, "missingComma",
  952.              XtCXtToolkitError,
  953.              "... possibly due to missing ',' in event sequence.",
  954.              (String*)NULL, (Cardinal*)NULL);
  955.     }
  956.     return PanicModeRecovery(str);
  957.     }
  958.     if (event->event.standard)
  959.     event->event.matchEvent = _XtMatchUsingStandardMods;
  960.     else 
  961.     event->event.matchEvent = _XtMatchUsingDontCareMods;
  962.  
  963.     return str;
  964. }
  965.  
  966. static String ParseTable(str, closure, event,error)
  967.     register String str;
  968.     Opaque closure;
  969.     EventPtr event;
  970.     Boolean* error;
  971. {
  972.     register String start = str;
  973.     char tableSymName[100];
  974.  
  975.     event->event.eventCode = 0L;
  976.     ScanAlphanumeric(str);
  977.     if (str == start) {event->event.eventCodeMask = 0L; return str; }
  978.     if (str-start >= 99) {
  979.     Syntax("Invalid Detail Type (string is too long).", "");
  980.     *error = TRUE;
  981.     return str;
  982.     }
  983.     bcopy(start, tableSymName, str-start);
  984.     tableSymName[str-start] = '\0';
  985.     if (! _XtLookupTableSym((NameValueTable)closure, tableSymName, 
  986.             (Value *)&event->event.eventCode)) {
  987.     Syntax("Unknown Detail Type:  ",tableSymName);
  988.         *error = TRUE;
  989.         return PanicModeRecovery(str);
  990.     }
  991.     event->event.eventCodeMask = ~0L;
  992.  
  993.     return str;
  994. }
  995.  
  996. /*ARGSUSED*/
  997. static String ParseNone(str, closure, event,error)
  998.     String str;
  999.     Opaque closure;
  1000.     EventPtr event;
  1001.     Boolean* error;
  1002. {
  1003.     event->event.eventCode = 0;
  1004.     event->event.eventCodeMask = 0;
  1005.  
  1006.     return BROKEN_OPTIMIZER_HACK(str);
  1007. }
  1008.  
  1009. /*ARGSUSED*/
  1010. static String ParseAtom(str, closure, event,error)
  1011.     String str;
  1012.     Opaque closure;
  1013.     EventPtr event;
  1014.     Boolean* error;
  1015. {
  1016.     ScanWhitespace(str);
  1017.  
  1018.     if (*str == ',' || *str == ':') {
  1019.     /* no detail */
  1020.     event->event.eventCode = 0L;
  1021.         event->event.eventCodeMask = 0L;
  1022.     } else {
  1023.     char *start, atomName[1000];
  1024.     start = str;
  1025.     while (
  1026.         *str != ','
  1027.         && *str != ':'
  1028.         && *str != ' '
  1029.         && *str != '\t'
  1030.                 && *str != '\n'
  1031.         && *str != '\0') str++;
  1032.     if (str-start >= 999) {
  1033.         Syntax( "Atom name must be less than 1000 characters long.", "" );
  1034.         *error = TRUE;
  1035.         return str;
  1036.     }
  1037.     bcopy(start, atomName, str-start);
  1038.     atomName[str-start] = '\0';
  1039.     event->event.eventCode = XrmStringToQuark(atomName);
  1040.     event->event.matchEvent = _XtMatchAtom;
  1041.     }
  1042.     return str;
  1043. }
  1044.  
  1045. static ModifierMask buttonModifierMasks[] = {
  1046.     0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask
  1047. };
  1048. static String ParseRepeat();
  1049.  
  1050. static String ParseEvent(str, event, reps, plus, error)
  1051.     register String str;
  1052.     EventPtr    event;
  1053.     int*    reps;
  1054.     Boolean*    plus;
  1055.     Boolean* error;
  1056. {
  1057.     Cardinal    tmEvent;
  1058.  
  1059.     str = ParseModifiers(str, event,error);
  1060.     if (*error) return str;
  1061.     if (*str != '<') {
  1062.          Syntax("Missing '<' while parsing event type.",""); 
  1063.          *error = TRUE;
  1064.          return PanicModeRecovery(str);
  1065.     }
  1066.     else str++;
  1067.     str = ParseXtEventType(str, event, &tmEvent,error);
  1068.     if (*error) return str;
  1069.     if (*str != '>'){
  1070.          Syntax("Missing '>' while parsing event type","");
  1071.          *error = TRUE;
  1072.          return PanicModeRecovery(str);
  1073.     }
  1074.     else str++;
  1075.     if (*str == '(') {
  1076.     str = ParseRepeat(str, reps, plus, error);
  1077.     if (*error) return str;
  1078.     }
  1079.     str = (*(events[tmEvent].parseDetail))(
  1080.         str, events[tmEvent].closure, event,error);
  1081.     if (*error) return str;
  1082.  
  1083. /* gross hack! ||| this kludge is related to the X11 protocol deficiency w.r.t.
  1084.  * modifiers in grabs.
  1085.  */
  1086.     if ((event->event.eventType == ButtonRelease)
  1087.     && (event->event.modifiers | event->event.modifierMask) /* any */
  1088.         && (event->event.modifiers != AnyModifier))
  1089.     {
  1090.     event->event.modifiers
  1091.         |= buttonModifierMasks[event->event.eventCode];
  1092.     /* the button that is going up will always be in the modifiers... */
  1093.     }
  1094.  
  1095.     return str;
  1096. }
  1097.  
  1098. static String ParseQuotedStringEvent(str, event,error)
  1099.     register String str;
  1100.     register EventPtr event;
  1101.     Boolean *error;
  1102. {
  1103.     register int j;
  1104.  
  1105.     Value ctrlMask;
  1106.     Value metaMask;
  1107.     Value shiftMask;
  1108.     register char    c;
  1109.     char    s[2];
  1110.     (void) _XtLookupModifier("Ctrl",(LateBindingsPtr*)NULL,
  1111.                  FALSE,(Value *) &ctrlMask,TRUE);
  1112.     (void) _XtLookupModifier("Meta", &event->event.lateModifiers,
  1113.                  FALSE,(Value *) &metaMask,FALSE);
  1114.     (void) _XtLookupModifier("Shift",(LateBindingsPtr*)NULL,
  1115.                  FALSE,(Value *) &shiftMask,TRUE);
  1116.     for (j=0; j < 2; j++)
  1117.     if (*str=='^' && !(event->event.modifiers | ctrlMask)) {
  1118.         str++;
  1119.         event->event.modifiers |= ctrlMask;
  1120.     } else if (*str == '$' && !(event->event.modifiers | metaMask)) {
  1121.         str++;
  1122.         event->event.modifiers |= metaMask;
  1123.     } else if (*str == '\\') {
  1124.         str++;
  1125.         c = *str;
  1126.         if (*str != '\0' && *str != '\n') str++;
  1127.         break;
  1128.     } else {
  1129.         c = *str;
  1130.         if (*str != '\0' && *str != '\n') str++;
  1131.         break;
  1132.     }
  1133.     event->event.eventType = KeyPress;
  1134.     s[0] = c;
  1135.     s[1] = '\0';
  1136.     event->event.eventCode = StringToKeySym(s, error);
  1137.     if (*error) return PanicModeRecovery(str);
  1138.     event->event.eventCodeMask = ~0L;
  1139.     event->event.matchEvent = _XtMatchUsingStandardMods;
  1140.     event->event.standard = True;
  1141.  
  1142.     return str;
  1143. }
  1144.  
  1145.  
  1146. static EventSeqRec timerEventRec = {
  1147.     {0, 0, NULL, _XtEventTimerEventType, 0L, 0L, NULL},
  1148.     /* (StatePtr) -1 */ NULL,
  1149.     NULL,
  1150.     NULL
  1151. };
  1152.  
  1153. static void RepeatDown(eventP, reps, actionsP)
  1154.     EventPtr *eventP;
  1155.     int reps;
  1156.     ActionPtr **actionsP;
  1157. {
  1158.     EventRec upEventRec;
  1159.     register EventPtr event, downEvent;
  1160.     EventPtr upEvent = &upEventRec;
  1161.     register int i;
  1162.  
  1163.     downEvent = event = *eventP;
  1164.     *upEvent = *downEvent;
  1165.     upEvent->event.eventType = ((event->event.eventType == ButtonPress) ?
  1166.     ButtonRelease : KeyRelease);
  1167.     if ((upEvent->event.eventType == ButtonRelease)
  1168.     && (upEvent->event.modifiers != AnyModifier)
  1169.         && (upEvent->event.modifiers | upEvent->event.modifierMask))
  1170.     upEvent->event.modifiers
  1171.         |= buttonModifierMasks[event->event.eventCode];
  1172.  
  1173.     if (event->event.lateModifiers)
  1174.     event->event.lateModifiers->ref_count += (reps - 1) * 2;
  1175.  
  1176.     for (i=1; i<reps; i++) {
  1177.  
  1178.     /* up */
  1179.     event->next = XtNew(EventSeqRec);
  1180.     event = event->next;
  1181.     *event = *upEvent;
  1182.  
  1183.     /* timer */
  1184.     event->next = XtNew(EventSeqRec);
  1185.     event = event->next;
  1186.     *event = timerEventRec;
  1187.  
  1188.     /* down */
  1189.     event->next = XtNew(EventSeqRec);
  1190.     event = event->next;
  1191.     *event = *downEvent;
  1192.  
  1193.     }
  1194.  
  1195.     event->next = NULL;
  1196.     *eventP = event;
  1197.     *actionsP = &event->actions;
  1198. }
  1199.  
  1200. static void RepeatDownPlus(eventP, reps, actionsP)
  1201.     EventPtr *eventP;
  1202.     int reps;
  1203.     ActionPtr **actionsP;
  1204. {
  1205.     EventRec upEventRec;
  1206.     register EventPtr event, downEvent, lastDownEvent;
  1207.     EventPtr upEvent = &upEventRec;
  1208.     register int i;
  1209.  
  1210.     downEvent = event = *eventP;
  1211.     *upEvent = *downEvent;
  1212.     upEvent->event.eventType = ((event->event.eventType == ButtonPress) ?
  1213.     ButtonRelease : KeyRelease);
  1214.     if ((upEvent->event.eventType == ButtonRelease)
  1215.     && (upEvent->event.modifiers != AnyModifier)
  1216.         && (upEvent->event.modifiers | upEvent->event.modifierMask))
  1217.     upEvent->event.modifiers
  1218.         |= buttonModifierMasks[event->event.eventCode];
  1219.  
  1220.     if (event->event.lateModifiers)
  1221.     event->event.lateModifiers->ref_count += reps * 2 - 1;
  1222.  
  1223.     for (i=0; i<reps; i++) {
  1224.  
  1225.     if (i > 0) {
  1226.     /* down */
  1227.     event->next = XtNew(EventSeqRec);
  1228.     event = event->next;
  1229.     *event = *downEvent;
  1230.     }
  1231.     lastDownEvent = event;
  1232.  
  1233.     /* up */
  1234.     event->next = XtNew(EventSeqRec);
  1235.     event = event->next;
  1236.     *event = *upEvent;
  1237.  
  1238.     /* timer */
  1239.     event->next = XtNew(EventSeqRec);
  1240.     event = event->next;
  1241.     *event = timerEventRec;
  1242.  
  1243.     }
  1244.  
  1245.     event->next = lastDownEvent;
  1246.     *eventP = event;
  1247.     *actionsP = &lastDownEvent->actions;
  1248. }
  1249.  
  1250. static void RepeatUp(eventP, reps, actionsP)
  1251.     EventPtr *eventP;
  1252.     int reps;
  1253.     ActionPtr **actionsP;
  1254. {
  1255.     EventRec upEventRec;
  1256.     register EventPtr event, downEvent;
  1257.     EventPtr upEvent = &upEventRec;
  1258.     register int i;
  1259.  
  1260.     /* the event currently sitting in *eventP is an "up" event */
  1261.     /* we want to make it a "down" event followed by an "up" event, */
  1262.     /* so that sequence matching on the "state" side works correctly. */
  1263.  
  1264.     downEvent = event = *eventP;
  1265.     *upEvent = *downEvent;
  1266.     downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ?
  1267.     ButtonPress : KeyPress);
  1268.     if ((downEvent->event.eventType == ButtonPress)
  1269.     && (downEvent->event.modifiers != AnyModifier)
  1270.         && (downEvent->event.modifiers | downEvent->event.modifierMask))
  1271.     downEvent->event.modifiers
  1272.         &= ~buttonModifierMasks[event->event.eventCode];
  1273.  
  1274.     if (event->event.lateModifiers)
  1275.     event->event.lateModifiers->ref_count += reps * 2 - 1;
  1276.  
  1277.     /* up */
  1278.     event->next = XtNew(EventSeqRec);
  1279.     event = event->next;
  1280.     *event = *upEvent;
  1281.  
  1282.     for (i=1; i<reps; i++) {
  1283.  
  1284.     /* timer */
  1285.     event->next = XtNew(EventSeqRec);
  1286.     event = event->next;
  1287.     *event = timerEventRec;
  1288.  
  1289.     /* down */
  1290.     event->next = XtNew(EventSeqRec);
  1291.     event = event->next;
  1292.     *event = *downEvent;
  1293.  
  1294.     /* up */
  1295.     event->next = XtNew(EventSeqRec);
  1296.     event = event->next;
  1297.     *event = *upEvent;
  1298.  
  1299.     }
  1300.  
  1301.     event->next = NULL;
  1302.     *eventP = event;
  1303.     *actionsP = &event->actions;
  1304. }
  1305.  
  1306. static void RepeatUpPlus(eventP, reps, actionsP)
  1307.     EventPtr *eventP;
  1308.     int reps;
  1309.     ActionPtr **actionsP;
  1310. {
  1311.     EventRec upEventRec;
  1312.     register EventPtr event, downEvent, lastUpEvent;
  1313.     EventPtr upEvent = &upEventRec;
  1314.     register int i;
  1315.  
  1316.     /* the event currently sitting in *eventP is an "up" event */
  1317.     /* we want to make it a "down" event followed by an "up" event, */
  1318.     /* so that sequence matching on the "state" side works correctly. */
  1319.  
  1320.     downEvent = event = *eventP;
  1321.     *upEvent = *downEvent;
  1322.     downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ?
  1323.     ButtonPress : KeyPress);
  1324.     if ((downEvent->event.eventType == ButtonPress)
  1325.     && (downEvent->event.modifiers != AnyModifier)
  1326.         && (downEvent->event.modifiers | downEvent->event.modifierMask))
  1327.     downEvent->event.modifiers
  1328.         &= ~buttonModifierMasks[event->event.eventCode];
  1329.  
  1330.     if (event->event.lateModifiers)
  1331.     event->event.lateModifiers->ref_count += reps * 2;
  1332.  
  1333.     for (i=0; i<reps; i++) {
  1334.  
  1335.     /* up */
  1336.     event->next = XtNew(EventSeqRec);
  1337.     lastUpEvent = event = event->next;
  1338.     *event = *upEvent;
  1339.  
  1340.     /* timer */
  1341.     event->next = XtNew(EventSeqRec);
  1342.     event = event->next;
  1343.     *event = timerEventRec;
  1344.  
  1345.     /* down */
  1346.     event->next = XtNew(EventSeqRec);
  1347.         event = event->next;
  1348.     *event = *downEvent;
  1349.  
  1350.     }
  1351.  
  1352.     event->next = lastUpEvent;
  1353.     *eventP = event;
  1354.     *actionsP = &lastUpEvent->actions;
  1355. }
  1356.  
  1357. static void RepeatOther(eventP, reps, actionsP)
  1358.     EventPtr *eventP;
  1359.     int reps;
  1360.     ActionPtr **actionsP;
  1361. {
  1362.     register EventPtr event, tempEvent;
  1363.     register int i;
  1364.  
  1365.     tempEvent = event = *eventP;
  1366.  
  1367.     if (event->event.lateModifiers)
  1368.     event->event.lateModifiers->ref_count += reps - 1;
  1369.  
  1370.     for (i=1; i<reps; i++) {
  1371.     event->next = XtNew(EventSeqRec);
  1372.     event = event->next;
  1373.     *event = *tempEvent;
  1374.     }
  1375.  
  1376.     *eventP = event;
  1377.     *actionsP = &event->actions;
  1378. }
  1379.  
  1380. static void RepeatOtherPlus(eventP, reps, actionsP)
  1381.     EventPtr *eventP;
  1382.     int reps;
  1383.     ActionPtr **actionsP;
  1384. {
  1385.     register EventPtr event, tempEvent;
  1386.     register int i;
  1387.  
  1388.     tempEvent = event = *eventP;
  1389.  
  1390.     if (event->event.lateModifiers)
  1391.     event->event.lateModifiers->ref_count += reps - 1;
  1392.  
  1393.     for (i=1; i<reps; i++) {
  1394.     event->next = XtNew(EventSeqRec);
  1395.     event = event->next;
  1396.     *event = *tempEvent;
  1397.     }
  1398.  
  1399.     event->next = event;
  1400.     *eventP = event;
  1401.     *actionsP = &event->actions;
  1402. }
  1403.  
  1404. static void RepeatEvent(eventP, reps, plus, actionsP)
  1405.     EventPtr *eventP;
  1406.     int reps;
  1407.     Boolean plus;
  1408.     ActionPtr **actionsP;
  1409. {
  1410.     switch ((*eventP)->event.eventType) {
  1411.  
  1412.     case ButtonPress:
  1413.     case KeyPress:
  1414.         if (plus) RepeatDownPlus(eventP, reps, actionsP);
  1415.         else RepeatDown(eventP, reps, actionsP);
  1416.         break;
  1417.  
  1418.     case ButtonRelease:
  1419.     case KeyRelease:
  1420.         if (plus) RepeatUpPlus(eventP, reps, actionsP);
  1421.         else RepeatUp(eventP, reps, actionsP);
  1422.         break;
  1423.  
  1424.     default:
  1425.         if (plus) RepeatOtherPlus(eventP, reps, actionsP);
  1426.         else RepeatOther(eventP, reps, actionsP);
  1427.     }
  1428. }
  1429.  
  1430. static String ParseRepeat(str, reps, plus, error)
  1431.     register String str;
  1432.     int    *reps;
  1433.     Boolean *plus, *error;
  1434. {
  1435.  
  1436.     /*** Parse the repetitions, for double click etc... ***/
  1437.     if (*str != '(' || !(isdigit(str[1]) || str[1] == '+' || str[1] == ')'))
  1438.     return str;
  1439.     str++;
  1440.     if (isdigit(*str)) {
  1441.     String start = str;
  1442.     char repStr[7];
  1443.     int len;
  1444.  
  1445.     ScanNumeric(str);
  1446.     len = (str - start);
  1447.     if (len < sizeof repStr) {
  1448.         bcopy(start, repStr, len);
  1449.         repStr[len] = '\0';
  1450.         *reps = StrToNum(repStr);
  1451.     } else {
  1452.         Syntax("Repeat count too large.", "");
  1453.         *error = True;
  1454.         return str;
  1455.     }
  1456.     }
  1457.     if (*reps == 0) {
  1458.     Syntax("Missing repeat count.","");
  1459.     *error = True;
  1460.     return str;
  1461.     }
  1462.  
  1463.     if (*str == '+') {
  1464.     *plus = TRUE;
  1465.     str++;
  1466.     }
  1467.     if (*str == ')')
  1468.     str++;
  1469.     else {
  1470.     Syntax("Missing ')'.","");
  1471.     *error = True;
  1472.     }
  1473.  
  1474.     return str;
  1475. }
  1476.  
  1477. /***********************************************************************
  1478.  * ParseEventSeq
  1479.  * Parses the left hand side of a translation table production
  1480.  * up to, and consuming the ":".
  1481.  * Takes a pointer to a char* (where to start parsing) and returns an
  1482.  * event seq (in a passed in variable), having updated the String 
  1483.  **********************************************************************/
  1484.  
  1485. static String ParseEventSeq(str, eventSeqP, actionsP,error)
  1486.     register String str;
  1487.     EventSeqPtr *eventSeqP;
  1488.     ActionPtr    **actionsP;
  1489.     Boolean *error;
  1490. {
  1491.     EventSeqPtr *nextEvent = eventSeqP;
  1492.  
  1493.     *eventSeqP = NULL;
  1494.  
  1495.     while ( *str != '\0' && *str != '\n') {
  1496.     static Event    nullEvent =
  1497.              {0, 0,0L, 0, 0L, 0L,_XtRegularMatch,FALSE};
  1498.     EventPtr    event;
  1499.  
  1500.     ScanWhitespace(str);
  1501.  
  1502.     if (*str == '"') {
  1503.         str++;
  1504.         while (*str != '"' && *str != '\0' && *str != '\n') {
  1505.                 event = XtNew(EventRec);
  1506.                 event->event = nullEvent;
  1507.                 event->state = /* (StatePtr) -1 */ NULL;
  1508.                 event->next = NULL;
  1509.                 event->actions = NULL;
  1510.         str = ParseQuotedStringEvent(str, event,error);
  1511.         if (*error) {
  1512.             XtWarningMsg(XtNtranslationParseError, "nonLatin1",
  1513.             XtCXtToolkitError,
  1514.             "... probably due to non-Latin1 character in quoted string",
  1515.             (String*)NULL, (Cardinal*)NULL);
  1516.             return PanicModeRecovery(str);
  1517.         }
  1518.         *nextEvent = event;
  1519.         *actionsP = &event->actions;
  1520.         nextEvent = &event->next;
  1521.         }
  1522.         if (*str != '"') {
  1523.                 Syntax("Missing '\"'.","");
  1524.                 *error = TRUE;
  1525.                 return PanicModeRecovery(str);
  1526.              }
  1527.              else str++;
  1528.     } else {
  1529.         int reps = 0;
  1530.         Boolean plus = False;
  1531.  
  1532.             event = XtNew(EventRec);
  1533.             event->event = nullEvent;
  1534.             event->state = /* (StatePtr) -1 */ NULL;
  1535.             event->next = NULL;
  1536.             event->actions = NULL;
  1537.  
  1538.         str = ParseEvent(str, event, &reps, &plus, error);
  1539.             if (*error) return str;
  1540.         *nextEvent = event;
  1541.         *actionsP = &event->actions;
  1542.         if (reps > 1 || plus)
  1543.         RepeatEvent(&event, reps, plus, actionsP);
  1544.         nextEvent = &event->next;
  1545.     }
  1546.     ScanWhitespace(str);
  1547.         if (*str == ':') break;
  1548.         else {
  1549.             if (*str != ',') {
  1550.                 Syntax("',' or ':' expected while parsing event sequence.","");
  1551.                 *error = TRUE;
  1552.                 return PanicModeRecovery(str);
  1553.         } else str++;
  1554.         }
  1555.     }
  1556.  
  1557.     if (*str != ':') {
  1558.         Syntax("Missing ':'after event sequence.",""); 
  1559.         *error = TRUE;
  1560.         return PanicModeRecovery(str);
  1561.     } else str++;
  1562.  
  1563.     return str;
  1564. }
  1565.  
  1566.  
  1567. static String ParseActionProc(str, actionProcNameP, error)
  1568.     register String str;
  1569.     XrmQuark *actionProcNameP;
  1570.     Boolean *error;
  1571. {
  1572.     register String start = str;
  1573.     char procName[200];
  1574.  
  1575.     str = ScanIdent(str);
  1576.     if (str-start >= 199) {
  1577.     Syntax("Action procedure name is longer than 199 chars","");
  1578.     *error = TRUE;
  1579.     return str;
  1580.     }
  1581.     bcopy(start, procName, str-start);
  1582.     procName[str-start] = '\0';
  1583.     *actionProcNameP = XrmStringToQuark( procName );
  1584.     return str;
  1585. }
  1586.  
  1587.  
  1588. static String ParseString(str, strP)
  1589.     register String str;
  1590.     String *strP;
  1591. {
  1592.     register String start;
  1593.  
  1594.     if (*str == '"') {
  1595.     register unsigned prev_len, len;
  1596.     str++;
  1597.     start = str;
  1598.     *strP = NULL;
  1599.     prev_len = 0;
  1600.  
  1601.     while (*str != '"' && *str != '\0') {
  1602.         /* \"  produces double quote embedded in a quoted parameter
  1603.          * \\" produces backslash as last character of a quoted parameter
  1604.          */
  1605.         if (*str == '\\' && 
  1606.         (*(str+1) == '"' || (*(str+1) == '\\' && *(str+2) == '"'))) {
  1607.         len = prev_len + (str-start+2);
  1608.         *strP = XtRealloc(*strP, len);
  1609.         bcopy(start, *strP + prev_len, str-start);
  1610.         prev_len = len-1;
  1611.         str++;
  1612.         (*strP)[prev_len-1] = *str;
  1613.         (*strP)[prev_len] = '\0';
  1614.         start = str+1;
  1615.         } 
  1616.         str++;
  1617.     }
  1618.     len = prev_len + (str-start+1);
  1619.     *strP = XtRealloc(*strP, len);
  1620.     bcopy(start, *strP + prev_len, str-start);
  1621.     (*strP)[len-1] = '\0';
  1622.     if (*str == '"') str++; else
  1623.             XtWarningMsg(XtNtranslationParseError,"parseString",
  1624.                       XtCXtToolkitError,"Missing '\"'.",
  1625.               (String *)NULL, (Cardinal *)NULL);
  1626.     } else {
  1627.     /* scan non-quoted string, stop on whitespace, ',' or ')' */
  1628.     start = str;
  1629.     while (*str != ' '
  1630.         && *str != '\t'
  1631.         && *str != ','
  1632.         && *str != ')'
  1633.                 && *str != '\n'
  1634.         && *str != '\0') str++;
  1635.     *strP = XtMalloc((unsigned)(str-start+1));
  1636.     bcopy(start, *strP, str-start);
  1637.     (*strP)[str-start] = '\0';
  1638.     }
  1639.     return str;
  1640. }
  1641.  
  1642.  
  1643. static String ParseParamSeq(str, paramSeqP, paramNumP)
  1644.     register String str;
  1645.     String **paramSeqP;
  1646.     Cardinal *paramNumP;
  1647. {
  1648.     typedef struct _ParamRec *ParamPtr;
  1649.     typedef struct _ParamRec {
  1650.     ParamPtr next;
  1651.     String    param;
  1652.     } ParamRec;
  1653.  
  1654.     ParamPtr params = NULL;
  1655.     register Cardinal num_params = 0;
  1656.     register Cardinal i;
  1657.  
  1658.     ScanWhitespace(str);
  1659.     while (*str != ')' && *str != '\0' && *str != '\n') {
  1660.     String newStr;
  1661.     str = ParseString(str, &newStr);
  1662.     if (newStr != NULL) {
  1663.         ParamPtr temp = (ParamRec*)
  1664.         ALLOCATE_LOCAL( (unsigned)sizeof(ParamRec) );
  1665.  
  1666.         num_params++;
  1667.         temp->next = params;
  1668.         params = temp;
  1669.         temp->param = newStr;
  1670.         ScanWhitespace(str);
  1671.         if (*str == ',') {
  1672.         str++;
  1673.         ScanWhitespace(str);
  1674.         }
  1675.     }
  1676.     }
  1677.  
  1678.     if (num_params != 0) {
  1679.     String *paramP = (String *)
  1680.         XtMalloc( (unsigned)(num_params+1) * sizeof(String) );
  1681.     *paramSeqP = paramP;
  1682.     *paramNumP = num_params;
  1683.     paramP += num_params; /* list is LIFO right now */
  1684.     *paramP-- = NULL;
  1685.     for (i=0; i < num_params; i++) {
  1686.         ParamPtr next = params->next;
  1687.         *paramP-- = params->param;
  1688.         DEALLOCATE_LOCAL( (char *)params );
  1689.         params = next;
  1690.     }
  1691.     } else {
  1692.     *paramSeqP = NULL;
  1693.     *paramNumP = 0;
  1694.     }
  1695.  
  1696.     return str;
  1697. }
  1698.  
  1699. static String ParseAction(str, actionP, quarkP, error)
  1700.     String str;
  1701.     ActionPtr actionP;
  1702.     XrmQuark* quarkP;
  1703.     Boolean* error;
  1704. {
  1705.     str = ParseActionProc(str, quarkP, error);
  1706.     if (*error) return str;
  1707.  
  1708.     if (*str == '(') {
  1709.     str++;
  1710.     str = ParseParamSeq(str, &actionP->params, &actionP->num_params);
  1711.     } else {
  1712.         Syntax("Missing '(' while parsing action sequence",""); 
  1713.         *error = TRUE;
  1714.         return str;
  1715.     }
  1716.     if (*str == ')') str++;
  1717.     else{
  1718.         Syntax("Missing ')' while parsing action sequence","");
  1719.         *error = TRUE;
  1720.         return str;
  1721.     }
  1722.     return str;
  1723. }
  1724.  
  1725.  
  1726. static String ParseActionSeq(parseTree, str, actionsP, error)
  1727.     TMParseStateTree       parseTree;
  1728.     String         str;
  1729.     ActionPtr         *actionsP;
  1730.     Boolean        *error;
  1731. {
  1732.     ActionPtr *nextActionP = actionsP;
  1733.  
  1734.     *actionsP = NULL;
  1735.     while (*str != '\0' && *str != '\n') {
  1736.     register ActionPtr    action;
  1737.     XrmQuark quark;
  1738.  
  1739.     action = XtNew(ActionRec);
  1740.         action->params = NULL;
  1741.         action->num_params = 0;
  1742.         action->next = NULL;
  1743.  
  1744.     str = ParseAction(str, action, &quark, error);
  1745.     if (*error) return PanicModeRecovery(str);
  1746.  
  1747.     action->idx = _XtGetQuarkIndex(parseTree, quark);
  1748.     ScanWhitespace(str);
  1749.     *nextActionP = action;
  1750.     nextActionP = &action->next;
  1751.     }
  1752.     if (*str == '\n') str++;
  1753.     ScanWhitespace(str);
  1754.     return str;
  1755. }
  1756.  
  1757.  
  1758. static void ShowProduction(currentProduction)
  1759.   String currentProduction;
  1760. {
  1761.     Cardinal num_params = 1;
  1762.     String params[1];
  1763.     int len = 499;
  1764.     char *eol, production[500];
  1765.  
  1766.     eol = strchr(currentProduction, '\n');
  1767.     if (eol) len = MIN(499, eol - currentProduction);
  1768.     bcopy(currentProduction, production, len);
  1769.     production[len] = '\0';
  1770.  
  1771.     params[0] = production;
  1772.     XtWarningMsg(XtNtranslationParseError, "showLine", XtCXtToolkitError,
  1773.          "... found while parsing '%s'", params, &num_params);
  1774. }
  1775.  
  1776. /***********************************************************************
  1777.  * ParseTranslationTableProduction
  1778.  * Parses one line of event bindings.
  1779.  ***********************************************************************/
  1780.  
  1781. static String ParseTranslationTableProduction(parseTree, str)
  1782.     TMParseStateTree     parseTree;
  1783.     register String str;
  1784. {
  1785.     EventSeqPtr    eventSeq = NULL;
  1786.     ActionPtr    *actionsP;
  1787.     Boolean error = FALSE;
  1788.     String    production = str;
  1789.  
  1790.     str = ParseEventSeq(str, &eventSeq, &actionsP,&error);
  1791.     if (error == TRUE) {
  1792.     ShowProduction(production);
  1793.         FreeEventSeq(eventSeq);
  1794.         return (str);
  1795.     }
  1796.     ScanWhitespace(str);
  1797.     str = ParseActionSeq(parseTree, str, actionsP, &error);
  1798.     if (error) {
  1799.     ShowProduction(production);
  1800.         FreeEventSeq(eventSeq);
  1801.         return (str);
  1802.     }
  1803.  
  1804.     _XtAddEventSeqToStateTree(eventSeq, parseTree);
  1805.     FreeEventSeq(eventSeq);
  1806.     return (str);
  1807. }
  1808.  
  1809.  
  1810. /*ARGSUSED*/
  1811. Boolean XtCvtStringToAcceleratorTable(dpy, args, num_args, from, to, closure)
  1812.     Display*    dpy;
  1813.     XrmValuePtr args;
  1814.     Cardinal    *num_args;
  1815.     XrmValuePtr from,to;
  1816.     XtPointer    *closure;
  1817. {
  1818.     String str;
  1819.  
  1820.     if (*num_args != 0)
  1821.         XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
  1822.       "wrongParameters","cvtStringToAcceleratorTable",XtCXtToolkitError,
  1823.           "String to AcceleratorTable conversion needs no extra arguments",
  1824.       (String *)NULL, (Cardinal *)NULL);
  1825.      str = (String)(from->addr);
  1826.      if (str == NULL)
  1827.          return False;
  1828.  
  1829.     if (to->addr != NULL) {
  1830.     if (to->size < sizeof(XtAccelerators)) {
  1831.         to->size = sizeof(XtAccelerators);
  1832.         return False;
  1833.     }
  1834.     *(XtAccelerators*)to->addr = XtParseAcceleratorTable(str);
  1835.     }
  1836.     else {
  1837.     static XtAccelerators staticStateTable;
  1838.     staticStateTable = XtParseAcceleratorTable(str);
  1839.     to->addr = (XPointer) &staticStateTable;
  1840.     to->size = sizeof(XtAccelerators);
  1841.     }
  1842.     return True;
  1843. }
  1844.  
  1845.  
  1846. /*ARGSUSED*/
  1847. Boolean
  1848. XtCvtStringToTranslationTable(dpy, args, num_args, from, to, closure_ret)
  1849.     Display    *dpy;
  1850.     XrmValuePtr args;
  1851.     Cardinal    *num_args;
  1852.     XrmValuePtr from,to;
  1853.     XtPointer    *closure_ret;
  1854. {
  1855.     String str;
  1856.     
  1857.     if (*num_args != 0)
  1858.       XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
  1859.         "wrongParameters","cvtStringToTranslationTable",XtCXtToolkitError,
  1860.         "String to TranslationTable conversion needs no extra arguments",
  1861.         (String *)NULL, (Cardinal *)NULL);
  1862.     str = (String)(from->addr);
  1863.     if (str == NULL)
  1864.       return False;
  1865.  
  1866.     if (to->addr != NULL) {
  1867.     if (to->size < sizeof(XtTranslations)) {
  1868.         to->size = sizeof(XtTranslations);
  1869.         return False;
  1870.     }
  1871.     *(XtTranslations*)to->addr = XtParseTranslationTable(str);
  1872.     }
  1873.     else {
  1874.     static XtTranslations staticStateTable;
  1875.     staticStateTable = XtParseTranslationTable(str);
  1876.     to->addr = (XPointer) &staticStateTable;
  1877.     to->size = sizeof(XtTranslations);
  1878.     }
  1879.     return True;
  1880. }
  1881.  
  1882. static String CheckForPoundSign(str, defaultOp, actualOpRtn)
  1883.     String str;
  1884.     _XtTranslateOp defaultOp;
  1885.     _XtTranslateOp *actualOpRtn;
  1886. {
  1887.     String start;
  1888.     char operation[20];
  1889.     _XtTranslateOp opType;
  1890.     
  1891.     opType = defaultOp;
  1892.     ScanWhitespace(str);
  1893.     if (*str == '#') {
  1894.     int len;
  1895.     str++;
  1896.     start = str;
  1897.     str = ScanIdent(str);
  1898.     len = MIN(19, str-start);
  1899.     bcopy(start, operation, len);
  1900.     operation[len] = '\0';
  1901.     if (!strcmp(operation,"replace"))
  1902.       opType = XtTableReplace;
  1903.     else if (!strcmp(operation,"augment"))
  1904.       opType = XtTableAugment;
  1905.     else if (!strcmp(operation,"override"))
  1906.       opType = XtTableOverride;
  1907.     ScanWhitespace(str);
  1908.     if (*str == '\n') {
  1909.         str++;
  1910.         ScanWhitespace(str);
  1911.     }
  1912.     }
  1913.     *actualOpRtn = opType;
  1914.     return str;
  1915. }
  1916.  
  1917. static XtTranslations ParseTranslationTable(source, isAccelerator, defaultOp)
  1918.     String     source;
  1919.     Boolean    isAccelerator;
  1920.     _XtTranslateOp defaultOp;
  1921. {
  1922.     XtTranslations        xlations;
  1923.     TMStateTree            stateTrees[8];
  1924.     TMParseStateTreeRec        parseTreeRec, *parseTree = &parseTreeRec;
  1925.     XrmQuark            stackQuarks[200];
  1926.     TMBranchHeadRec        stackBranchHeads[200];
  1927.     StatePtr            stackComplexBranchHeads[200];
  1928.     _XtTranslateOp        actualOp;
  1929.  
  1930.     if (source == NULL)
  1931.       return (XtTranslations)NULL;
  1932.  
  1933.     source = CheckForPoundSign(source, defaultOp, &actualOp);
  1934.  
  1935.     parseTree->isSimple = True;
  1936.     parseTree->mappingNotifyInterest = False;
  1937.     parseTree->isAccelerator = isAccelerator;
  1938.     parseTree->isStackBranchHeads =
  1939.       parseTree->isStackQuarks =
  1940.     parseTree->isStackComplexBranchHeads = True;
  1941.  
  1942.     parseTree->numQuarks =
  1943.       parseTree->numBranchHeads =
  1944.     parseTree->numComplexBranchHeads = 0;
  1945.  
  1946.     parseTree->quarkTblSize =
  1947.       parseTree->branchHeadTblSize =
  1948.     parseTree->complexBranchHeadTblSize = 200;
  1949.  
  1950.     parseTree->quarkTbl = stackQuarks;
  1951.     parseTree->branchHeadTbl = stackBranchHeads;
  1952.     parseTree->complexBranchHeadTbl = stackComplexBranchHeads;
  1953.  
  1954.     while (source != NULL && *source != '\0') {
  1955.     source =  ParseTranslationTableProduction(parseTree, source);
  1956.     }
  1957.     stateTrees[0] = _XtParseTreeToStateTree(parseTree);
  1958.  
  1959.     if (!parseTree->isStackQuarks)
  1960.       XtFree((char *)parseTree->quarkTbl);
  1961.     if (!parseTree->isStackBranchHeads)
  1962.       XtFree((char *)parseTree->branchHeadTbl);
  1963.     if (!parseTree->isStackComplexBranchHeads)
  1964.       XtFree((char *)parseTree->complexBranchHeadTbl);
  1965.  
  1966.     xlations = _XtCreateXlations(stateTrees, 1, NULL, NULL);
  1967.     xlations->operation = actualOp;
  1968.  
  1969. #ifdef notdef
  1970.     XtFree(stateTrees);
  1971. #endif /* notdef */
  1972.     return xlations;
  1973. }
  1974.  
  1975. /*** public procedures ***/
  1976.  
  1977. /*
  1978.  * Parses a user's or applications translation table
  1979.  */
  1980. #if NeedFunctionPrototypes
  1981. XtAccelerators XtParseAcceleratorTable(
  1982.     _Xconst char* source
  1983.     )
  1984. #else
  1985. XtAccelerators XtParseAcceleratorTable(source)
  1986.     String source;
  1987. #endif
  1988. {
  1989.     return ((XtAccelerators)ParseTranslationTable(source, True, XtTableAugment));
  1990. }
  1991.  
  1992. #if NeedFunctionPrototypes
  1993. XtTranslations XtParseTranslationTable(
  1994.     _Xconst char* source
  1995.     )
  1996. #else
  1997. XtTranslations XtParseTranslationTable(source)
  1998.     String source;
  1999. #endif
  2000. {
  2001.     return (ParseTranslationTable(source, False, XtTableReplace));
  2002. }
  2003.  
  2004. void _XtTranslateInitialize()
  2005. {
  2006.     if (initialized) {
  2007.     XtWarningMsg("translationError","xtTranslateInitialize",
  2008.                   XtCXtToolkitError,"Initializing Translation manager twice.",
  2009.                     (String *)NULL, (Cardinal *)NULL);
  2010.     return;
  2011.     }
  2012.  
  2013.     initialized = TRUE;
  2014.  
  2015.     Compile_XtEventTable( events, XtNumber(events) );
  2016.     Compile_XtModifierTable( modifiers, XtNumber(modifiers) );
  2017.     CompileNameValueTable( buttonNames );
  2018.     CompileNameValueTable( notifyModes );
  2019.     CompileNameValueTable( motionDetails );
  2020. #if 0
  2021.     CompileNameValueTable( notifyDetail );
  2022.     CompileNameValueTable( visibilityNotify );
  2023.     CompileNameValueTable( circulation );
  2024.     CompileNameValueTable( propertyChanged );
  2025. #endif
  2026.     CompileNameValueTable( mappingNotify );
  2027. }
  2028.  
  2029. _XtAddTMConverters(table)
  2030.     ConverterTable table;
  2031. {
  2032.      _XtTableAddConverter(table,
  2033.          _XtQString,
  2034.          XrmPermStringToQuark(XtRTranslationTable), 
  2035.           XtCvtStringToTranslationTable, (XtConvertArgList) NULL,
  2036.          (Cardinal)0, True, CACHED, _XtFreeTranslations);
  2037.      _XtTableAddConverter(table, _XtQString,
  2038.          XrmPermStringToQuark(XtRAcceleratorTable),
  2039.           XtCvtStringToAcceleratorTable, (XtConvertArgList) NULL,
  2040.          (Cardinal)0, True, CACHED, _XtFreeTranslations);
  2041.      _XtTableAddConverter(table,
  2042.          XrmPermStringToQuark( _XtRStateTablePair ),
  2043.          XrmPermStringToQuark(XtRTranslationTable), 
  2044.           _XtCvtMergeTranslations, (XtConvertArgList) NULL,
  2045.          (Cardinal)0, True, CACHED, _XtFreeTranslations);
  2046. }
  2047.