From 6d6afe788c3ec1f320e12449eee230fb366228c5 Mon Sep 17 00:00:00 2001 From: Paul LeoNerd Evans Date: Wed, 18 Jan 2012 14:03:39 +0000 Subject: [PATCH] Allow passing fd = -1 to constructor to make an instance not associated with an fd; must use push_bytes to provide it input --- driver-ti.c | 4 ++-- man/termkey_advisereadable.3 | 2 +- man/termkey_get_fd.3 | 2 +- man/termkey_new.3 | 4 +++- man/termkey_waitkey.3.sh | 2 +- t/01base.c | 2 +- t/02getkey.c | 2 +- t/03utf8.c | 2 +- t/04flags.c | 2 +- t/10keyname.c | 2 +- t/11strfkey.c | 2 +- t/12strpkey.c | 2 +- t/13cmpkey.c | 2 +- t/20canon.c | 2 +- termkey.c | 12 +++++++++++- 15 files changed, 28 insertions(+), 16 deletions(-) diff --git a/driver-ti.c b/driver-ti.c index 49e8c6d..e8515e3 100644 --- a/driver-ti.c +++ b/driver-ti.c @@ -296,7 +296,7 @@ static void start_driver(TermKey *tk, void *info) /* The terminfo database will contain keys in application cursor key mode. * We may need to enable that mode */ - if(ti->start_string) { + if(tk->fd != -1 && ti->start_string) { // Can't call putp or tputs because they suck and don't give us fd control write(tk->fd, ti->start_string, strlen(ti->start_string)); } @@ -306,7 +306,7 @@ static void stop_driver(TermKey *tk, void *info) { TermKeyTI *ti = info; - if(ti->stop_string) { + if(tk->fd != -1 && ti->stop_string) { // Can't call putp or tputs because they suck and don't give us fd control write(tk->fd, ti->stop_string, strlen(ti->stop_string)); } diff --git a/man/termkey_advisereadable.3 b/man/termkey_advisereadable.3 index 3c63fdd..2d7ca4a 100644 --- a/man/termkey_advisereadable.3 +++ b/man/termkey_advisereadable.3 @@ -10,7 +10,7 @@ termkey_advisereadable \- read more bytes from the underlying terminal .sp Link with \fI-ltermkey\fP. .SH DESCRIPTION -\fBtermkey_advisereadable\fP() informs the instance that new input may be available on the underlying file descriptor and so it should call \fBread\fP(2) to obtain it. If at least one more byte was read it will return \fBTERMKEY_RES_AGAIN\fP to indicate it may be useful to call \fBtermkey_getkey\fP(3) again. If no more input was read then \fBTERMKEY_RES_NONE\fP is returned. If there was no buffer space remaining, then \fBTERMKEY_RES_ERROR\fP is returned with \fIerrno\fP set to \fBENOMEM\fP. +\fBtermkey_advisereadable\fP() informs the instance that new input may be available on the underlying file descriptor and so it should call \fBread\fP(2) to obtain it. If at least one more byte was read it will return \fBTERMKEY_RES_AGAIN\fP to indicate it may be useful to call \fBtermkey_getkey\fP(3) again. If no more input was read then \fBTERMKEY_RES_NONE\fP is returned. If there was no buffer space remaining, then \fBTERMKEY_RES_ERROR\fP is returned with \fIerrno\fP set to \fBENOMEM\fP. If no filehandle is associated with this instance, \fBTERMKEY_RES_ERROR\fP is returned with \fIerrno\fP set to \fBEBADF\fP. .PP This function, along with \fBtermkey_getkey\fP(3) make it possible to use the termkey instance in an asynchronous program. To provide bytes without using a readable file handle, use \fBtermkey_push_bytes\fP(3). .PP diff --git a/man/termkey_get_fd.3 b/man/termkey_get_fd.3 index 733f820..d94de5f 100644 --- a/man/termkey_get_fd.3 +++ b/man/termkey_get_fd.3 @@ -12,7 +12,7 @@ Link with \fI-ltermkey\fP. .SH DESCRIPTION \fBtermkey_get_fd\fP() returns the file descriptor that was passed as the \fIfd\fP argument to \fBtermkey_new\fP(3). .SH "RETURN VALUE" -\fBtermkey_get_fd\fP() returns the current file descriptor. +\fBtermkey_get_fd\fP() returns the current file descriptor, or -1 if no file descriptor is associated with this instance. .SH "SEE ALSO" .BR termkey_new (3), .BR termkey_get_flags (3) diff --git a/man/termkey_new.3 b/man/termkey_new.3 index e4a3a37..b9ded7b 100644 --- a/man/termkey_new.3 +++ b/man/termkey_new.3 @@ -12,10 +12,12 @@ termkey_new, termkey_destroy \- create or destroy new termkey instance .sp Link with \fI\-ltermkey\fP. .SH DESCRIPTION -\fBtermkey_new\fP() creates a new termkey instance connected to the file handle opened by \fIfd\fP using the \fIflags\fP. The \fITermKey\fP structure should be considered opaque; its contents are not intended for use outside of the library. +\fBtermkey_new\fP() creates a new termkey instance connected to the file handle opened by \fIfd\fP using the \fIflags\fP. The \fITermKey\fP structure should be considered opaque; its contents are not intended for use outside of the library. If \fIfd\fP is given the value -1, then no file handle will be associated. .PP \fBtermkey_destroy\fP() destroys the given instance and releases any resources controlled by it. It will not close the underlying filehandle given as the \fIfd\fP argument to \fBtermkey_new\fP(). .PP +A termkey instance contains a buffer of bytes representing keypresses yet to be returned to the application. This buffer may be fed bytes directly by calling \fBtermkey_push_bytes\fP(3), or by calling \fBtermkey_advisereadable\fP(3) which itself will \fBread\fP(3) them from the filehandle given by \fIfd\fP. Once in the buffer, these bytes can be returned as key press events by calling \fBtermkey_getkey\fP(3). The read and get operations are combined in a single function \fBtermkey_waitkey\fP(3), which may be more convenient to use in the standard case of blocking reads from the \fIstdin\fP filehandle. +.PP The following values may be given as the \fIflags\fP bitmask: .TP .B TERMKEY_FLAG_NOINTERPRET diff --git a/man/termkey_waitkey.3.sh b/man/termkey_waitkey.3.sh index 754ac21..9155656 100644 --- a/man/termkey_waitkey.3.sh +++ b/man/termkey_waitkey.3.sh @@ -12,7 +12,7 @@ termkey_waitkey \- wait for and retrieve the next key event .sp Link with \fI-ltermkey\fP. .SH DESCRIPTION -\fBtermkey_waitkey\fP(3) attempts to retrieve a single keypress event from the buffer, and put it in the structure referred to by \fIkey\fP. If successful it will return \fBTERMKEY_RES_KEY\fP to indicate that the structure now contains a new keypress event. If nothing is in the buffer it will block until one is available. If no events are ready and the input stream is now closed, will return \fBTERMKEY_RES_EOF\fP. +\fBtermkey_waitkey\fP(3) attempts to retrieve a single keypress event from the buffer, and put it in the structure referred to by \fIkey\fP. If successful it will return \fBTERMKEY_RES_KEY\fP to indicate that the structure now contains a new keypress event. If nothing is in the buffer it will block until one is available. If no events are ready and the input stream is now closed, will return \fBTERMKEY_RES_EOF\fP. If no filehandle is associated with this instance, \fBTERMKEY_RES_ERROR\fP is returned with \fIerrno\fP set to \fBEBADF\fP. .PP Before returning, this function canonicalises the \fIkey\fP structure according to the rules given for \fBtermkey_canonicalise\fP(3). .PP diff --git a/t/01base.c b/t/01base.c index 359c9ca..88e2c84 100644 --- a/t/01base.c +++ b/t/01base.c @@ -8,7 +8,7 @@ int main(int argc, char *argv[]) plan_tests(2); - tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS); + tk = termkey_new(-1, 0); ok(!!tk, "termkey_new"); diff --git a/t/02getkey.c b/t/02getkey.c index 6d076cb..0c893c6 100644 --- a/t/02getkey.c +++ b/t/02getkey.c @@ -12,7 +12,7 @@ int main(int argc, char *argv[]) /* Sanitise this just in case */ putenv("TERM=vt100"); - tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS); + tk = termkey_new(-1, 0); is_int(termkey_get_buffer_remaining(tk), 256, "buffer free initially 256"); diff --git a/t/03utf8.c b/t/03utf8.c index 9290613..bb97328 100644 --- a/t/03utf8.c +++ b/t/03utf8.c @@ -11,7 +11,7 @@ int main(int argc, char *argv[]) /* Sanitise this just in case */ putenv("TERM=vt100"); - tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS|TERMKEY_FLAG_UTF8); + tk = termkey_new(-1, TERMKEY_FLAG_UTF8); termkey_push_bytes(tk, "a", 1); diff --git a/t/04flags.c b/t/04flags.c index cf8e2c3..d803be8 100644 --- a/t/04flags.c +++ b/t/04flags.c @@ -12,7 +12,7 @@ int main(int argc, char *argv[]) /* Sanitise this just in case */ putenv("TERM=vt100"); - tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS); + tk = termkey_new(-1, 0); termkey_push_bytes(tk, " ", 1); diff --git a/t/10keyname.c b/t/10keyname.c index 54bc208..7a35ad7 100644 --- a/t/10keyname.c +++ b/t/10keyname.c @@ -9,7 +9,7 @@ int main(int argc, char *argv[]) plan_tests(10); - tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS); + tk = termkey_new(-1, 0); sym = termkey_keyname2sym(tk, "Space"); is_int(sym, TERMKEY_SYM_SPACE, "keyname2sym Space"); diff --git a/t/11strfkey.c b/t/11strfkey.c index bdfcf6a..67208a7 100644 --- a/t/11strfkey.c +++ b/t/11strfkey.c @@ -10,7 +10,7 @@ int main(int argc, char *argv[]) plan_tests(28); - tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS); + tk = termkey_new(-1, 0); key.type = TERMKEY_TYPE_UNICODE; key.code.codepoint = 'A'; diff --git a/t/12strpkey.c b/t/12strpkey.c index ef5acd9..f591d9b 100644 --- a/t/12strpkey.c +++ b/t/12strpkey.c @@ -11,7 +11,7 @@ int main(int argc, char *argv[]) plan_tests(53); - tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS); + tk = termkey_new(-1, 0); CLEAR_KEY; endp = termkey_strpkey(tk, "A", &key, 0); diff --git a/t/13cmpkey.c b/t/13cmpkey.c index 62902cc..13ff313 100644 --- a/t/13cmpkey.c +++ b/t/13cmpkey.c @@ -8,7 +8,7 @@ int main(int argc, char *argv[]) plan_tests(12); - tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS); + tk = termkey_new(-1, 0); key1.type = TERMKEY_TYPE_UNICODE; key1.code.codepoint = 'A'; diff --git a/t/20canon.c b/t/20canon.c index 35f84e2..ec6de1f 100644 --- a/t/20canon.c +++ b/t/20canon.c @@ -11,7 +11,7 @@ int main(int argc, char *argv[]) plan_tests(26); - tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS); + tk = termkey_new(-1, 0); CLEAR_KEY; endp = termkey_strpkey(tk, " ", &key, 0); diff --git a/termkey.c b/termkey.c index 249fc22..a66d951 100644 --- a/termkey.c +++ b/termkey.c @@ -284,7 +284,7 @@ static TermKey *termkey_new_full(int fd, int flags, size_t buffsize, int waittim goto abort_free_keynames; } - if(!(flags & TERMKEY_FLAG_NOTERMIOS)) { + if(fd != -1 && !(flags & TERMKEY_FLAG_NOTERMIOS)) { struct termios termios; if(tcgetattr(fd, &termios) == 0) { tk->restore_termios = termios; @@ -887,6 +887,11 @@ TermKeyResult termkey_getkey_force(TermKey *tk, TermKeyKey *key) TermKeyResult termkey_waitkey(TermKey *tk, TermKeyKey *key) { + if(tk->fd == -1) { + errno = EBADF; + return TERMKEY_RES_ERROR; + } + while(1) { TermKeyResult ret = termkey_getkey(tk, key); @@ -944,6 +949,11 @@ TermKeyResult termkey_advisereadable(TermKey *tk) { ssize_t len; + if(tk->fd == -1) { + errno = EBADF; + return TERMKEY_RES_ERROR; + } + if(tk->buffstart) { memmove(tk->buffer, tk->buffer + tk->buffstart, tk->buffcount); tk->buffstart = 0;