home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
x
/
volume6
/
wsxc2
/
part03
/
WsCvtStrToCallback.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-04-26
|
12KB
|
370 lines
/*
*******************************************************************************
* Copyright 1990 by Auto-trol Technology Corporation, Denver, Colorado.
*
* All Rights Reserved
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appears on all copies and that both the
* copyright and this permission notice appear in supporting documentation
* and that the name of Auto-trol not be used in advertising or publicity
* pertaining to distribution of the software without specific, prior written
* permission.
*
* Auto-trol disclaims all warranties with regard to this software, including
* all implied warranties of merchantability and fitness, in no event shall
* Auto-trol be liable for any special, indirect or consequential damages or
* any damages whatsoever resulting from loss of use, data or profits, whether
* in an action of contract, negligence or other tortious action, arising out
* of or in connection with the use or performance of this software.
*
* SCCS_data: @(#)WsCvtStrToCallback.c 1.2(4/18/90)
*
* Module_name:
*
* WsCvtStrToCallback
*
* Subsystem_group:
*
* Window System, Widget Set, Converters
*
* Related_keywords:
*
* Converter
*
* Module_description:
*
* This module contains the String To Callback X resource converter.
*
* The converter parses the resource string in the format:
*
* ...path: name[(args)][,name[(args)]]...
*
* where: name: specifies the registered callback function name
* args: specifies the string passed to a callback as
* "client data".
*
* Multiple callbacks can be specified for a single callback list
* resource. Any callbacks must be "registered" by the application
* prior converter invocation (.i.e.prior widget creation).
* If no "args" string is provided, the default "client data"
* specified at callback registration are used.
*
* Module_interface_summary:
*
*
* Resource converter is invoked indirectly by the toolkit. The
* converter is added to the toolkit by widgets calling
* WsAddStrToCallbackP() in the widget intialization code.
*
* To register application callbacks, use:
*
* WsRegisterCallback (
* WsAppContext app, - application context
* String name, - register name, case insensitive
* Callback callback, - callback function pointer
* ClientData closure ) - default client data
*
* Module_history:
*
* mm/dd/yy initials function action
* -------- -------- -------- ---------------------------------------------
* 04/03/90 MarBru CvtStr.. Fixed argument termination with a NUL char
* 02/26/90 MarBru All Created
*
* Design_notes:
*
* For VMS, we could have used LIB$FIND_IMAGE_SYMBOL and use dynamic
* (runtime) binding. But since most UNIX systems lack such capability,
* we stick to the concept of "registration" routines.
*
* One time, I considered applying conversion to callback argument, which
* would take the burden of conversion from the callback code (runtime)
* to the callback conversion (one time initialization). The problem is
* that some conversions are widget context specific (color to pixel needs
* display connection), and at the time of callback conversion I do not
* have a widget. I could require the widget argument, but this would kill
* caching of the conversion result.
*
* The sequential search of the callback cache is far from optimal. I should
* use binary search, or some of the R4 conversion support code.
*
*******************************************************************************
*/
/*
*******************************************************************************
* Include_files.
*******************************************************************************
*/
/* -- Operating system includes */
#include <X11/Xos.h>
#include <ctype.h>
/* -- X Window System includes */
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
/* -- Auto-trol Window System includes */
/*
*******************************************************************************
* Private_constant_declarations.
*******************************************************************************
*/
#undef NUL
#define NUL '\0'
/*
*******************************************************************************
* Private_type_declarations.
*******************************************************************************
*/
#define MAX_XRMSTRING 1024 /* max length of the DB string */
#define MAX_CALLBACKS 64 /* max number of callbacks per list */
#define ADD_CALLBACKS 16 /* increment of callback cache size */
/*
*******************************************************************************
* Private_macro_definitions.
*******************************************************************************
*/
/*
*******************************************************************************
* Private_data_definitions.
*******************************************************************************
The following cache/registry of known callbacks, initially empty,
is loaded by the application using "registration" routines.
Assuming small numbers of callbacks, the sequential search
of such cache is (initially) considered acceptable.
*/
/* -- Named callback procedures cache, intially empty */
typedef struct
{
XrmQuark quark; /* quarkified callback name */
XtCallbackProc callback; /* callback procedure pointer */
caddr_t closure; /* default client data */
} CBCacheRec;
static int callbacks_num = 0;
static int callbacks_max = 0;
static CBCacheRec *callbacks_ptr = NULL;
/*
*******************************************************************************
* Private_function_declarations.
*******************************************************************************
*/
/*
-- Convert String To Callback
*******************************************************************************
This conversion creates a callback list structure from the X resource
database string in format:
name(arg),name(arg).....
Note "name" is not case sensitive, while "arg" may be - it is passed to
a callback as client data as a null terminated string (first level
parenthesis stripped off).
*/
void CvtStringToCallback (args, num_args, fromVal, toVal)
XrmValue *args;
Cardinal *num_args;
XrmValue *fromVal;
XrmValue *toVal;
{
typedef struct
{
char *nsta,*nend; /* callback name start, end */
char *asta,*aend; /* argument string start, end */
} Segment;
static XtCallbackRec *cb;
XtCallbackRec callback_list[MAX_CALLBACKS];
int callback_num = 0;
String string = (char *) fromVal->addr;
Segment segs[MAX_CALLBACKS];
Segment *seg;
register char *s;
register int i,ipar;
/* -- assume error or undefined input argument */
toVal->size = 0;
toVal->addr = (caddr_t) NULL;
if (string == NULL) return;
/* -- parse input string finding segments "name(arg)" comma separated */
ipar = 0;
seg = segs;
seg->nsta = seg->nend = seg->asta = seg->aend = (char*)NULL;
for ( s=string; ; s++ )
{
switch (*s)
{
case NUL:
case ',': if ( ipar > 0 ) break; /* commas in arguments ignored */
if ( seg->nend == NULL ) seg->nend = s-1; /* no argument */
seg++; /* start the next segment */
seg->nsta = seg->nend = seg->asta = seg->aend = (char*)NULL;
break;
case '(': if ( ipar++ == 0 ) { seg->nend = s-1; seg->asta = s+1; };
break;
case ')': if ( --ipar == 0 ) { seg->aend = s-1; };
break;
default: if ( *s > ' ' && seg->nsta == NULL )
seg->nsta = s; /* only start a new segment on non-blank char*/
}
if (*s == NUL) break;
}
seg++; /* start the terminating segment */
seg->nsta = (char*)NULL;
if (ipar)
{
XtStringConversionWarning (string, "Callback, unbalanced parenthesis");
return;
}
/* -- process individual callback string segments "name(arg)" */
for( seg = segs; seg->nsta; seg++)
{
char cb_name[MAX_XRMSTRING];
XtCallbackProc found = (XtCallbackProc)NULL;
XrmQuark quark;
register char *d;
register char *end;
/* our callback cache names are case insensitive, no white space */
for ( s=seg->nsta, d=cb_name; s<=seg->nend; )
if ( *s > ' ')
*d++ = (isupper(*s) ) ? tolower (*s++) : *s++;
else
s++;
*d = NUL;
/* try to locate callback in our cache of callbacks */
quark = XrmStringToQuark (cb_name);
for (i=0; i<callbacks_num; i++)
if ( callbacks_ptr[i].quark == quark )
{
register XtCallbackRec *rec = &callback_list[callback_num];
rec->callback = found = callbacks_ptr[i].callback;
rec->closure = callbacks_ptr[i].closure;
break;
}
/* we have found a registered callback, process arguments */
if (found)
{
register char *arg;
register int alen;
register XtCallbackRec *rec = &callback_list[callback_num];
if ( seg->asta )
{
alen = (int)seg->aend - (int)seg->asta +1;
arg = XtMalloc(alen+1);
strncpy ( arg, seg->asta, alen );
arg[alen] = NUL;
rec->closure = (caddr_t)arg;
}
callback_num++;
}
else
{
XtStringConversionWarning (cb_name, "Callback, unknown callback name");
}
} /* end for seg loop */
/* -- terminate the callback list */
{
register XtCallbackRec *rec = &callback_list[callback_num];
rec->callback = NULL;
rec->closure = NULL;
callback_num++;
}
/* -- make a permanent copy of the new callback list, and return a pointer */
cb = (XtCallbackRec*)XtMalloc( callback_num * sizeof (XtCallbackRec) );
memcpy ( (char*)cb, (char*)callback_list,
callback_num * sizeof (XtCallbackRec));
toVal->size = sizeof (XtCallbackRec*);
toVal->addr = (caddr_t)&cb;
}
/*
*******************************************************************************
* Public_function_declarations.
*******************************************************************************
*/
/*
-- Add String To Callback Convertor
*******************************************************************************
*/
void WsAddStringToCallbackP ()
{
static Boolean added = FALSE;
if ( !added )
{
XtAddConverter (XtRString,
XtRCallback,
CvtStringToCallback,
(XtConvertArgList)NULL,
(Cardinal)0);
added = TRUE;
}
}
/*
-- Register callback
*******************************************************************************
This procedure adds callback procedure/name to our list of registered
callbacks. So far very simplistic ... without checking for duplicate
entries, no cache hashing scheme, no ties to app_context.
*/
void WsRegisterCallback ( app, name, callback, closure )
XtAppContext app; /* not used (yet), must be present */
String name; /* callback name, case insensitive */
XtCallbackProc callback; /* callback function pointer */
caddr_t closure; /* default closure (client data) */
{
char cb_name[MAX_XRMSTRING];
CBCacheRec *rec;
register char *s;
register char *d;
for ( d=cb_name, s=name; *s; s++)
*d++ = (isupper(*s)) ? tolower (*s) : *s;
*d = '\0';
if (callbacks_num >= callbacks_max )
{
callbacks_max += ADD_CALLBACKS;
callbacks_ptr = (CBCacheRec*) XtRealloc((char*)callbacks_ptr,
sizeof(CBCacheRec) * callbacks_max);
}
rec = &callbacks_ptr[callbacks_num++];
rec->quark = XrmStringToQuark ( cb_name );
rec->callback = callback;
rec->closure = closure;
}