1 /* LuaEvent - Copyright (C) 2007 Thomas Harning <harningt@gmail.com>
2 * Licensed as LGPL - See doc/COPYING for details */
4 #include "event_buffer.h"
9 #define EVENT_BUFFER_MT "EVENT_BUFFER_MT"
11 #define BUFFER_ADD_CHECK_INPUT_FIRST 1
13 /* Obtains an le_buffer structure from a given index */
14 static le_buffer
* event_buffer_get(lua_State
* L
, int idx
) {
15 return (le_buffer
*)luaL_checkudata(L
, idx
, EVENT_BUFFER_MT
);
18 /* Obtains an le_buffer structure from a given index
19 AND checks that it hadn't been prematurely freed
21 static le_buffer
* event_buffer_check(lua_State
* L
, int idx
) {
22 le_buffer
* buf
= (le_buffer
*)luaL_checkudata(L
, idx
, EVENT_BUFFER_MT
);
24 luaL_argerror(L
, idx
, "Attempt to use closed event_buffer object");
28 /* Checks if the given index contains an le_buffer object */
29 static int is_event_buffer(lua_State
* L
, int idx
) {
31 lua_getmetatable(L
, idx
);
32 luaL_getmetatable(L
, EVENT_BUFFER_MT
);
33 ret
= lua_rawequal(L
, -2, -1);
38 /* TODO: Use lightuserdata mapping to locate hanging object instances */
39 /* Pushes the specified evbuffer object onto the stack, attaching a metatable to it */
40 static int event_buffer_push(lua_State
* L
, struct evbuffer
* buffer
) {
41 le_buffer
*buf
= (le_buffer
*)lua_newuserdata(L
, sizeof(le_buffer
));
43 luaL_getmetatable(L
, EVENT_BUFFER_MT
);
44 lua_setmetatable(L
, -2);
49 Pushes a new evbuffer instance on the stack
51 static int event_buffer_push_new(lua_State
* L
) {
52 return event_buffer_push(L
, evbuffer_new());
55 /* LUA: __gc and buffer:close()
56 Releases the buffer resources
58 static int event_buffer_gc(lua_State
* L
) {
59 le_buffer
* buf
= event_buffer_get(L
, 1);
61 evbuffer_free(buf
->buffer
);
67 /* LUA: buffer:add(...)
68 progressively adds items to the buffer
69 if arg[*] is string, treat as a string:format call
70 if arg[*] is a buffer, perform event_add_buffer
71 expects at least 1 other argument
72 returns number of bytes added
74 static int event_buffer_add(lua_State
* L
) {
75 le_buffer
* buf
= event_buffer_check(L
, 1);
76 struct evbuffer
* buffer
= buf
->buffer
;
77 int oldLength
= EVBUFFER_LENGTH(buffer
);
78 int last
= lua_gettop(L
);
80 if(last
== 1) luaL_error(L
, "Not enough arguments to add: expects at least 1 additional operand");
81 for(i
= 2; i
<= last
; i
++) {
82 if(!lua_isstring(L
, i
) && !is_event_buffer(L
, i
))
83 luaL_argerror(L
, i
, "Argument is not a string or buffer object");
84 if(lua_equal(L
, 1, i
))
85 luaL_argerror(L
, i
, "Cannot add buffer to itself");
86 /* Optionally perform checks and data loading separately to avoid overfilling the buffer */
87 #if BUFFER_ADD_CHECK_INPUT_FIRST
89 for(i
= 2; i
<= last
; i
++) {
91 if(lua_isstring(L
, i
)) {
93 const char* data
= lua_tolstring(L
, i
, &len
);
94 if(0 != evbuffer_add(buffer
, data
, len
))
95 luaL_error(L
, "Failed to add data to the buffer");
97 le_buffer
* buf2
= event_buffer_check(L
, i
);
98 if(0 != evbuffer_add_buffer(buffer
, buf2
->buffer
))
99 luaL_error(L
, "Failed to move buffer-data to the buffer");
102 lua_pushinteger(L
, EVBUFFER_LENGTH(buffer
) - oldLength
);
106 /* LUA: buffer:length()
107 Returns the length of the buffer contents
109 static int event_buffer_get_length(lua_State
* L
) {
110 le_buffer
* buf
= event_buffer_check(L
, 1);
111 lua_pushinteger(L
, EVBUFFER_LENGTH(buf
->buffer
));
115 /* MAYBE: Could add caching */
116 /* LUA: buffer:get_data
117 () - Returns all data in buffer
118 (len) - Returns data up to 'len' bytes long
119 (begin,len) - Returns data beginning at 'begin' up to 'len' bytes long
120 If begin < 0, wraps at data length
121 ex: (-1, 1) returns last character
122 (-2,2) returns last 2 chars [length meaning does not get inverted]
124 static int event_buffer_get_data(lua_State
* L
) {
125 le_buffer
* buf
= event_buffer_check(L
, 1);
127 switch(lua_gettop(L
)) {
129 /* Obtain full data */
131 len
= EVBUFFER_LENGTH(buf
->buffer
);
135 len
= luaL_checkinteger(L
, 2);
136 if(len
> EVBUFFER_LENGTH(buf
->buffer
))
137 len
= EVBUFFER_LENGTH(buf
->buffer
);
141 /* - 1 to map it to Lua's 1-based indexing
142 * If begin < 0 add length to cause position wrapping
144 begin
= luaL_checkinteger(L
, 2);
146 begin
+= EVBUFFER_LENGTH(buf
->buffer
);
149 len
= luaL_checkinteger(L
, 3);
150 /* If length is less than zero, capture entire remaining string */
152 if(len
< 0) len
= EVBUFFER_LENGTH(buf
->buffer
);
153 if(begin
> EVBUFFER_LENGTH(buf
->buffer
))
154 begin
= EVBUFFER_LENGTH(buf
->buffer
);
155 if(begin
+ len
> EVBUFFER_LENGTH(buf
->buffer
))
156 len
= EVBUFFER_LENGTH(buf
->buffer
) - begin
;
159 lua_pushlstring(L
, (const char*)EVBUFFER_DATA(buf
->buffer
) + begin
, len
);
163 /* LUA: buffer:readline()
164 Returns a line terminated by either '\r\n','\n\r' or '\r' or '\n'
165 Returns nil and leaves data alone if no terminator is found
166 Newline is not present in the captured string.
168 static int event_buffer_readline(lua_State
* L
) {
169 le_buffer
* buf
= event_buffer_check(L
, 1);
170 char* line
= evbuffer_readline(buf
->buffer
);
173 lua_pushstring(L
, line
);
178 /* LUA: buffer:drain(amt)
179 Drains 'amt' bytes from the buffer
180 If amt < 0, drains all data
181 (Due to auto-casting to unsigned int and automatic capping)
183 static int event_buffer_drain(lua_State
* L
) {
184 le_buffer
* buf
= event_buffer_check(L
, 1);
185 size_t len
= luaL_checkinteger(L
, 2);
186 evbuffer_drain(buf
->buffer
, len
);
191 (integer/lightuserdata fd) - Attempts to write all the data out to the FD
192 (socket) - Attempts to write all the data out to the socket object
194 static int event_buffer_write(lua_State
* L
) {
195 le_buffer
* buf
= event_buffer_check(L
, 1);
197 if(lua_isnumber(L
, 2)) {
198 ret
= evbuffer_write(buf
->buffer
, lua_tointeger(L
, 2));
199 } else if(lua_islightuserdata(L
, 2)) {
200 ret
= evbuffer_write(buf
->buffer
, (int)(long)lua_touserdata(L
, 2));
201 } else if(lua_isuserdata(L
, 2)) {
202 ret
= evbuffer_write(buf
->buffer
, getSocketFd(L
, 2));
204 luaL_argerror(L
, 2, "Unexpected data type. Expects: integer/lightuserdata/socket");
206 lua_pushinteger(L
, ret
);
211 (integer/lightuserdata fd, len) - Attempts to read up to 'len' out of the FD
212 (socket, len) - Attempts to read up to 'len' out of the socket object
214 static int event_buffer_read(lua_State
* L
) {
215 le_buffer
* buf
= event_buffer_check(L
, 1);
216 int len
= luaL_checkinteger(L
, 3);
218 if(lua_isnumber(L
, 2)) {
219 ret
= evbuffer_read(buf
->buffer
, lua_tointeger(L
, 2), len
);
220 } else if(lua_islightuserdata(L
, 2)) {
221 ret
= evbuffer_read(buf
->buffer
, (int)(long)lua_touserdata(L
, 2), len
);
222 } else if(lua_isuserdata(L
, 2)) {
223 ret
= evbuffer_read(buf
->buffer
, getSocketFd(L
, 2), len
);
225 luaL_argerror(L
, 2, "Unexpected data type. Expects: integer/lightuserdata/socket");
227 lua_pushinteger(L
, ret
);
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
},
241 static luaL_Reg funcs
[] = {
242 {"new", event_buffer_push_new
},
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");
255 luaL_register(L
, NULL
, buffer_funcs
);
256 lua_setfield(L
, -2, "__index");
259 luaL_register(L
, "luaevent.core.buffer", funcs
);