diff --git a/oop.h b/oop.h
index 0e6861877185c961f94a55ea1c402d2dd117f24d..a9552800b108536f560330f6ae808b9aa9437c10 100644
--- a/oop.h
+++ b/oop.h
@@ -19,7 +19,7 @@ typedef struct oop_source oop_source;
 typedef enum {
 	OOP_READ,
 	OOP_WRITE,
-	OOP_EXCEPT,
+	OOP_EXCEPTION,
 
 	OOP_NUM_EVENTS
 } oop_event;
diff --git a/readline.c b/readline.c
new file mode 100644
index 0000000000000000000000000000000000000000..60a1b026d27793d19cdd13166e955a9d88e18537
--- /dev/null
+++ b/readline.c
@@ -0,0 +1,26 @@
+/* readline.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_READLINE
+
+#include <stdio.h> /* readline needs this! */
+#include "readline/readline.h"
+#include "oop-rl.h"
+
+static void *on_input(oop_source *oop,int fd,oop_event evt,void *x) {
+	rl_callback_read_char();
+	return OOP_CONTINUE;
+}
+
+void oop_readline_register(oop_source *oop) {
+	oop->on_fd(oop,0,OOP_READ,on_input,NULL);
+}
+
+void oop_readline_cancel(oop_source *oop) {
+	oop->cancel_fd(oop,0,OOP_READ);
+}
+
+#endif
diff --git a/select.c b/select.c
index 1f4f96940fadbef979c48f1b5231dbc555be3ec8..1c2796766b7f6a503901dc44f853c227c1775a2d 100644
--- a/select.c
+++ b/select.c
@@ -98,12 +98,12 @@ void oop_select_set(
 		}
 
 		if (xfd_set && !w_xfd_set) {
-			s->source->on_fd(s->source,fd,OOP_EXCEPT,on_fd,s);
+			s->source->on_fd(s->source,fd,OOP_EXCEPTION,on_fd,s);
 			FD_SET(fd,&s->watch.xfd);
 		}
 
 		if (!xfd_set && w_xfd_set) {
-			s->source->cancel_fd(s->source,fd,OOP_EXCEPT);
+			s->source->cancel_fd(s->source,fd,OOP_EXCEPTION);
 			FD_CLR(fd,&s->watch.xfd);
 		}
 	}
@@ -155,7 +155,7 @@ 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:
+	case OOP_EXCEPTION:
 		assert(FD_ISSET(fd,&s->watch.xfd));
 		set_fd(fd,&s->active.xfd,&s->num_fd_active);
 		break;
diff --git a/test-oop.c b/test-oop.c
index 605f6598ff025237e4d5ac16a8d565666ca040b8..49cc9be7b878fd20a78b473abdcdfd9a10fe175a 100644
--- a/test-oop.c
+++ b/test-oop.c
@@ -167,7 +167,7 @@ static void add_readline(oop_source *src) {
 #include "adns.h"
 #include "oop-adns.h"
 
-#define ADNS_CANCEL
+#undef ADNS_CANCEL
 #define NUM_Q 6
 oop_adns_query *q[NUM_Q];
 oop_adapter_adns *adns;
@@ -443,7 +443,8 @@ int main(int argc,char *argv[]) {
 	int i;
 
 	if (argc < 3) usage();
-	puts("test-oop: use ^\\ (SIGQUIT) for clean shutdown");
+	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)