Added termkey_push_bytes(), a new API for providing input bytes

This commit is contained in:
Paul LeoNerd Evans 2012-01-18 13:39:50 +00:00
parent 082b49f0f8
commit 82ad14175c
11 changed files with 158 additions and 80 deletions

View File

@ -126,3 +126,6 @@ TARBALL=$(DISTDIR).tar.gz
dist: distdir dist: distdir
tar -czf $(TARBALL) $(DISTDIR) tar -czf $(TARBALL) $(DISTDIR)
rm -rf $(DISTDIR) rm -rf $(DISTDIR)
htmldocs:
perl $(HOME)/src/perl/Parse-Man/examples/man-to-html.pl -O $(HOME)/website-source2/code/libtermkey/doc --file-extension tmpl --link-extension html --template home_lou.tt2 *.3

View File

@ -12,7 +12,7 @@ Link with \fI-ltermkey\fP.
.SH DESCRIPTION .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.
.PP .PP
This function, along with \fBtermkey_getkey\fP(3) make it possible to use the termkey instance in an asynchronous program. 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 .PP
For synchronous usage, \fBtermkey_waitkey\fP(3) performs the input blocking task. For synchronous usage, \fBtermkey_waitkey\fP(3) performs the input blocking task.
.SH "RETURN VALUE" .SH "RETURN VALUE"

View File

@ -10,11 +10,12 @@ termkey_get_buffer_remaining \- returns the free buffer space
.sp .sp
Link with \fI-ltermkey\fP. Link with \fI-ltermkey\fP.
.SH DESCRIPTION .SH DESCRIPTION
A termkey instance contains a buffer of pending bytes that have been read by \fBtermkey_advisereadable\fP(3) but not yet consumed by \fBtermkey_getkey\fP(3). \fBtermkey_get_buffer_remaining\fP() returns the number of bytes of buffer space currently free in the termkey instance. A termkey instance contains a buffer of pending bytes that have been read by \fBtermkey_advisereadable\fP(3) or provided by \fBtermkey_push_bytes\fP(3) but not yet consumed by \fBtermkey_getkey\fP(3). \fBtermkey_get_buffer_remaining\fP() returns the number of bytes of buffer space currently free in the termkey instance.
.PP .PP
.SH "RETURN VALUE" .SH "RETURN VALUE"
\fBtermkey_get_buffer_remaining\fP() returns a size in bytes. \fBtermkey_get_buffer_remaining\fP() returns a size in bytes.
.SH "SEE ALSO" .SH "SEE ALSO"
.BR termkey_new (3), .BR termkey_new (3),
.BR termkey_push_bytes (3),
.BR termkey_advisereadable (3), .BR termkey_advisereadable (3),
.BR termkey_getkey (3) .BR termkey_getkey (3)

View File

@ -30,7 +30,7 @@ no bytes are waiting in the buffer.
.PP .PP
\fBtermkey_getkey_force\fP() is similar to \fBtermkey_getkey\fP() but will not return \fBTERMKEY_RES_AGAIN\fP if a partial match is found. Instead, it will force an interpretation of the bytes, even if this means interpreting the start of an Escape-prefixed multi-byte sequence as a literal "Escape" key followed by normal letters. \fBtermkey_getkey_force\fP() is similar to \fBtermkey_getkey\fP() but will not return \fBTERMKEY_RES_AGAIN\fP if a partial match is found. Instead, it will force an interpretation of the bytes, even if this means interpreting the start of an Escape-prefixed multi-byte sequence as a literal "Escape" key followed by normal letters.
.PP .PP
Neither of these functions will block or perform any IO operations on the underlying filehandle. To use the instance in an asynchronous program, see \fBtermkey_advisereadable\fP(3). For a blocking call suitable for use in a synchronous program, use \fBtermkey_waitkey\fP(3) instead of \fBtermkey_getkey\fP(). Neither of these functions will block or perform any IO operations on the underlying filehandle. To use the instance in an asynchronous program, see \fBtermkey_advisereadable\fP(3). For a blocking call suitable for use in a synchronous program, use \fBtermkey_waitkey\fP(3) instead of \fBtermkey_getkey\fP(). For providing input without a readable filehandle, use \fBtermkey_push_bytes\fP(3).
.PP .PP
Before returning, this function canonicalises the \fIkey\fP structure according to the rules given for \fBtermkey_canonicalise\fP(3). Before returning, this function canonicalises the \fIkey\fP structure according to the rules given for \fBtermkey_canonicalise\fP(3).
.PP .PP
@ -86,6 +86,7 @@ cat <<EOF
.SH "SEE ALSO" .SH "SEE ALSO"
.BR termkey_new (3), .BR termkey_new (3),
.BR termkey_advisereadable (3), .BR termkey_advisereadable (3),
.BR termkey_push_bytes (3),
.BR termkey_waitkey (3), .BR termkey_waitkey (3),
.BR termkey_set_waittime (3), .BR termkey_set_waittime (3),
.BR termkey_get_keyname (3), .BR termkey_get_keyname (3),

