home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume6 / wsxc2 / part03 / WsCvtStrToCallback.c < prev    next >
C/C++ Source or Header  |  1990-04-26  |  12KB  |  370 lines

  1. /*
  2. *******************************************************************************
  3. * Copyright 1990 by Auto-trol Technology Corporation, Denver, Colorado.
  4. *
  5. *                        All Rights Reserved
  6. *
  7. * Permission to use, copy, modify, and distribute this software and its
  8. * documentation for any purpose and without fee is hereby granted, provided
  9. * that the above copyright notice appears on all copies and that both the
  10. * copyright and this permission notice appear in supporting documentation
  11. * and that the name of Auto-trol not be used in advertising or publicity
  12. * pertaining to distribution of the software without specific, prior written
  13. * permission.
  14. * Auto-trol disclaims all warranties with regard to this software, including
  15. * all implied warranties of merchantability and fitness, in no event shall
  16. * Auto-trol be liable for any special, indirect or consequential damages or
  17. * any damages whatsoever resulting from loss of use, data or profits, whether 
  18. * in an action of contract, negligence or other tortious action, arising out 
  19. * of or in connection with the use or performance of this software.
  20. *
  21. * SCCS_data: @(#)WsCvtStrToCallback.c 1.2(4/18/90)
  22. *
  23. * Module_name:
  24. *
  25. *     WsCvtStrToCallback
  26. *
  27. * Subsystem_group:
  28. *
  29. *     Window System, Widget Set, Converters
  30. *
  31. * Related_keywords: 
  32. *
  33. *     Converter
  34. *
  35. * Module_description:
  36. *
  37. *     This module contains the String To Callback X resource converter.
  38. *
  39. *     The converter parses the resource string in the format:
  40. *
  41. *       ...path:   name[(args)][,name[(args)]]...
  42. *
  43. *     where:  name:   specifies the registered callback function name
  44. *             args:   specifies the string passed to a callback as
  45. *              "client data".
  46. *
  47. *     Multiple callbacks can be specified for a single callback list
  48. *     resource.  Any callbacks must be "registered" by the application
  49. *     prior converter invocation (.i.e.prior widget creation).
  50. *     If no "args" string is provided, the default "client data" 
  51. *     specified at callback registration are used.
  52. *
  53. * Module_interface_summary: 
  54. *
  55. *
  56. *     Resource converter is invoked indirectly by the toolkit. The
  57. *     converter is added to the toolkit by widgets calling
  58. *     WsAddStrToCallbackP() in the widget intialization code.
  59. *
  60. *     To register application callbacks, use:
  61. *
  62. *     WsRegisterCallback ( 
  63. *        WsAppContext    app,    - application context
  64. *        String        name,    - register name, case insensitive
  65. *        Callback        callback,    - callback function pointer
  66. *        ClientData      closure )    - default client data
  67. *
  68. * Module_history:
  69. *                                                  
  70. *   mm/dd/yy  initials  function  action
  71. *   --------  --------  --------  ---------------------------------------------
  72. *   04/03/90  MarBru    CvtStr..  Fixed argument termination with a NUL char
  73. *   02/26/90  MarBru    All       Created
  74. *
  75. * Design_notes:
  76. *
  77. *   For VMS, we could have used LIB$FIND_IMAGE_SYMBOL and use dynamic
  78. *   (runtime) binding. But since most UNIX systems lack such capability,
  79. *   we stick to the concept of "registration" routines.
  80. *
  81. *   One time, I considered applying conversion to callback argument, which
  82. *   would take the burden of conversion from the callback code (runtime)
  83. *   to the callback  conversion (one time initialization). The problem is
  84. *   that some conversions are widget context specific (color to pixel needs
  85. *   display connection), and at the time of callback conversion I do not
  86. *   have a widget. I could require the widget argument, but this would kill
  87. *   caching of the conversion result.
  88. *
  89. *   The sequential search of the callback cache is far from optimal. I should
  90. *   use binary search, or some of the R4 conversion support code.
  91. *   
  92. *******************************************************************************
  93. */
  94. /*
  95. *******************************************************************************
  96. * Include_files.
  97. *******************************************************************************
  98. */
  99.  
  100. /*  -- Operating system includes */
  101. #include <X11/Xos.h>
  102. #include <ctype.h>
  103.  
  104. /*  -- X Window System includes */
  105. #include <X11/IntrinsicP.h>
  106. #include <X11/StringDefs.h> 
  107.  
  108. /*  -- Auto-trol Window System includes */
  109.  
  110. /*
  111. *******************************************************************************
  112. * Private_constant_declarations.
  113. *******************************************************************************
  114. */
  115. #undef  NUL
  116. #define NUL '\0'
  117.  
  118. /*
  119. *******************************************************************************
  120. * Private_type_declarations.
  121. *******************************************************************************
  122. */
  123. #define MAX_XRMSTRING  1024        /* max length of the DB string        */
  124. #define MAX_CALLBACKS    64        /* max number of callbacks per list */
  125. #define ADD_CALLBACKS     16             /* increment of callback cache size */
  126.  
  127. /*
  128. *******************************************************************************
  129. * Private_macro_definitions.
  130. *******************************************************************************
  131. */
  132.  
  133. /*
  134. *******************************************************************************
  135. * Private_data_definitions.
  136. *******************************************************************************
  137.     The following cache/registry of known callbacks, initially empty, 
  138.     is loaded by the application using "registration" routines.
  139.     Assuming small numbers of callbacks, the sequential search
  140.     of such cache is (initially) considered acceptable.
  141. */
  142.  
  143. /*  -- Named callback procedures cache, intially empty */
  144.  
  145. typedef struct
  146. {
  147.     XrmQuark       quark;        /* quarkified callback name   */
  148.     XtCallbackProc callback;        /* callback procedure pointer */
  149.     caddr_t        closure;             /* default client data        */
  150. } CBCacheRec;
  151.  
  152.  
  153.  
  154. static int       callbacks_num = 0;
  155. static int       callbacks_max = 0;
  156. static CBCacheRec *callbacks_ptr = NULL;
  157.  
  158.  
  159. /*
  160. *******************************************************************************
  161. * Private_function_declarations.
  162. *******************************************************************************
  163. */
  164.  
  165. /*
  166.     -- Convert String To Callback
  167. *******************************************************************************
  168.     This conversion creates a callback list structure from the X resource
  169.     database string in format:
  170.  
  171.     name(arg),name(arg).....
  172.  
  173.     Note "name" is not case sensitive, while "arg" may be - it is passed to
  174.     a callback as client data as a null terminated string (first level
  175.     parenthesis stripped off).
  176. */
  177. void CvtStringToCallback (args, num_args, fromVal, toVal)
  178.  
  179. XrmValue *args;
  180. Cardinal *num_args;
  181. XrmValue *fromVal;
  182. XrmValue *toVal;
  183. {
  184.     typedef struct 
  185.     {
  186.     char *nsta,*nend;        /* callback name start, end */
  187.     char *asta,*aend;        /* argument string start, end */
  188.     } Segment;
  189.  
  190.     static XtCallbackRec *cb;
  191.     XtCallbackRec      callback_list[MAX_CALLBACKS];
  192.     int                   callback_num = 0;
  193.     String                string = (char *) fromVal->addr;
  194.     Segment               segs[MAX_CALLBACKS];    
  195.     Segment              *seg;
  196.     register char        *s;
  197.     register int          i,ipar;
  198.  
  199. /*  -- assume error or undefined input argument */
  200.     toVal->size = 0;
  201.     toVal->addr = (caddr_t) NULL;
  202.     if (string == NULL) return;
  203.  
  204. /*  -- parse input string finding segments   "name(arg)" comma separated */
  205.     ipar = 0;
  206.     seg  = segs;
  207.     seg->nsta = seg->nend = seg->asta = seg->aend = (char*)NULL;
  208.  
  209.     for ( s=string;  ;  s++ )
  210.     {
  211.     switch (*s)
  212.     {
  213.         case NUL:
  214.     case ',':  if ( ipar > 0 ) break;  /* commas in arguments ignored  */
  215.            if ( seg->nend == NULL ) seg->nend = s-1;  /* no argument */
  216.                seg++;           /* start the next segment */
  217.                seg->nsta = seg->nend = seg->asta = seg->aend = (char*)NULL;
  218.            break;           
  219.  
  220.     case '(':  if ( ipar++ == 0 ) { seg->nend = s-1; seg->asta = s+1; };
  221.                break;
  222.            
  223.     case ')':  if ( --ipar == 0 ) { seg->aend = s-1; };
  224.            break;
  225.  
  226.     default:   if ( *s > ' '  &&  seg->nsta == NULL )
  227.                     seg->nsta = s;   /* only start a new segment on non-blank char*/
  228.  
  229.     }
  230.     if (*s == NUL) break;
  231.     }
  232.     seg++;           /* start the terminating segment */
  233.     seg->nsta = (char*)NULL;
  234.  
  235.     if (ipar)
  236.     {
  237.     XtStringConversionWarning (string, "Callback, unbalanced parenthesis");
  238.     return;
  239.     }
  240.  
  241.  
  242. /*  -- process individual callback string segments "name(arg)" */
  243.     for( seg = segs;  seg->nsta;   seg++)
  244.     {
  245.         char                 cb_name[MAX_XRMSTRING];
  246.     XtCallbackProc       found = (XtCallbackProc)NULL;
  247.     XrmQuark             quark;
  248.     register char    *d;
  249.     register char    *end;
  250.  
  251.     /* our callback cache names are case insensitive, no white space */
  252.     for ( s=seg->nsta, d=cb_name; s<=seg->nend; )
  253.        if ( *s > ' ')
  254.              *d++ = (isupper(*s) ) ? tolower (*s++) : *s++;
  255.        else
  256.           s++;
  257.     *d   = NUL;
  258.  
  259.         /* try to locate callback in our cache of callbacks */
  260.         quark = XrmStringToQuark (cb_name);
  261.     for (i=0; i<callbacks_num; i++)
  262.         if ( callbacks_ptr[i].quark == quark )
  263.         {
  264.             register XtCallbackRec *rec = &callback_list[callback_num];
  265.         rec->callback = found = callbacks_ptr[i].callback;
  266.             rec->closure  = callbacks_ptr[i].closure;
  267.         break;
  268.         }
  269.  
  270.     /* we have found a registered callback, process arguments */
  271.     if (found)
  272.     {
  273.        register char *arg;
  274.        register int   alen;
  275.        register XtCallbackRec *rec = &callback_list[callback_num];
  276.        
  277.        if ( seg->asta )
  278.        {
  279.            alen = (int)seg->aend - (int)seg->asta +1;
  280.            arg  = XtMalloc(alen+1);
  281.            strncpy ( arg, seg->asta, alen );
  282.            arg[alen]    = NUL;
  283.            rec->closure = (caddr_t)arg;
  284.        }
  285.        callback_num++;
  286.         }
  287.     else
  288.     {
  289.            XtStringConversionWarning (cb_name, "Callback, unknown callback name");
  290.     }
  291.     } /* end for seg loop */
  292.  
  293. /*  -- terminate the callback list */
  294.     {
  295.     register XtCallbackRec *rec = &callback_list[callback_num];
  296.         rec->callback = NULL;
  297.     rec->closure  = NULL;
  298.     callback_num++;
  299.     }
  300.  
  301. /*  -- make a permanent copy of the new callback list, and return a pointer */
  302.     cb = (XtCallbackRec*)XtMalloc( callback_num * sizeof (XtCallbackRec) );
  303.     memcpy ( (char*)cb, (char*)callback_list,  
  304.               callback_num * sizeof (XtCallbackRec));
  305.     toVal->size = sizeof (XtCallbackRec*);
  306.     toVal->addr = (caddr_t)&cb;
  307.  
  308. }
  309.  
  310. /*
  311. *******************************************************************************
  312. * Public_function_declarations.
  313. *******************************************************************************
  314. */
  315.  
  316. /*
  317.     -- Add String To Callback Convertor
  318. *******************************************************************************
  319. */
  320.  
  321. void WsAddStringToCallbackP ()
  322. {
  323.     static Boolean added = FALSE;
  324.     if ( !added )
  325.     {
  326.        XtAddConverter    (XtRString, 
  327.                           XtRCallback,
  328.                           CvtStringToCallback,
  329.                           (XtConvertArgList)NULL,
  330.                           (Cardinal)0);
  331.        added = TRUE;
  332.     }
  333. }
  334.  
  335.  
  336. /*
  337.     -- Register callback
  338. *******************************************************************************
  339.     This procedure adds callback procedure/name to our list of registered
  340.     callbacks. So far very simplistic ... without checking for duplicate
  341.     entries, no cache hashing scheme, no ties to app_context.
  342. */
  343. void WsRegisterCallback ( app, name, callback, closure )
  344. XtAppContext    app;        /* not used (yet), must be present      */
  345. String          name;       /* callback name, case insensitive      */
  346. XtCallbackProc  callback;   /* callback function pointer            */
  347. caddr_t         closure;    /* default closure (client data)        */
  348. {
  349.     char           cb_name[MAX_XRMSTRING];
  350.     CBCacheRec    *rec;
  351.     register char *s;
  352.     register char *d;
  353.  
  354.     for ( d=cb_name, s=name; *s; s++)
  355.          *d++ = (isupper(*s)) ? tolower (*s) : *s;
  356.     *d = '\0';
  357.  
  358.     if (callbacks_num >= callbacks_max )
  359.     {
  360.     callbacks_max += ADD_CALLBACKS;
  361.     callbacks_ptr  = (CBCacheRec*) XtRealloc((char*)callbacks_ptr, 
  362.                       sizeof(CBCacheRec) * callbacks_max);
  363.     }
  364.     rec = &callbacks_ptr[callbacks_num++];
  365.     rec->quark    = XrmStringToQuark ( cb_name );
  366.     rec->callback = callback;
  367.     rec->closure  = closure;
  368. }
  369.