From 4ced40349467434176146c5539f6ce6aff4e654d Mon Sep 17 00:00:00 2001 From: daurnimator Date: Sat, 8 Aug 2015 18:35:13 +1000 Subject: [PATCH 1/4] socket:unget now looks at the current mode and inserts carriage returns if in text mode This means :unget then :read roundtrips --- src/socket.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/socket.c b/src/socket.c index c7f1e2e..157ff19 100644 --- a/src/socket.c +++ b/src/socket.c @@ -26,7 +26,7 @@ #include /* NULL offsetof size_t */ #include /* va_list va_start va_arg va_end */ #include /* strtol(3) */ -#include /* memset(3) memchr(3) memcpy(3) memmem(3) */ +#include /* memset(3) memchr(3) memcpy(3) memmem(3) memrchr(3) */ #include /* NAN */ #include /* EBADF ENOTSOCK EOPNOTSUPP EOVERFLOW EPIPE */ @@ -2137,12 +2137,30 @@ static lso_nargs_t lso_recv3(lua_State *L) { static lso_nargs_t lso_unget2(lua_State *L) { struct luasocket *S = lso_checkself(L, 1); - const void *src; - size_t len; + const char *src, *new_base; + size_t len, found; struct iovec iov; - int error; + int mode, error; src = luaL_checklstring(L, 2, &len); + mode = S->ibuf.mode; + + if (mode & LSO_TEXT) { + /* insert \r before each \n */ + while ((new_base = memrchr(src, '\n', len))) { + found = len - (new_base - src); /* number of bytes found including \n */ + + if ((error = fifo_grow(&S->ibuf.fifo, found+1))) + goto error; + + fifo_rewind(&S->ibuf.fifo, found+1); + fifo_slice(&S->ibuf.fifo, &iov, 0, found+1); + memcpy(iov.iov_base+1, new_base, found); + ((char*)iov.iov_base)[0] = '\r'; + + len = new_base - src; + } + } if ((error = fifo_grow(&S->ibuf.fifo, len))) goto error; From 10067615e095922d0c3b4297a0d23119b9fedaa8 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Sat, 8 Aug 2015 18:42:24 +1000 Subject: [PATCH 2/4] Add support for 'mode' argument to socket:unget --- src/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.c b/src/socket.c index 157ff19..f149229 100644 --- a/src/socket.c +++ b/src/socket.c @@ -2143,7 +2143,7 @@ static lso_nargs_t lso_unget2(lua_State *L) { int mode, error; src = luaL_checklstring(L, 2, &len); - mode = S->ibuf.mode; + mode = lso_imode(luaL_optstring(L, 3, ""), S->ibuf.mode); if (mode & LSO_TEXT) { /* insert \r before each \n */ From d09c9d671e46af5b5207e1bed1e9bc7ef967aeda Mon Sep 17 00:00:00 2001 From: daurnimator Date: Sat, 8 Aug 2015 18:44:49 +1000 Subject: [PATCH 3/4] document the new 'mode' option to socket:unget --- doc/cqueues.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/cqueues.tex b/doc/cqueues.tex index 7431243..e120c52 100644 --- a/doc/cqueues.tex +++ b/doc/cqueues.tex @@ -695,8 +695,9 @@ \subsubsection{\routine{cqueues.COMMIT}} \subsubsection[\fn{socket:fill}]{\fn{socket:fill(size[, timeout])}} Fills the input buffer with `size' bytes. Returns true on success, false and an error code on failure. -\subsubsection[{\fn{socket:unget}}]{\fn{socket:unget(string)}} +\subsubsection[{\fn{socket:unget}}]{\fn{socket:unget(string [, mode])}} Writes `string' to the head of the socket input buffer. +$mode$ should be in the format described at \method{socket:setmode} \subsubsection[{\fn{socket:pending}}]{\fn{socket:pending()}} Returns two numbers---the counts of buffered bytes in the input and output streams. This does not include the bytes in the kernel's buffer. From 37cf34b3a61e37f5026c15f1649ffbe5efbdb05f Mon Sep 17 00:00:00 2001 From: daurnimator Date: Sat, 8 Aug 2015 19:29:25 +1000 Subject: [PATCH 4/4] Add test case for socket:unget roundtrip --- regress/90-unget-textmode.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100755 regress/90-unget-textmode.lua diff --git a/regress/90-unget-textmode.lua b/regress/90-unget-textmode.lua new file mode 100755 index 0000000..ebf2b58 --- /dev/null +++ b/regress/90-unget-textmode.lua @@ -0,0 +1,28 @@ +#!/bin/sh +_=[[ + . "${0%%/*}/regress.sh" + exec runlua "$0" "$@" +]] +require"regress".export".*" + +local function test_with_mode(str, mode) + local c, s = socket.pair() + check(s:xwrite(str, "bn")) + local foo = c:xread(-99999, mode) + check(c:unget(foo, mode)) + local bar = c:xread(-99999, mode) + check(foo == bar, "unget + read does not round trip") +end +local function test(str) + info("testing: %q", str) + test_with_mode(str, "t") + test_with_mode(str, "b") +end + +test'test' +test'test\n' +test'hi\r\nthere\nworld\r' +test'\n\n' +test'foo\r\r\n' + +say("OK")