jbe@79: jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: jbe@79: #include jbe@79: #include jbe@79: #include jbe@79: jbe@80: #define MOONBR_IO_MAXSTRERRORLEN 80 jbe@80: #define MOONBR_IO_WRITEBUFLEN 4096 jbe@80: jbe@80: #define moonbr_io_errmsg() \ jbe@80: char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \ jbe@80: strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN) jbe@80: jbe@80: jbe@79: #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle" jbe@79: #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public" jbe@79: jbe@79: typedef struct { jbe@79: int fd; jbe@80: int writecnt; jbe@80: char writebuf[MOONBR_IO_WRITEBUFLEN]; jbe@79: } moonbr_io_handle_t; jbe@79: jbe@80: static int moonbr_io_close(lua_State *L) { jbe@80: moonbr_io_handle_t *handle; jbe@80: handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@80: if (handle->fd < 0) luaL_error(L, "Attempt to close a closed I/O handle"); jbe@80: if (close(handle->fd)) { jbe@80: handle->fd = -1; jbe@80: moonbr_io_errmsg(); jbe@80: lua_pushnil(L); jbe@80: lua_pushstring(L, errmsg); jbe@80: return 2; jbe@80: } jbe@80: handle->fd = -1; jbe@80: lua_pushboolean(L, 1); jbe@80: return 1; jbe@80: } jbe@80: jbe@80: static int moonbr_io_write(lua_State *L) { jbe@80: moonbr_io_handle_t *handle; jbe@80: int i, top; jbe@80: const char *str; jbe@80: size_t strlen; jbe@80: size_t written; jbe@80: ssize_t result; jbe@80: handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@80: if (handle->writecnt < 0) { jbe@80: lua_pushnil(L); jbe@80: lua_pushliteral(L, "Previous write error"); jbe@80: return 2; jbe@80: } jbe@80: top = lua_gettop(L); jbe@80: for (i=2; i<=top; i++) { jbe@80: str = luaL_checklstring(L, i, &strlen); jbe@80: while (strlen) { jbe@80: if (strlen < MOONBR_IO_WRITEBUFLEN - handle->writecnt) { jbe@80: memcpy(handle->writebuf + handle->writecnt, str, strlen); jbe@80: handle->writecnt += strlen; jbe@80: break; jbe@80: } else { jbe@80: written = 0; jbe@80: memcpy(handle->writebuf + handle->writecnt, str, MOONBR_IO_WRITEBUFLEN - handle->writecnt); jbe@80: while (written < MOONBR_IO_WRITEBUFLEN) { jbe@80: result = write(handle->fd, handle->writebuf + written, MOONBR_IO_WRITEBUFLEN - written); jbe@80: if (result < 0) { jbe@80: if (errno != EINTR) { jbe@80: moonbr_io_errmsg(); jbe@80: handle->writecnt = -1; jbe@80: lua_pushnil(L); jbe@80: lua_pushstring(L, errmsg); jbe@80: return 2; jbe@80: } jbe@80: } else { jbe@80: written += result; jbe@80: } jbe@80: } jbe@80: str += MOONBR_IO_WRITEBUFLEN - handle->writecnt; jbe@80: strlen -= MOONBR_IO_WRITEBUFLEN - handle->writecnt; jbe@80: handle->writecnt = 0; jbe@80: } jbe@80: } jbe@80: } jbe@80: lua_settop(L, 1); jbe@80: return 1; jbe@80: } jbe@80: jbe@80: static int moonbr_io_flush(lua_State *L) { jbe@80: moonbr_io_handle_t *handle; jbe@80: size_t written; jbe@80: ssize_t result; jbe@80: handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@80: if (handle->writecnt < 0) { jbe@80: lua_pushnil(L); jbe@80: lua_pushliteral(L, "Previous write error"); jbe@80: return 2; jbe@80: } jbe@80: written = 0; jbe@80: while (written < handle->writecnt) { jbe@80: result = write(handle->fd, handle->writebuf + written, handle->writecnt - written); jbe@80: if (result < 0) { jbe@80: if (errno != EINTR) { jbe@80: moonbr_io_errmsg(); jbe@80: handle->writecnt = -1; jbe@80: lua_pushnil(L); jbe@80: lua_pushstring(L, errmsg); jbe@80: return 2; jbe@80: } jbe@80: } else { jbe@80: written += result; jbe@80: } jbe@80: } jbe@80: handle->writecnt = 0; jbe@80: lua_settop(L, 1); jbe@80: return 1; jbe@80: } jbe@80: jbe@80: void moonbr_io_pushhandle(lua_State *L, int fd, int gc_idx) { jbe@79: moonbr_io_handle_t *handle; jbe@79: handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t)); jbe@79: handle->fd = fd; jbe@80: handle->writecnt = 0; jbe@79: luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY); jbe@79: lua_setmetatable(L, -2); jbe@79: lua_newtable(L); // uservalue jbe@80: if (gc_idx) lua_pushvalue(L, gc_idx); jbe@80: else lua_pushcfunction(L, moonbr_io_close); jbe@80: lua_setfield(L, -2, "gc"); jbe@79: lua_newtable(L); // public jbe@79: luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY); jbe@79: lua_setmetatable(L, -2); jbe@79: lua_setfield(L, -2, "public"); jbe@79: lua_setuservalue(L, -2); jbe@79: } jbe@79: jbe@79: static int moonbr_io_handleindex(lua_State *L) { jbe@80: luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@79: lua_getuservalue(L, 1); jbe@79: lua_getfield(L, -1, "public"); jbe@79: lua_pushvalue(L, 2); jbe@79: lua_gettable(L, -2); jbe@79: return 1; jbe@79: } jbe@79: jbe@79: static int moonbr_io_handlenewindex(lua_State *L) { jbe@80: luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@79: lua_getuservalue(L, 1); jbe@79: lua_getfield(L, -1, "public"); jbe@79: lua_pushvalue(L, 2); jbe@79: lua_pushvalue(L, 3); jbe@79: lua_settable(L, -3); jbe@79: return 0; jbe@79: } jbe@79: jbe@80: static int moonbr_io_handlegc(lua_State *L) { jbe@80: moonbr_io_handle_t *handle; jbe@80: handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); jbe@80: if (handle->fd >= 0) { jbe@80: lua_getuservalue(L, 1); jbe@80: lua_getfield(L, -1, "gc"); jbe@80: lua_pushvalue(L, 1); jbe@80: lua_call(L, 1, 0); jbe@80: } jbe@80: return 0; jbe@80: } jbe@80: jbe@79: static int moonbr_io_getdummy(lua_State *L) { jbe@80: moonbr_io_pushhandle(L, 2, 0); jbe@79: return 1; jbe@79: } jbe@79: jbe@79: static const struct luaL_Reg moonbr_io_handle_methods[] = { jbe@80: {"close", moonbr_io_close}, jbe@80: {"write", moonbr_io_write}, jbe@80: {"flush", moonbr_io_flush}, jbe@79: {NULL, NULL} jbe@79: }; jbe@79: jbe@79: static const struct luaL_Reg moonbr_io_handle_metamethods[] = { jbe@79: {"__index", moonbr_io_handleindex}, jbe@79: {"__newindex", moonbr_io_handlenewindex}, jbe@80: {"__gc", moonbr_io_handlegc}, jbe@79: {NULL, NULL} jbe@79: }; jbe@79: jbe@79: static const struct luaL_Reg moonbr_io_module_funcs[] = { jbe@79: {"getdummy", moonbr_io_getdummy}, jbe@79: {NULL, NULL} jbe@79: }; jbe@79: jbe@79: int luaopen_moonbridge_io(lua_State *L) { jbe@79: jbe@80: lua_newtable(L); // module jbe@80: jbe@79: lua_newtable(L); // public metatable jbe@79: lua_newtable(L); // handle methods jbe@79: luaL_setfuncs(L, moonbr_io_handle_methods, 0); jbe@80: lua_pushvalue(L, -1); jbe@80: lua_setfield(L, -4, "handle"); jbe@79: lua_setfield(L, -2, "__index"); jbe@79: lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY); jbe@79: jbe@79: lua_newtable(L); // handle metatable jbe@79: luaL_setfuncs(L, moonbr_io_handle_metamethods, 0); jbe@79: lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY); jbe@79: jbe@79: luaL_setfuncs(L, moonbr_io_module_funcs, 0); jbe@79: return 1; jbe@79: jbe@79: } jbe@79: