# HG changeset patch # User jbe # Date 1428353931 -7200 # Node ID ef552870f1b66648ce79e5ac6fb06b4f8d32b2da # Parent 8a6e2a80fcada6806ff331b15f83a1a82c84b4a5 Implementation of read and read_nb in I/O module diff -r 8a6e2a80fcad -r ef552870f1b6 moonbridge_io.c --- a/moonbridge_io.c Mon Apr 06 15:41:37 2015 +0200 +++ b/moonbridge_io.c Mon Apr 06 22:58:51 2015 +0200 @@ -16,6 +16,7 @@ #include #define MOONBR_IO_MAXSTRERRORLEN 80 +#define MOONBR_IO_READBUFLEN 4096 #define MOONBR_IO_WRITEBUFLEN 4096 #define moonbr_io_errmsg() \ @@ -30,6 +31,8 @@ int fd; int issocket; int nonblocking; + int readerr; + int readbufcnt; int writeerr; size_t writeleft; #if LUA_VERSION_NUM >= 503 @@ -41,6 +44,7 @@ #endif size_t writeqoff; int writebufcnt; + char readbuf[MOONBR_IO_READBUFLEN]; char writebuf[MOONBR_IO_WRITEBUFLEN]; } moonbr_io_handle_t; @@ -61,6 +65,77 @@ } } +static int moonbr_io_read_impl(lua_State *L, int nonblocking) { + moonbr_io_handle_t *handle; + lua_Integer maxread; + const char *terminatorstr; + size_t terminatorlen; + char terminator; + luaL_Buffer luabuf; + size_t luabufcnt = 0; + int restcnt; + char *terminatorpos; + ssize_t result; + handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); + maxread = luaL_optinteger(L, 2, 0); + terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen); + if (terminatorlen) { + luaL_argcheck(L, terminatorlen == 1, 3, "single byte expected"); + terminator = terminatorstr[0]; + } + if (handle->fd < 0) luaL_error(L, "Attempt to read from a closed I/O handle"); + if (handle->readerr) { + lua_pushnil(L); + lua_pushliteral(L, "Previous read error"); + return 2; + } + moonbr_io_handle_set_nonblocking(L, handle, nonblocking); + luaL_buffinit(L, &luabuf); + while (1) { + restcnt = -1; + if (maxread > 0 && handle->readbufcnt >= maxread - luabufcnt) { + restcnt = maxread - luabufcnt; + } else if (terminatorlen) { + terminatorpos = memchr(handle->readbuf, terminator, handle->readbufcnt); + if (terminatorpos) restcnt = 1 + (terminatorpos - handle->readbuf); + } + if (restcnt >= 0) { + luaL_addlstring(&luabuf, handle->readbuf, restcnt); + handle->readbufcnt -= restcnt; + memmove(handle->readbuf, handle->readbuf + restcnt, handle->readbufcnt); + luaL_pushresult(&luabuf); + return 1; + } + luaL_addlstring(&luabuf, handle->readbuf, handle->readbufcnt); + luabufcnt += handle->readbufcnt; + handle->readbufcnt = 0; + do { + result = read(handle->fd, handle->readbuf, MOONBR_IO_READBUFLEN); + } while (result < 0 && (errno == EINTR)); + if (result == 0 || (nonblocking && result < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))) break; + if (result < 0) { + moonbr_io_errmsg(); + handle->readerr = 1; + lua_pushnil(L); + lua_pushstring(L, errmsg); + return 2; + } + handle->readbufcnt += result; + } + luaL_addlstring(&luabuf, handle->readbuf, handle->readbufcnt); + handle->readbufcnt = 0; + luaL_pushresult(&luabuf); + return 1; +} + +static int moonbr_io_read(lua_State *L) { + return moonbr_io_read_impl(L, 0); +} + +static int moonbr_io_read_nb(lua_State *L) { + return moonbr_io_read_impl(L, 1); +} + static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) { moonbr_io_handle_t *handle; int i, top; @@ -221,6 +296,8 @@ handle->fd = fd; handle->issocket = issocket; handle->nonblocking = -1; + handle->readerr = 0; + handle->readbufcnt = 0; handle->writeerr = 0; handle->writeleft = 0; handle->writeqin = 0; @@ -271,17 +348,19 @@ } static int moonbr_io_getdummy(lua_State *L) { - moonbr_io_pushhandle(L, 2, 0); + moonbr_io_pushhandle(L, 0, 0); return 1; } static const struct luaL_Reg moonbr_io_handle_methods[] = { - {"reset", moonbr_io_reset}, - {"close", moonbr_io_close}, + {"read", moonbr_io_read}, + {"read_nb", moonbr_io_read_nb}, {"write", moonbr_io_write}, {"write_nb", moonbr_io_write_nb}, {"flush", moonbr_io_flush}, {"flush_nb", moonbr_io_flush_nb}, + {"reset", moonbr_io_reset}, + {"close", moonbr_io_close}, {NULL, NULL} };