#include "lua_objs.h"
#include <lua5.1/lua.h>
#include <lua5.1/lualib.h>
#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 {
struct irc_net *net;
};
/**
* Create a lua_net userdata from the given irc_net and push it onto the stack, returning 1.
*/
static int lua_net_create (lua_State *L, struct irc_net *net)
{
// create the new obj
struct lua_net *lua_net = lua_obj_create_obj(L, "evirc.net", sizeof(*lua_net));
// initialize
lua_net->net = net;
// ok
return 1;
}
/**
* 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 = lua_obj_get_obj(L, __func__, "evirc.net");
struct irc_chan_info chan_info;
struct irc_chan *chan;
struct error_info err;
// the channel name
chan_info.channel = luaL_checkstring(L, 2);
// add it
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));
// 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 void lua_net_init (lua_State *L)
{
lua_obj_create_type(L, "evirc.net", lua_net_methods);
}
/**
* Wrapper for irc_client
*/
struct lua_client {
struct irc_client *client;
};
static int lua_client_quit (lua_State *L)
{
struct lua_client *lua_client = lua_obj_get_obj(L, __func__, "evirc.client");
err_t err;
// the message
const char *message = luaL_checkstring(L, 2);
// execute
if ((err = irc_client_quit(lua_client->client, message)))
return luaL_error(L, "irc_client_quit: %s", error_name(err));
// ok
return 0;
}
static int lua_client_get_network (lua_State *L)
{
struct lua_client *lua_client = lua_obj_get_obj(L, __func__, "evirc.client");
struct irc_net *net;
// the network name
const char *network = luaL_checkstring(L, 2);
// lookup the irc_net
if ((net = irc_client_get_net(lua_client->client, network)) == NULL)
return luaL_error(L, "irc_client_get_net: no such network: %s", network);
// wrap it
return lua_net_create(L, net);
}
static const struct luaL_Reg lua_client_methods[] = {
{ "quit", &lua_client_quit },
{ "network", &lua_client_get_network },
{ NULL, NULL }
};
/**
* 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 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));
// create the type metatable
lua_obj_create_type(L, "evirc.client", lua_client_methods);
// set the client userdata's metatable
lua_setmetatable(L, -2);
// initialize it
lua_client->client = client;
// store it as a global
lua_setglobal(L, "client");
}
err_t lua_objs_init (lua_State *L, struct nexus *nexus)
{
// init the various bits
lua_client_init(L, nexus->client);
lua_net_init(L);
lua_chan_init(L);
return SUCCESS;
}