23
man/termkey_push_bytes.3 Normal file
View File

@ -0,0 +1,23 @@
.TH TERMKEY_PUSH_BYTES 3
.SH NAME
termkey_push_bytes \- supply more bytes to the input buffer
.SH SYNOPSIS
.nf
.B #include <termkey.h>
.sp
.BI "size_t termkey_push_bytes(TermKey *" tk ", const char *" bytes ", size_t " len ");
.fi
.sp
Link with \fI-ltermkey\fP.
.SH DESCRIPTION
\fBtermkey_push_bytes\fP() allows more bytes of input to be supplied directly into the input buffer of the termkey instance. If there was no buffer space remaining, then -1 is returned with \fIerrno\fP set to \fBENOMEM\fP.
.PP
This function, along with \fBtermkey_getkey\fP(3) make it possible to use the termkey instance in an asynchronous program, or with a source of bytes other than from reading a filehandle.
.PP
For synchronous usage, \fBtermkey_waitkey\fP(3) performs the input blocking task. For use against a regular stream filehandle that supports \fBread\fP(2), see \fBtermkey_advisereadable\fP(3).
.SH "RETURN VALUE"
\fBtermkey_push_bytes\fP() the number of bytes consumed from the input (which may be smaller than the length provided, if the buffer runs out of space) or -1 cast to \fBsize_t\fP if an error occurs.
.SH "SEE ALSO"
.BR termkey_new (3),
.BR termkey_getkey (3),
.BR termkey_advise_readable (3)

View File

