summaryrefslogtreecommitdiffhomepage
path: root/stream.c
blob: f9cdb6d790d2232db4e8d73f537372c0e51faed9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "stream.h"

#include <stdlib.h>

#include <lauxlib.h>
#include <lua.h>

/// Creates and pushes new Stream into the Lua stack.
/// \param L Lua state to push to
/// \param fd File descriptor used by the Stream
/// \return TODO
int stream_push_new(lua_State * L, const int fd)
{
	struct stream * s = lua_newuserdata(L, sizeof(struct stream));
	s->fd = fd;

	if (1 == luaL_newmetatable(L, "stream"))
	{
		lua_pushliteral(L, "__gc");
		lua_pushcfunction(L, stream_gc);
		lua_rawset(L, -3);

		lua_pushliteral(L, "__index");
		lua_createtable(L, 0, 1);
		lua_pushliteral(L, "read");
		lua_pushcfunction(L, stream_read);
		lua_rawset(L, -3);
		lua_rawset(L, -3);
	}

	lua_setmetatable(L, -2);

	return LUA_OK;
}

/// Metamethod to handle garbage collection of Stream userdata.
/// \param L Lua state in which Stream resides
/// \return Number of the results pushed to the stack; always zero in this case
int stream_gc(lua_State * L)
{
	int n = lua_gettop(L);

	if (1 != n)
	{
		lua_pushliteral(L, "Invalid number of arguments received");
		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->in.data)
	{
		free(s->in.data);
	}

	lua_pop(L, 1);

	return 0;
}

/// Starts reading operation from a stream.
/// \param L Lua state in which Stream resides
/// \return Number of the results pushed to the stack
int stream_read(lua_State * L)
{
	struct stream * s = lua_touserdata(L, -1);

	if (NULL == s)
	{
		// TODO: Improve error handling and raising in steam_* lua_CFunctions
		lua_pushliteral(L, "Missing stream argument");
		return lua_error(L);
	}

	if (NULL == s->in.data)
	{
		void * buffer = malloc(1024);

		if (NULL == buffer)
		{
			lua_pushliteral(L, "Could not allocate buffer for stream");
			return lua_error(L);
		}

		s->in.data = buffer;
	}

	return stream_readk(L, LUA_OK, 0); // Intentionally do not pop Stream that's on top of the stack.
}

/// Continuation function and core implementation of the reading operation from a stream.
/// \param L Lua state running reading operation
/// \param status TODO
/// \param ctx TODO
/// \param Number of the results pushed to the stack
int stream_readk(lua_State * L, int status, lua_KContext ctx)
{
	lua_pop(L, 0);
	return 0;
}