terom@93: #include "lua_objs.h" terom@116: #include "lua_irc.h" terom@203: #include "lua_func.h" terom@104: #include "log.h" terom@93: terom@108: #include terom@98: #include terom@98: terom@96: /** terom@103: * Wrapper for module terom@103: */ terom@103: struct lua_module { terom@103: struct module *module; terom@103: }; terom@103: terom@145: static struct lua_type lua_module_type = LUA_TYPE("spbot.module"); terom@145: terom@103: /** terom@103: * Create a lua_module userdata from the given module and push it onto the stack, returning 1. terom@113: * terom@113: * The given module should be a reference of its own right. terom@103: */ terom@103: static int lua_module_create (lua_State *L, struct module *module) terom@103: { terom@103: // create the new obj terom@145: struct lua_module *lua_module = lua_type_create(L, &lua_module_type, sizeof(*lua_module)); terom@103: terom@103: // initialize terom@103: lua_module->module = module; terom@103: terom@103: // ok terom@103: return 1; terom@103: } terom@103: terom@107: /** terom@113: * module_put() our module reference terom@113: */ terom@113: static int lua_module__gc (lua_State *L) terom@113: { terom@145: struct lua_module *lua_module = lua_type_get(L, &lua_module_type, 1); terom@113: terom@113: // put it terom@113: module_put(lua_module->module); terom@113: terom@113: return 0; terom@113: } terom@113: terom@103: static int lua_module_conf (lua_State *L) terom@103: { terom@145: struct lua_module *lua_module = lua_type_get(L, &lua_module_type, 1); terom@103: const struct config_option *option; terom@124: struct error_info err; terom@124: bool is_err = true; terom@124: terom@124: // the list of given config values, and temporary storage for string values terom@122: struct config_value values[CONFIG_VALUES_MAX], *value = values; terom@122: char *value_bufs[CONFIG_VALUES_MAX], **value_buf = value_bufs; terom@122: terom@122: // number of arguments given terom@122: int nargs = lua_gettop(L), argidx = 2; terom@122: terom@122: // init to zero terom@122: memset(values, 0, sizeof(values)); terom@122: memset(value_bufs, 0, sizeof(value_bufs)); terom@103: terom@103: // XXX: come up with some better way... terom@103: struct nexus *nexus = lua_module->module->modules->nexus; terom@103: terom@103: // the config name terom@122: const char *conf_name = luaL_checkstring(L, argidx++); terom@103: terom@103: // look it up terom@103: if ((option = module_conf_lookup(lua_module->module, conf_name, &err)) == NULL) terom@103: return luaL_error(L, "module_conf_lookup: %s/%s: %s", module_name(lua_module->module), conf_name, error_msg(&err)); terom@107: terom@122: // maximum number of arguments accepted terom@122: int maxargs = config_params_count(option); terom@107: terom@122: // too many arguments? terom@124: if (nargs - argidx > maxargs) terom@124: return luaL_error(L, "lua_module_conf: too many arguments (>%d) given (%d)", maxargs, nargs - argidx); terom@122: terom@122: // the current param terom@122: const struct config_param *param = option->params; terom@107: terom@124: // apply each given argument to the correct param, storing it in value terom@122: for (; argidx <= nargs; argidx++, value++, param++) { terom@124: // the given config value terom@122: switch (lua_type(L, argidx)) { terom@124: case LUA_TNONE: terom@124: case LUA_TNIL: terom@124: // no value terom@124: value->type = CONFIG_NULL; terom@124: terom@124: break; terom@124: terom@122: case LUA_TSTRING: { terom@122: // string arg terom@122: const char *arg_str = lua_tostring(L, argidx); terom@122: terom@122: // copy it as a mutable string buffer terom@122: if ((*value_buf = strdup(arg_str)) == NULL) { terom@122: lua_pushfstring(L, "strdup"); terom@122: goto error; terom@122: } terom@122: terom@122: // parse it as a raw value terom@122: if (config_parse_param(param, nexus, value, *value_buf, &err)) { terom@122: lua_pushfstring(L, "config_parse: %s/%s: %s", option->name, *value_buf, error_msg(&err)); terom@122: goto error; terom@122: } terom@122: terom@122: // seek to next value_buf terom@122: value_buf++; terom@122: terom@122: } break; terom@122: terom@122: case LUA_TUSERDATA: terom@122: // some kind of userdata, use its metatable to figure out what type it is terom@122: if (!lua_getmetatable(L, argidx)) { terom@122: lua_pushfstring(L, "config value is userdata without metatable"); terom@122: goto error; terom@122: } terom@122: terom@122: // get the target metatable terom@122: lua_getfield(L, LUA_REGISTRYINDEX, "evirc.chan"); terom@122: terom@122: // is it a chan? terom@122: if (!lua_rawequal(L, -1, -2)) { terom@122: lua_pushfstring(L, "config value is userdata of unknown type"); terom@122: goto error; terom@122: } terom@122: terom@122: // pop the metatables terom@122: lua_pop(L, 2); terom@122: terom@122: // get the irc_chan terom@122: struct lua_chan *lua_chan = lua_touserdata(L, argidx); terom@122: terom@122: // build the value terom@122: value->type = CONFIG_IRC_CHAN; terom@122: value->irc_chan = lua_chan->chan; terom@122: terom@122: break; terom@107: terom@122: default: terom@122: lua_pushfstring(L, "config value is of unknown lua type '%s'", lua_typename(L, argidx)); terom@122: goto error; terom@107: terom@122: } terom@122: } terom@122: terom@122: // apply it terom@122: if (module_conf(lua_module->module, option, values, &err)) { terom@122: lua_pushfstring(L, "module_conf: %s/%s: %s", module_name(lua_module->module), option->name, error_msg(&err)); terom@122: goto error; terom@107: } terom@103: terom@103: // ok terom@122: is_err = false; terom@122: terom@122: error: terom@122: // release any allocated strings terom@122: for (value_buf = value_bufs; value_buf <= value_bufs + CONFIG_VALUES_MAX && *value_buf; value_buf++) terom@122: free(*value_buf); terom@122: terom@122: // either error or successful return terom@122: if (is_err) terom@122: return lua_error(L); terom@122: else terom@122: return 0; terom@103: } terom@103: terom@113: static int lua_module_unload (lua_State *L) terom@113: { terom@145: struct lua_module *lua_module = lua_type_get(L, &lua_module_type, 1); terom@113: struct error_info err; terom@113: terom@113: // just unload it terom@113: if ((ERROR_CODE(&err) = module_unload(lua_module->module))) terom@113: return luaL_error(L, "module_unload: %s: %s", module_name(lua_module->module), error_msg(&err)); terom@113: terom@113: // ok terom@113: return 0; terom@113: } terom@113: terom@145: static struct lua_method lua_module_methods[] = LUA_METHODS( terom@145: LUA_METHOD("__gc", lua_module__gc, NULL ), terom@145: LUA_METHOD("conf", lua_module_conf, NULL ), terom@145: LUA_METHOD("unload", lua_module_unload, NULL ) terom@145: ); terom@103: terom@103: /** terom@103: * Wrapper for modules terom@103: */ terom@103: struct lua_modules { terom@103: struct modules *modules; terom@108: terom@108: // strdup'd path for module_path terom@108: // XXX: remove when gc'd terom@108: char *path; terom@103: }; terom@103: terom@145: static struct lua_type lua_modules_type = LUA_TYPE("spbot.modules"); terom@145: terom@114: static int lua_modules__gc (lua_State *L) terom@114: { terom@145: struct lua_modules *lua_modules = lua_type_get(L, &lua_modules_type, 1); terom@114: terom@114: // remove the modules path if it was set by us terom@114: if (lua_modules->path && modules_path(lua_modules->modules, NULL) == lua_modules->path) terom@114: modules_path(lua_modules->modules, ""); terom@114: terom@114: // release any strdup'd path terom@114: free(lua_modules->path); terom@114: terom@114: // ok terom@114: return 0; terom@114: } terom@114: terom@108: static int lua_modules_path (lua_State *L) terom@108: { terom@145: struct lua_modules *lua_modules = lua_type_get(L, &lua_modules_type, 1); terom@108: char *path = NULL; terom@108: const char *old_path; terom@108: terom@108: if (!lua_isnoneornil(L, 2)) { terom@108: // the new path terom@108: if ((path = strdup(luaL_checkstring(L, 2))) == NULL) terom@108: return luaL_error(L, "strdup"); terom@108: } terom@108: terom@108: // set or get terom@108: old_path = modules_path(lua_modules->modules, path); terom@108: terom@108: // return the old path terom@108: if (old_path) terom@108: lua_pushstring(L, old_path); terom@108: else terom@108: lua_pushnil(L); terom@108: terom@108: if (path) { terom@108: // replace the old path terom@108: free(lua_modules->path); terom@108: lua_modules->path = path; terom@108: } terom@108: terom@108: // ok terom@108: return 1; terom@108: } terom@108: terom@103: static int lua_modules_load (lua_State *L) terom@103: { terom@145: struct lua_modules *lua_modules = lua_type_get(L, &lua_modules_type, 1); terom@103: struct module *module; terom@103: struct module_info info; terom@103: struct error_info err; terom@103: terom@103: // the module name/path terom@103: info.name = luaL_checkstring(L, 2); terom@108: info.path = lua_isnoneornil(L, 3) ? NULL : luaL_checkstring(L, 3); terom@103: terom@113: // load and get a new reference terom@103: if (module_load(lua_modules->modules, &module, &info, &err)) terom@103: return luaL_error(L, "module_load: %s/%s: %s", info.name, info.path, error_msg(&err)); terom@103: terom@103: // wrap terom@103: return lua_module_create(L, module); terom@103: } terom@103: terom@103: static int lua_modules_module (lua_State *L) terom@103: { terom@145: struct lua_modules *lua_modules = lua_type_get(L, &lua_modules_type, 1); terom@103: struct module *module; terom@103: terom@103: // the module name terom@103: const char *name = luaL_checkstring(L, 2); terom@103: terom@113: // look it up, as a new reference terom@134: if ((module = modules_get(lua_modules->modules, name)) == NULL) terom@103: return luaL_error(L, "module_get: %s: no such module", name); terom@103: terom@103: // wrap terom@103: return lua_module_create(L, module); terom@103: } terom@103: terom@145: static struct lua_method lua_modules_methods[] = LUA_METHODS( terom@145: LUA_METHOD("__gc", lua_modules__gc, NULL ), terom@145: LUA_METHOD("path", lua_modules_path, NULL ), terom@145: LUA_METHOD("load", lua_modules_load, NULL ), terom@145: LUA_METHOD("module", lua_modules_module, NULL ) terom@145: ); terom@145: terom@145: terom@103: terom@103: /** terom@103: * Initialize the spbot.modules type for lua_modules, and registers an instance bound to the given modules list at terom@103: * 'modules'. terom@103: */ terom@103: static void lua_modules_init (lua_State *L, struct modules *modules) terom@103: { terom@103: // allocate the global "modules" object terom@145: struct lua_modules *lua_modules = lua_type_register_global(L, &lua_modules_type, lua_modules_methods, "modules", sizeof(*lua_modules)); terom@103: terom@103: // initialize it terom@103: lua_modules->modules = modules; terom@103: } terom@103: terom@103: /** terom@103: * Wrapper for nexus terom@103: */ terom@103: struct lua_nexus { terom@103: struct nexus *nexus; terom@103: }; terom@103: terom@145: static struct lua_type lua_nexus_type = LUA_TYPE("spbot.nexus"); terom@145: terom@103: static int lua_nexus_shutdown (lua_State *L) terom@103: { terom@145: struct lua_nexus *lua_nexus = lua_type_get(L, &lua_nexus_type, 1); terom@103: terom@103: // just shut it down terom@103: nexus_shutdown(lua_nexus->nexus); terom@103: terom@103: return 0; terom@103: } terom@103: terom@109: static int lua_nexus_load_config (lua_State *L) terom@109: { terom@145: struct lua_nexus *lua_nexus = lua_type_get(L, &lua_nexus_type, 1); terom@109: struct error_info err; terom@109: terom@109: const char *path = luaL_checkstring(L, 2); terom@109: terom@109: // just load it terom@109: if (nexus_load_config(lua_nexus->nexus, path, &err)) terom@109: return luaL_error(L, "nexus_load_config(%s): %s", path, error_msg(&err)); terom@109: terom@109: return 0; terom@109: } terom@109: terom@203: static struct lua_func lua_nexus_sleep_func = LUA_FUNC(&lua_nexus_type, "sleep", terom@203: "Schedules itself to resume after the given delay (in seconds) and yields", terom@203: terom@203: LUA_FUNC_ARG_INT("tv_sec", LUA_ARG_REQUIRED) terom@203: ); terom@203: terom@203: static void lua_nexus_sleep_wakeup (evutil_socket_t fd, short what, void *arg) terom@203: { terom@203: lua_State *L = arg; terom@203: terom@203: (void) fd; terom@203: (void) what; terom@203: terom@203: // resume the thread that called lua_nexus_sleep terom@203: lua_thread_resume_state(L); terom@203: } terom@203: terom@203: static int lua_nexus_sleep (lua_State *L) terom@203: { terom@203: struct lua_nexus *lua_nexus; terom@203: long tv_sec; terom@203: terom@203: // parse args terom@203: lua_args_parse(L, &lua_nexus_sleep_func, (void *) &lua_nexus, &tv_sec); terom@203: terom@203: // build tv terom@203: struct timeval tv = { tv_sec, 0 }; terom@203: terom@203: // schedule wakeup terom@203: // use a pure-timeout event terom@207: if (event_base_once(lua_nexus->nexus->ev_base, -1, EV_TIMEOUT, lua_nexus_sleep_wakeup, L, &tv)) terom@203: return luaL_error(L, "event_base_once"); terom@203: terom@203: // yield terom@203: return lua_yield(L, 0); terom@203: } terom@145: terom@145: static struct lua_method lua_nexus_methods[] = LUA_METHODS( terom@203: LUA_METHOD("shutdown", lua_nexus_shutdown, NULL ), terom@203: LUA_METHOD("load_config", lua_nexus_load_config, NULL ), terom@203: LUA_METHOD("sleep", lua_nexus_sleep, &lua_nexus_sleep_func ) terom@145: ); terom@103: terom@103: /** terom@103: * Initialize the spbot.nexus type for lua_nexus, and registers an instance bound to the given nexus list at terom@103: * 'nexus'. terom@103: */ terom@103: static void lua_nexus_init (lua_State *L, struct nexus *nexus) terom@103: { terom@103: // allocate the global "nexus" object terom@145: struct lua_nexus *lua_nexus = lua_type_register_global(L, &lua_nexus_type, lua_nexus_methods, "nexus", sizeof(*lua_nexus)); terom@103: terom@103: // initialize it terom@103: lua_nexus->nexus = nexus; terom@93: } terom@93: terom@145: terom@98: /** terom@104: * Global functions terom@104: */ terom@104: static int lua_log_level (lua_State *L) terom@104: { terom@104: // log level as a string terom@104: enum log_level new_level = luaL_checkoption(L, 1, NULL, log_level_names); terom@104: terom@104: // set it terom@104: set_log_level(new_level); terom@104: terom@104: // ok terom@104: return 0; terom@104: } terom@104: terom@104: static int lua_log (lua_State *L) terom@104: { terom@104: // log level as a string terom@104: enum log_level level = luaL_checkoption(L, 1, NULL, log_level_names); terom@104: terom@104: // log message terom@104: const char *msg = luaL_checkstring(L, 2); terom@104: terom@104: // log it terom@195: _log_msg(level, "lua", "%s", msg); terom@104: terom@104: // ok terom@104: return 0; terom@104: } terom@104: terom@104: static const struct luaL_Reg lua_global_functions[] = { terom@203: { "log_level", lua_log_level }, terom@203: { "log", lua_log }, terom@104: { NULL, NULL } terom@104: }; terom@104: terom@104: static void lua_global_init (lua_State *L) terom@104: { terom@104: const struct luaL_Reg *reg; terom@104: terom@104: for (reg = lua_global_functions; reg->name && reg->func; reg++) { terom@104: // put the function on the stack terom@104: lua_pushcfunction(L, reg->func); terom@104: terom@104: // set the global terom@104: lua_setglobal(L, reg->name); terom@104: } terom@104: } terom@104: terom@116: void lua_objs_init (struct nexus_lua *lua) terom@93: { terom@145: // register types terom@145: lua_type_register(lua->st, &lua_module_type, lua_module_methods); terom@145: terom@145: // globals terom@116: lua_nexus_init(lua->st, lua->nexus); terom@116: lua_modules_init(lua->st, lua->nexus->modules); terom@145: terom@145: // global functions terom@145: lua_global_init(lua->st); terom@93: } terom@98: terom@145: