# HG changeset patch # User jbe # Date 1430524109 -7200 # Node ID 41da87a681d6ae8fb25d28ecdf3f915bd60edbc6 # Parent 8cd9acda385300da81577bcc567b69fcc40530cf Method "read" always returns two return values diff -r 8cd9acda3853 -r 41da87a681d6 moonbridge_io.c --- a/moonbridge_io.c Fri May 01 13:56:52 2015 +0200 +++ b/moonbridge_io.c Sat May 02 01:48:29 2015 +0200 @@ -174,8 +174,14 @@ lua_pushliteral(L, "Previous read error"); return 2; } + if (handle->fd < 0) { + /* fake EOF to simulate shutdown */ + if (!drain) lua_pushliteral(L, ""); + else lua_pushinteger(L, 0); + lua_pushliteral(L, "eof"); + return 2; + } handle->readerr = 1; - if (handle->fd < 0) goto moonbr_io_read_impl_eof; /* fake EOF to simulate shutdown */ moonbr_io_handle_set_nonblocking(L, handle, nonblocking); if (!drain) luaL_buffinit(L, &luabuf); while (1) { @@ -183,7 +189,7 @@ terminatorpos = NULL; if ( maxread > 0 && - (size_t)maxread - luabufcnt <= handle->readbufin - handle->readbufout + handle->readbufin - handle->readbufout >= (size_t)maxread - luabufcnt ) { remaining = (size_t)maxread - luabufcnt; terminatorpos = memchr( @@ -212,13 +218,15 @@ } else { lua_pushinteger(L, luabufcnt + remaining); } + if (terminatorpos) lua_pushliteral(L, "term"); + else lua_pushliteral(L, "maxlen"); handle->readbufout += remaining; if (handle->readbufout == handle->readbufin) { handle->readbufin = 0; - handle->readbufout =0; + handle->readbufout = 0; } handle->readerr = 0; - return 1; + return 2; } if (!drain) luaL_addlstring( &luabuf, @@ -226,6 +234,7 @@ handle->readbufin - handle->readbufout ); luabufcnt += handle->readbufin - handle->readbufout; + handle->readbufout = 0; do { bytesread = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN); } while (bytesread < 0 && (errno == EINTR)); @@ -236,23 +245,12 @@ ) ) { handle->readbufin = 0; - handle->readbufout = 0; - if (!drain) { - luaL_pushresult(&luabuf); - if (!luabufcnt && bytesread == 0) { - lua_pop(L, 1); - moonbr_io_read_impl_eof: - lua_pushboolean(L, 0); - lua_pushliteral(L, "End of file"); - handle->readerr = 0; - return 2; - } - } else { - if (!luabufcnt && bytesread == 0) lua_pushboolean(L, 1); - else lua_pushboolean(L, luabufcnt); - } + if (!drain) luaL_pushresult(&luabuf); + else lua_pushinteger(L, luabufcnt); + if (bytesread == 0) lua_pushliteral(L, "eof"); + else lua_pushliteral(L, "block"); handle->readerr = 0; - return 1; + return 2; } if (bytesread < 0) { moonbr_io_errmsg(); @@ -261,7 +259,6 @@ return 2; } handle->readbufin = bytesread; - handle->readbufout = 0; } } @@ -286,11 +283,8 @@ #else static int moonbr_io_read_cont(lua_State *L) { #endif - size_t len, remaining; - const char *terminatorstr = NULL; - size_t terminatorlen = 0; - const char *chunk; - size_t chunklen; + lua_Integer remaining; + size_t len; #if !(LUA_VERSION_NUM >= 503) int ctx = 0; lua_getctx(L, &ctx); @@ -302,46 +296,29 @@ lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_call(L, 3, 2); - if (lua_isnil(L, -2)) { - return 2; - } else if (!lua_toboolean(L, -2)) { - if (ctx) { - lua_pushnil(L); - lua_pushliteral(L, "Unexpected EOF"); - } - return 2; - } - len = lua_rawlen(L, -2); - if (!len) { - lua_pop(L, 2); + if (lua_isnil(L, -2)) return 2; + lua_insert(L, -2); + len = lua_rawlen(L, -1); + if (ctx == 0) { + lua_replace(L, 5); + ctx = 1; + } else if (ctx == 1) { + lua_pushvalue(L, 5); + lua_newtable(L); + lua_replace(L, 5); + lua_rawseti(L, 5, 2); + lua_rawseti(L, 5, 1); + ctx = 2; } else { - lua_pop(L, 1); - if (!terminatorstr) { - terminatorstr = lua_tolstring(L, 4, &terminatorlen); - if (!terminatorstr) terminatorstr = ""; - } - if (terminatorlen) chunk = lua_tolstring(L, -1, &chunklen); - if (ctx == 0) { - lua_replace(L, 5); - ctx = 1; - } else if (ctx == 1) { - lua_pushvalue(L, 5); - lua_newtable(L); - lua_replace(L, 5); - lua_rawseti(L, 5, 2); - lua_rawseti(L, 5, 1); - ctx = 2; - } else { - lua_rawseti(L, 5, lua_rawlen(L, 5) + 1); - } - if (remaining) { - if (len >= remaining) break; - remaining -= len; - lua_pushinteger(L, remaining); - lua_replace(L, 3); - } - if (terminatorlen && chunk[chunklen-1] == terminatorstr[0]) break; + lua_rawseti(L, 5, lua_rawlen(L, 5) + 1); } + if (remaining >= 0) { + remaining -= len; + lua_pushinteger(L, remaining); + lua_replace(L, 3); + } + if (strcmp(lua_tostring(L, -1), "block") != 0) break; + lua_pop(L, 1); lua_pushvalue(L, 2); lua_pushvalue(L, 1); lua_pushliteral(L, "r"); @@ -360,7 +337,8 @@ } luaL_pushresult(&buf); } - return 1; + lua_pushvalue(L, -2); + return 2; } static int moonbr_io_read_call(lua_State *L) { diff -r 8cd9acda3853 -r 41da87a681d6 reference.txt --- a/reference.txt Fri May 01 13:56:52 2015 +0200 +++ b/reference.txt Sat May 02 01:48:29 2015 +0200 @@ -70,8 +70,8 @@ ### socket:drain(maxlen, terminator) Same as socket:read(maxlen, terminator), but discards the input and returns the -number of discarded bytes. If no bytes could be read but EOF was encountered, -then true is returned. +number of discarded bytes (as first return value) and the status code ("term", +"maxlen", "eof" as second return value). In case of an I/O error, nil (as first return value) plus an error message (as second return value) are returned. @@ -79,9 +79,9 @@ ### socket:drain_nb(maxlen, terminator) -Same as socket:read_nb(maxlen, terminator), but discards the input and returns -the number of discarded bytes. If no bytes could be read but EOF was -encountered, then true is returned. +Same as socket:drain(maxlen, terminator), but non-blocking. The status code +(which is returned as second return value) may therefore be "term", "maxlen", +"eof", or "block". In case of an I/O error, nil (as first return value) plus an error message (as second return value) are returned. @@ -144,16 +144,24 @@ ### socket:read(maxlen, terminator) -Read up to maxlen bytes or until an optional termination character is +Reads up to maxlen bytes or until an optional termination character is encountered (which is included in the result). The maxlen value may be nil, in which case there is no limit on the number of bytes read. -If EOF is encountered before any data could be read, then false (as first -return value) plus a notice string (as second return value) are returned. - In case of an I/O error, nil (as first return value) plus an error message (as second return value) are returned. +In all other cases (including EOF), the following two values are returned: + +- a string containing the bytes read (first return value, may be empty string) +- a status code equal to "term", "maxlen", or "eof" (second return value) + +If an EOF is encountered before all data could be read, then "eof" is returned +as second return value. If maxlen bytes have been read and no termination +character has been read, then "maxlen" is returned as second return value. If +the termination character is the last character of the read string, the second +return value will be "term". + ### socket:read_call(waitfunc, maxlen, terminator) @@ -163,20 +171,20 @@ ### socket:read_nb(maxlen, terminator) -Read up to maxlen bytes, until an optional termination character is encountered -(which is included in the result), or until no more data is available for -reading. The maxlen value may be nil, in which case there is no limit on the -number of bytes read. - -If EOF is encountered before any data could be read, then false (as first -return value) plus a notice string (as second return value) are returned. - -If no data was available for reading, but no EOF was encountered, then an empty -string is returned. +Same as socket:read(maxlen, terminator), but does not block. In case of an I/O error, nil (as first return value) plus an error message (as second return value) are returned. +In all other cases (including EOF), the following two values are returned: + +- a string containing the bytes read (first return value, may be empty string) +- a status code equal to "term", "maxlen", "eof", "block" (second return value) + +The status code "block" as second return value is used if the function returned +prematurely because it would block otherwise. In this case, the first return +value is a string that contains the bytes that could be read without blocking. + ### socket:read_yield(maxlen, terminator)