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