@ -4,30 +4,23 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int fd[2];
TermKey *tk; TermKey *tk;
TermKeyKey key; TermKeyKey key;
plan_tests(29); plan_tests(27);
pipe(fd);
/* Sanitise this just in case */ /* Sanitise this just in case */
putenv("TERM=vt100"); putenv("TERM=vt100");
tk = termkey_new(fd[0], TERMKEY_FLAG_NOTERMIOS); tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS);
is_int(termkey_get_buffer_remaining(tk), 256, "buffer free initially 256"); is_int(termkey_get_buffer_remaining(tk), 256, "buffer free initially 256");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey yields RES_NONE when empty"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey yields RES_NONE when empty");
write(fd[1], "h", 1); is_int(termkey_push_bytes(tk, "h", 1), 1, "push_bytes returns 1");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey yields RES_NONE before advisereadable"); is_int(termkey_get_buffer_remaining(tk), 255, "buffer free 255 after push_bytes");
is_int(termkey_advisereadable(tk), TERMKEY_RES_AGAIN, "advisereadable yields RES_AGAIN after h");
is_int(termkey_get_buffer_remaining(tk), 255, "buffer free 255 after advisereadable");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after h"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after h");
@ -40,9 +33,7 @@ int main(int argc, char *argv[])
is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey yields RES_NONE a second time"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey yields RES_NONE a second time");
write(fd[1], "\x01", 1); termkey_push_bytes(tk, "\x01", 1);
is_int(termkey_advisereadable(tk), TERMKEY_RES_AGAIN, "advisereadable yields RES_AGAIN after C-a");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after C-a"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after C-a");
@ -50,9 +41,7 @@ int main(int argc, char *argv[])
is_int(key.code.number, 'a', "key.code.number after C-a"); is_int(key.code.number, 'a', "key.code.number after C-a");
is_int(key.modifiers, TERMKEY_KEYMOD_CTRL, "key.modifiers after C-a"); is_int(key.modifiers, TERMKEY_KEYMOD_CTRL, "key.modifiers after C-a");
write(fd[1], "\eOA", 3); termkey_push_bytes(tk, "\eOA", 3);
is_int(termkey_advisereadable(tk), TERMKEY_RES_AGAIN, "advisereadable yields RES_AGAIN after Up");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after Up"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after Up");
@ -60,15 +49,13 @@ int main(int argc, char *argv[])
is_int(key.code.sym, TERMKEY_SYM_UP, "key.code.sym after Up"); is_int(key.code.sym, TERMKEY_SYM_UP, "key.code.sym after Up");
is_int(key.modifiers, 0, "key.modifiers after Up"); is_int(key.modifiers, 0, "key.modifiers after Up");
write(fd[1], "\eO", 2); is_int(termkey_push_bytes(tk, "\eO", 2), 2, "push_bytes returns 2");
termkey_advisereadable(tk);
is_int(termkey_get_buffer_remaining(tk), 254, "buffer free 254 after partial write"); is_int(termkey_get_buffer_remaining(tk), 254, "buffer free 254 after partial write");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN after partial write"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN after partial write");
write(fd[1], "C", 1); termkey_push_bytes(tk, "C", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after Right completion"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after Right completion");

View File

