From 18b2a4391fe8d442e917f5b2c2f26b18ec9374ac Mon Sep 17 00:00:00 2001 From: Aki Date: Thu, 4 Mar 2021 22:22:28 +0100 Subject: Partially implementd writing --- stream.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) (limited to 'stream.c') diff --git a/stream.c b/stream.c index d456619..0863cfd 100644 --- a/stream.c +++ b/stream.c @@ -38,11 +38,15 @@ int stream_push_new(lua_State * L, const int fd) lua_rawset(L, -3); lua_pushliteral(L, "write"); - lua_pushnil(L); // TODO: Implement writing operation. + lua_pushcfunction(L, stream_write); lua_rawset(L, -3); lua_pushliteral(L, "flush"); - lua_pushnil(L); // TODO: Implement flush for output buffer. + lua_pushcfunction(L, stream_flush); + lua_rawset(L, -3); + + lua_pushliteral(L, "flush"); + lua_pushcfunction(L, stream_flush); lua_rawset(L, -3); } lua_rawset(L, -3); @@ -262,3 +266,134 @@ int stream_readk(lua_State * L, int status, lua_KContext ctx) return lua_gettop(L); } + +/// Writes to output buffer. +/// \param L Lua state in which Stream resides +/// \return Number of the results pushed to the stack +int stream_write(lua_State * L) +{ + const int n = lua_gettop(L); + if (2 > n) + { + lua_pushliteral(L, "At least two arguments expected"); + return lua_error(L); + } + + struct stream * s = lua_touserdata(L, 1); + + if (NULL == s) + { + lua_pushliteral(L, "Missing stream argument"); + return lua_error(L); + } + + if (NULL == s->out.data) + { + void * buffer = malloc(1024); + + if (NULL == buffer) + { + lua_pushliteral(L, "Could not allocate buffer for stream"); + return lua_error(L); + } + + s->out.data = buffer; + s->out.allocated = 1024; + s->out.length = 0; + s->out.offset = 0; + s->out.next = 0; + } + + for (int i = 2; n >= i; ++i) + { + size_t data_length; + const char * data = lua_tolstring(L, i, &data_length); + const int free_space = s->out.allocated - s->out.length; + + if (free_space >= (int) data_length) + { + memcpy(&s->out.data[s->out.length], data, data_length); + s->out.length += (int) data_length; + } + else + { + // TODO: grow + } + } + + lua_pop(L, n); + return 0; +} + +/// Flushes the contents of output buffer writing it to the socket. +/// \param L Lua state in which Stream resides +/// \return Number of the results pushed to the stack +int stream_flush(lua_State * L) +{ + const int n = lua_gettop(L); + + if (1 != n) + { + lua_pushliteral(L, "Expected one argument"); + return lua_error(L); + } + + struct stream * s = lua_touserdata(L, 1); + + if (NULL == s) + { + lua_pushliteral(L, "Missing stream argument"); + return lua_error(L); + } + + const int bytes_written = write(s->fd, s->out.data, s->out.length); + + if (-1 == bytes_written) + { + // TODO: Errors and yield + } + else + { + s->out.length -= bytes_written; + } + + lua_pop(L, 1); + return 0; +} + +/// Continuation of the flush operation. +/// \param L Lua state in which Stream resides +/// \param status Unused +/// \param ctx TODO +/// \return Number of the results pushed to the stack +int stream_flushk(lua_State * L, const int status, lua_KContext ctx) +{ + return 0; +} + +/// Discards the contents of output buffer without writing it anywhere. +/// \param L Lua state in which Stream resides +/// \return Number of the results pushed to the stack +int stream_discard(lua_State * L) +{ + const int n = lua_gettop(L); + + if (1 != n) + { + lua_pushliteral(L, "Expected one argument"); + return lua_error(L); + } + + struct stream * s = lua_touserdata(L, 1); + + if (NULL == s) + { + lua_pushliteral(L, "Missing stream argument"); + return lua_error(L); + } + + s->out.length = 0; + + lua_pop(L, 1); + return 0; +} -- cgit v1.1