src/event_buffer.c

1
/* LuaEvent - Copyright (C) 2007 Thomas Harning <harningt@gmail.com>
2
 * Licensed as LGPL - See doc/COPYING for details */
3
#include <stdlib.h>
4
#include "event_buffer.h"
5
#include <lauxlib.h>
6
 
7
#define EVENT_BUFFER_MT "EVENT_BUFFER_MT"
8
 
9
#define BUFFER_ADD_CHECK_INPUT_FIRST 1
10
 
11
/* Obtains an le_buffer structure from a given index */
12
static le_buffer* event_buffer_get(lua_State* L, int idx) {
13
	return (le_buffer*)luaL_checkudata(L, idx, EVENT_BUFFER_MT);
14
}
15
 
16
/* Obtains an le_buffer structure from a given index
17
	AND checks that it hadn't been prematurely freed
18
*/
19
le_buffer* event_buffer_check(lua_State* L, int idx) {
20
	le_buffer* buf = (le_buffer*)luaL_checkudata(L, idx, EVENT_BUFFER_MT);
21
	if(!buf->buffer)
22
		luaL_argerror(L, idx, "Attempt to use closed event_buffer object");
23
	return buf;
24
}
25
 
26
/* Checks if the given index contains an le_buffer object */
27
int is_event_buffer(lua_State* L, int idx) {
28
	int ret;
29
	lua_getmetatable(L, idx);
30
	luaL_getmetatable(L, EVENT_BUFFER_MT);
31
	ret = lua_rawequal(L, -2, -1);
32
	lua_pop(L, 2);
33
	return ret;
34
}
35
 
36
/* TODO: Use lightuserdata mapping to locate hanging object instances */
37
/* Pushes the specified evbuffer object onto the stack, attaching a metatable to it */
38
int event_buffer_push(lua_State* L, struct evbuffer* buffer) {
39
	le_buffer *buf = (le_buffer*)lua_newuserdata(L, sizeof(le_buffer));
40
	buf->buffer = buffer;
41
	luaL_getmetatable(L, EVENT_BUFFER_MT);
42
	lua_setmetatable(L, -2);
43
	return 1;
44
}
45
 
46
/* LUA: new()
47
	Pushes a new evbuffer instance on the stack
48
*/
49
static int event_buffer_push_new(lua_State* L) {
50
	return event_buffer_push(L, evbuffer_new());
51
}
52
 
53
/* LUA: __gc and buffer:close()
54
	Releases the buffer resources
55
*/
56
static int event_buffer_gc(lua_State* L) {
57
	le_buffer* buf = event_buffer_get(L, 1);
58
	if(buf->buffer) {
59
		evbuffer_free(buf->buffer);
60
		buf->buffer = NULL;
61
	}
62
	return 0;
63
}
64
 
65
/* LUA: buffer:add(...)
66
	progressively adds items to the buffer
67
		if arg[*] is string, treat as a string:format call
68
		if arg[*] is a buffer, perform event_add_buffer
69
	expects at least 1 other argument
70
	returns number of bytes added
71
*/
72
static int event_buffer_add(lua_State* L) {
73
	le_buffer* buf = event_buffer_check(L, 1);
74
	struct evbuffer* buffer = buf->buffer;
75
	int oldLength = EVBUFFER_LENGTH(buffer);
76
	int last = lua_gettop(L);
77
	int i;
78
	if(last == 1) luaL_error(L, "Not enough arguments to add: expects at least 1 additional operand");
79
	for(i = 2; i <= last; i++) {
80
		if(!lua_isstring(L, i) && !is_event_buffer(L, i))
81
			luaL_argerror(L, i, "Argument is not a string or buffer object");
82
		if(lua_equal(L, 1, i))
83
			luaL_argerror(L, i, "Cannot add buffer to itself");
84
/* Optionally perform checks and data loading separately to avoid overfilling the buffer */
85
#if BUFFER_ADD_CHECK_INPUT_FIRST
86
	}
87
	for(i = 2; i <= last; i++) {
88
#endif
89
		if(lua_isstring(L, i)) {
90
			size_t len;
91
			const char* data = lua_tolstring(L, i, &len);
92
			if(0 != evbuffer_add(buffer, data, len))
93
				luaL_error(L, "Failed to add data to the buffer");
94
		} else {
95
			le_buffer* buf2 = event_buffer_check(L, i);
96
			if(0 != evbuffer_add_buffer(buffer, buf2->buffer))
97
				luaL_error(L, "Failed to move buffer-data to the buffer");
98
		}
99
	}
100
	lua_pushinteger(L, EVBUFFER_LENGTH(buffer) - oldLength);
101
	return 1;
102
}
103
 
104
/* LUA: buffer:length()
105
	Returns the length of the buffer contents
106
*/
107
static int event_buffer_get_length(lua_State* L) {
108
	le_buffer* buf = event_buffer_check(L, 1);
109
	lua_pushinteger(L, EVBUFFER_LENGTH(buf->buffer));
110
	return 1;
111
}
112
 
113
/* MAYBE: Could add caching */
114
/* LUA: buffer:get_data
115
	() - Returns all data in buffer
116
	(len) - Returns data up to 'len' bytes long
117
	(begin,len) - Returns data beginning at 'begin' up to 'len' bytes long
118
	If begin < 0, wraps at data length
119
		ex: (-1, 1) returns last character
120
		(-2,2) returns last 2 chars [length meaning does not get inverted]
121
*/
122
static int event_buffer_get_data(lua_State* L) {
123
	le_buffer* buf = event_buffer_check(L, 1);
124
	int begin, len;
125
	switch(lua_gettop(L)) {
126
	case 1:
127
		/* Obtain full data */
128
		begin = 0;
129
		len = EVBUFFER_LENGTH(buf->buffer);
130
		break;
131
	case 2:
132
		begin = 0;
133
		len = luaL_checkinteger(L, 2);
134
		if(len > EVBUFFER_LENGTH(buf->buffer))
135
			len = EVBUFFER_LENGTH(buf->buffer);
136
		break;
137
	case 3:
138
	default:
139
		/* - 1 to map it to Lua's 1-based indexing
140
		 * If begin < 0 add length to cause position wrapping
141
		 */
142
		begin = luaL_checkinteger(L, 2);
143
		if(begin < 0)
144
			begin += EVBUFFER_LENGTH(buf->buffer);
145
		else
146
			begin--;
147
		len = luaL_checkinteger(L, 3);
148
		/* If length is less than zero, capture entire remaining string */
149
 
150
		if(len < 0) len = EVBUFFER_LENGTH(buf->buffer);
151
		if(begin > EVBUFFER_LENGTH(buf->buffer))
152
			begin = EVBUFFER_LENGTH(buf->buffer);
153
		if(begin + len > EVBUFFER_LENGTH(buf->buffer))
154
			len = EVBUFFER_LENGTH(buf->buffer) - begin;
155
		break;
156
	}
157
	lua_pushlstring(L, (const char*)EVBUFFER_DATA(buf->buffer) + begin, len);
158
	return 1;
159
}
160
 
161
/* LUA: buffer:readline()
162
	Returns a line terminated by either '\r\n','\n\r' or '\r' or '\n'
163
	Returns nil and leaves data alone if no terminator is found
164
	Newline is not present in the captured string.
165
*/
166
static int event_buffer_readline(lua_State* L) {
167
	le_buffer* buf = event_buffer_check(L, 1);
168
	char* line = evbuffer_readline(buf->buffer);
169
	if(!line)
170
		return 0;
171
	lua_pushstring(L, line);
172
	free(line);
173
	return 1;
174
}
175
 
176
/* LUA: buffer:drain(amt)
177
	Drains 'amt' bytes from the buffer
178
	If amt < 0, drains all data
179
		(Due to auto-casting to unsigned int and automatic capping)
180
*/
181
static int event_buffer_drain(lua_State* L) {
182
	le_buffer* buf = event_buffer_check(L, 1);
183
	size_t len = luaL_checkinteger(L, 2);
184
	evbuffer_drain(buf->buffer, len);
185
	return 0;
186
}
187
 
188
/* LUA: buffer:write
189
	(integer/lightuserdata fd) - Attempts to write all the data out to the FD
190
	(socket) - Attempts to write all the data out to the socket object
191
*/
192
static int event_buffer_write(lua_State* L) {
193
	le_buffer* buf = event_buffer_check(L, 1);
194
	int ret;
195
	if(lua_isnumber(L, 2)) {
196
		ret = evbuffer_write(buf->buffer, lua_tointeger(L, 2));
197
	} else if(lua_islightuserdata(L, 2)) {
198
		ret = evbuffer_write(buf->buffer, (int)(long)lua_touserdata(L, 2));
199
	} else if(lua_isuserdata(L, 2)) {
200
		ret = evbuffer_write(buf->buffer, getSocketFd(L, 2));
201
	} else {
202
		ret = 0; /* Shush uninitialized warning */
203
		luaL_argerror(L, 2, "Unexpected data type.  Expects: integer/lightuserdata/socket");
204
	}
205
	lua_pushinteger(L, ret);
206
	return 1;
207
}
208
 
209
/* LUA: buffer:read
210
	(integer/lightuserdata fd, len) - Attempts to read up to 'len' out of the FD
211
	(socket, len) - Attempts to read up to 'len' out of the socket object
212
*/
213
static int event_buffer_read(lua_State* L) {
214
	le_buffer* buf = event_buffer_check(L, 1);
215
	int len = luaL_checkinteger(L, 3);
216
	int ret;
217
	if(lua_isnumber(L, 2)) {
218
		ret = evbuffer_read(buf->buffer, lua_tointeger(L, 2), len);
219
	} else if(lua_islightuserdata(L, 2)) {
220
		ret = evbuffer_read(buf->buffer, (int)(long)lua_touserdata(L, 2), len);
221
	} else if(lua_isuserdata(L, 2)) {
222
		ret = evbuffer_read(buf->buffer, getSocketFd(L, 2), len);
223
	} else {
224
		ret = 0; /* Shush uninitialized warning */
225
		luaL_argerror(L, 2, "Unexpected data type.  Expects: integer/lightuserdata/socket");
226
	}
227
	lua_pushinteger(L, ret);
228
	return 1;
229
}
230
static luaL_Reg buffer_funcs[] = {
231
	{"add", event_buffer_add},
232
	{"length", event_buffer_get_length},
233
	{"get_data", event_buffer_get_data},
234
	{"readline", event_buffer_readline},
235
	{"drain", event_buffer_drain},
236
	{"close", event_buffer_gc},
237
	{"read", event_buffer_read},
238
	{"write", event_buffer_write},
239
	{NULL, NULL}
240
};
241
static luaL_Reg funcs[] = {
242
	{"new", event_buffer_push_new},
243
	{NULL, NULL}
244
};
245
 
246
int event_buffer_register(lua_State* L) {
247
	luaL_newmetatable(L, EVENT_BUFFER_MT);
248
	lua_pushcfunction(L, event_buffer_gc);
249
	lua_setfield(L, -2, "__gc");
250
	lua_pushcfunction(L, event_buffer_get_length);
251
	lua_setfield(L, -2, "__len");
252
	lua_pushcfunction(L, event_buffer_get_data);
253
	lua_setfield(L, -2, "__tostring");
254
	lua_newtable(L);
255
	luaL_register(L, NULL, buffer_funcs);
256
	lua_setfield(L, -2, "__index");
257
	lua_pop(L, 1);
258
	
259
	luaL_register(L, "luaevent.core.buffer", funcs);
260
	return 1;
261
}