home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1682 / parse.c
C/C++ Source or Header  |  1990-12-28  |  21KB  |  781 lines

  1. /*
  2.  *    parse.c - Parse event specifications (see Xt manual, appendix B)
  3.  *
  4.  *    George Ferguson, ferguson@cs.rochester.edu, 1 Jun 1990.
  5.  *
  6.  *    $Id: parse.c,v 1.4 90/08/15 11:32:19 ferguson Exp $
  7.  *
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <ctype.h>
  12. #include <string.h>
  13. #include <X11/Xlib.h>
  14. #include <X11/keysym.h>
  15. #include "parse.h"
  16. extern Display *display;
  17. extern Window root;
  18.  
  19. /*
  20.  * Functions defined
  21.  */
  22. char *parseEventList();
  23. void freeEventList();
  24. static char *parseEvent(),*parseMods(),*parseType(),*parseDetail();
  25. static unsigned int lookup();
  26. static void parseError();
  27.  
  28. #define SKIPWHITE(S)    while (isspace(*(S))) (S) += 1
  29.  
  30. /*
  31.  * Text to value mappings
  32.  */
  33. typedef struct {
  34.         char *name;
  35.         unsigned int value;
  36. } NameValue;
  37.  
  38. static NameValue booleans[] = {
  39.     {"True",    True},
  40.     {"False",    False},
  41.     {"On",    True},
  42.     {"Off",    False},
  43.     {NULL,    0},
  44. };
  45.  
  46. static NameValue modifiers[] = {
  47.     {"None",    None},
  48.     {"Shift",    ShiftMask},
  49.     {"Lock",    LockMask},
  50.     {"Ctrl",    ControlMask},
  51.     {"Mod1",    Mod1Mask},
  52.     {"Mod2",    Mod2Mask},
  53.     {"Mod3",    Mod3Mask},
  54.     {"Mod4",    Mod4Mask},
  55.     {"Mod5",    Mod5Mask},
  56.     {"Meta",    XK_Meta_L},
  57.     {"m",    XK_Meta_L},
  58.     {"h",    XK_Hyper_L},
  59.     {"su",    XK_Super_L},
  60.     {"a",    XK_Alt_L},
  61.     {"Hyper",    XK_Hyper_L},
  62.     {"Super",    XK_Super_L},
  63.     {"Alt",    XK_Alt_L},
  64.     {"Button1",    Button1Mask},
  65.     {"Button2",    Button2Mask},
  66.     {"Button3",    Button3Mask},
  67.     {"Button4",    Button4Mask},
  68.     {"Button5",    Button5Mask},
  69.     {"Any",    AnyModifier},
  70.     {"c",    ControlMask},
  71.     {"s",    ShiftMask},
  72.     {"l",    LockMask},
  73.     {NULL,    0},
  74. };
  75.  
  76. static NameValue buttonNames[] = {
  77.     {"Button1",    Button1},
  78.     {"Button2", Button2},
  79.     {"Button3", Button3},
  80.     {"Button4", Button4},
  81.     {"Button5", Button5},
  82.     {NULL,    0},
  83. };
  84.  
  85. static NameValue motionDetails[] = {
  86.     {"Normal",    NotifyNormal},
  87.     {"Hint",    NotifyHint},
  88.     {NULL,    0},
  89. };
  90.  
  91. static NameValue notifyModes[] = {
  92.     {"Normal",        NotifyNormal},
  93.     {"Grab",        NotifyGrab},
  94.     {"Ungrab",        NotifyUngrab},
  95.     {"WhileGrabbed",    NotifyWhileGrabbed},
  96.     {NULL,        0},
  97. };
  98.  
  99. static NameValue notifyDetails[] = {
  100.     {"Ancestor",    NotifyAncestor},
  101.     {"Virtual",        NotifyVirtual},
  102.     {"Inferior",    NotifyInferior},
  103.     {"Nonlinear",    NotifyNonlinear},
  104.     {"NonlinearVirtual",NotifyNonlinearVirtual},
  105.     {"Pointer",        NotifyPointer},
  106.     {"PointerRoot",    NotifyPointerRoot},
  107.     {"DetailNone",    NotifyDetailNone},
  108.     {NULL,        0},
  109. };
  110.  
  111. static NameValue circulateDetails[] = {
  112.     {"PlaceOnTop",    PlaceOnTop},
  113.     {"OnTop",        PlaceOnTop},
  114.     {"PlaceOnBottom",     PlaceOnBottom},
  115.     {"OnBottom",     PlaceOnBottom},
  116.     {NULL,        0},
  117. };
  118.  
  119. static NameValue mappingDetails[] = {
  120.     {"Modifier",    MappingModifier},
  121.     {"Keyboard",    MappingKeyboard},
  122.     {"Pointer",        MappingPointer},
  123.     {NULL,        0},
  124. };
  125.  
  126. static NameValue visibilityDetails[] = {
  127.     {"Unobscured",     VisibilityUnobscured},
  128.     {"PartiallyObscured",VisibilityPartiallyObscured},
  129.     {"FullyObscured",    VisibilityFullyObscured},
  130.     {NULL,        0},
  131. };
  132.  
  133. static NameValue propertyDetails[] = {
  134.     {"NewValue",    PropertyNewValue},
  135.     {"Delete",        PropertyDelete},
  136.     {NULL,        0},
  137. };
  138.  
  139. typedef struct {
  140.         char *name;
  141.         unsigned int value;
  142.         unsigned int mods;
  143.         unsigned int detail;
  144. } NameValueModsDetail;
  145.  
  146. static NameValueModsDetail types[] = {
  147. {"KeyPress",         KeyPress,     0,        0},
  148. {"Key",          KeyPress,     0,        0},
  149. {"KeyDown",         KeyPress,     0,        0},
  150. {"Ctrl",             KeyPress,   ControlMask,    0},
  151. {"Shift",            KeyPress,   ShiftMask,    0},
  152. {"Meta",             KeyPress,   0,        0},
  153. {"KeyUp",         KeyRelease, 0,        0},
  154. {"KeyRelease",         KeyRelease, 0,        0},
  155. {"ButtonPress",      ButtonPress, 0,    0},
  156. {"BtnDown",         ButtonPress, 0,    0},
  157. {"Btn1Down",         ButtonPress, 0,    Button1},
  158. {"Btn2Down",          ButtonPress, 0,    Button2},
  159. {"Btn3Down",          ButtonPress, 0,    Button3},
  160. {"Btn4Down",          ButtonPress, 0,    Button4},
  161. {"Btn5Down",          ButtonPress, 0,    Button5},
  162. {"ButtonRelease",    ButtonRelease, 0,    0},
  163. {"BtnUp",          ButtonRelease, 0,    0},
  164. {"Btn1Up",          ButtonRelease, 0,    Button1},
  165. {"Btn2Up",          ButtonRelease, 0,    Button2},
  166. {"Btn3Up",          ButtonRelease, 0,    Button3},
  167. {"Btn4Up",          ButtonRelease, 0,    Button4},
  168. {"Btn5Up",          ButtonRelease, 0,    Button5},
  169. {"MotionNotify",     MotionNotify, 0,            0},
  170. {"PtrMoved",          MotionNotify, 0,            0},
  171. {"Motion",          MotionNotify, 0,            0},
  172. {"MouseMoved",          MotionNotify, 0,            0},
  173. {"BtnMotion",        MotionNotify, 0,            0},
  174. {"Btn1Motion",       MotionNotify, Button1Mask,        0},
  175. {"Btn2Motion",       MotionNotify, Button2Mask,        0},
  176. {"Btn3Motion",       MotionNotify, Button3Mask,        0},
  177. {"Btn4Motion",       MotionNotify, Button4Mask,        0},
  178. {"Btn5Motion",       MotionNotify, Button5Mask,        0},
  179. {"EnterNotify",      EnterNotify, 0, 0},
  180. {"Enter",         EnterNotify, 0, 0},
  181. {"EnterWindow",      EnterNotify, 0, 0},
  182. {"LeaveNotify",      LeaveNotify, 0, 0},
  183. {"LeaveWindow",      LeaveNotify, 0, 0},
  184. {"Leave",         LeaveNotify, 0, 0},
  185. {"FocusIn",         FocusIn,  0, 0},
  186. {"FocusOut",         FocusOut, 0, 0},
  187. {"KeymapNotify",     KeymapNotify, 0, 0},
  188. {"Keymap",         KeymapNotify, 0, 0},
  189. {"Expose",          Expose, 0, 0},
  190. {"GraphicsExpose",   GraphicsExpose, 0, 0},
  191. {"GrExp",         GraphicsExpose, 0, 0},
  192. {"NoExpose",         NoExpose, 0, 0},
  193. {"NoExp",         NoExpose, 0, 0},
  194. {"VisibilityNotify", VisibilityNotify, 0, 0},
  195. {"Visible",         VisibilityNotify, 0, 0},
  196. {"CreateNotify",     CreateNotify, 0, 0},
  197. {"Create",         CreateNotify, 0, 0},
  198. {"DestroyNotify",    DestroyNotify, 0, 0},
  199. {"Destroy",         DestroyNotify, 0, 0},
  200. {"UnmapNotify",      UnmapNotify, 0, 0},
  201. {"Unmap",         UnmapNotify, 0, 0},
  202. {"MapNotify",         MapNotify,    0, 0},
  203. {"Map",             MapNotify,    0, 0},
  204. {"MapRequest",         MapRequest, 0, 0},
  205. {"MapReq",         MapRequest, 0, 0},
  206. {"ReparentNotify",   ReparentNotify, 0, 0},
  207. {"Reparent",         ReparentNotify, 0, 0},
  208. {"ConfigureNotify",  ConfigureNotify, 0, 0},
  209. {"Configure",         ConfigureNotify, 0, 0},
  210. {"ConfigureRequest", ConfigureRequest, 0, 0},
  211. {"ConfigureReq",     ConfigureRequest, 0, 0},
  212. {"GravityNotify",    GravityNotify, 0, 0},
  213. {"Grav",         GravityNotify, 0, 0},
  214. {"ResizeRequest",    ResizeRequest, 0, 0},
  215. {"ResReq",         ResizeRequest, 0, 0},
  216. {"CirculateNotify",  CirculateNotify, 0, 0},
  217. {"Circ",         CirculateNotify, 0, 0},
  218. {"CirculateRequest", CirculateRequest, 0, 0},
  219. {"CircReq",         CirculateRequest, 0, 0},
  220. {"PropertyNotify",   PropertyNotify, 0, 0},
  221. {"Prop",         PropertyNotify, 0, 0},
  222. {"SelectionClear",   SelectionClear, 0, 0},
  223. {"SelClr",         SelectionClear, 0, 0},
  224. {"SelectionRequest", SelectionRequest, 0, 0},
  225. {"SelReq",         SelectionRequest, 0, 0},
  226. {"SelectionNotify",  SelectionNotify, 0, 0},
  227. {"Select",         SelectionNotify, 0, 0},
  228. {"ColormapNotify",   ColormapNotify, 0, 0},
  229. {"Clrmap",         ColormapNotify, 0, 0},
  230. {"ClientMessage",    ClientMessage, 0, 0},
  231. {"Message",         ClientMessage, 0, 0},
  232. {"MappingNotify",    MappingNotify, 0, 0},
  233. {"Mapping",         MappingNotify, 0, 0},
  234. {NULL,             0, 0, 0}
  235. };
  236.  
  237. /*    -    -    -    -    -    -    -    -    */
  238.  
  239. static unsigned int
  240. lookup(table,name)
  241. NameValue *table;
  242. char *name;
  243. {
  244.     while (table->name != NULL && strcasecmp(name,table->name) != 0)
  245.     table += 1;
  246.     return(table->value);
  247. }
  248.  
  249. char *
  250. parseEventList(str,evp)
  251. char *str;
  252. EventListPtr *evp;
  253. {
  254.     EventListPtr ev,end;
  255.  
  256.     *evp == NULL;
  257.     while (*str) {
  258.     str = parseEvent(str,&ev);
  259.     if (ev != NULL)
  260.         if (*evp == NULL)
  261.         end = *evp = ev;
  262.         else
  263.         end = end->next = ev;    /* wow! */
  264.     else
  265.         return(str);
  266.     if (*str && *str != ',') {
  267.         parseError("',' expected",str);
  268.         return(str);
  269.     } else if (*str)
  270.        str += 1;        /* skip comma */
  271.     }
  272.     return(str);
  273. }
  274.  
  275. static char *
  276. parseEvent(str,evp)
  277. char *str;
  278. EventListPtr *evp;
  279. {
  280.     unsigned int mods;
  281.     int type,count;
  282.     unsigned int detail;
  283.  
  284.     str = parseMods(str,&mods);
  285.     SKIPWHITE(str);
  286.     if (*str != '<') {
  287.     parseError("'<' expected",str);
  288.     return(str);
  289.     } else
  290.     str += 1;
  291.     str = parseType(str,&type,&mods,&detail);
  292.     if (*str != '>') {
  293.     parseError("'>' expected",str);
  294.     return(str);
  295.     } else
  296.     str += 1;
  297.     SKIPWHITE(str);
  298.     count = 1;        /* default */
  299.     if (*str == '(') {
  300.     str += 1;
  301.     count = (int)strtol(str,&str,0);
  302.     if (count == 0) {
  303.         parseError("count expected",str);
  304.         return(str);
  305.     }
  306.     if (*str != ')')  {
  307.         parseError("')' expected",str);
  308.         return(str);
  309.     } else
  310.         str += 1;
  311.     }
  312.     SKIPWHITE(str);
  313.     *evp = (EventListElem *)malloc(sizeof(EventListElem)); 
  314.     (*evp)->count = count;
  315.     (*evp)->next = NULL;
  316.     str = parseDetail(str,&((*evp)->event),type,mods,detail);
  317.     return(str);
  318. }
  319.  
  320. static char *
  321. parseMods(str,modsp)
  322. char *str;
  323. unsigned int *modsp;
  324. {
  325.     char modstr[32];
  326.     int i;
  327.     unsigned int m;
  328.  
  329.     *modsp = (unsigned int)0;
  330.     while (*str && *str != '<') {
  331.     SKIPWHITE(str);
  332.     i = 0;
  333.     while (isalnum(*str) && i < 30)
  334.         modstr[i++] = *str++;
  335.     if (i == 31)
  336.         parseError("modifier name too long",str);
  337.     modstr[i] = '\0';
  338.     if ((m=lookup(modifiers,modstr)) == 0)
  339.         parseError("unknown modifier",modstr);
  340.     else
  341.         *modsp |= m;
  342.     }
  343.     return(str);
  344. }
  345.  
  346. static char *
  347. parseType(str,typep,modsp,detailp)
  348. char *str;
  349. int *typep;
  350. unsigned int *modsp,*detailp;
  351. {
  352.     char typestr[32];
  353.     int i; 
  354.  
  355.     i = 0;
  356.     while (isalnum(*str) && i < 30)
  357.     typestr[i++] = *str++;
  358.     if (i == 31)
  359.     parseError("event type too long",str);
  360.     typestr[i] = '\0';
  361.     for (i=0; types[i].name!=NULL && strcasecmp(types[i].name,typestr)!=0; i++);
  362.     if (types[i].name == NULL) {
  363.     parseError("unknown event type",typestr);
  364.     *typep = 0;
  365.     } else {
  366.     *typep = types[i].value;
  367.     *detailp = types[i].detail;
  368.     *modsp |= types[i].mods;
  369.     }
  370.     return(str);
  371. }
  372.  
  373. static char *
  374. parseDetail(str,xevp,type,mods,detail)
  375. char *str;
  376. XEvent *xevp;
  377. int type;
  378. unsigned int mods,detail;
  379. {
  380.     char detailstr[256];
  381.     int i;
  382.  
  383.     i = 0;
  384.     while (*str && !(i > 0 && *str == ',') && i < 255)
  385.     detailstr[i++] = *str++;
  386.     if (i == 255)
  387.     parseError("detail too long (truncated)",str);
  388.     detailstr[i] = '\0';
  389.     xevp->type = type;
  390.     switch (type) {
  391.     case KeyPress:
  392.     case KeyRelease: {
  393.         XKeyEvent *xkevp = (XKeyEvent *)xevp;
  394.         KeyCode k;
  395.         char *s = strchr(detailstr,' ');
  396.         if (s != NULL)
  397.         *s++ = '\0';
  398.         k = XKeysymToKeycode(display,XStringToKeysym(detailstr));
  399.         if (detail != 0 && k != 0) {
  400.         parseError("key detail conflict",detailstr);
  401.             xkevp->type = -1;
  402.         break;
  403.         } else if (detail == 0)
  404.             xkevp->keycode = k;
  405.         else
  406.             xkevp->keycode = detail;
  407.         if (s != NULL) {
  408.         xkevp->x = (int)strtol(s,&s,0);
  409.         xkevp->y = (int)strtol(s,&s,0);
  410.         xkevp->x_root = (int)strtol(s,&s,0);
  411.         xkevp->y_root = (int)strtol(s,&s,0);
  412.         }
  413.         xkevp->state = mods;
  414.         xkevp->root = root;
  415.         xkevp->same_screen = True;
  416.         break;
  417.     }
  418.     case ButtonPress:
  419.     case ButtonRelease: {
  420.         XButtonEvent *xbevp = (XButtonEvent *)xevp;
  421.         unsigned b = lookup(buttonNames,detailstr);
  422.         if (*detailstr && b == 0) {
  423.         parseError("bad button detail",detailstr);
  424.         xbevp->type = -1;
  425.         break;
  426.         }
  427.         if (detail != 0 && b != 0) {
  428.         parseError("button detail conflict",detailstr);
  429.             xbevp->button = 0;
  430.         } else if (detail == 0)
  431.             xbevp->button = b;
  432.         else
  433.             xbevp->button = detail;
  434.         xbevp->state = mods;
  435.         xbevp->root = root;
  436.         xbevp->same_screen = True;
  437.         break;
  438.     }
  439.     case MotionNotify: {
  440.         XMotionEvent *xmevp = (XMotionEvent *)xevp;
  441.         xmevp->is_hint = lookup(motionDetails,detailstr);
  442.         if (*detailstr && xmevp->is_hint == 0) {
  443.         parseError("bad motion detail",detailstr);
  444.         xmevp->type = -1;
  445.         }
  446.         xmevp->state = mods;
  447.         xmevp->root = root;
  448.         xmevp->same_screen = True;
  449.         break;
  450.     }
  451.     case EnterNotify:
  452.     case LeaveNotify: {
  453.         XCrossingEvent *xcevp = (XCrossingEvent *)xevp;
  454.         char *s = strchr(detailstr,' ');
  455.         if (s != NULL)
  456.         *s++ = '\0';
  457.         xcevp->mode = lookup(notifyModes,detailstr);
  458.         if (s != NULL)
  459.         xcevp->detail = lookup(notifyDetails,s);
  460.         xcevp->state = mods;
  461.         xcevp->root = root;
  462.         xcevp->same_screen = True;
  463.         break;
  464.     }
  465.     case FocusIn:
  466.     case FocusOut: {
  467.         XFocusChangeEvent *xfcevp = (XFocusChangeEvent *)xevp;
  468.         char *s = strchr(detailstr,' ');
  469.         if (s != NULL)
  470.         *s++ = '\0';
  471.         xfcevp->mode = lookup(notifyModes,detailstr);
  472.         if (s != NULL)
  473.             xfcevp->detail = lookup(notifyDetails,s);
  474.         if (*detailstr && xfcevp->mode == 0 && xfcevp->detail == 0) {
  475.         parseError("bad focus mode or detail",detailstr);
  476.         xfcevp->type = -1;
  477.         }
  478.         break;
  479.     }
  480.     case KeymapNotify: {
  481.         XKeymapEvent *xkevp = (XKeymapEvent *)xevp;
  482.         int i;
  483.         char *s = detailstr;
  484.         for (i=0; i < 32; i++)
  485.         xkevp->key_vector[i] = (char)strtol(s,&s,0);
  486.         break;
  487.     }
  488.     case Expose: {
  489.         XExposeEvent *xeevp = (XExposeEvent *)xevp;
  490.         char *s = detailstr;
  491.         xeevp->x = (int)strtol(s,&s,0);
  492.         xeevp->y = (int)strtol(s,&s,0);
  493.         xeevp->width = (int)strtol(s,&s,0);
  494.         xeevp->height = (int)strtol(s,&s,0);
  495.         xeevp->count = (int)strtol(s,&s,0);
  496.         break;
  497.     }
  498.     case GraphicsExpose: {
  499.         XGraphicsExposeEvent *xgevp = (XGraphicsExposeEvent *)xevp;
  500.         char *s = detailstr;
  501.         xgevp->x = (int)strtol(s,&s,0);
  502.         xgevp->y = (int)strtol(s,&s,0);
  503.         xgevp->width = (int)strtol(s,&s,0);
  504.         xgevp->height = (int)strtol(s,&s,0);
  505.         xgevp->count = (int)strtol(s,&s,0);
  506.         xgevp->major_code = (int)strtol(s,&s,0);
  507.         xgevp->minor_code = (int)strtol(s,&s,0);
  508.         break;
  509.     }
  510.     case NoExpose: {
  511.         XNoExposeEvent *xnevp = (XNoExposeEvent *)xevp;
  512.         char *s = detailstr;
  513.         xnevp->major_code = (int)strtol(s,&s,0);
  514.         xnevp->minor_code = (int)strtol(s,&s,0);
  515.         break;
  516.     }
  517.     case CirculateNotify:
  518.     case CirculateRequest: {
  519.         XCirculateEvent *xcevp = (XCirculateEvent *)xevp;
  520.         if ((xcevp->place=lookup(circulateDetails,detailstr)) == 99) {
  521.         parseError("bad circulate detail",detailstr);
  522.         xcevp->type = -1;
  523.         }
  524.         break;
  525.     }
  526.     case ConfigureNotify:
  527.     case ConfigureRequest: {
  528.         XConfigureEvent *xcevp = (XConfigureEvent *)xevp;
  529.         char *s = detailstr;
  530.         xcevp->x = (int)strtol(s,&s,0);
  531.         xcevp->y = (int)strtol(s,&s,0);
  532.         xcevp->width = (int)strtol(s,&s,0);
  533.         xcevp->height = (int)strtol(s,&s,0);
  534.         xcevp->border_width = (int)strtol(s,&s,0);
  535.         xcevp->above = (Window)strtol(s,&s,0);
  536.         SKIPWHITE(s);
  537.         xcevp->override_redirect=lookup(booleans,s);
  538.         break;
  539.     }
  540.     case CreateNotify: {
  541.         XCreateWindowEvent *xcevp = (XCreateWindowEvent *)xevp;
  542.         char *s = detailstr;
  543.         xcevp->x = (int)strtol(s,&s,0);
  544.         xcevp->y = (int)strtol(s,&s,0);
  545.         xcevp->width = (int)strtol(s,&s,0);
  546.         xcevp->height = (int)strtol(s,&s,0);
  547.         xcevp->border_width = (int)strtol(s,&s,0);
  548.         SKIPWHITE(s);
  549.         xcevp->override_redirect=lookup(booleans,s);
  550.         break;
  551.     }
  552.     case DestroyNotify: {
  553.         XDestroyWindowEvent *xdevp = (XDestroyWindowEvent *)xevp;
  554.         xdevp->window = (Window)strtol(detailstr,NULL,0);
  555.         break;
  556.     }
  557.     case GravityNotify: {
  558.         XGravityEvent *xgevp = (XGravityEvent *)xevp;
  559.         char *s = detailstr;
  560.         xgevp->x = (int)strtol(s,&s,0);
  561.         xgevp->y = (int)strtol(s,&s,0);
  562.         break;
  563.     }
  564.     case MapNotify:
  565.     case MapRequest: {
  566.         XMapEvent *xmevp = (XMapEvent *)xevp;
  567.         xmevp->override_redirect = lookup(booleans,detailstr);
  568.         break;
  569.     }
  570.     case MappingNotify: {
  571.         XMappingEvent *xmevp = (XMappingEvent *)xevp;
  572.         char *s=strchr(detailstr,' ');
  573.         if (s != NULL)
  574.         *s++ = '\0';
  575.         if ((xmevp->request=lookup(mappingDetails,detailstr)) == 0) {
  576.         parseError("bad mapping detail",detailstr);
  577.         xmevp->type = -1;
  578.         }
  579.         if (xmevp->request == MappingKeyboard && s != NULL) {
  580.         SKIPWHITE(s);
  581.         xmevp->first_keycode = (int)strtol(s,&s,0);
  582.         xmevp->count = (int)strtol(s,&s,0);
  583.         }
  584.         break;
  585.     }
  586.     case ReparentNotify: {
  587.         XReparentEvent *xrevp = (XReparentEvent *)xevp;
  588.         char *s = strchr(detailstr,' ');
  589.         if (s != NULL)
  590.         *s++ = '\0';
  591.         xrevp->parent = (Window)strtol(detailstr,NULL,0);
  592.         if (s != NULL) {
  593.         SKIPWHITE(s);
  594.         xrevp->x = (int)strtol(s,&s,0);
  595.         xrevp->y = (int)strtol(s,&s,0);
  596.         SKIPWHITE(s);
  597.         xrevp->override_redirect = lookup(booleans,s);
  598.         }
  599.         break;
  600.     }
  601.     case UnmapNotify: {
  602.         XUnmapEvent *xuevp = (XUnmapEvent *)xevp;
  603.         xuevp->from_configure = lookup(booleans,detailstr);
  604.         break;
  605.     }
  606.     case VisibilityNotify: {
  607.         XVisibilityEvent *xvevp = (XVisibilityEvent *)xevp;
  608.         xvevp->state = lookup(visibilityDetails,detailstr);
  609.         break;
  610.     }
  611.     case ResizeRequest: {
  612.         XResizeRequestEvent *xrevp = (XResizeRequestEvent *)xevp;
  613.         char *s = detailstr;
  614.         xrevp->width = (int)strtol(s,&s,0);
  615.         xrevp->height = (int)strtol(s,&s,0);
  616.         break;
  617.     }
  618.     case ColormapNotify:
  619.         parseError("can't handle ColormapNotify events","");
  620.         xevp->type = -1;
  621.         break;
  622.     case ClientMessage: {
  623.         XClientMessageEvent *xcevp = (XClientMessageEvent *)xevp;
  624.         char *s = strchr(detailstr,' ');
  625.         int i;
  626.         if (*detailstr == '\0') {
  627.         parseError("missing atom for client message","");
  628.         xcevp->type = -1;
  629.         break;
  630.         }
  631.         if (s != NULL)
  632.         *s++ = '\0';
  633.         xcevp->message_type = XInternAtom(display,detailstr,True);
  634.         if (s != NULL) {
  635.         SKIPWHITE(s);
  636.         if (*s == 'b') {
  637.             xcevp->format = 8;
  638.             SKIPWHITE(s);
  639.             for (i=0; i < 20; i++)
  640.             xcevp->data.b[i] = (char)strtol(s,&s,0);
  641.         } else if (*s == 'c') {
  642.             xcevp->format = 8;
  643.             SKIPWHITE(s);
  644.             for (i=0; i < 20; i++)
  645.             xcevp->data.b[i] = *s++;
  646.         } else if (*s == 's') {
  647.             xcevp->format = 16;
  648.             SKIPWHITE(s);
  649.             for (i=0; i < 10; i++)
  650.             xcevp->data.s[i] = (short)strtol(s,&s,0);
  651.         } else if (*s == 'l') {
  652.             xcevp->format = 32;
  653.             SKIPWHITE(s);
  654.             for (i=0; i < 5; i++)
  655.             xcevp->data.l[i] = strtol(s,&s,0);
  656.         }
  657.         }
  658.     }
  659.     case PropertyNotify: {
  660.         XPropertyEvent *xpevp = (XPropertyEvent *)xevp;
  661.         char *s = strchr(detailstr,' ');
  662.         if (*detailstr == '\0') {
  663.         parseError("missing atom for property notify","");
  664.         xpevp->type = -1;
  665.         break;
  666.         }
  667.         if (s != NULL)
  668.         *s++ = '\0';
  669.         xpevp->atom = XInternAtom(display,detailstr,True);
  670.         if (s != NULL) {
  671.         SKIPWHITE(s);
  672.         xpevp->state = lookup(propertyDetails,s);
  673.         }
  674.         xpevp->time = CurrentTime;
  675.         break;
  676.     }
  677.     case SelectionClear: {
  678.         XSelectionClearEvent *xsevp = (XSelectionClearEvent *)xevp;
  679.         if (*detailstr == '\0') {
  680.         parseError("missing atom for selection clear","");
  681.         xsevp->type = -1;
  682.         break;
  683.         }
  684.         xsevp->selection = XInternAtom(display,detailstr,True);
  685.         xsevp->time = CurrentTime;
  686.         break;
  687.     }
  688.     /* Note SelectionRequest and Selection are identical except the
  689.        event types have different structures (and different errors). */
  690.     case SelectionRequest: {
  691.         XSelectionRequestEvent *xsevp = (XSelectionRequestEvent *)xevp;
  692.         char *s1 = detailstr;
  693.         char *s2,*s3;
  694.         if (*s1 == '\0') {
  695.         parseError("missing atom for selection request (selection)","");
  696.         xsevp->type = -1;
  697.         break;
  698.         }
  699.         if ((s2=strchr(s1,' ')) == NULL) {
  700.         parseError("missing atom for selection request (target)","");
  701.         xsevp->type = -1;
  702.         break;
  703.         }
  704.         *s2++ = '\0';
  705.         SKIPWHITE(s2);
  706.         if ((s3=strchr(s2,' ')) == NULL) {
  707.         parseError("missing atom for selection request (property)","");
  708.         xsevp->type = -1;
  709.         break;
  710.         }
  711.         *s3++ = '\0';
  712.         SKIPWHITE(s3);
  713.         xsevp->selection = XInternAtom(display,s1,True);
  714.         xsevp->target = XInternAtom(display,s2,True);
  715.         if (*s3 == '\0' || strcasecmp(s3,"None") == 0)
  716.         xsevp->property = None;
  717.         else
  718.         xsevp->property = XInternAtom(display,s3,True);
  719.         xsevp->time = CurrentTime;
  720.     }
  721.     case SelectionNotify: {
  722.         XSelectionEvent *xsevp = (XSelectionEvent *)xevp;
  723.         char *s1 = detailstr;
  724.         char *s2,*s3;
  725.         if (*s1 == '\0') {
  726.         parseError("missing atom for selection notify (selection)","");
  727.         xsevp->type = -1;
  728.         break;
  729.         }
  730.         if ((s2=strchr(s1,' ')) == NULL) {
  731.         parseError("missing atom for selection notify (target)","");
  732.         xsevp->type = -1;
  733.         break;
  734.         }
  735.         *s2++ = '\0';
  736.         SKIPWHITE(s2);
  737.         if ((s3=strchr(s2,' ')) == NULL) {
  738.         parseError("missing atom for selection notify (property)","");
  739.         xsevp->type = -1;
  740.         break;
  741.         }
  742.         *s3++ = '\0';
  743.         SKIPWHITE(s3);
  744.         xsevp->selection = XInternAtom(display,s1,True);
  745.         xsevp->target = XInternAtom(display,s2,True);
  746.         if (*s3 == '\0' || strcasecmp(s3,"None") == 0)
  747.         xsevp->property = None;
  748.         else
  749.         xsevp->property = XInternAtom(display,s3,True);
  750.         xsevp->time = CurrentTime;
  751.     }
  752.     default:
  753.         parseError("don't understand event type\n","");
  754.         xevp->type = -1;
  755.     }
  756.     return(str);
  757. }
  758.  
  759. static void
  760. parseError(s1,s2)
  761. char *s1,*s2;
  762. {
  763.     if (*s2 == '\0')
  764.     fprintf(stderr,"xse: %s\n",s1);
  765.     else
  766.     fprintf(stderr,"xse: %s: \"%s\"\n",s1,s2);
  767. }
  768.  
  769. void
  770. freeEventList(p)
  771. EventListPtr p;
  772. {
  773.     EventListPtr q;
  774.  
  775.     while (p != NULL) {
  776.     q = p;
  777.     p = p->next;
  778.     free(q);
  779.     }
  780. }
  781.