base: updates copyright date
[luaevent.git] / src / event_buffer.c
blobdda9b2236d7276b63a6a6251a0d6d108fb8b4b55
1 /* LuaEvent - Copyright (C) 2007,2012 Thomas Harning <harningt@gmail.com>
2 * Licensed as LGPL - See doc/COPYING for details */
3 #include <stdlib.h>
4 #include "event_buffer.h"
5 #include <lauxlib.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);
21 if(!buf->buffer)
22 luaL_argerror(L, idx, "Attempt to use closed event_buffer object");
23 return buf;
26 /* Checks if the given index contains an le_buffer object */
27 int is_event_buffer(lua_State* L, int idx) {
28 int ret;
29 lua_getmetatable(L, idx);
30 luaL_getmetatable(L, EVENT_BUFFER_MT);
31 ret = lua_rawequal(L, -2, -1);
32 lua_pop(L, 2);
33 return ret;
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));
40 buf->buffer = buffer;
41 luaL_getmetatable(L, EVENT_BUFFER_MT);
42 lua_setmetatable(L, -2);
43 return 1;
46 /* LUA: new()
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);
58 if(buf->buffer) {
59 evbuffer_free(buf->buffer);
60 buf->buffer = NULL;
62 return 0;
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);
77 int i;
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++) {
88 #endif
89 if(lua_isstring(L, i)) {
90 size_t len;
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");
94 } else {
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);
101 return 1;
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));
110 return 1;
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);
124 int begin, len;
125 switch(lua_gettop(L)) {
126 case 1:
127 /* Obtain full data */
128 begin = 0;
129 len = EVBUFFER_LENGTH(buf->buffer);
130 break;
131 case 2:
132 begin = 0;
133 len = luaL_checkinteger(L, 2);
134 if(len > EVBUFFER_LENGTH(buf->buffer))
135 len = EVBUFFER_LENGTH(buf->buffer);
136 break;
137 case 3:
138 default:
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);
143 if(begin < 0)
144 begin += EVBUFFER_LENGTH(buf->buffer);
145 else
146 begin--;
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;
155 break;
157 lua_pushlstring(L, (const char*)EVBUFFER_DATA(buf->buffer) + begin, len);
158 return 1;
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);
169 if(!line)
170 return 0;
171 lua_pushstring(L, line);
172 free(line);
173 return 1;
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);
185 return 0;
188 /* LUA: buffer:write
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);
194 int ret;
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));
201 } else {
202 ret = 0; /* Shush uninitialized warning */
203 luaL_argerror(L, 2, "Unexpected data type. Expects: integer/lightuserdata/socket");
205 lua_pushinteger(L, ret);
206 return 1;
209 /* LUA: buffer:read
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);
216 int ret;
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);
223 } else {
224 ret = 0; /* Shush uninitialized warning */
225 luaL_argerror(L, 2, "Unexpected data type. Expects: integer/lightuserdata/socket");
227 lua_pushinteger(L, ret);
228 return 1;
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},
239 {NULL, NULL}
241 static luaL_Reg funcs[] = {
242 {"new", event_buffer_push_new},
243 {NULL, NULL}
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");
254 lua_newtable(L);
255 luaL_register(L, NULL, buffer_funcs);
256 lua_setfield(L, -2, "__index");
257 lua_pop(L, 1);
259 lua_newtable(L);
260 luaL_register(L, NULL, funcs);
261 lua_setfield(L, coreIndex, "buffer");