From d5a22b4c586ff61b8c9b0ad2967c1edd69ffc0e9 Mon Sep 17 00:00:00 2001 From: Dan Egnor <egnor@ofb.net> Date: Tue, 18 Sep 2001 22:11:41 +0000 Subject: [PATCH] version 0.8 --- Makefile.am | 8 ++- configure.in | 13 +++- oop-tcl.h | 18 +++++ tcl.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++ test-oop.c | 55 ++++++++++++--- 5 files changed, 272 insertions(+), 13 deletions(-) create mode 100644 oop-tcl.h create mode 100644 tcl.c diff --git a/Makefile.am b/Makefile.am index 65c2393..0ae1eba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ # See the file COPYING for details. AUTOMAKE_OPTIONS = foreign 1.2 -lib_LTLIBRARIES = liboop-adns.la liboop-glib.la liboop-www.la liboop-rl.la liboop.la +lib_LTLIBRARIES = liboop-adns.la liboop-glib.la liboop-tcl.la liboop-www.la liboop-rl.la liboop.la INCLUDES = $(GLIB_INCLUDES) $(WWW_INCLUDES) # versions updated as of 0.7 @@ -22,6 +22,10 @@ liboop_glib_la_LDFLAGS = -version-info 1:0:0 liboop_glib_la_LIBADD = $(GLIB_LIBS) liboop_glib_la_SOURCES = glib.c +liboop_tcl_la_LDFLAGS = -version-info 0:0:0 +liboop_tcl_la_LIBADD = $(TCL_LIBS) +liboop_tcl_la_SOURCES = tcl.c + liboop_www_la_LDFLAGS = -version-info 0:0:0 liboop_www_la_LIBADD = $(WWW_LIBS) liboop_www_la_SOURCES = www.c @@ -30,7 +34,7 @@ liboop_rl_la_LDFLAGS = -version-info 0:0:0 liboop_rl_la_LIBADD = $(READLINE_LIBS) liboop_rl_la_SOURCES = readline.c -include_HEADERS = oop.h oop-adns.h oop-glib.h oop-www.h oop-rl.h oop-read.h +include_HEADERS = oop.h oop-adns.h oop-glib.h oop-tcl.h oop-www.h oop-rl.h oop-read.h noinst_PROGRAMS = test-oop diff --git a/configure.in b/configure.in index 23ac539..8c42094 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(INSTALL) -AM_INIT_AUTOMAKE(liboop,0.7) +AM_INIT_AUTOMAKE(liboop,0.8) AC_CANONICAL_HOST dnl Use libtool for shared libraries @@ -44,6 +44,15 @@ if test -n "$PROG_GLIB_CONFIG" ; then AC_DEFINE(HAVE_GLIB) fi +for version in 8.4 8.3 8.2 8.1 8.0 ; do + AC_CHECK_LIB(tcl$version,Tcl_Main,[ + AC_DEFINE(HAVE_TCL) + TCL_INCLUDES="-I/usr/include/tcl$version" + TCL_LIBS="-ltcl$version" + break + ]) +done + # the libwww RPM puts headers here: AC_CHECK_LIB(wwwcore,HTEvent_setRegisterCallback,[ AC_DEFINE(HAVE_WWW) @@ -66,6 +75,8 @@ CFLAGS="-Wall -Wno-comment -Wmissing-prototypes -Wstrict-prototypes -Wpointer-ar AC_SUBST(PROG_LDCONFIG) AC_SUBST(GLIB_INCLUDES) AC_SUBST(GLIB_LIBS) +AC_SUBST(TCL_INCLUDES) +AC_SUBST(TCL_LIBS) AC_SUBST(ADNS_LIBS) AC_SUBST(WWW_INCLUDES) AC_SUBST(WWW_LIBS) diff --git a/oop-tcl.h b/oop-tcl.h new file mode 100644 index 0000000..f2a339a --- /dev/null +++ b/oop-tcl.h @@ -0,0 +1,18 @@ +/* oop-glib.h, liboop, copyright 1999 Dan Egnor + + This is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License, version 2.1 or later. + See the file COPYING for details. */ + +#ifndef OOP_TCL_H +#define OOP_TCL_H + +#include "oop.h" + +/* Create an event source based on the Tcl event loop. */ +oop_source *oop_tcl_new(void); + +/* Delete the event source so created. (Uses reference counting.) */ +void oop_tcl_done(void); + +#endif diff --git a/tcl.c b/tcl.c new file mode 100644 index 0000000..f1d5c63 --- /dev/null +++ b/tcl.c @@ -0,0 +1,191 @@ +/* glib.c, liboop, copyright 1999 Dan Egnor + + This is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License, version 2.1 or later. + See the file COPYING for details. */ + +#ifdef HAVE_TCL + +#include "oop-tcl.h" +#include <tcl.h> +#include <assert.h> + +struct file_handler { + oop_call_fd *f[OOP_NUM_EVENTS]; + void *d[OOP_NUM_EVENTS]; +}; + +struct timer_handler { + struct timeval t; + oop_call_time *f; + void *d; + Tcl_TimerToken token; + struct timer_handler *next; +}; + +static int use_count = 0; +static struct oop_source source; +static struct oop_adapter_signal *signal; + +static int array_size; +static struct file_handler *array; +static struct timer_handler *list; + +static void file_call(ClientData data,int mask) { + const int fd = (int) data; + oop_source * const oop = oop_tcl_new(); + const struct file_handler *h; + + if (fd >= array_size) { + oop_tcl_done(); + return; + } + + /* BUG: what if !OOP_CONTINUE? */ + + h = &array[fd]; + if ((mask & TCL_READABLE) && NULL != h->f[OOP_READ]) + h->f[OOP_READ](oop,fd,OOP_READ,h->d[OOP_READ]); + + h = &array[fd]; + if ((mask & TCL_WRITABLE) && NULL != h->f[OOP_WRITE]) + h->f[OOP_WRITE](oop,fd,OOP_WRITE,h->d[OOP_WRITE]); + + h = &array[fd]; + if ((mask & TCL_EXCEPTION) && NULL != h->f[OOP_EXCEPTION]) + h->f[OOP_EXCEPTION](oop,fd,OOP_EXCEPTION,h->d[OOP_EXCEPTION]); + + oop_tcl_done(); +} + +static void set_mask(int fd) { + int mask = 0; + const struct file_handler * const h = &array[fd]; + if (NULL != h->f[OOP_READ]) mask |= TCL_READABLE; + if (NULL != h->f[OOP_WRITE]) mask |= TCL_WRITABLE; + if (NULL != h->f[OOP_EXCEPTION]) mask |= TCL_EXCEPTION; + + if (0 == mask) + Tcl_DeleteFileHandler(fd); + else + Tcl_CreateFileHandler(fd,mask,file_call,(ClientData) fd); +} + +static void on_fd(oop_source *x,int fd,oop_event event,oop_call_fd *f,void *d) { + struct file_handler *h; + + if (fd >= array_size) { + const int new_size = fd + 1; + struct file_handler * const new_array = + oop_realloc(array,new_size * sizeof(*new_array)); + if (NULL == new_array) return; /* YUCK */ + + array = new_array; + while (array_size != new_size) { + int i; + for (i = 0; i < OOP_NUM_EVENTS; ++i) + array[array_size].f[i] = NULL; + ++array_size; + } + } + + h = &array[fd]; + assert(NULL == h->f[event] && NULL != f); + h->f[event] = f; + h->d[event] = d; + set_mask(fd); +} + +static void cancel_fd(oop_source *x,int fd,oop_event event) { + if (fd < array_size) { + struct file_handler * const h = &array[fd]; + h->f[event] = NULL; + set_mask(fd); + } +} + +static void timer_call(ClientData data) { + struct timer_handler * const timer = (struct timer_handler *) data; + struct timer_handler **ptr; + + Tcl_DeleteTimerHandler(timer->token); + for (ptr = &list; timer != *ptr; ptr = &(*ptr)->next) ; + *ptr = timer->next; + + /* BUG: What if !OOP_CONTINUE? */ + timer->f(oop_signal_source(signal),timer->t,timer->d); + oop_free(timer); +} + +static void on_time(oop_source *x,struct timeval t,oop_call_time *f,void *d) { + struct timer_handler * const timer = oop_malloc(sizeof(*timer)); + struct timeval now; + int msec; + if (NULL == timer) return; /* YUCK */ + + gettimeofday(&now,NULL); + if (t.tv_sec < now.tv_sec + || (t.tv_sec == now.tv_sec && t.tv_usec < now.tv_usec)) + msec = 0; + else { + msec = 1000 * (t.tv_sec - now.tv_sec); + msec = msec + (t.tv_usec - now.tv_usec) / 1000; + } + + assert(msec >= 0); + timer->t = t; + timer->f = f; + timer->d = d; + timer->next = list; + timer->token = Tcl_CreateTimerHandler(msec,timer_call,timer); + list = timer; +} + +static void cancel_time(oop_source *x,struct timeval t,oop_call_time *f,void *d) { + struct timer_handler **timer; + for (timer = &list; NULL != *timer; timer = &(*timer)->next) + if ((*timer)->d == d && (*timer)->f == f + && (*timer)->t.tv_sec == t.tv_sec + && (*timer)->t.tv_usec == t.tv_usec) { + struct timer_handler *dead = *timer; + *timer = dead->next; + Tcl_DeleteTimerHandler(dead->token); + oop_free(dead); + return; + } +} + +oop_source *oop_tcl_new(void) { + if (0 == use_count) { + source.on_fd = on_fd; + source.cancel_fd = cancel_fd; + source.on_time = on_time; + source.cancel_time = cancel_time; + source.on_signal = NULL; + source.cancel_signal = NULL; + array = NULL; + array_size = 0; + list = NULL; + + /* Do this last, after everything is set up. */ + signal = oop_signal_new(&source); + if (NULL == signal) return NULL; + } + + ++use_count; + return oop_signal_source(signal); +} + +void oop_tcl_done(void) { + if (0 == --use_count) { + int i,j; + for (i = 0; i < array_size; ++i) + for (j = 0; j < OOP_NUM_EVENTS; ++j) + assert(NULL == array[i].f[j]); + oop_free(array); + assert(NULL == list); + oop_signal_delete(signal); + } +} + +#endif diff --git a/test-oop.c b/test-oop.c index 82c38d5..f9b522e 100644 --- a/test-oop.c +++ b/test-oop.c @@ -25,6 +25,11 @@ GMainLoop *glib_loop; #endif +#ifdef HAVE_TCL +#include <tcl.h> +#include "oop-tcl.h" +#endif + #ifdef HAVE_WWW /* Yuck: */ #define HAVE_CONFIG_H @@ -60,6 +65,9 @@ static void usage(void) { #ifdef HAVE_GLIB " glib GLib source adapter\n" #endif +#ifdef HAVE_TCL +" tcl Tcl source adapter\n" +#endif "sinks: timer some timers\n" " signal some signal handlers\n" " echo a stdin->stdout copy\n" @@ -603,19 +611,46 @@ static void add_sink(oop_source *src,const char *name) { usage(); } -int main(int argc,char *argv[]) { - oop_source *source; +static void init(oop_source *source,int count,char *sinks[]) { int i; - - if (argc < 3) usage(); + source->on_signal(source,SIGQUIT,stop_loop,NULL); puts("test-oop: use ^\\ (SIGQUIT) for clean shutdown or " "^C (SIGINT) to stop abruptly."); - source = create_source(argv[1]); - source->on_signal(source,SIGQUIT,stop_loop,NULL); - for (i = 2; i < argc; ++i) - add_sink(source,argv[i]); - run_source(argv[1]); - delete_source(argv[1]); + for (i = 0; i < count; ++i) + add_sink(source,sinks[i]); +} + +/* -- tcl source ----------------------------------------------------------- */ + +#ifdef HAVE_TCL +static int tcl_count; +static char **tcl_sinks; + +static int tcl_init(Tcl_Interp *interp) { + init(oop_tcl_new(),tcl_count,tcl_sinks); + return TCL_OK; +} +#endif + +/* -- main ----------------------------------------------------------------- */ + +int main(int argc,char *argv[]) { + if (argc < 3) usage(); + +#ifdef HAVE_TCL + if (!strcmp(argv[1],"tcl")) { /* Tcl is a little ... different. */ + tcl_count = argc - 2; + tcl_sinks = argv + 2; + Tcl_Main(1,argv,tcl_init); + } else +#endif + { + oop_source * const source = create_source(argv[1]); + init(source,argc - 2,argv + 2); + run_source(argv[1]); + delete_source(argv[1]); + } + return 0; } -- GitLab