@ -3,22 +3,18 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int fd[2];
TermKey *tk; TermKey *tk;
TermKeyKey key; TermKeyKey key;
plan_tests(57); plan_tests(57);
pipe(fd);
/* Sanitise this just in case */ /* Sanitise this just in case */
putenv("TERM=vt100"); putenv("TERM=vt100");
tk = termkey_new(fd[0], TERMKEY_FLAG_NOTERMIOS|TERMKEY_FLAG_UTF8); tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS|TERMKEY_FLAG_UTF8);
write(fd[1], "a", 1); termkey_push_bytes(tk, "a", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY low ASCII"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY low ASCII");
is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type low ASCII"); is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type low ASCII");
is_int(key.code.number, 'a', "key.code.number low ASCII"); is_int(key.code.number, 'a', "key.code.number low ASCII");
@ -26,97 +22,85 @@ int main(int argc, char *argv[])
/* 2-byte UTF-8 range is U+0080 to U+07FF (0xDF 0xBF) */ /* 2-byte UTF-8 range is U+0080 to U+07FF (0xDF 0xBF) */
/* However, we'd best avoid the C1 range, so we'll start at U+00A0 (0xC2 0xA0) */ /* However, we'd best avoid the C1 range, so we'll start at U+00A0 (0xC2 0xA0) */
write(fd[1], "\xC2\xA0", 2); termkey_push_bytes(tk, "\xC2\xA0", 2);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 low"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 low");
is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 2 low"); is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 2 low");
is_int(key.code.number, 0x00A0, "key.code.number UTF-8 2 low"); is_int(key.code.number, 0x00A0, "key.code.number UTF-8 2 low");
write(fd[1], "\xDF\xBF", 2); termkey_push_bytes(tk, "\xDF\xBF", 2);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 high"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 high");
is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 2 high"); is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 2 high");
is_int(key.code.number, 0x07FF, "key.code.number UTF-8 2 high"); is_int(key.code.number, 0x07FF, "key.code.number UTF-8 2 high");
/* 3-byte UTF-8 range is U+0800 (0xE0 0xA0 0x80) to U+FFFD (0xEF 0xBF 0xBD) */ /* 3-byte UTF-8 range is U+0800 (0xE0 0xA0 0x80) to U+FFFD (0xEF 0xBF 0xBD) */
write(fd[1], "\xE0\xA0\x80", 3); termkey_push_bytes(tk, "\xE0\xA0\x80", 3);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 low"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 low");
is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 3 low"); is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 3 low");
is_int(key.code.number, 0x0800, "key.code.number UTF-8 3 low"); is_int(key.code.number, 0x0800, "key.code.number UTF-8 3 low");
write(fd[1], "\xEF\xBF\xBD", 3); termkey_push_bytes(tk, "\xEF\xBF\xBD", 3);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 high"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 high");
is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 3 high"); is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 3 high");
is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 3 high"); is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 3 high");
/* 4-byte UTF-8 range is U+10000 (0xF0 0x90 0x80 0x80) to U+10FFFF (0xF4 0x8F 0xBF 0xBF) */ /* 4-byte UTF-8 range is U+10000 (0xF0 0x90 0x80 0x80) to U+10FFFF (0xF4 0x8F 0xBF 0xBF) */
write(fd[1], "\xF0\x90\x80\x80", 4); termkey_push_bytes(tk, "\xF0\x90\x80\x80", 4);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 low"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 low");
is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 4 low"); is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 4 low");
is_int(key.code.number, 0x10000, "key.code.number UTF-8 4 low"); is_int(key.code.number, 0x10000, "key.code.number UTF-8 4 low");
write(fd[1], "\xF4\x8F\xBF\xBF", 4); termkey_push_bytes(tk, "\xF4\x8F\xBF\xBF", 4);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 high"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 high");
is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 4 high"); is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type UTF-8 4 high");
is_int(key.code.number, 0x10FFFF, "key.code.number UTF-8 4 high"); is_int(key.code.number, 0x10FFFF, "key.code.number UTF-8 4 high");
/* Invalid continuations */ /* Invalid continuations */
write(fd[1], "\xC2!", 2); termkey_push_bytes(tk, "\xC2!", 2);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 invalid cont"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 invalid cont");
is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 2 invalid cont"); is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 2 invalid cont");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 invalid after"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 invalid after");
is_int(key.code.number, '!', "key.code.number UTF-8 2 invalid after"); is_int(key.code.number, '!', "key.code.number UTF-8 2 invalid after");
write(fd[1], "\xE0!", 2); termkey_push_bytes(tk, "\xE0!", 2);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 invalid cont"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 invalid cont");
is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 3 invalid cont"); is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 3 invalid cont");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 invalid after"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 invalid after");
is_int(key.code.number, '!', "key.code.number UTF-8 3 invalid after"); is_int(key.code.number, '!', "key.code.number UTF-8 3 invalid after");
write(fd[1], "\xE0\xA0!", 3); termkey_push_bytes(tk, "\xE0\xA0!", 3);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 invalid cont 2"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 invalid cont 2");
is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 3 invalid cont 2"); is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 3 invalid cont 2");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 invalid after"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 invalid after");
is_int(key.code.number, '!', "key.code.number UTF-8 3 invalid after"); is_int(key.code.number, '!', "key.code.number UTF-8 3 invalid after");
write(fd[1], "\xF0!", 2); termkey_push_bytes(tk, "\xF0!", 2);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid cont"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid cont");
is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 4 invalid cont"); is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 4 invalid cont");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid after"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid after");
is_int(key.code.number, '!', "key.code.number UTF-8 4 invalid after"); is_int(key.code.number, '!', "key.code.number UTF-8 4 invalid after");
write(fd[1], "\xF0\x90!", 3); termkey_push_bytes(tk, "\xF0\x90!", 3);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid cont 2"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid cont 2");
is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 4 invalid cont 2"); is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 4 invalid cont 2");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid after"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid after");
is_int(key.code.number, '!', "key.code.number UTF-8 4 invalid after"); is_int(key.code.number, '!', "key.code.number UTF-8 4 invalid after");
write(fd[1], "\xF0\x90\x80!", 4); termkey_push_bytes(tk, "\xF0\x90\x80!", 4);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid cont 3"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid cont 3");
is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 4 invalid cont 3"); is_int(key.code.number, 0xFFFD, "key.code.number UTF-8 4 invalid cont 3");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid after"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 invalid after");
@ -124,42 +108,33 @@ int main(int argc, char *argv[])
/* Partials */ /* Partials */
write(fd[1], "\xC2", 1); termkey_push_bytes(tk, "\xC2", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 2 partial"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 2 partial");
write(fd[1], "\xA0", 1); termkey_push_bytes(tk, "\xA0", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 partial"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 2 partial");
is_int(key.code.number, 0x00A0, "key.code.number UTF-8 2 partial"); is_int(key.code.number, 0x00A0, "key.code.number UTF-8 2 partial");
write(fd[1], "\xE0", 1); termkey_push_bytes(tk, "\xE0", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 3 partial"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 3 partial");
write(fd[1], "\xA0", 1); termkey_push_bytes(tk, "\xA0", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 3 partial"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 3 partial");
write(fd[1], "\x80", 1); termkey_push_bytes(tk, "\x80", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 partial"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 3 partial");
is_int(key.code.number, 0x0800, "key.code.number UTF-8 3 partial"); is_int(key.code.number, 0x0800, "key.code.number UTF-8 3 partial");
write(fd[1], "\xF0", 1); termkey_push_bytes(tk, "\xF0", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 4 partial"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 4 partial");
write(fd[1], "\x90", 1); termkey_push_bytes(tk, "\x90", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 4 partial"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 4 partial");
write(fd[1], "\x80", 1); termkey_push_bytes(tk, "\x80", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 4 partial"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN UTF-8 4 partial");
write(fd[1], "\x80", 1); termkey_push_bytes(tk, "\x80", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 partial"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY UTF-8 4 partial");
is_int(key.code.number, 0x10000, "key.code.number UTF-8 4 partial"); is_int(key.code.number, 0x10000, "key.code.number UTF-8 4 partial");

