diff options
Diffstat (limited to 'xpa/tclloop.c')
-rw-r--r-- | xpa/tclloop.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/xpa/tclloop.c b/xpa/tclloop.c new file mode 100644 index 0000000..a8b4ac5 --- /dev/null +++ b/xpa/tclloop.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +#if HAVE_TCL + +#include <tcl.h> + +/* We build XPA on Windows using Cygwin and, for convenience, we sense the + presence of Windows by the presence of Cygwin. This is important for Tcl + because Windows does not support Tcl_CreateFileHandler */ +#ifndef HAVE_TCLFILEHANDLER +#if HAVE_CYGWIN|HAVE_MINGW32 +#define HAVE_TCLFILEHANDLER 0 +#else +#define HAVE_TCLFILEHANDLER 1 +#endif +#endif + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +#define TCL_SOCKET TCL_UNIX_FD + +/* + * + * record struct for maintining Tcl info in Tcl select loop + * + */ +typedef struct xpatclrec{ + Tcl_Event header; + int fd; + void *client_data; +} *XPATcl, XPATclRec; + + +#if HAVE_TCLFILEHANDLER +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclHandler + * + * Purpose: handle one request for an xpaset or xpaget + * + * Return: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPATclHandler (ClientData client_data, int mask) +#else +static void XPATclHandler(client_data, mask) + ClientData client_data; + int mask; +#endif +{ + XPATcl xptr = (XPATcl)client_data; + if( (xptr == NULL) || (xptr->client_data == NULL) ) + return; + XPAHandler((XPA)xptr->client_data, xptr->fd); +} + +#else + +#define TCL_BLOCKTIME_SEC 0 +#define TCL_BLOCKTIME_USEC 1000 + +/* + *---------------------------------------------------------------------- + * + * XPAEventProc -- + * + * This procedure is called by Tcl_ServiceEvent when an XPA event + * reaches the front of the event queue. This procedure is + * responsible for notifying the generic channel code. + * + * Results: + * Returns 1 if the event was handled, meaning it should be removed + * from the queue. Returns 0 if the event was not handled, meaning + * it should stay on the queue. The only time the event isn't + * handled is if the TCL_FILE_EVENTS flag bit isn't set. + * + * Side effects: + * Whatever the channel callback procedures do. + * + *---------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAEventProc(Tcl_Event *evPtr, int flags) +#else +static int +XPAEventProc(evPtr, flags) + Tcl_Event *evPtr; /* Event to service. */ + int flags; /* Flags that indicate what events to + * handle, such as TCL_FILE_EVENTS. */ +#endif +{ + XPATcl xptr = (XPATcl)evPtr; + if( xptr && xptr->client_data ) + XPAHandler((XPA)xptr->client_data, xptr->fd); + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * XPASetupProc -- + * + * This procedure is invoked before Tcl_DoOneEvent blocks waiting + * for an event. + * + * Results: + * None. + * + * Side effects: + * Adjusts the block time if needed. + * + *---------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPASetupProc(ClientData data, int flags) +#else +static void +XPASetupProc(data, flags) + ClientData data; + int flags; +#endif +{ + Tcl_Time blockTime = { TCL_BLOCKTIME_SEC, TCL_BLOCKTIME_USEC }; + + Tcl_SetMaxBlockTime(&blockTime); + return; +} + +/* + *---------------------------------------------------------------------- + * + * XPACheckProc -- + * + * This procedure is called by Tcl_DoOneEvent to check the XPA + * event source for events. + * + * Results: + * None. + * + * Side effects: + * May queue an event. + * + *---------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPACheckProc(ClientData data, int flags) +#else +static void +XPACheckProc(data, flags) + ClientData data; + int flags; +#endif +{ + XPATcl xptr = (XPATcl)data; + XPATcl evPtr; + fd_set readfds; + struct timeval tv; + int got; + +again: + FD_ZERO(&readfds); + if( XPAActiveFd(xptr->fd) ){ + FD_SET(xptr->fd, &readfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + got = xselect(xptr->fd+1, &readfds, NULL, NULL, &tv); + if( got < 0 ){ + if( errno == EINTR ) + goto again; + perror("xpa select event"); + Tcl_DeleteEventSource(XPASetupProc, XPACheckProc, xptr); + } + else if( got ){ + evPtr = (XPATcl)Tcl_Alloc(sizeof(XPATclRec)); + memcpy(evPtr, xptr, sizeof(XPATclRec)); + evPtr->header.proc = XPAEventProc; + Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); + } + } +} +#endif + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclEnableOneInput + * + * Purpose: Enable 1 XPA entry from the Tcl event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPATclEnableOneInput (void *client_data) +#else +static void XPATclEnableOneInput(client_data) + void *client_data; +#endif +{ + XPATcl xptr = (XPATcl)client_data; + if( xptr == NULL ) + return; +#if HAVE_TCLFILEHANDLER + Tcl_CreateFileHandler(xptr->fd, TCL_READABLE, XPATclHandler, xptr); +#else + Tcl_CreateEventSource(XPASetupProc, XPACheckProc, xptr); +#endif +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclDisableOneInput + * + * Purpose: Disable 1 XPA entry from the Tcl event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPATclDisableOneInput (void *client_data) +#else +static void XPATclDisableOneInput(client_data) + void *client_data; +#endif +{ + XPATcl xptr = (XPATcl)client_data; + if( xptr == NULL ) + return; +#if HAVE_TCLFILEHANDLER + Tcl_CreateFileHandler(xptr->fd, 0, XPATclHandler, xptr->client_data); +#else + Tcl_DeleteEventSource(XPASetupProc, XPACheckProc, xptr); +#endif +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclAddOneInput + * + * Purpose: Add 1 XPA entry to the Tcl event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void * +XPATclAddOneInput (void *client_data, int fd) +#else +static void *XPATclAddOneInput(client_data, fd) + void *client_data; + int fd; +#endif +{ + XPATcl xptr; + if( fd < 0 ) + return(NULL); + xptr = (XPATcl)xcalloc(1, sizeof(XPATclRec)); + xptr->fd = fd; + xptr->client_data = (XPA)client_data; + XPATclEnableOneInput(xptr); + return(xptr); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclDelOneInput + * + * Purpose: Delete 1 XPA entry from the Tcl event loop (called by XPAFree) + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPATclDelOneInput (void *client_data) +#else +static void XPATclDelOneInput(client_data) + void *client_data; +#endif +{ + XPATcl xptr = (XPATcl)client_data; + if( xptr == NULL ) + return; + XPATclDisableOneInput(xptr); + xfree(xptr); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclAddInput + * + * Purpose: Add XPA entries to the Tcl event loop + * + * Results: number of xpa entried added + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPATclAddInput (XPA xpa) +#else +int XPATclAddInput(xpa) + XPA xpa; +#endif +{ + XPA cur; + int got=0; + + /* if a specific xpa was specified, just add it */ + if( xpa != NULL ){ + /* remove old one */ + if( xpa->seldel && xpa->selptr ){ + (xpa->seldel)(xpa->selptr); + } + /* add new one */ + xpa->seladd = XPATclAddOneInput; + xpa->seldel = XPATclDelOneInput; +#if HAVE_TCLFILEHANDLER + xpa->selon = XPATclEnableOneInput; + xpa->seloff = XPATclDisableOneInput; +#endif + xpa->selptr = XPATclAddOneInput((void *)xpa, xpa->fd); + got = 1; + } + /* otherwise set up all xpa's */ + else{ + for(cur=(XPA)XPAListHead(); cur!=NULL; cur=cur->next){ + /* remove old one */ + if( cur->seldel && cur->selptr ){ + (cur->seldel)(cur->selptr); + } + /* add new one */ + cur->seladd = XPATclAddOneInput; + cur->seldel = XPATclDelOneInput; +#if HAVE_TCLFILEHANDLER + cur->selon = XPATclEnableOneInput; + cur->seloff = XPATclDisableOneInput; +#endif + cur->selptr = XPATclAddOneInput((void *)cur, cur->fd); + got++; + } + } + return(got); +} + +int xpa_tcl = 1; + +#else + +int xpa_tcl = 0; + +#endif |