# HG changeset patch # User Thomas Harning Jr # Date 1247668750 14400 # Node ID dd47dbe85becb65878ecfc3a92c09adda0eab811 # Parent ed98dcbaacb0134896e86a1c561fac9069740415# Parent 1b8cbf640378172ed6c9650fefb6bc84099254f3 Merge branch 'v0.2' diff -r 1b8cbf640378 -r dd47dbe85bec doc/api.mdwn --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/api.mdwn Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,15 @@ +LuaEvent API Documentation +---- + +Modules: + +* [[modules/luaevent.core]] - Interface to core libevent functions + * [[modules/luaevent.core.buffer]] - Interface to libevent's evbuffer + * [[modules/luaevent.core.bufferevent]] - Interface to libevent's bufferevent +* [[modules/luaevent]] - Higher level wrapper mimicking [copas](http://www.luaforge.net/projects/copas) + +Note: Any reference to a "File Descriptor" may in fact be one of the following: + +* Integer value of file descriptor +* lightuserdata 'handle' (cast to a native integer) +* [LuaSocket](http://www.luaforge.net/projects/luasocket)-based socket handle diff -r 1b8cbf640378 -r dd47dbe85bec doc/index.mdwn --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/index.mdwn Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,13 @@ +LuaEvent is a Lua wrapper around [libevent](http://monkey.org/~provos/libevent/). +It provides an interface with which you can write applications that wait on +file-descriptor events (primarily socket-based). + +[[API_Reference|api]] + +---- +Related links for this project: + +* LuaForge @ +* GitRepo @ +* ohloh @ + diff -r 1b8cbf640378 -r dd47dbe85bec doc/modules/luaevent.core.buffer.mdwn --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/modules/luaevent.core.buffer.mdwn Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,60 @@ +---- +Functions: + +[[toc levels=1]] + +## buffer.new +* Instantiates a new buffer object + +## buffer:add +* Successively concatenates each of the arguments onto the buffer +* Input: `(...)` + * Sequence of strings or buffer instances +* Side Effects: Buffers 'add'ed are emptied of their contents (per libevent semantics) +* Output: Amount of data added +(QUESTION: Should add return the buffer itself so that chaining can be easy) + +## buffer:length (__len) +* Output: Length of the remaining buffer contents + +## buffer:get\_data (__tostring) +* Input: + * `()` and `__tostring` - Returns all data in the buffer + * `(len)` - Returns data up to `len` bytes long + * `(begin, len)` - Returns data beginning at `begin` up to `len` bytes long + * If `begin < 0`, wraps at data length. Ex: (-1, 1) returns last byte, (-2, 2) returns last 2 bytes +* Output: A copy of contents from the buffer + +## buffer:read +* Reads data from a file-descriptor/socket into the buffer directly +* Input: `(fd, length)` + * `fd` - File descriptor to read from + * `length` - Amount of data to attempt to read into the buffer +* Output: Length of data actually read into the buffer +* Side Effects: fd/socket 'drain'ed of data + +## buffer:write +* Attempts to write out all buffer's data to a file-descriptor/socket +* Input: `(fd, length)` + * `fd` - File descriptor to write to + * `socket` - [LuaSocket](http://www.luaforge.net/projects/luasocket)-based socket handle +* Output: Amount of data written +* Side Effects: buffer 'drain'ed of written data + +## buffer:readline +* Reads a line terminated by either '\r\n', '\n\r', '\r', or, '\n' +* Output: + * If no terminator found: nil + * If terminator found: Line returned without terminators +* NOTE: If a '\r' or '\n' are the last characters in the buffer, then the data is returned even if the +potential later data would contain the paired '\n' or '\r'. (TODO: Ask libevent list on how this is handled...) + +## buffer:drain +* Removes data from the buffer +* Input: `(amt)` + * If `amt < 0` drains all data due to auto-casting to unsigned int and capping... + TODO: Add code to check this condition explicitly for safety + * If `amt >= 0`, drain up to amt from the buffer (no problem w/ too-large values) + +## buffer:close (__gc) +* Immediately frees/closes a buffer. Note that diff -r 1b8cbf640378 -r dd47dbe85bec doc/modules/luaevent.core.bufferevent.mdwn --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/modules/luaevent.core.bufferevent.mdwn Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,67 @@ +---- +Functions: + +[[toc levels=1]] + +## Read/Write/Error Callback: +* Input: `(bufferevent, what)` + * `bufferevent` - Reference to the bufferevent that raised the callback + * `what` - What happened: + * == `EVBUFFER_READ` - Buffer contains at least low-watermark length and no more than high-watermark length + * == `EVBUFFER_WRITE` - Buffer ready to write to + * (other) - Error condition + * May be or-ed/added with `EVBUFFER_READ`/`EVBUFFER_WRITE` to specify where it happened + * `EVBUFFER_ERROR` - Marks error condition (need to look at 'errno' for error.. not exposed yet) + * `EVBUFFER_TIMEOUT` - Marks activity timeout + * `EVBUFFER_EOF` - Marks disconnection/end-of-file condition + +## bufferevent.new +* Input: `(fd, read, write, error)` + * `fd` - File descriptor to watch + * `read` - (may be nil) - callback to call when data in buffer is above the low watermark + * `write` - (may be nil) - callback to call when the output buffer contains less data than the low watermark + * `error` - callback to call when there is an erroneous condition + +## bufferevent (__gc) +* Releases the bufferevent + * Disconnects event buffers since they were owned by the bufferevent object in 'C' land + * Disconnects all references so that any erroneous callbacks don't cause failures + +## bufferevent:get_read +* Obtains the input buffer associated w/ the bufferevent + +## bufferevent:get_write +* Obtains the output buffer associated w/ the bufferevent + +## bufferevent:set_read_watermarks +* Input: `(low, high)` + * `low` - Size of buffer at which an event would be fired + * `high` - Maximum size of buffer to read to + +## bufferevent:set_write_watermarks +* Input: `(low, high)` + * `low` - When buffer is below this, the event will be fired + * `high` - N/A to libevent, user app may use this + +## bufferevent:get_read_watermarks +* Output: `low, high` +* See `set_read_watermarks` + +## bufferevent:get_write_watermarks +* Output: `low, high` +* See `set_write_watermarks` + +## bufferevent:set_timeouts +* Sets timeouts for the bufferevent's events +* Input: `(read, write)` + * `read` - Read readiness timeout + * `write` - Write readiness timeout + +## bufferevent:get_timeouts +* Output: `read, write` +* See `set_timeouts` + +## bufferevent:enable/disable +* Input: `event flag` + * `event flag` - `EV_READ`, `EV_WRITE`, or `EV_READ|EV_WRITE` +* Enables/Disables events from being triggered in the next round (some events may get triggered after disable is called) diff -r 1b8cbf640378 -r dd47dbe85bec doc/modules/luaevent.core.mdwn --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/modules/luaevent.core.mdwn Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,67 @@ +---- +Constants: + +* `LEAVE` - When returned will cause event callback to be cancelled +* `EV_READ` + * Marks read readiness/event capture. + * Read readiness can also mean that an 'accept' operation will succeed, or + a disconnection on the other end is detected (read will return nothing). +* `EV_WRITE` + * Marks write readiness/event capture. + * Can also mark the successful completion of a non-blocking connect + if `SO_ERROR`@`SOL_SOCKET` is zero. +* `EV_SIGNAL` + * Marks signal received/event capture +* `EV_TIMEOUT` + * Timeout occurred while waiting for an event +* `EV_PERSIST` + * Marks an event as persistent and not one-shot +* `EV_*` + * Can be OR'd together to capture multiple events that make sense. + (Should not OR `EV_READ`/`EV_WRITE` with `EV_SIGNAL`) + * Can be received OR'd together. + For example: `EV_READ` | `EV_TIMEOUT` means that a timeout + occurred while waiting for a read event. +* `EVBUFFER_READ` + * Marks that the input buffer has data available > low watermark +* `EVBUFFER_WRITE` + * Marks that the output buffer level is below low watermark +* `EVBUFFER_EOF` + * Received tagged with either read/write based on location received in the error callback +* `EVBUFFER_ERROR` + * An error occurred (tagged w/ either read/write) and the error is in `errno` +* `EVBUFFER_TIMEOUT` + * A timeout occurred (tagged w/ either read/write) + +Functions: + +[[toc levels=1]] + +## luaevent.core.new +* Allocates a new event 'core' (`event base`) + +## event_callback fn +* Input: `(event)` +* Output: `(newEvent, [newTimeout])` + * `newEvent` - New event to register, typically `LEAVE`, `EV_READ`, `EV_WRITE`, or `EV_READ`|`EV_WRITE` + * `newTimeout` - New timeout value to use + +## core:addevent +* Adds a new event to the eventloop +* Input: `(fd, event, event_callback, [timeout])` + * `fd` - File descriptor to read from / or NIL for pure timeout event + * `event` - `EV_*` flagset to mark what events to capture + * `EV_SIGNAL` and `EV_PERSIST` is unavailable currently + * `EV_PERSIST` is used internally. + * `event_callback` - Callback to call... (see above) + * `timeout` - Time in seconds to timeout (decimal values supported) +* Output: `event_callback` object + * Has a `close` and `__gc` FN which will erase the callback, + so preserve this until done. + +## core:loop +* Begins the event loop and doesn't return until there are no events left + +## core:close (__gc) +* Closes the event base +* Do not allow this to be called while `core:loop` is running diff -r 1b8cbf640378 -r dd47dbe85bec doc/modules/luaevent.mdwn diff -r 1b8cbf640378 -r dd47dbe85bec include/buffer_event.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/buffer_event.h Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,21 @@ +/* LuaEvent - Copyright (C) 2007 Thomas Harning + * Licensed as LGPL - See doc/COPYING for details */ +#ifndef BUFFER_EVENT_H +#define BUFFER_EVENT_H + +#include "luaevent.h" +#include +#include +#include +#include + +typedef struct { + struct bufferevent* ev; + le_base* base; +} le_bufferevent; + +int buffer_event_register(lua_State* L); +int is_buffer_event(lua_State* L, int idx); +le_bufferevent* buffer_event_check(lua_State* L, int idx); + +#endif diff -r 1b8cbf640378 -r dd47dbe85bec include/event_buffer.h --- a/include/event_buffer.h Wed Jul 15 10:38:52 2009 -0400 +++ b/include/event_buffer.h Wed Jul 15 10:39:10 2009 -0400 @@ -14,5 +14,8 @@ } le_buffer; int event_buffer_register(lua_State* L); +int is_event_buffer(lua_State* L, int idx); +le_buffer* event_buffer_check(lua_State* L, int idx); +int event_buffer_push(lua_State* L, struct evbuffer* buffer); #endif diff -r 1b8cbf640378 -r dd47dbe85bec include/utility.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/utility.h Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,13 @@ +/* LuaEvent - Copyright (C) 2007 Thomas Harning + * Licensed as LGPL - See doc/COPYING for details */ +#ifndef UTILITY_H +#define UTILITY_H + +#include + +void le_weak_ref(lua_State* L, void* ptr, int idx); +void le_weak_unref(lua_State* L, void* ptr); +void le_weak_get(lua_State* L, void* ptr); + +void le_register_utility(lua_State* L); +#endif diff -r 1b8cbf640378 -r dd47dbe85bec makeDocs.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/makeDocs.sh Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,2 @@ +#!/bin/sh +ikiwiki doc/ html/ --no-usedirs --plugin=goodstuff --plugin=toc diff -r 1b8cbf640378 -r dd47dbe85bec src/buffer_event.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/buffer_event.c Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,255 @@ +/* LuaEvent - Copyright (C) 2007 Thomas Harning + * Licensed as LGPL - See doc/COPYING for details */ +#include "buffer_event.h" +#include "luaevent.h" +#include "utility.h" +#include +#include +#include "event_buffer.h" + +#define BUFFER_EVENT_MT "BUFFER_EVENT_MT" + +/* Locations of READ/WRITE buffers in the fenv */ +#define READ_BUFFER_LOCATION 4 +#define WRITE_BUFFER_LOCATION 5 + +/* Obtains an le_bufferevent structure from a given index */ +static le_bufferevent* buffer_event_get(lua_State* L, int idx) { + return (le_bufferevent*)luaL_checkudata(L, idx, BUFFER_EVENT_MT); +} + +/* Obtains an le_bufferevent structure from a given index + AND checks that it hadn't been prematurely freed +*/ +le_bufferevent* buffer_event_check(lua_State* L, int idx) { + le_bufferevent* buf = (le_bufferevent*)luaL_checkudata(L, idx, BUFFER_EVENT_MT); + if(!buf->ev) + luaL_argerror(L, idx, "Attempt to use closed buffer_event object"); + return buf; +} + +/* Checks if the given index contains an le_buffer object */ +int is_buffer_event(lua_State* L, int idx) { + int ret; + lua_getmetatable(L, idx); + luaL_getmetatable(L, BUFFER_EVENT_MT); + ret = lua_rawequal(L, -2, -1); + lua_pop(L, 2); + return ret; +} + +static void handle_callback(le_bufferevent* le_ev, short what, int callbackIndex) { + lua_State* L = le_ev->base->loop_L; + le_weak_get(L, le_ev); + lua_getfenv(L, -1); + lua_rawgeti(L, -1, callbackIndex); + lua_remove(L, -2); + lua_pushvalue(L, -2); + lua_remove(L, -3); + /* func, bufferevent */ + lua_pushinteger(L, what); + /* What to do w/ errors...? */ + lua_pcall(L, 2, 0, 0); +} + +static void buffer_event_readcb(struct bufferevent *ev, void *ptr) { + handle_callback((le_bufferevent*)ptr, EVBUFFER_READ, 1); +} + +static void buffer_event_writecb(struct bufferevent *ev, void *ptr) { + handle_callback((le_bufferevent*)ptr, EVBUFFER_WRITE, 2); +} + +static void buffer_event_errorcb(struct bufferevent *ev, short what, void *ptr) { + handle_callback((le_bufferevent*)ptr, what, 3); +} + +/* LUA: new(fd, read, write, error) + Pushes a new bufferevent instance on the stack + Accepts: base, fd, read, write, error cb + Requires base, fd and error cb +*/ +static int buffer_event_push(lua_State* L) { + le_bufferevent *ev; + le_base* base = event_base_get(L, 1); + /* NOTE: Should probably reference the socket as well... */ + int fd = getSocketFd(L, 2); + luaL_checktype(L, 5, LUA_TFUNCTION); + if(!lua_isnil(L, 3)) luaL_checktype(L, 3, LUA_TFUNCTION); + if(!lua_isnil(L, 4)) luaL_checktype(L, 4, LUA_TFUNCTION); + ev= (le_bufferevent*)lua_newuserdata(L, sizeof(le_bufferevent)); + luaL_getmetatable(L, BUFFER_EVENT_MT); + lua_setmetatable(L, -2); + ev->ev = bufferevent_new(fd, buffer_event_readcb, buffer_event_writecb, buffer_event_errorcb, ev); + lua_createtable(L, 5, 0); + lua_pushvalue(L, 3); + lua_rawseti(L, -2, 1); // Read + lua_pushvalue(L, 4); + lua_rawseti(L, -2, 2); // Write + lua_pushvalue(L, 5); + lua_rawseti(L, -2, 3); // Err + + event_buffer_push(L, ev->ev->input); + lua_rawseti(L, -2, READ_BUFFER_LOCATION); + event_buffer_push(L, ev->ev->output); + lua_rawseti(L, -2, WRITE_BUFFER_LOCATION); + lua_setfenv(L, -2); + ev->base = base; + return 1; +} + +/* LUA: __gc and buffer:close() + Releases the buffer resources +*/ +static int buffer_event_gc(lua_State* L) { + le_bufferevent* ev = buffer_event_get(L, 1); + if(ev->ev) { + le_buffer *read, *write; + bufferevent_free(ev->ev); + ev->ev = NULL; + /* Also clear out the associated input/output event_buffers + * since they would have already been freed.. */ + lua_getfenv(L, 1); + lua_rawgeti(L, -1, READ_BUFFER_LOCATION); + lua_rawgeti(L, -2, WRITE_BUFFER_LOCATION); + read = event_buffer_check(L, -2); + write = event_buffer_check(L, -1); + /* Erase Lua's link to the buffers */ + lua_pushnil(L); + /* LS: ..., fenv, readBuf, writeBuf, nil */ + lua_rawseti(L, -4, READ_BUFFER_LOCATION); + lua_pushnil(L); + lua_rawseti(L, -4, WRITE_BUFFER_LOCATION); + /* Erase their knowledge of the buffer so that the GC won't try to double-free */ + read->buffer = NULL; + write->buffer = NULL; + } + return 0; +} + +static int buffer_event_get_read(lua_State* L) { + (void)buffer_event_get(L, 1); + lua_getfenv(L, 1); + lua_rawgeti(L, -1, READ_BUFFER_LOCATION); + return 1; +} + +static int buffer_event_get_write(lua_State* L) { + (void)buffer_event_get(L, 1); + lua_getfenv(L, 1); + lua_rawgeti(L, -1, WRITE_BUFFER_LOCATION); + return 1; +} + +static int buffer_event_set_read_watermarks(lua_State* L) { + int low, high; + le_bufferevent* ev = buffer_event_get(L, 1); + if(!ev->ev) return 0; + + low = lua_tonumber(L, 2); + high = lua_tonumber(L, 3); + + ev->ev->wm_read.low = low; + ev->ev->wm_read.high = high; + return 0; +} + +static int buffer_event_set_write_watermarks(lua_State* L) { + int low, high; + le_bufferevent* ev = buffer_event_get(L, 1); + if(!ev->ev) return 0; + + low = lua_tonumber(L, 2); + high = lua_tonumber(L, 3); + + ev->ev->wm_write.low = low; + ev->ev->wm_write.high = high; + return 0; +} + +static int buffer_event_get_read_watermarks(lua_State* L) { + le_bufferevent* ev = buffer_event_get(L, 1); + if(!ev->ev) return 0; + + lua_pushinteger(L, ev->ev->wm_read.low); + lua_pushinteger(L, ev->ev->wm_read.high); + return 2; +} + +static int buffer_event_get_write_watermarks(lua_State* L) { + le_bufferevent* ev = buffer_event_get(L, 1); + if(!ev->ev) return 0; + + lua_pushinteger(L, ev->ev->wm_write.low); + lua_pushinteger(L, ev->ev->wm_write.high); + return 2; +} + +static int buffer_event_set_timeouts(lua_State* L) { + int timeout_read, timeout_write; + le_bufferevent* ev = buffer_event_get(L, 1); + if(!ev->ev) return 0; + + timeout_read = lua_tointeger(L, 2); + timeout_write = lua_tointeger(L, 3); + + bufferevent_settimeout(ev->ev, timeout_read, timeout_write); + return 0; +} + +static int buffer_event_get_timeouts(lua_State* L) { + le_bufferevent* ev = buffer_event_get(L, 1); + if(!ev->ev) return 0; + + lua_pushinteger(L, ev->ev->timeout_read); + lua_pushinteger(L, ev->ev->timeout_write); + return 2; +} + +static int buffer_event_enable(lua_State* L) { + le_bufferevent* ev = buffer_event_get(L, 1); + if(!ev->ev) return 0; + + lua_pushinteger(L, bufferevent_enable(ev->ev, luaL_checkinteger(L, 2))); + return 1; +} + +static int buffer_event_disable(lua_State* L) { + le_bufferevent* ev = buffer_event_get(L, 1); + if(!ev->ev) return 0; + + lua_pushinteger(L, bufferevent_disable(ev->ev, luaL_checkinteger(L, 2))); + return 1; +} + +static luaL_Reg buffer_event_funcs[] = { + {"get_read", buffer_event_get_read}, + {"get_write", buffer_event_get_write}, + {"set_read_watermarks", buffer_event_set_read_watermarks}, + {"set_write_watermarks", buffer_event_set_write_watermarks}, + {"get_read_watermarks", buffer_event_get_read_watermarks}, + {"get_write_watermarks", buffer_event_get_write_watermarks}, + {"set_timeouts", buffer_event_set_timeouts}, + {"get_timeouts", buffer_event_get_timeouts}, + {"enable", buffer_event_enable}, + {"disable", buffer_event_disable}, + {NULL, NULL} +}; + +static luaL_Reg funcs[] = { + {"new", buffer_event_push}, + {NULL, NULL} +}; + +int buffer_event_register(lua_State* L) { + luaL_newmetatable(L, BUFFER_EVENT_MT); + lua_pushcfunction(L, buffer_event_gc); + lua_setfield(L, -2, "__gc"); + lua_newtable(L); + luaL_register(L, NULL, buffer_event_funcs); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + + luaL_register(L, "luaevent.core.bufferevent", funcs); + return 1; +} diff -r 1b8cbf640378 -r dd47dbe85bec src/event_buffer.c --- a/src/event_buffer.c Wed Jul 15 10:38:52 2009 -0400 +++ b/src/event_buffer.c Wed Jul 15 10:39:10 2009 -0400 @@ -18,7 +18,7 @@ /* Obtains an le_buffer structure from a given index AND checks that it hadn't been prematurely freed */ -static le_buffer* event_buffer_check(lua_State* L, int idx) { +le_buffer* event_buffer_check(lua_State* L, int idx) { le_buffer* buf = (le_buffer*)luaL_checkudata(L, idx, EVENT_BUFFER_MT); if(!buf->buffer) luaL_argerror(L, idx, "Attempt to use closed event_buffer object"); @@ -26,7 +26,7 @@ } /* Checks if the given index contains an le_buffer object */ -static int is_event_buffer(lua_State* L, int idx) { +int is_event_buffer(lua_State* L, int idx) { int ret; lua_getmetatable(L, idx); luaL_getmetatable(L, EVENT_BUFFER_MT); @@ -37,7 +37,7 @@ /* TODO: Use lightuserdata mapping to locate hanging object instances */ /* Pushes the specified evbuffer object onto the stack, attaching a metatable to it */ -static int event_buffer_push(lua_State* L, struct evbuffer* buffer) { +int event_buffer_push(lua_State* L, struct evbuffer* buffer) { le_buffer *buf = (le_buffer*)lua_newuserdata(L, sizeof(le_buffer)); buf->buffer = buffer; luaL_getmetatable(L, EVENT_BUFFER_MT); @@ -257,5 +257,5 @@ lua_pop(L, 1); luaL_register(L, "luaevent.core.buffer", funcs); - return 0; + return 1; } diff -r 1b8cbf640378 -r dd47dbe85bec src/luaevent.c --- a/src/luaevent.c Wed Jul 15 10:38:52 2009 -0400 +++ b/src/luaevent.c Wed Jul 15 10:39:10 2009 -0400 @@ -4,6 +4,7 @@ #include "luaevent.h" #include "event_callback.h" #include "event_buffer.h" +#include "buffer_event.h" #include #include @@ -109,6 +110,14 @@ {"EV_READ", EV_READ}, {"EV_WRITE", EV_WRITE}, {"EV_TIMEOUT", EV_TIMEOUT}, + {"EV_SIGNAL", EV_SIGNAL}, + {"EV_PERSIST", EV_PERSIST}, + /* bufferevent */ + {"EVBUFFER_READ", EVBUFFER_READ}, + {"EVBUFFER_WRITE", EVBUFFER_WRITE}, + {"EVBUFFER_EOF", EVBUFFER_EOF}, + {"EVBUFFER_ERROR", EVBUFFER_ERROR}, + {"EVBUFFER_TIMEOUT", EVBUFFER_TIMEOUT}, {NULL, 0} }; @@ -131,6 +140,8 @@ /* Register external items */ event_callback_register(L); event_buffer_register(L); + buffer_event_register(L); + lua_settop(L, 0); /* Setup metatable */ luaL_newmetatable(L, EVENT_BASE_MT); lua_newtable(L); diff -r 1b8cbf640378 -r dd47dbe85bec src/utility.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/utility.c Wed Jul 15 10:39:10 2009 -0400 @@ -0,0 +1,45 @@ +/* LuaEvent - Copyright (C) 2007 Thomas Harning + * Licensed as LGPL - See doc/COPYING for details */ +#include "utility.h" +#include + +#define WEAK_REF_LOCATION le_register_utility + +static void get_weakref_table(lua_State* L) { + lua_pushlightuserdata(L, WEAK_REF_LOCATION); + lua_gettable(L, LUA_REGISTRYINDEX); +} + +void le_weak_ref(lua_State* L, void* ptr, int idx) { + get_weakref_table(L); + lua_pushlightuserdata(L, ptr); + if(idx < 0) idx-=2; + lua_pushvalue(L, idx); + lua_settable(L, -3); +} +void le_weak_unref(lua_State* L, void* ptr) { + get_weakref_table(L); + lua_pushlightuserdata(L, ptr); + lua_pushnil(L); + lua_settable(L, -3); +} + +void le_weak_get(lua_State* L, void* ptr) { + get_weakref_table(L); + lua_pushlightuserdata(L, ptr); + lua_gettable(L, -2); +} + +static void push_weak_table(lua_State* L, const char* mode) { + lua_newtable(L); + lua_createtable(L,0,1); + lua_pushstring(L,mode); + lua_setfield(L,-2,"__mode"); + lua_setmetatable(L,-2); +} + +void le_register_utility(lua_State* L) { + lua_pushlightuserdata(L, WEAK_REF_LOCATION); + push_weak_table(L, "v"); + lua_settable(L, LUA_REGISTRYINDEX); +}