--- a/src/lua_objs.c Tue Mar 31 20:33:31 2009 +0300
+++ b/src/lua_objs.c Tue Mar 31 20:33:45 2009 +0300
@@ -5,6 +5,104 @@
#include <lua5.1/lauxlib.h>
/**
+ * Convenience function to register a new metatable for a type, this leaves the metatable on the stack
+ */
+static void lua_obj_create_type (lua_State *L, const char *name, const struct luaL_Reg methods[])
+{
+ luaL_newmetatable(L, name);
+
+ // set the metatable __index to itself
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -1, "__index");
+
+ // register the methods to the metatable
+ luaL_register(L, NULL, methods);
+}
+
+/**
+ * Convenience function to create a new userdata with the given type metatable name, return the pointer, and keep it
+ * on the stack
+ */
+static void* lua_obj_create_obj (lua_State *L, const char *name, size_t size)
+{
+ // create the new userdata on the stack
+ void *ud = lua_newuserdata(L, size);
+
+ // get the type and set it
+ luaL_getmetatable(L, name);
+ lua_setmetatable(L, -2);
+
+ // ok
+ return ud;
+}
+
+/**
+ * Convenience function to get a userdata with the given type metatable name as the first argument for a function
+ */
+static void* lua_obj_get_obj (lua_State *L, const char *func, const char *name)
+{
+ void *ud;
+
+ // validate the userdata arg
+ if ((ud = luaL_checkudata(L, 1, name)) == NULL) {
+ luaL_error(L, "bad type argument to %s: `%s` expected", func, name);
+
+ } else {
+ // ok
+ return ud;
+
+ }
+}
+
+/**
+ * Our lua wrapper for irc_chan
+ */
+struct lua_chan {
+ struct irc_chan *chan;
+};
+
+/**
+ * Create a lua_chan userdata from the given irc_chan and leave it on the stack, returning 1
+ */
+static int lua_chan_create (lua_State *L, struct irc_chan *chan)
+{
+ // create the new obj
+ struct lua_chan *lua_chan = lua_obj_create_obj(L, "evirc.chan", sizeof(*lua_chan));
+
+ // initialize
+ lua_chan->chan = chan;
+
+ // ok
+ return 1;
+}
+
+/**
+ * Return the channel name as a lua string
+ */
+static int lua_chan_tostring (lua_State *L)
+{
+ struct lua_chan *lua_chan = lua_obj_get_obj(L, __func__, "evirc.chan");
+
+ lua_pushfstring(L, "<irc_chan %s>", irc_chan_name(lua_chan->chan));
+
+ return 1;
+}
+
+
+static const struct luaL_Reg lua_chan_methods[] = {
+ { "__tostring", &lua_chan_tostring },
+ { NULL, NULL },
+};
+
+/**
+ * Initialize the lua_chan object type
+ */
+static void lua_chan_init (lua_State *L)
+{
+ lua_obj_create_type(L, "evirc.chan", lua_chan_methods);
+}
+
+/**
* Our lua wrapper for irc_net
*/
struct lua_net {
@@ -16,12 +114,8 @@
*/
static int lua_net_create (lua_State *L, struct irc_net *net)
{
- // create the new userdata on the stack
- struct lua_net *lua_net = lua_newuserdata(L, sizeof(*lua_net));
-
- // get the type and set it
- luaL_getmetatable(L, "evirc.net");
- lua_setmetatable(L, -2);
+ // create the new obj
+ struct lua_net *lua_net = lua_obj_create_obj(L, "evirc.net", sizeof(*lua_net));
// initialize
lua_net->net = net;
@@ -31,19 +125,27 @@
}
/**
+ * Return the network name as a lua string
+ */
+static int lua_net_tostring (lua_State *L)
+{
+ struct lua_net *lua_net = lua_obj_get_obj(L, __func__, "evirc.net");
+
+ lua_pushfstring(L, "<irc_net %s>", irc_net_name(lua_net->net));
+
+ return 1;
+}
+
+/**
* Join a new channel, returning the lua_chan
*/
static int lua_net_join (lua_State *L)
{
- struct lua_net *lua_net;
+ struct lua_net *lua_net = lua_obj_get_obj(L, __func__, "evirc.net");
struct irc_chan_info chan_info;
struct irc_chan *chan;
struct error_info err;
- // validate the lua_net arg
- if ((lua_net = luaL_checkudata(L, 1, "evirc.net")) == NULL)
- return luaL_argerror(L, 1, "`evirc.net` expected");
-
// the channel name
chan_info.channel = luaL_checkstring(L, 2);
@@ -51,30 +153,42 @@
if (irc_net_add_chan(lua_net->net, &chan, &chan_info, &err))
return luaL_error(L, "irc_net_add_chan: %s: %s", chan_info.channel, error_msg(&err));
- // XXX: wrap it
- return 0;
+ // return it
+ return lua_chan_create(L, chan);
+}
+
+/**
+ * Look up a channel by name, returning the lua_chan
+ */
+static int lua_net_get_chan (lua_State *L)
+{
+ struct lua_net *lua_net = lua_obj_get_obj(L, __func__, "evirc.net");
+ struct irc_chan *chan;
+
+ // the channel name
+ const char *channel = luaL_checkstring(L, 2);
+
+ // lookup the irc_chan
+ if ((chan = irc_net_get_chan(lua_net->net, channel)) == NULL)
+ return luaL_error(L, "irc_net_get_chan: no such channel: %s", channel);
+
+ // wrap it
+ return lua_chan_create(L, chan);
}
static const struct luaL_Reg lua_net_methods[] = {
+ { "__tostring", &lua_net_tostring },
{ "join", &lua_net_join },
+ { "channel", &lua_net_get_chan },
{ NULL, NULL }
};
/**
* Initialize the lua_net object type
*/
-static err_t lua_net_init (lua_State *L)
+static void lua_net_init (lua_State *L)
{
- luaL_newmetatable(L, "evirc.net");
-
- // set the metatable __index to itself
- lua_pushvalue(L, -1);
- lua_setfield(L, -1, "__index");
-
- // register the methods to the metatable
- luaL_register(L, NULL, lua_net_methods);
-
- return SUCCESS;
+ lua_obj_create_type(L, "evirc.net", lua_net_methods);
}
/**
@@ -86,13 +200,9 @@
static int lua_client_quit (lua_State *L)
{
- struct lua_client *lua_client;
+ struct lua_client *lua_client = lua_obj_get_obj(L, __func__, "evirc.client");
err_t err;
- // validate the lua_client arg
- if ((lua_client = luaL_checkudata(L, 1, "evirc.client")) == NULL)
- return luaL_argerror(L, 1, "`evirc.client` expected");
-
// the message
const char *message = luaL_checkstring(L, 2);
@@ -106,13 +216,9 @@
static int lua_client_get_network (lua_State *L)
{
- struct lua_client *lua_client;
+ struct lua_client *lua_client = lua_obj_get_obj(L, __func__, "evirc.client");
struct irc_net *net;
- // validate the lua_client arg
- if ((lua_client = luaL_checkudata(L, 1, "evirc.client")) == NULL)
- return luaL_argerror(L, 1, "`evirc.client` expected");
-
// the network name
const char *network = luaL_checkstring(L, 2);
@@ -134,21 +240,14 @@
* Initializes a lua_irc_client wrapper for the given client in the give lua state. This registers a set of globals for
* 'client' and 'networks'.
*/
-static err_t lua_client_init (lua_State *L, struct irc_client *client)
+static void lua_client_init (lua_State *L, struct irc_client *client)
{
// allocate the global "client" object
// XXX: mem errors?
struct lua_client *lua_client = lua_newuserdata(L, sizeof(*lua_client));
- // push a new metatable to identify the client object
- luaL_newmetatable(L, "evirc.client");
-
- // set the metatable __index to itself
- lua_pushvalue(L, -1);
- lua_setfield(L, -1, "__index");
-
- // register the methods to the metatable
- luaL_register(L, NULL, lua_client_methods);
+ // create the type metatable
+ lua_obj_create_type(L, "evirc.client", lua_client_methods);
// set the client userdata's metatable
lua_setmetatable(L, -2);
@@ -158,9 +257,6 @@
// store it as a global
lua_setglobal(L, "client");
-
- // ok
- return SUCCESS;
}
err_t lua_objs_init (lua_State *L, struct nexus *nexus)
@@ -168,6 +264,7 @@
// init the various bits
lua_client_init(L, nexus->client);
lua_net_init(L);
+ lua_chan_init(L);
return SUCCESS;
}