View File

@ -4,22 +4,19 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int fd[2];
TermKey *tk; TermKey *tk;
TermKeyKey key; TermKeyKey key;
plan_tests(8); plan_tests(8);
pipe(fd);
/* Sanitise this just in case */ /* Sanitise this just in case */
putenv("TERM=vt100"); putenv("TERM=vt100");
tk = termkey_new(fd[0], TERMKEY_FLAG_NOTERMIOS); tk = termkey_new(0, TERMKEY_FLAG_NOTERMIOS);
write(fd[1], " ", 1); termkey_push_bytes(tk, " ", 1);
is_int(termkey_waitkey(tk, &key), TERMKEY_RES_KEY, "waitkey yields RES_KEY after space"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after space");
is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type after space"); is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type after space");
is_int(key.code.number, ' ', "key.code.number after space"); is_int(key.code.number, ' ', "key.code.number after space");
@ -27,9 +24,9 @@ int main(int argc, char *argv[])
termkey_set_flags(tk, TERMKEY_FLAG_SPACESYMBOL); termkey_set_flags(tk, TERMKEY_FLAG_SPACESYMBOL);
write(fd[1], " ", 1); termkey_push_bytes(tk, " ", 1);
is_int(termkey_waitkey(tk, &key), TERMKEY_RES_KEY, "waitkey yields RES_KEY after space"); is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after space");
is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after space with FLAG_SPACESYMBOL"); is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after space with FLAG_SPACESYMBOL");
is_int(key.code.number, TERMKEY_SYM_SPACE, "key.code.sym after space with FLAG_SPACESYMBOL"); is_int(key.code.number, TERMKEY_SYM_SPACE, "key.code.sym after space with FLAG_SPACESYMBOL");

66
t/05read.c Normal file
View File

@ -0,0 +1,66 @@
#include <stdio.h>
#include "../termkey.h"
#include "taplib.h"
int main(int argc, char *argv[])
{
int fd[2];
TermKey *tk;
TermKeyKey key;
plan_tests(19);
/* We'll need a real filehandle we can write/read.
* pipe() can make us one */
pipe(fd);
/* Sanitise this just in case */
putenv("TERM=vt100");
tk = termkey_new(fd[0], TERMKEY_FLAG_NOTERMIOS);
is_int(termkey_get_buffer_remaining(tk), 256, "buffer free initially 256");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey yields RES_NONE when empty");
write(fd[1], "h", 1);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey yields RES_NONE before advisereadable");
is_int(termkey_advisereadable(tk), TERMKEY_RES_AGAIN, "advisereadable yields RES_AGAIN after h");
is_int(termkey_get_buffer_remaining(tk), 255, "buffer free 255 after advisereadable");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after h");
is_int(key.type, TERMKEY_TYPE_UNICODE, "key.type after h");
is_int(key.code.number, 'h', "key.code.number after h");
is_int(key.modifiers, 0, "key.modifiers after h");
is_str(key.utf8, "h", "key.utf8 after h");
is_int(termkey_get_buffer_remaining(tk), 256, "buffer free 256 after getkey");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey yields RES_NONE a second time");
write(fd[1], "\eO", 2);
termkey_advisereadable(tk);
is_int(termkey_get_buffer_remaining(tk), 254, "buffer free 254 after partial write");
is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN after partial write");
write(fd[1], "C", 1);
termkey_advisereadable(tk);
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY after Right completion");
is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Right");
is_int(key.code.sym, TERMKEY_SYM_RIGHT, "key.code.sym after Right");
is_int(key.modifiers, 0, "key.modifiers after Right");
is_int(termkey_get_buffer_remaining(tk), 256, "buffer free 256 after completion");
termkey_destroy(tk);
return exit_status();
}

View File

@ -976,6 +976,29 @@ retry:
} }
} }
size_t termkey_push_bytes(TermKey *tk, const char *bytes, size_t len)
{
if(tk->buffstart) {
memmove(tk->buffer, tk->buffer + tk->buffstart, tk->buffcount);
tk->buffstart = 0;
}
/* Not expecting it ever to be greater but doesn't hurt to handle that */
if(tk->buffcount >= tk->buffsize) {
errno = ENOMEM;
return (size_t)-1;
}
if(len > tk->buffsize - tk->buffcount)
len = tk->buffsize - tk->buffcount;
// memcpy(), not strncpy() in case of null bytes in input
memcpy(tk->buffer + tk->buffcount, bytes, len);
tk->buffcount += len;
return len;
}
TermKeySym termkey_register_keyname(TermKey *tk, TermKeySym sym, const char *name) TermKeySym termkey_register_keyname(TermKey *tk, TermKeySym sym, const char *name)
{ {
if(!sym) if(!sym)

View File

@ -181,6 +181,8 @@ TermKeyResult termkey_waitkey(TermKey *tk, TermKeyKey *key);
TermKeyResult termkey_advisereadable(TermKey *tk); TermKeyResult termkey_advisereadable(TermKey *tk);
size_t termkey_push_bytes(TermKey *tk, const char *bytes, size_t len);
TermKeySym termkey_register_keyname(TermKey *tk, TermKeySym sym, const char *name); TermKeySym termkey_register_keyname(TermKey *tk, TermKeySym sym, const char *name);
const char *termkey_get_keyname(TermKey *tk, TermKeySym sym); const char *termkey_get_keyname(TermKey *tk, TermKeySym sym);
char *termkey_lookup_keyname(TermKey *tk, const char *str, TermKeySym *sym); char *termkey_lookup_keyname(TermKey *tk, const char *str, TermKeySym *sym);