# HG changeset patch # User jbe # Date 1428174101 -7200 # Node ID daef4a38cc98fe6946a625feaa7eeec5d4b54518 # Parent ad06fc76906aa3e5179ff445809808039eb6000f Work on io.poll(...) and file handle methods "xread", "xread_nb", "write_nb" diff -r ad06fc76906a -r daef4a38cc98 moonbridge.c --- a/moonbridge.c Sat Apr 04 17:19:12 2015 +0200 +++ b/moonbridge.c Sat Apr 04 21:01:41 2015 +0200 @@ -936,7 +936,7 @@ return lua_gettop(L); } -/* Lua method for socket object to read from input stream until terminator */ +/* Lua method for socket object to read from input stream using xread */ static int moonbr_child_lua_xread_stream(lua_State *L) { lua_getfield(L, 1, "input"); lua_getfield(L, -1, "xread"); @@ -946,6 +946,16 @@ return lua_gettop(L); } +/* Lua method for socket object to read from input stream using xread_nb */ +static int moonbr_child_lua_xread_nb_stream(lua_State *L) { + lua_getfield(L, 1, "input"); + lua_getfield(L, -1, "xread_nb"); + lua_insert(L, 1); + lua_replace(L, 2); + lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); + return lua_gettop(L); +} + /* Lua method for socket object to iterate over input stream */ static int moonbr_child_lua_lines_stream(lua_State *L) { lua_getfield(L, 1, "input"); @@ -966,6 +976,16 @@ return lua_gettop(L); } +/* Lua method for socket object to write to output stream using write_nb */ +static int moonbr_child_lua_write_nb_stream(lua_State *L) { + lua_getfield(L, 1, "input"); + lua_getfield(L, -1, "write_nb"); + lua_insert(L, 1); + lua_replace(L, 2); + lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); + return lua_gettop(L); +} + /* Lua method for socket object to flush the output stream */ static int moonbr_child_lua_flush_stream(lua_State *L) { lua_getfield(L, 1, "output"); @@ -1042,13 +1062,15 @@ /* Methods of (bidirectional) socket object passed to handler */ static luaL_Reg moonbr_child_lua_socket_functions[] = { - {"read", moonbr_child_lua_read_stream}, - {"xread", moonbr_child_lua_xread_stream}, - {"lines", moonbr_child_lua_lines_stream}, - {"write", moonbr_child_lua_write_stream}, - {"flush", moonbr_child_lua_flush_stream}, - {"close", moonbr_child_lua_close_both_streams}, - {"cancel", moonbr_child_lua_cancel_both_streams}, + {"read", moonbr_child_lua_read_stream}, + {"xread", moonbr_child_lua_xread_stream}, + {"xread_nb", moonbr_child_lua_xread_nb_stream}, + {"lines", moonbr_child_lua_lines_stream}, + {"write", moonbr_child_lua_write_stream}, + {"write_nb", moonbr_child_lua_write_nb_stream}, + {"flush", moonbr_child_lua_flush_stream}, + {"close", moonbr_child_lua_close_both_streams}, + {"cancel", moonbr_child_lua_cancel_both_streams}, {NULL, NULL} }; @@ -2372,49 +2394,88 @@ } } -/* New method for Lua file objects: read until terminator or length exceeded */ -static int moonbr_io_xread(lua_State *L) { +/* New methods for Lua file objects: read until terminator or length exceeded (optional non-blocking) */ +static int moonbr_io_xread_impl(lua_State *L, int nonblock) { luaL_Stream *stream; - FILE *file; + lua_Integer maxlen; const char *terminatorstr; size_t terminatorlen; + FILE *file; + int fd, flags, chr, terminator; luaL_Buffer buf; - lua_Integer maxlen; - char terminator; - int byte; + int wouldblock = 0; stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); - terminatorstr = luaL_checklstring(L, 2, &terminatorlen); - luaL_argcheck(L, terminatorlen == 1, 2, "single byte expected"); - maxlen = luaL_optinteger(L, 3, 0); + maxlen = luaL_optinteger(L, 2, 0); + terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen); + luaL_argcheck(L, terminatorlen <= 1, 3, "single byte expected"); if (!stream->closef) luaL_error(L, "attempt to use a closed file"); file = stream->f; - luaL_buffinit(L, &buf); + if (ferror(file)) { + lua_pushnil(L); + lua_pushliteral(L, "Previous error condition on file handle"); + return 2; + } + if (nonblock) { + fd = fileno(file); + flags = fcntl(fd, F_GETFL, 0); + if (flags == -1) goto moonbr_io_xread_impl_error; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_xread_impl_error; + } if (!maxlen) maxlen = -1; - terminator = terminatorstr[0]; - flockfile(file); + terminator = terminatorlen ? terminatorstr[0] : -1; + luaL_buffinit(L, &buf); while (maxlen > 0 ? maxlen-- : maxlen) { - byte = getc_unlocked(file); - if (byte == EOF) { + chr = getc(file); + if (chr == EOF) { if (ferror(file)) { - char errmsg[MOONBR_MAXSTRERRORLEN]; - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ - funlockfile(file); - lua_pushnil(L); - lua_pushstring(L, errmsg); - return 2; - } else { - break; + if (nonblock && errno == EAGAIN) { + clearerr(file); + wouldblock = 1; + } else { + char errmsg[MOONBR_MAXSTRERRORLEN]; + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ + if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_xread_impl_error; + lua_pushnil(L); + lua_pushstring(L, errmsg); + return 2; + } } + break; } - luaL_addchar(&buf, byte); - if (byte == terminator) break; + luaL_addchar(&buf, chr); + if (chr == terminator) break; + } + if (nonblock) { + if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_xread_impl_error; } - funlockfile(file); luaL_pushresult(&buf); - if (!lua_rawlen(L, -1)) lua_pushnil(L); - return 1; + if (wouldblock || lua_rawlen(L, -1)) { + return 1; + } else { + lua_pushboolean(L, 0); + lua_pushliteral(L, "End of file"); + return 2; + } + moonbr_io_xread_impl_error: + { + char errmsg[MOONBR_MAXSTRERRORLEN]; + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ + return luaL_error(L, "Unexpected error in xread method: %s", errmsg); + } +} +static int moonbr_io_xread(lua_State *L) { + return moonbr_io_xread_impl(L, 0); +} +static int moonbr_io_xread_nb(lua_State *L) { + return moonbr_io_xread_impl(L, 1); } +/* New methods for Lua file objects: non-blocking writing */ +static int moonbr_io_write_nb(lua_State *L) { + return luaL_error(L, "Not implemented"); // TODO +} + +/* New global function timeout(...) */ static int moonbr_timeout(lua_State *L) { struct itimerval oldval; if (lua_isnoneornil(L, 1) && lua_isnoneornil(L, 2)) { @@ -2893,6 +2954,10 @@ lua_getfield(L, -1, "__index"); lua_pushcfunction(L, moonbr_io_xread); lua_setfield(L, -2, "xread"); + lua_pushcfunction(L, moonbr_io_xread_nb); + lua_setfield(L, -2, "xread_nb"); + lua_pushcfunction(L, moonbr_io_write_nb); + lua_setfield(L, -2, "write_nb"); lua_pop(L, 2); lua_pushcfunction(L, moonbr_timeout); lua_setglobal(L, "timeout");