From 4ba4a43a195f509d9021563e40de5184e013b8f3 Mon Sep 17 00:00:00 2001 From: Dan Egnor <egnor@ofb.net> Date: Thu, 12 Oct 2000 17:27:19 +0000 Subject: [PATCH] v0.6 + Ian's EXCEPT patch --- Makefile.am | 13 +++++--- adns.c | 8 ++--- configure.in | 11 ++++-- glib.c | 17 +++++++--- oop-rl.h | 20 +++++++++++ oop.h | 5 +-- select.c | 27 ++++++++++++--- test-oop.c | 94 ++++++++++++++++++++++++++++++++++++++++------------ 8 files changed, 151 insertions(+), 44 deletions(-) create mode 100644 oop-rl.h diff --git a/Makefile.am b/Makefile.am index 0a53de1..b611eac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,11 +7,11 @@ # See the file COPYING for details. AUTOMAKE_OPTIONS = foreign 1.2 -lib_LTLIBRARIES = liboop.la liboop-adns.la liboop-glib.la liboop-www.la +lib_LTLIBRARIES = liboop.la liboop-adns.la liboop-glib.la liboop-www.la liboop-rl.la INCLUDES = $(GLIB_INCLUDES) $(WWW_INCLUDES) -EXTRA_DIST = liboop.spec -# versions updated as of 0.4; 0.5 and 0.6 only change build stuff. +# versions updated as of 0.4; 0.5 only changes build stuff; +# 0.6 only adds the readline interface. liboop_la_LDFLAGS = -version-info 2:0:0 # version:revision:age liboop_la_SOURCES = sys.c select.c signal.c alloc.c @@ -25,12 +25,15 @@ liboop_glib_la_SOURCES = glib.c liboop_www_la_LDFLAGS = -version-info 0:0:0 liboop_www_la_SOURCES = www.c -include_HEADERS = oop.h oop-adns.h oop-glib.h oop-www.h +liboop_rl_la_LDFLAGS = -version-info 0:0:0 +liboop_rl_la_SOURCES = readline.c + +include_HEADERS = oop.h oop-adns.h oop-glib.h oop-www.h oop-rl.h noinst_PROGRAMS = test-oop test_oop_SOURCES = test-oop.c -test_oop_LDADD = $(ADNS_LIBS) $(GLIB_LIBS) $(WWW_LIBS) liboop.la +test_oop_LDADD = $(ADNS_LIBS) $(GLIB_LIBS) $(WWW_LIBS) $(READLINE_LIBS) liboop.la release: dist gzip -dc $(PACKAGE)-$(VERSION).tar.gz | bzip2 -9 \ diff --git a/adns.c b/adns.c index 4b6abfc..f290e6c 100644 --- a/adns.c +++ b/adns.c @@ -97,7 +97,7 @@ static void set_select(oop_adapter_adns *a) { FD_ZERO(&xfd); gettimeofday(&now,NULL); adns_beforeselect(a->state,&maxfd,&rfd,&wfd,&xfd,&out,&buf,&now); - oop_select_set(a->select,maxfd,&rfd,&wfd,out); + oop_select_set(a->select,maxfd,&rfd,&wfd,&xfd,out); } static void *on_process(oop_source *source,struct timeval when,void *data) { @@ -133,14 +133,12 @@ static void *on_process(oop_source *source,struct timeval when,void *data) { static void *on_select( oop_adapter_select *select, - int num,fd_set *rfd,fd_set *wfd, + int num,fd_set *rfd,fd_set *wfd,fd_set *xfd, struct timeval now,void *data) { oop_adapter_adns *a = (oop_adapter_adns *) data; - fd_set xfd; - FD_ZERO(&xfd); - adns_afterselect(a->state,num,rfd,wfd,&xfd,&now); + adns_afterselect(a->state,num,rfd,wfd,xfd,&now); return on_process(a->source,OOP_TIME_NOW,a); } diff --git a/configure.in b/configure.in index 8aaa68c..80f751f 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.5) +AM_INIT_AUTOMAKE(liboop,0.6) AC_CANONICAL_HOST dnl Use libtool for shared libraries @@ -27,10 +27,16 @@ esac AC_CHECK_HEADERS(poll.h sys/select.h) AC_CHECK_LIB(adns,adns_init,[ - AC_DEFINE(HAVE_ADNS) ADNS_LIBS="liboop-adns.la -ladns" + AC_DEFINE(HAVE_ADNS) ]) +AC_CHECK_LIB(readline,rl_callback_handler_install,[ +AC_CHECK_HEADER(readline/readline.h,[ + READLINE_LIBS="liboop-rl.la -lreadline" + AC_DEFINE(HAVE_READLINE) +])]) + AC_CHECK_PROG(PROG_GLIB_CONFIG,glib-config,glib-config) if test -n "$PROG_GLIB_CONFIG" ; then GLIB_INCLUDES="`glib-config --cflags`" @@ -60,4 +66,5 @@ AC_SUBST(GLIB_LIBS) AC_SUBST(ADNS_LIBS) AC_SUBST(WWW_INCLUDES) AC_SUBST(WWW_LIBS) +AC_SUBST(READLINE_LIBS) AC_OUTPUT(Makefile) diff --git a/glib.c b/glib.c index d96d7df..942a24a 100644 --- a/glib.c +++ b/glib.c @@ -24,16 +24,17 @@ static int use_count = 0; static oop_source_sys *sys; static oop_adapter_select *sel; -static fd_set read_set,write_set; +static fd_set read_set,write_set,except_set; static int count; static void *ret = NULL; static void *on_select( - oop_adapter_select *s,int num,fd_set *r,fd_set *w, - struct timeval now,void *x) + oop_adapter_select *s,int num,fd_set *r,fd_set *w,fd_set *x, + struct timeval now,void *unused) { read_set = *r; write_set = *w; + except_set = *x; count = num; return &use_count; } @@ -44,12 +45,17 @@ static gint on_poll(GPollFD *array,guint num,gint timeout) { FD_ZERO(&read_set); FD_ZERO(&write_set); + FD_ZERO(&except_set); count = 0; for (i = 0; i < num; ++i) { if (array[i].events & G_IO_IN) FD_SET(array[i].fd,&read_set); if (array[i].events & G_IO_OUT) FD_SET(array[i].fd,&write_set); + if (array[i].events & G_IO_PRI) + FD_SET(array[i].fd,&except_set); + /* {G_IO_,POLL}{ERR,HUP,INVAL} don't correspond to anything + in select(2), and aren't `normal' events anyway. */ if (array[i].fd >= count) count = 1 + array[i].fd; } @@ -57,7 +63,8 @@ static gint on_poll(GPollFD *array,guint num,gint timeout) { tv.tv_sec = timeout / 1000; tv.tv_usec = timeout % 1000; - oop_select_set(sel,count,&read_set,&write_set,timeout < 0 ? NULL : &tv); + oop_select_set(sel,count,&read_set,&write_set,&except_set, + timeout < 0 ? NULL : &tv); ret = oop_sys_run(sys); if (&use_count != ret) { @@ -71,6 +78,8 @@ static gint on_poll(GPollFD *array,guint num,gint timeout) { array[i].revents |= G_IO_IN; if (FD_ISSET(array[i].fd,&write_set)) array[i].revents |= G_IO_OUT; + if (FD_ISSET(array[i].fd,&except_set)) + array[i].revents |= G_IO_PRI; } return count; diff --git a/oop-rl.h b/oop-rl.h new file mode 100644 index 0000000..174719c --- /dev/null +++ b/oop-rl.h @@ -0,0 +1,20 @@ +/* oop-rl.h, liboop, copyright 2000 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_READLINE_H +#define OOP_READLINE_H + +#include "oop.h" + +/* Use a liboop event source to call rl_callback_read_char(). + It is up to you to call rl_callback_handler_install(). + Note well that readline uses malloc(), not oop_malloc(). */ +void oop_readline_register(oop_source *); + +/* Stop notifying readline of input characters. */ +void oop_readline_cancel(oop_source *); + +#endif diff --git a/oop.h b/oop.h index ebc8923..0e68618 100644 --- a/oop.h +++ b/oop.h @@ -19,6 +19,7 @@ typedef struct oop_source oop_source; typedef enum { OOP_READ, OOP_WRITE, + OOP_EXCEPT, OOP_NUM_EVENTS } oop_event; @@ -81,7 +82,7 @@ oop_source *oop_sys_source(oop_source_sys *); typedef struct oop_adapter_select oop_adapter_select; typedef void *oop_call_select( oop_adapter_select *, - int num,fd_set *r,fd_set *w, + int num,fd_set *r,fd_set *w,fd_set *x, struct timeval now,void *); oop_adapter_select *oop_select_new( @@ -91,7 +92,7 @@ oop_adapter_select *oop_select_new( void oop_select_set( oop_adapter_select *,int num_fd, - fd_set *rfd,fd_set *wfd,struct timeval *timeout); + fd_set *rfd,fd_set *wfd,fd_set *xfd,struct timeval *timeout); void oop_select_delete(oop_adapter_select *); diff --git a/select.c b/select.c index 9972d65..1f4f969 100644 --- a/select.c +++ b/select.c @@ -9,7 +9,7 @@ #include <assert.h> struct select_set { - fd_set rfd,wfd; + fd_set rfd,wfd,xfd; }; struct oop_adapter_select { @@ -33,8 +33,10 @@ oop_adapter_select *oop_select_new( s->source = source; FD_ZERO(&s->watch.rfd); FD_ZERO(&s->watch.wfd); + FD_ZERO(&s->watch.xfd); FD_ZERO(&s->active.rfd); FD_ZERO(&s->active.wfd); + FD_ZERO(&s->active.xfd); s->num_fd = 0; s->do_timeout = 0; s->is_active = 0; @@ -58,19 +60,22 @@ static void deactivate(oop_adapter_select *s) { s->num_fd_active = 0; FD_ZERO(&s->active.rfd); FD_ZERO(&s->active.wfd); + FD_ZERO(&s->active.xfd); } } void oop_select_set( oop_adapter_select *s,int num_fd, - fd_set *rfd,fd_set *wfd,struct timeval *timeout) + fd_set *rfd,fd_set *wfd,fd_set *xfd,struct timeval *timeout) { int fd; for (fd = 0; fd < num_fd || fd < s->num_fd; ++fd) { int rfd_set = fd < num_fd && FD_ISSET(fd,rfd); int wfd_set = fd < num_fd && FD_ISSET(fd,wfd); + int xfd_set = fd < num_fd && FD_ISSET(fd,xfd); int w_rfd_set = fd < s->num_fd && FD_ISSET(fd,&s->watch.rfd); int w_wfd_set = fd < s->num_fd && FD_ISSET(fd,&s->watch.wfd); + int w_xfd_set = fd < s->num_fd && FD_ISSET(fd,&s->watch.xfd); if (rfd_set && !w_rfd_set) { s->source->on_fd(s->source,fd,OOP_READ,on_fd,s); @@ -91,6 +96,16 @@ void oop_select_set( s->source->cancel_fd(s->source,fd,OOP_WRITE); FD_CLR(fd,&s->watch.wfd); } + + if (xfd_set && !w_xfd_set) { + s->source->on_fd(s->source,fd,OOP_EXCEPT,on_fd,s); + FD_SET(fd,&s->watch.xfd); + } + + if (!xfd_set && w_xfd_set) { + s->source->cancel_fd(s->source,fd,OOP_EXCEPT); + FD_CLR(fd,&s->watch.xfd); + } } s->num_fd = num_fd; @@ -118,7 +133,7 @@ void oop_select_set( void oop_select_delete(oop_adapter_select *s) { fd_set fd; FD_ZERO(&fd); - oop_select_set(s,0,&fd,&fd,NULL); + oop_select_set(s,0,&fd,&fd,&fd,NULL); oop_free(s); } @@ -140,6 +155,10 @@ static void *on_fd(oop_source *source,int fd,oop_event event,void *data) { assert(FD_ISSET(fd,&s->watch.wfd)); set_fd(fd,&s->active.wfd,&s->num_fd_active); break; + case OOP_EXCEPT: + assert(FD_ISSET(fd,&s->watch.xfd)); + set_fd(fd,&s->active.xfd,&s->num_fd_active); + break; default: assert(0); break; @@ -160,5 +179,5 @@ static void *on_collect(oop_source *source,struct timeval when,void *data) { struct timeval now; gettimeofday(&now,NULL); deactivate(s); - return s->call(s,num,&set.rfd,&set.wfd,now,s->data); + return s->call(s,num,&set.rfd,&set.wfd,&set.xfd,now,s->data); } diff --git a/test-oop.c b/test-oop.c index 13d2baa..605f659 100644 --- a/test-oop.c +++ b/test-oop.c @@ -21,6 +21,10 @@ GMainLoop *glib_loop; #endif +#ifdef HAVE_READLINE +#include <readline/readline.h> +#endif + struct timer { struct timeval tv; int delay; @@ -38,8 +42,11 @@ static void usage(void) { " glib GLib source adapter\n" #endif "sinks: timer some timers\n" -" echo a stdin->stdout copy\n" " signal some signal handlers\n" +" echo a stdin->stdout copy\n" +#ifdef HAVE_READLINE +" readline like echo but with line editing\n" +#endif #ifdef HAVE_ADNS " adns some asynchronous DNS lookups\n" #endif @@ -80,6 +87,26 @@ void add_timer(oop_source *source,int interval) { on_timer(source,timer->tv,timer); } +/* -- signal --------------------------------------------------------------- */ + +static oop_call_signal on_signal; +static void *on_signal(oop_source *source,int sig,void *data) { + switch (sig) { + case SIGINT: + puts("signal: SIGINT (control-C) caught. " + "(Use SIGQUIT, control-\\, to terminate.)"); + break; + case SIGQUIT: + puts("signal: SIGQUIT (control-\\) caught, terminating."); + source->cancel_signal(source,SIGINT,on_signal,NULL); + source->cancel_signal(source,SIGQUIT,on_signal,NULL); + break; + default: + assert(0 && "unknown signal?"); + } + return OOP_CONTINUE; +} + /* -- echo ----------------------------------------------------------------- */ static oop_call_fd on_data; @@ -97,26 +124,42 @@ static void *stop_data(oop_source *source,int sig,void *data) { return OOP_CONTINUE; } -/* -- signal --------------------------------------------------------------- */ +/* -- readline ------------------------------------------------------------- */ -static oop_call_signal on_signal; -static void *on_signal(oop_source *source,int sig,void *data) { - switch (sig) { - case SIGINT: - puts("signal: SIGINT (control-C) caught. " - "(Use SIGQUIT, control-\\, to terminate.)"); - break; - case SIGQUIT: - puts("signal: SIGQUIT (control-\\) caught, terminating."); - source->cancel_signal(source,SIGINT,on_signal,NULL); - source->cancel_signal(source,SIGQUIT,on_signal,NULL); - break; - default: - assert(0 && "unknown signal?"); +#ifdef HAVE_READLINE + +static void on_readline(const char *input) { + if (NULL == input) + puts("\rreadline: EOF"); + else { + fputs("readline: \"",stdout); + fputs(input,stdout); + puts("\""); } +} + +static void *stop_readline(oop_source *src,int sig,void *data) { + oop_readline_cancel(src); + src->cancel_signal(src,SIGQUIT,stop_readline,NULL); + rl_callback_handler_remove(); return OOP_CONTINUE; } +static void add_readline(oop_source *src) { + rl_callback_handler_install("> ",(VFunction *) on_readline); + oop_readline_register(src); + src->on_signal(src,SIGQUIT,stop_readline,NULL); +} + +#else + +static void add_readline(oop_source *src) { + fputs("sorry, readline not available\n",stderr); + usage(); +} + +#endif + /* -- adns ----------------------------------------------------------------- */ #ifdef HAVE_ADNS @@ -129,7 +172,7 @@ static void *on_signal(oop_source *source,int sig,void *data) { oop_adns_query *q[NUM_Q]; oop_adapter_adns *adns; -void cancel_adns(void) { +static void cancel_adns(void) { int i; for (i = 0; i < NUM_Q; ++i) @@ -144,13 +187,13 @@ void cancel_adns(void) { } } -void *stop_lookup(oop_source *src,int sig,void *data) { +static void *stop_lookup(oop_source *src,int sig,void *data) { cancel_adns(); src->cancel_signal(src,SIGQUIT,stop_lookup,NULL); return OOP_CONTINUE; } -void *on_lookup(oop_adapter_adns *adns,adns_answer *reply,void *data) { +static void *on_lookup(oop_adapter_adns *adns,adns_answer *reply,void *data) { int i; for (i = 0; i < NUM_Q; ++i) if (data == &q[i]) q[i] = NULL; @@ -358,17 +401,24 @@ static void add_sink(oop_source *src,const char *name) { return; } + if (!strcmp(name,"signal")) { + src->on_signal(src,SIGINT,on_signal,NULL); + src->on_signal(src,SIGQUIT,on_signal,NULL); + return; + } + if (!strcmp(name,"echo")) { src->on_fd(src,0,OOP_READ,on_data,NULL); src->on_signal(src,SIGQUIT,stop_data,NULL); return; } - if (!strcmp(name,"signal")) { - src->on_signal(src,SIGINT,on_signal,NULL); - src->on_signal(src,SIGQUIT,on_signal,NULL); +#ifdef HAVE_READLINE + if (!strcmp(name,"readline")) { + add_readline(src); return; } +#endif #ifdef HAVE_ADNS if (!strcmp(name,"adns")) { -- GitLab