src/lua_objs.c
changeset 96 a07d917adec1
parent 94 05a96b200d7b
child 97 d3bc82ee76cb
--- 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;
 }