# HG changeset patch # User Tero Marttila # Date 1238520825 -10800 # Node ID a07d917adec1bb8ee07499eaaa51ee7d67a247ba # Parent 6bb8ef294689f7b943ea091bbbced01a44b6c04c add irc_chan and unify type/obj creation diff -r 6bb8ef294689 -r a07d917adec1 src/lua_objs.c --- 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 /** + * 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_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_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; }