summaryrefslogtreecommitdiffhomepage
path: root/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'stream.c')
-rw-r--r--stream.c139
1 files changed, 137 insertions, 2 deletions
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;
+}