terom@93: #include "lua_objs.h" terom@93: terom@98: #include terom@98: terom@93: #include terom@93: #include terom@93: #include terom@93: terom@93: /** terom@96: * Convenience function to register a new metatable for a type, this leaves the metatable on the stack terom@96: */ terom@96: static void lua_obj_create_type (lua_State *L, const char *name, const struct luaL_Reg methods[]) terom@96: { terom@96: luaL_newmetatable(L, name); terom@96: terom@96: // set the metatable __index to itself terom@96: lua_pushvalue(L, -1); terom@96: lua_setfield(L, -1, "__index"); terom@96: terom@96: // register the methods to the metatable terom@96: luaL_register(L, NULL, methods); terom@96: } terom@96: terom@96: /** terom@96: * Convenience function to create a new userdata with the given type metatable name, return the pointer, and keep it terom@96: * on the stack terom@96: */ terom@96: static void* lua_obj_create_obj (lua_State *L, const char *name, size_t size) terom@96: { terom@96: // create the new userdata on the stack terom@96: void *ud = lua_newuserdata(L, size); terom@96: terom@96: // get the type and set it terom@96: luaL_getmetatable(L, name); terom@96: lua_setmetatable(L, -2); terom@96: terom@96: // ok terom@96: return ud; terom@96: } terom@96: terom@96: /** terom@96: * Convenience function to get a userdata with the given type metatable name as the first argument for a function terom@96: */ terom@96: static void* lua_obj_get_obj (lua_State *L, const char *func, const char *name) terom@96: { terom@96: void *ud; terom@96: terom@96: // validate the userdata arg terom@96: if ((ud = luaL_checkudata(L, 1, name)) == NULL) { terom@96: luaL_error(L, "bad type argument to %s: `%s` expected", func, name); terom@96: terom@96: } else { terom@96: // ok terom@96: return ud; terom@96: terom@96: } terom@96: } terom@96: terom@96: /** terom@96: * Our lua wrapper for irc_chan terom@96: */ terom@96: struct lua_chan { terom@96: struct irc_chan *chan; terom@96: }; terom@96: terom@96: /** terom@96: * Create a lua_chan userdata from the given irc_chan and leave it on the stack, returning 1 terom@96: */ terom@96: static int lua_chan_create (lua_State *L, struct irc_chan *chan) terom@96: { terom@96: // create the new obj terom@96: struct lua_chan *lua_chan = lua_obj_create_obj(L, "evirc.chan", sizeof(*lua_chan)); terom@96: terom@96: // initialize terom@96: lua_chan->chan = chan; terom@96: terom@96: // ok terom@96: return 1; terom@96: } terom@96: terom@96: /** terom@96: * Return the channel name as a lua string terom@96: */ terom@96: static int lua_chan_tostring (lua_State *L) terom@96: { terom@96: struct lua_chan *lua_chan = lua_obj_get_obj(L, __func__, "evirc.chan"); terom@96: terom@96: lua_pushfstring(L, "", irc_chan_name(lua_chan->chan)); terom@96: terom@96: return 1; terom@96: } terom@96: terom@97: /** terom@97: * Send a PRIVMSG to the channel terom@97: */ terom@97: static int lua_chan_say (lua_State *L) terom@97: { terom@97: err_t err; terom@97: terom@97: struct lua_chan *lua_chan = lua_obj_get_obj(L, __func__, "evirc.chan"); terom@97: terom@97: // the message terom@97: const char *message = luaL_checkstring(L, 2); terom@97: terom@97: // send terom@97: if ((err = irc_chan_PRIVMSG(lua_chan->chan, message))) terom@97: return luaL_error(L, "irc_chan_PRIVMSG: '%s': %s", message, error_name(err)); terom@97: terom@97: // ok terom@97: return 0; terom@97: } terom@96: terom@96: static const struct luaL_Reg lua_chan_methods[] = { terom@96: { "__tostring", &lua_chan_tostring }, terom@97: { "say", &lua_chan_say }, terom@96: { NULL, NULL }, terom@96: }; terom@96: terom@96: /** terom@96: * Initialize the lua_chan object type terom@96: */ terom@96: static void lua_chan_init (lua_State *L) terom@96: { terom@96: lua_obj_create_type(L, "evirc.chan", lua_chan_methods); terom@96: } terom@96: terom@96: /** terom@93: * Our lua wrapper for irc_net terom@93: */ terom@94: struct lua_net { terom@93: struct irc_net *net; terom@93: }; terom@93: terom@93: /** terom@94: * Create a lua_net userdata from the given irc_net and push it onto the stack, returning 1. terom@94: */ terom@94: static int lua_net_create (lua_State *L, struct irc_net *net) terom@94: { terom@96: // create the new obj terom@96: struct lua_net *lua_net = lua_obj_create_obj(L, "evirc.net", sizeof(*lua_net)); terom@94: terom@94: // initialize terom@94: lua_net->net = net; terom@94: terom@94: // ok terom@94: return 1; terom@94: } terom@94: terom@94: /** terom@96: * Return the network name as a lua string terom@96: */ terom@96: static int lua_net_tostring (lua_State *L) terom@96: { terom@96: struct lua_net *lua_net = lua_obj_get_obj(L, __func__, "evirc.net"); terom@96: terom@96: lua_pushfstring(L, "", irc_net_name(lua_net->net)); terom@96: terom@96: return 1; terom@96: } terom@96: terom@96: /** terom@94: * Join a new channel, returning the lua_chan terom@94: */ terom@94: static int lua_net_join (lua_State *L) terom@94: { terom@96: struct lua_net *lua_net = lua_obj_get_obj(L, __func__, "evirc.net"); terom@94: struct irc_chan_info chan_info; terom@94: struct irc_chan *chan; terom@94: struct error_info err; terom@94: terom@94: // the channel name terom@94: chan_info.channel = luaL_checkstring(L, 2); terom@94: terom@94: // add it terom@94: if (irc_net_add_chan(lua_net->net, &chan, &chan_info, &err)) terom@94: return luaL_error(L, "irc_net_add_chan: %s: %s", chan_info.channel, error_msg(&err)); terom@94: terom@96: // return it terom@96: return lua_chan_create(L, chan); terom@96: } terom@96: terom@96: /** terom@96: * Look up a channel by name, returning the lua_chan terom@96: */ terom@96: static int lua_net_get_chan (lua_State *L) terom@96: { terom@96: struct lua_net *lua_net = lua_obj_get_obj(L, __func__, "evirc.net"); terom@96: struct irc_chan *chan; terom@96: terom@96: // the channel name terom@96: const char *channel = luaL_checkstring(L, 2); terom@96: terom@96: // lookup the irc_chan terom@96: if ((chan = irc_net_get_chan(lua_net->net, channel)) == NULL) terom@96: return luaL_error(L, "irc_net_get_chan: no such channel: %s", channel); terom@96: terom@96: // wrap it terom@96: return lua_chan_create(L, chan); terom@94: } terom@94: terom@94: static const struct luaL_Reg lua_net_methods[] = { terom@96: { "__tostring", &lua_net_tostring }, terom@94: { "join", &lua_net_join }, terom@96: { "channel", &lua_net_get_chan }, terom@94: { NULL, NULL } terom@94: }; terom@94: terom@94: /** terom@94: * Initialize the lua_net object type terom@94: */ terom@96: static void lua_net_init (lua_State *L) terom@94: { terom@96: lua_obj_create_type(L, "evirc.net", lua_net_methods); terom@94: } terom@94: terom@94: /** terom@93: * Wrapper for irc_client terom@93: */ terom@93: struct lua_client { terom@93: struct irc_client *client; terom@93: }; terom@93: terom@98: static int lua_client_connect (lua_State *L) terom@93: { terom@96: struct lua_client *lua_client = lua_obj_get_obj(L, __func__, "evirc.client"); terom@98: struct irc_net_info net_info; terom@98: struct irc_net *net; terom@98: struct error_info err; terom@93: terom@98: // init net_info terom@98: memset(&net_info, 0, sizeof(net_info)); terom@93: terom@98: // the network name terom@98: net_info.network = luaL_checkstring(L, 2); terom@98: terom@98: // the hostname terom@98: net_info.hostname = luaL_checkstring(L, 3); terom@98: terom@98: // service remains default terom@98: net_info.service = "6667"; terom@98: terom@98: // create it terom@98: if (irc_client_add_net(lua_client->client, &net, &net_info, &err)) terom@98: return luaL_error(L, "irc_client_add_net: %s/%s: %s", net_info.network, net_info.hostname, error_msg(&err)); terom@98: terom@98: // wrap it terom@98: return lua_net_create(L, net); terom@93: } terom@93: terom@94: static int lua_client_get_network (lua_State *L) terom@94: { terom@96: struct lua_client *lua_client = lua_obj_get_obj(L, __func__, "evirc.client"); terom@94: struct irc_net *net; terom@94: terom@94: // the network name terom@94: const char *network = luaL_checkstring(L, 2); terom@94: terom@94: // lookup the irc_net terom@94: if ((net = irc_client_get_net(lua_client->client, network)) == NULL) terom@94: return luaL_error(L, "irc_client_get_net: no such network: %s", network); terom@94: terom@94: // wrap it terom@94: return lua_net_create(L, net); terom@94: } terom@94: terom@98: static int lua_client_quit (lua_State *L) terom@98: { terom@98: struct lua_client *lua_client = lua_obj_get_obj(L, __func__, "evirc.client"); terom@98: err_t err; terom@98: terom@98: // the message terom@98: const char *message = luaL_checkstring(L, 2); terom@98: terom@98: // execute terom@98: if ((err = irc_client_quit(lua_client->client, message))) terom@98: return luaL_error(L, "irc_client_quit: %s", error_name(err)); terom@98: terom@98: // ok terom@98: return 0; terom@98: } terom@98: terom@94: static const struct luaL_Reg lua_client_methods[] = { terom@98: { "connect", &lua_client_connect }, terom@98: { "network", &lua_client_get_network }, terom@94: { "quit", &lua_client_quit }, terom@94: { NULL, NULL } terom@93: }; terom@93: terom@93: /** terom@93: * Initializes a lua_irc_client wrapper for the given client in the give lua state. This registers a set of globals for terom@93: * 'client' and 'networks'. terom@93: */ terom@96: static void lua_client_init (lua_State *L, struct irc_client *client) terom@93: { terom@93: // allocate the global "client" object terom@94: struct lua_client *lua_client = lua_newuserdata(L, sizeof(*lua_client)); terom@93: terom@96: // create the type metatable terom@96: lua_obj_create_type(L, "evirc.client", lua_client_methods); terom@93: terom@93: // set the client userdata's metatable terom@93: lua_setmetatable(L, -2); terom@93: terom@93: // initialize it terom@93: lua_client->client = client; terom@93: terom@93: // store it as a global terom@93: lua_setglobal(L, "client"); terom@93: } terom@93: terom@98: /** terom@98: * Set up the lua state in protected mode terom@98: */ terom@98: static int _lua_objs_init (lua_State *L) terom@93: { terom@98: struct nexus *nexus; terom@98: terom@98: // read the nexus off the stack terom@98: if ((nexus = lua_touserdata(L, 1)) == NULL) terom@98: luaL_error(L, "lua_touserdata: NULL"); terom@98: terom@93: // init the various bits terom@94: lua_client_init(L, nexus->client); terom@94: lua_net_init(L); terom@96: lua_chan_init(L); terom@94: terom@98: // nothing terom@98: return 0; terom@93: } terom@98: terom@98: err_t lua_objs_init (lua_State *L, struct nexus *nexus) terom@98: { terom@98: // call in protected mode terom@98: switch (lua_cpcall(L, &_lua_objs_init, nexus)) { terom@98: case 0: return SUCCESS; terom@98: case LUA_ERRRUN: return ERR_LUA_RUN; terom@98: case LUA_ERRMEM: return ERR_LUA_MEM; terom@98: case LUA_ERRERR: return ERR_LUA_ERR; terom@98: default: return ERR_UNKNOWN; terom@98: } terom@98: } terom@98: