1 /* LuaEvent - Copyright (C) 2007,2012 Thomas Harning <harningt@gmail.com>
2 * Licensed as LGPL - See doc/COPYING for details */
4 #include "event_buffer.h"
7 #define EVENT_BUFFER_MT "EVENT_BUFFER_MT"
9 #define BUFFER_ADD_CHECK_INPUT_FIRST 1
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
);
16 /* Obtains an le_buffer structure from a given index
17 AND checks that it hadn't been prematurely freed
19 le_buffer
* event_buffer_check(lua_State
* L
, int idx
) {
20 le_buffer
* buf
= (le_buffer
*)luaL_checkudata(L
, idx
, EVENT_BUFFER_MT
);
22 luaL_argerror(L
, idx
, "Attempt to use closed event_buffer object");
26 /* Checks if the given index contains an le_buffer object */
27 int is_event_buffer(lua_State
* L
, int idx
) {
29 lua_getmetatable(L
, idx
);
30 luaL_getmetatable(L
, EVENT_BUFFER_MT
);
31 ret
= lua_rawequal(L
, -2, -1);
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
));
41 luaL_getmetatable(L
, EVENT_BUFFER_MT
);
42 lua_setmetatable(L
, -2);
47 Pushes a new evbuffer instance on the stack
49 static int event_buffer_push_new(lua_State
* L
) {
50 return event_buffer_push(L
, evbuffer_new());
53 /* LUA: __gc and buffer:close()
54 Releases the buffer resources
56 static int event_buffer_gc(lua_State
* L
) {
57 le_buffer
* buf
= event_buffer_get(L
, 1);
59 evbuffer_free(buf
->buffer
);
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
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
);
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
87 for(i
= 2; i
<= last
; i
++) {
89 if(lua_isstring(L
, i
)) {
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");
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");
100 lua_pushinteger(L
, EVBUFFER_LENGTH(buffer
) - oldLength
);
104 /* LUA: buffer:length()
105 Returns the length of the buffer contents
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
));
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]
122 static int event_buffer_get_data(lua_State
* L
) {
123 le_buffer
* buf
= event_buffer_check(L
, 1);
125 switch(lua_gettop(L
)) {
127 /* Obtain full data */
129 len
= EVBUFFER_LENGTH(buf
->buffer
);
133 len
= luaL_checkinteger(L
, 2);
134 if(len
> EVBUFFER_LENGTH(buf
->buffer
))
135 len
= EVBUFFER_LENGTH(buf
->buffer
);
139 /* - 1 to map it to Lua's 1-based indexing
140 * If begin < 0 add length to cause position wrapping
142 begin
= luaL_checkinteger(L
, 2);
144 begin
+= EVBUFFER_LENGTH(buf
->buffer
);
147 len
= luaL_checkinteger(L
, 3);
148 /* If length is less than zero, capture entire remaining string */
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
;
157 lua_pushlstring(L
, (const char*)EVBUFFER_DATA(buf
->buffer
) + begin
, len
);
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.
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
);
171 lua_pushstring(L
, line
);
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)
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
);
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
192 static int event_buffer_write(lua_State
* L
) {
193 le_buffer
* buf
= event_buffer_check(L
, 1);
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));
202 ret
= 0; /* Shush uninitialized warning */
203 luaL_argerror(L
, 2, "Unexpected data type. Expects: integer/lightuserdata/socket");
205 lua_pushinteger(L
, ret
);
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
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);
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
);
224 ret
= 0; /* Shush uninitialized warning */
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 void event_buffer_register(lua_State
* L
, int coreIndex
) {
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");
260 luaL_register(L
, NULL
, funcs
);
261 lua_setfield(L
, coreIndex
, "buffer");