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
121 static int event_buffer_get_data(lua_State
* L
) {
122 le_buffer
* buf
= event_buffer_check(L
, 1);
124 switch(lua_gettop(L
)) {
126 /* Obtain full data */
128 len
= EVBUFFER_LENGTH(buf
->buffer
);
132 len
= luaL_checkinteger(L
, 2);
133 if(len
> EVBUFFER_LENGTH(buf
->buffer
))
134 len
= EVBUFFER_LENGTH(buf
->buffer
);
138 begin
= luaL_checkinteger(L
, 2);
139 len
= luaL_checkinteger(L
, 3);
140 if(begin
> EVBUFFER_LENGTH(buf
->buffer
))
141 begin
= EVBUFFER_LENGTH(buf
->buffer
);
142 if(begin
+ len
> EVBUFFER_LENGTH(buf
->buffer
))
143 len
= EVBUFFER_LENGTH(buf
->buffer
) - begin
;
146 lua_pushlstring(L
, (const char*)EVBUFFER_DATA(buf
->buffer
) + begin
, len
);
150 /* LUA: buffer:readline()
151 Returns a line terminated by either '\r\n','\n\r' or '\r' or '\n'
152 Returns nil and leaves data alone if no terminator is found
153 TODO: Evaluate whether or not the newline is included
155 static int event_buffer_readline(lua_State
* L
) {
156 le_buffer
* buf
= event_buffer_check(L
, 1);
157 char* line
= evbuffer_readline(buf
->buffer
);
160 lua_pushstring(L
, line
);
165 /* LUA: buffer:drain(amt)
166 Drains 'amt' bytes from the buffer
168 static int event_buffer_drain(lua_State
* L
) {
169 le_buffer
* buf
= event_buffer_check(L
, 1);
170 size_t len
= luaL_checkinteger(L
, 2);
171 evbuffer_drain(buf
->buffer
, len
);
176 (integer/lightuserdata fd) - Attempts to write all the data out to the FD
177 (socket) - Attempts to write all the data out to the socket object
179 static int event_buffer_write(lua_State
* L
) {
180 le_buffer
* buf
= event_buffer_check(L
, 1);
182 if(lua_isnumber(L
, 2)) {
183 ret
= evbuffer_write(buf
->buffer
, lua_tointeger(L
, 2));
184 } else if(lua_islightuserdata(L
, 2)) {
185 ret
= evbuffer_write(buf
->buffer
, (int)(long)lua_touserdata(L
, 2));
186 } else if(lua_isuserdata(L
, 2)) {
187 ret
= evbuffer_write(buf
->buffer
, getSocketFd(L
, 2));
189 luaL_argerror(L
, 2, "Unexpected data type. Expects: integer/lightuserdata/socket");
191 lua_pushinteger(L
, ret
);
196 (integer/lightuserdata fd, len) - Attempts to read up to 'len' out of the FD
197 (socket, len) - Attempts to read up to 'len' out of the socket object
199 static int event_buffer_read(lua_State
* L
) {
200 le_buffer
* buf
= event_buffer_check(L
, 1);
201 int len
= luaL_checkinteger(L
, 3);
203 if(lua_isnumber(L
, 2)) {
204 ret
= evbuffer_read(buf
->buffer
, lua_tointeger(L
, 2), len
);
205 } else if(lua_islightuserdata(L
, 2)) {
206 ret
= evbuffer_read(buf
->buffer
, (int)(long)lua_touserdata(L
, 2), len
);
207 } else if(lua_isuserdata(L
, 2)) {
208 ret
= evbuffer_read(buf
->buffer
, getSocketFd(L
, 2), len
);
210 luaL_argerror(L
, 2, "Unexpected data type. Expects: integer/lightuserdata/socket");
212 lua_pushinteger(L
, ret
);
215 static luaL_Reg buffer_funcs
[] = {
216 {"add", event_buffer_add
},
217 {"length", event_buffer_get_length
},
218 {"get_data", event_buffer_get_data
},
219 {"readline", event_buffer_readline
},
220 {"drain", event_buffer_drain
},
221 {"close", event_buffer_gc
},
222 {"read", event_buffer_read
},
223 {"write", event_buffer_write
},
226 static luaL_Reg funcs
[] = {
227 {"new", event_buffer_push_new
},
231 int event_buffer_register(lua_State
* L
) {
232 luaL_newmetatable(L
, EVENT_BUFFER_MT
);
233 lua_pushcfunction(L
, event_buffer_gc
);
234 lua_setfield(L
, -2, "__gc");
235 lua_pushcfunction(L
, event_buffer_get_length
);
236 lua_setfield(L
, -2, "__len");
237 lua_pushcfunction(L
, event_buffer_get_data
);
238 lua_setfield(L
, -2, "__tostring");
240 luaL_register(L
, NULL
, buffer_funcs
);
241 lua_setfield(L
, -2, "__index");
244 luaL_register(L
, "luaevent.core.buffer", funcs
);