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 returns number of bytes added
73 static int event_buffer_add(lua_State
* L
) {
74 le_buffer
* buf
= event_buffer_check(L
, 1);
75 struct evbuffer
* buffer
= buf
->buffer
;
76 int oldLength
= EVBUFFER_LENGTH(buffer
);
77 int last
= lua_gettop(L
);
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
119 static int event_buffer_get_data(lua_State
* L
) {
120 le_buffer
* buf
= event_buffer_check(L
, 1);
122 switch(lua_gettop(L
)) {
124 /* Obtain full data */
126 len
= EVBUFFER_LENGTH(buf
->buffer
);
130 len
= luaL_checkinteger(L
, 2);
131 if(len
> EVBUFFER_LENGTH(buf
->buffer
))
132 len
= EVBUFFER_LENGTH(buf
->buffer
);
136 begin
= luaL_checkinteger(L
, 2);
137 len
= luaL_checkinteger(L
, 3);
138 if(begin
> EVBUFFER_LENGTH(buf
->buffer
))
139 begin
= EVBUFFER_LENGTH(buf
->buffer
);
140 if(begin
+ len
> EVBUFFER_LENGTH(buf
->buffer
))
141 len
= EVBUFFER_LENGTH(buf
->buffer
) - begin
;
144 lua_pushlstring(L
, (const char*)EVBUFFER_DATA(buf
->buffer
) + begin
, len
);
148 /* LUA: buffer:readline()
149 Returns a line terminated by either '\r\n','\n\r' or '\r' or '\n'
150 Returns nil and leaves data alone if no terminator is found
151 TODO: Evaluate whether or not the newline is included
153 static int event_buffer_readline(lua_State
* L
) {
154 le_buffer
* buf
= event_buffer_check(L
, 1);
155 char* line
= evbuffer_readline(buf
->buffer
);
158 lua_pushstring(L
, line
);
163 /* LUA: buffer:drain(amt)
164 Drains 'amt' bytes from the buffer
166 static int event_buffer_drain(lua_State
* L
) {
167 le_buffer
* buf
= event_buffer_check(L
, 1);
168 size_t len
= luaL_checkinteger(L
, 2);
169 evbuffer_drain(buf
->buffer
, len
);
174 (integer/lightuserdata fd) - Attempts to write all the data out to the FD
175 (socket) - Attempts to write all the data out to the socket object
177 static int event_buffer_write(lua_State
* L
) {
178 le_buffer
* buf
= event_buffer_check(L
, 1);
180 if(lua_isnumber(L
, 2)) {
181 ret
= evbuffer_write(buf
->buffer
, lua_tointeger(L
, 2));
182 } else if(lua_islightuserdata(L
, 2)) {
183 ret
= evbuffer_write(buf
->buffer
, (int)(long)lua_touserdata(L
, 2));
184 } else if(lua_isuserdata(L
, 2)) {
185 ret
= evbuffer_write(buf
->buffer
, getSocketFd(L
, 2));
187 luaL_argerror(L
, 2, "Unexpected data type. Expects: integer/lightuserdata/socket");
189 lua_pushinteger(L
, ret
);
194 (integer/lightuserdata fd, len) - Attempts to read up to 'len' out of the FD
195 (socket, len) - Attempts to read up to 'len' out of the socket object
197 static int event_buffer_read(lua_State
* L
) {
198 le_buffer
* buf
= event_buffer_check(L
, 1);
199 int len
= luaL_checkinteger(L
, 3);
201 if(lua_isnumber(L
, 2)) {
202 ret
= evbuffer_read(buf
->buffer
, lua_tointeger(L
, 2), len
);
203 } else if(lua_islightuserdata(L
, 2)) {
204 ret
= evbuffer_read(buf
->buffer
, (int)(long)lua_touserdata(L
, 2), len
);
205 } else if(lua_isuserdata(L
, 2)) {
206 ret
= evbuffer_read(buf
->buffer
, getSocketFd(L
, 2), len
);
208 luaL_argerror(L
, 2, "Unexpected data type. Expects: integer/lightuserdata/socket");
210 lua_pushinteger(L
, ret
);
213 static luaL_Reg buffer_funcs
[] = {
214 {"add", event_buffer_add
},
215 {"length", event_buffer_get_length
},
216 {"get_data", event_buffer_get_data
},
217 {"readline", event_buffer_readline
},
218 {"drain", event_buffer_drain
},
219 {"close", event_buffer_gc
},
220 {"read", event_buffer_read
},
221 {"write", event_buffer_write
},
224 static luaL_Reg funcs
[] = {
225 {"new", event_buffer_push_new
},
229 int event_buffer_register(lua_State
* L
) {
230 luaL_newmetatable(L
, EVENT_BUFFER_MT
);
231 lua_pushcfunction(L
, event_buffer_gc
);
232 lua_setfield(L
, -2, "__gc");
233 lua_pushcfunction(L
, event_buffer_get_length
);
234 lua_setfield(L
, -2, "__len");
235 lua_pushcfunction(L
, event_buffer_get_data
);
236 lua_setfield(L
, -2, "__tostring");
238 luaL_register(L
, NULL
, buffer_funcs
);
239 lua_setfield(L
, -2, "__index");
242 luaL_register(L
, "luaevent.core.buffer", funcs
);