moonbridge
changeset 69:daef4a38cc98
Work on io.poll(...) and file handle methods "xread", "xread_nb", "write_nb"
author | jbe |
---|---|
date | Sat Apr 04 21:01:41 2015 +0200 (2015-04-04) |
parents | ad06fc76906a |
children | 360a1860bb14 |
files | moonbridge.c |
line diff
1.1 --- a/moonbridge.c Sat Apr 04 17:19:12 2015 +0200 1.2 +++ b/moonbridge.c Sat Apr 04 21:01:41 2015 +0200 1.3 @@ -936,7 +936,7 @@ 1.4 return lua_gettop(L); 1.5 } 1.6 1.7 -/* Lua method for socket object to read from input stream until terminator */ 1.8 +/* Lua method for socket object to read from input stream using xread */ 1.9 static int moonbr_child_lua_xread_stream(lua_State *L) { 1.10 lua_getfield(L, 1, "input"); 1.11 lua_getfield(L, -1, "xread"); 1.12 @@ -946,6 +946,16 @@ 1.13 return lua_gettop(L); 1.14 } 1.15 1.16 +/* Lua method for socket object to read from input stream using xread_nb */ 1.17 +static int moonbr_child_lua_xread_nb_stream(lua_State *L) { 1.18 + lua_getfield(L, 1, "input"); 1.19 + lua_getfield(L, -1, "xread_nb"); 1.20 + lua_insert(L, 1); 1.21 + lua_replace(L, 2); 1.22 + lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.23 + return lua_gettop(L); 1.24 +} 1.25 + 1.26 /* Lua method for socket object to iterate over input stream */ 1.27 static int moonbr_child_lua_lines_stream(lua_State *L) { 1.28 lua_getfield(L, 1, "input"); 1.29 @@ -966,6 +976,16 @@ 1.30 return lua_gettop(L); 1.31 } 1.32 1.33 +/* Lua method for socket object to write to output stream using write_nb */ 1.34 +static int moonbr_child_lua_write_nb_stream(lua_State *L) { 1.35 + lua_getfield(L, 1, "input"); 1.36 + lua_getfield(L, -1, "write_nb"); 1.37 + lua_insert(L, 1); 1.38 + lua_replace(L, 2); 1.39 + lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); 1.40 + return lua_gettop(L); 1.41 +} 1.42 + 1.43 /* Lua method for socket object to flush the output stream */ 1.44 static int moonbr_child_lua_flush_stream(lua_State *L) { 1.45 lua_getfield(L, 1, "output"); 1.46 @@ -1042,13 +1062,15 @@ 1.47 1.48 /* Methods of (bidirectional) socket object passed to handler */ 1.49 static luaL_Reg moonbr_child_lua_socket_functions[] = { 1.50 - {"read", moonbr_child_lua_read_stream}, 1.51 - {"xread", moonbr_child_lua_xread_stream}, 1.52 - {"lines", moonbr_child_lua_lines_stream}, 1.53 - {"write", moonbr_child_lua_write_stream}, 1.54 - {"flush", moonbr_child_lua_flush_stream}, 1.55 - {"close", moonbr_child_lua_close_both_streams}, 1.56 - {"cancel", moonbr_child_lua_cancel_both_streams}, 1.57 + {"read", moonbr_child_lua_read_stream}, 1.58 + {"xread", moonbr_child_lua_xread_stream}, 1.59 + {"xread_nb", moonbr_child_lua_xread_nb_stream}, 1.60 + {"lines", moonbr_child_lua_lines_stream}, 1.61 + {"write", moonbr_child_lua_write_stream}, 1.62 + {"write_nb", moonbr_child_lua_write_nb_stream}, 1.63 + {"flush", moonbr_child_lua_flush_stream}, 1.64 + {"close", moonbr_child_lua_close_both_streams}, 1.65 + {"cancel", moonbr_child_lua_cancel_both_streams}, 1.66 {NULL, NULL} 1.67 }; 1.68 1.69 @@ -2372,49 +2394,88 @@ 1.70 } 1.71 } 1.72 1.73 -/* New method for Lua file objects: read until terminator or length exceeded */ 1.74 -static int moonbr_io_xread(lua_State *L) { 1.75 +/* New methods for Lua file objects: read until terminator or length exceeded (optional non-blocking) */ 1.76 +static int moonbr_io_xread_impl(lua_State *L, int nonblock) { 1.77 luaL_Stream *stream; 1.78 - FILE *file; 1.79 + lua_Integer maxlen; 1.80 const char *terminatorstr; 1.81 size_t terminatorlen; 1.82 + FILE *file; 1.83 + int fd, flags, chr, terminator; 1.84 luaL_Buffer buf; 1.85 - lua_Integer maxlen; 1.86 - char terminator; 1.87 - int byte; 1.88 + int wouldblock = 0; 1.89 stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.90 - terminatorstr = luaL_checklstring(L, 2, &terminatorlen); 1.91 - luaL_argcheck(L, terminatorlen == 1, 2, "single byte expected"); 1.92 - maxlen = luaL_optinteger(L, 3, 0); 1.93 + maxlen = luaL_optinteger(L, 2, 0); 1.94 + terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen); 1.95 + luaL_argcheck(L, terminatorlen <= 1, 3, "single byte expected"); 1.96 if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.97 file = stream->f; 1.98 - luaL_buffinit(L, &buf); 1.99 + if (ferror(file)) { 1.100 + lua_pushnil(L); 1.101 + lua_pushliteral(L, "Previous error condition on file handle"); 1.102 + return 2; 1.103 + } 1.104 + if (nonblock) { 1.105 + fd = fileno(file); 1.106 + flags = fcntl(fd, F_GETFL, 0); 1.107 + if (flags == -1) goto moonbr_io_xread_impl_error; 1.108 + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_xread_impl_error; 1.109 + } 1.110 if (!maxlen) maxlen = -1; 1.111 - terminator = terminatorstr[0]; 1.112 - flockfile(file); 1.113 + terminator = terminatorlen ? terminatorstr[0] : -1; 1.114 + luaL_buffinit(L, &buf); 1.115 while (maxlen > 0 ? maxlen-- : maxlen) { 1.116 - byte = getc_unlocked(file); 1.117 - if (byte == EOF) { 1.118 + chr = getc(file); 1.119 + if (chr == EOF) { 1.120 if (ferror(file)) { 1.121 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.122 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.123 - funlockfile(file); 1.124 - lua_pushnil(L); 1.125 - lua_pushstring(L, errmsg); 1.126 - return 2; 1.127 - } else { 1.128 - break; 1.129 + if (nonblock && errno == EAGAIN) { 1.130 + clearerr(file); 1.131 + wouldblock = 1; 1.132 + } else { 1.133 + char errmsg[MOONBR_MAXSTRERRORLEN]; 1.134 + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.135 + if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_xread_impl_error; 1.136 + lua_pushnil(L); 1.137 + lua_pushstring(L, errmsg); 1.138 + return 2; 1.139 + } 1.140 } 1.141 + break; 1.142 } 1.143 - luaL_addchar(&buf, byte); 1.144 - if (byte == terminator) break; 1.145 + luaL_addchar(&buf, chr); 1.146 + if (chr == terminator) break; 1.147 + } 1.148 + if (nonblock) { 1.149 + if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_xread_impl_error; 1.150 } 1.151 - funlockfile(file); 1.152 luaL_pushresult(&buf); 1.153 - if (!lua_rawlen(L, -1)) lua_pushnil(L); 1.154 - return 1; 1.155 + if (wouldblock || lua_rawlen(L, -1)) { 1.156 + return 1; 1.157 + } else { 1.158 + lua_pushboolean(L, 0); 1.159 + lua_pushliteral(L, "End of file"); 1.160 + return 2; 1.161 + } 1.162 + moonbr_io_xread_impl_error: 1.163 + { 1.164 + char errmsg[MOONBR_MAXSTRERRORLEN]; 1.165 + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.166 + return luaL_error(L, "Unexpected error in xread method: %s", errmsg); 1.167 + } 1.168 +} 1.169 +static int moonbr_io_xread(lua_State *L) { 1.170 + return moonbr_io_xread_impl(L, 0); 1.171 +} 1.172 +static int moonbr_io_xread_nb(lua_State *L) { 1.173 + return moonbr_io_xread_impl(L, 1); 1.174 } 1.175 1.176 +/* New methods for Lua file objects: non-blocking writing */ 1.177 +static int moonbr_io_write_nb(lua_State *L) { 1.178 + return luaL_error(L, "Not implemented"); // TODO 1.179 +} 1.180 + 1.181 +/* New global function timeout(...) */ 1.182 static int moonbr_timeout(lua_State *L) { 1.183 struct itimerval oldval; 1.184 if (lua_isnoneornil(L, 1) && lua_isnoneornil(L, 2)) { 1.185 @@ -2893,6 +2954,10 @@ 1.186 lua_getfield(L, -1, "__index"); 1.187 lua_pushcfunction(L, moonbr_io_xread); 1.188 lua_setfield(L, -2, "xread"); 1.189 + lua_pushcfunction(L, moonbr_io_xread_nb); 1.190 + lua_setfield(L, -2, "xread_nb"); 1.191 + lua_pushcfunction(L, moonbr_io_write_nb); 1.192 + lua_setfield(L, -2, "write_nb"); 1.193 lua_pop(L, 2); 1.194 lua_pushcfunction(L, moonbr_timeout); 1.195 lua_setglobal(L, "timeout");