Add guards
authorMyhailo Danylenko <isbear@ukrpost.net>
Sun, 20 May 2012 06:24:50 +0300
changeset 120 1be9411caf31
parent 119 2e5d5571a4ba
child 121 75a7d595817c
Add guards
lua.c
--- a/lua.c	Sat May 19 23:44:25 2012 +0300
+++ b/lua.c	Sun May 20 06:24:50 2012 +0300
@@ -1499,18 +1499,9 @@
 	lua_pop (L, 1);
 }
 
-#if 0
 // OPTION GUARDS
 
-GSList *lua_installed_guards = NULL;
-
-typedef struct {
-	lua_State *L;       // lua environment for handler use
-	int        nameref; // reference to key name string
-	int        cbref;   // reference to guard function
-//	int        objref;  // self_reference to object
-	guint      hid;     // hook id for object destruction
-} lua_guard_t;
+#define MLUA_GUARD_REGISTRY "mcabber_guards"
 
 /// guard function
 /// Function to be called, when option changes it's value.
@@ -1519,115 +1510,92 @@
 /// R: string (value to save in hash table)
 static gchar *lua_guard_cb (const gchar *key, const gchar *value)
 {
-	lua_guard_t *cb = ;// FIXME
-	lua_State   *L  = cb -> L;
+	lua_State *L = lua; // FIXME
 
-	if (cb -> cbref == LUA_NOREF)
-		return g_strdup (value);
-
-	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> cbref);
-	if (!lua_isfunction (L, -1)) {
-		lua_pop (L, 1);
-		return g_strdup (value);
+	lua_getfield ( L, LUA_REGISTRYINDEX, MLUA_GUARD_REGISTRY ); // +1
+	lua_getfield ( L, -1, key );                                // +2
+	if ( ! lua_isfunction ( L, -1 ) ) {
+		lua_pop ( L, 2 );
+		return g_strdup ( value );
 	}
 
-	lua_pushstring (L, key);
-	lua_psuhstring (L, value);
+	lua_pushstring ( L, key );                                  // +3
+	lua_pushstring ( L, value );                                // +4
 
-	if (lua_pcall (L, 2, 1, 0)) {
-		scr_log_print (LPRINT_NORMAL, "lua: Error in hook handler: %s", lua_tostring (L, -1));
-		lua_pop (L, 1);
-		return g_strdup (value);
+	if ( lua_pcall ( L, 2, 1, 0 ) ) {                           // +2
+		scr_log_print ( LPRINT_NORMAL, "lua: Error in hook handler: %s", lua_tostring ( L, -1 ) );
+		lua_pop ( L, 2 );
+		return g_strdup ( value );
+	} else {
+		gchar *result = g_strdup ( lua_tostring ( L, -1 ) );
+		lua_pop ( L, 2 );
+		return result;
 	}
-
-	return g_strdup (lua_tostring (L, -1));
 }
 
-/// main.guard
-/// Installs option guard for given option. Returns guard object, that
-/// should be kept around as long, as guard is needed.
-/// A: string (option name), guard function
-/// R: userdata (guard object)
-static int lua_main_guard (lua_State *L)
+/// main.add_guard
+/// Installs option guard for given option.
+/// A: string ( option name ), guard function
+/// R: boolean ( success )
+static int lua_main_add_guard ( lua_State *L )
 {
-	const char   *name      = luaL_checkstring (L, 1);
-	int           priority  = G_PRIORITY_DEFAULT;
-	lua_guard_t   *cb;
+	const char *name = luaL_checkstring ( L, 1 );
+	luaL_argcheck ( L, lua_isfunction (L, 2), 2, "function expected" );
+	lua_settop ( L, 2 );
 
-	luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected");
-
-	cb = lua_newuserdata (L, sizeof (lua_guard_t));
-	luaL_getmetatable (L, "mcabber.guard");
-	lua_setmetatable (L, -2);
-
-	lua_pushvalue (L, 1);
-	cb -> nameref = luaL_ref (L, LUA_REGISTRYINDEX);
-	lua_pushvalue (L, 2);
-	cb -> cbref   = luaL_ref (L, LUA_REGISTRYINDEX);
-	cb -> L       = L;
-
-	settings_set_guard (name, lua_guard_cb)
+	if ( settings_set_guard ( name, lua_guard_cb ) ) {
+		lua_getfield ( L, LUA_REGISTRYINDEX, MLUA_GUARD_REGISTRY );
+		lua_pushvalue ( L, 2 );
+		lua_setfield ( L, 3, name );
+		lua_pushboolean ( L, 1 );
+	} else
+		lua_pushboolean ( L, 0 );
 
 	return 1;
 }
 
-static void lua_mcabber_unregister_guard (lua_State *L, lua_guard_t *cb)
-{
-	const char *name;
-
-	if (cb -> nameref == LUA_NOREF)
-		return;
-
-	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> nameref);
-	name = lua_tostring (L, -1);
-	if (name) {
-		settings_del_guard (name);
-		luaL_unref (L, LUA_REGISTRYINDEX, cb -> nameref);
-		cb -> nameref = LUA_NOREF;
-	}
-
-	lua_pop (L, 1);
-}
-
-/// guard:del
-/// Unregisters given option guard from mcabber. Object will be destroyed later.
-static int lua_mcabber_guard_del (lua_State *L)
+/// main.del_guard
+/// Removes option guard from given option.
+/// By default, lua will refuse to remove guards, not installed
+/// by lua. Still, you can force guard removal.
+/// A: string ( option name ), boolean ( force removal )
+/// R: boolean ( success )
+static int lua_main_del_guard ( lua_State *L )
 {
-	lua_guard_t *cb = luaL_checkudata (L, 1, "mcabber.guard");
-	luaL_argcheck (L, cb != NULL, 1, "mcabber guard object expected");
-	lua_mcabber_unregister_guard (L, cb);
-	return 0;
-}
+	const char *name = luaL_checkstring ( L, 1 );
+	lua_settop ( L, 2 );
+
+	lua_getfield ( L, LUA_REGISTRYINDEX, MLUA_GUARD_REGISTRY );
+	lua_getfield ( L, 3, name );
 
-static int lua_mcabber_guard_gc (lua_State *L)
-{
-	lua_hook_t *cb = luaL_checkudata (L, 1, "mcabber.guard");
-	luaL_argcheck (L, cb != NULL, 1, "mcabber guard object expected");
-	lua_mcabber_unregister_guard (L, cb);
-	if (cb -> cbref != LUA_NOREF)
-		luaL_unref (L, LUA_REGISTRYINDEX, cb -> cbref);
-	return 0;
+	if ( ! lua_isnil ( L, 4 ) || lua_toboolean ( L, 2 ) ) {
+		settings_del_guard ( name );
+		lua_pushnil ( L );
+		lua_setfield ( L, 3, name );
+		lua_pushboolean ( L, 1 );
+	} else
+		lua_pushboolean ( L, 0 );
+
+	return 1;
 }
 
-static const luaL_Reg lua_mcabber_hook_reg_m[] = {
-	{ "del",  lua_mcabber_guard_del },
-	{ "__gc", lua_mcabber_guard_gc  },
-	{ NULL,   NULL                 },
-};
-
 static void lua_guard_init (lua_State *L)
 {
-	luaL_newmetatable (L, "mcabber.guard");
-	lua_pushvalue (L, -1);
-	lua_setfield (L, -2, "__index");
-	luaL_register (L, NULL, lua_mcabber_guard_reg_m);
-	lua_pop (L, 1);
+	lua_createtable ( L, 0, 0 );
+	lua_setfield ( L, LUA_REGISTRYINDEX, MLUA_GUARD_REGISTRY );
 }
 
 static void lua_guard_uninit (lua_State *L)
 {
+	lua_getfield ( L, LUA_REGISTRYINDEX, MLUA_GUARD_REGISTRY );
+	lua_pushnil ( L );
+	while ( lua_next ( L, -2 ) ) {
+		const char *key = lua_tostring ( L, -2 );
+		settings_del_guard ( key );
+		lua_pop ( L, 1 );
+	}
+	lua_pop ( L, 1 );
 }
-#endif
 
 // MAIN INITIALIZATION CODE
 
@@ -1719,6 +1687,8 @@
 	reg ( timer          ) 
 	reg ( bgread         ) 
 	reg ( hook           )
+	reg ( add_guard      )
+	reg ( del_guard      )
 	{ NULL, NULL },
 };
 #undef reg
@@ -1776,6 +1746,7 @@
 
 	lua_hook_init    (lua);
 	lua_command_init (lua);
+	lua_guard_init   (lua);
 
 	{
 		char *initfile = expand_filename (settings_opt_get ("lua_init_filename"));
@@ -1803,7 +1774,7 @@
 	}
 }
 
-static void lua_events_cancel (gpointer data, gpointer ignore)
+static void lua_events_destroy ( gpointer data )
 {
 	lua_event_callback_t *cb = data;
 	const char *evid;
@@ -1812,38 +1783,29 @@
 	lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->evid);
 	evid = lua_tostring (cb ->L, -1);
 	evs_callback (evid, EVS_CONTEXT_CANCEL, "Module unloading");
+	evs_del (evid); // XXX before these were two different runs. is there some reason for that?
 }
 
-static void lua_events_destroy (gpointer data, gpointer ignore)
+static void lua_bgreads_destroy ( gpointer data )
 {
-	lua_event_callback_t *cb = data;
-	const char *evid;
-	if (cb->evid == LUA_NOREF)
-		return;
-	lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->evid);
-	evid = lua_tostring (cb ->L, -1);
-	evs_del (evid);
+	g_source_remove ( ( gulong ) data );
 }
 
-static void lua_bgreads_destroy (guint source, gpointer ignore)
+static void lua_timers_destroy ( gpointer data )
 {
-	g_source_remove (source);
+	g_source_remove ( ( gulong ) data );
 }
 
-static void lua_timers_destroy (guint source, gpointer ignore)
+static void lua_features_destroy ( gpointer data )
 {
-	g_source_remove (source);
-}
-
-static void lua_features_destroy (char *xmlns, gpointer ignore)
-{
+	gchar *xmlns = data;
 	xmpp_del_feature (xmlns);
 	g_free (xmlns);
 }
 
-static void lua_categories_destroy (guint id, gpointer ignore)
+static void lua_categories_destroy ( gpointer data )
 {
-	compl_del_category (id);
+	compl_del_category ( ( gulong ) data );
 }
 
 void mlua_uninit (void)
@@ -1856,23 +1818,17 @@
 
 		// hook handlers and commands will be unregistered upon objects destruction
 
-		g_slist_foreach (lua_bgreads, (GFunc) lua_bgreads_destroy, NULL);
-		g_slist_free (lua_bgreads);
+		lua_guard_uninit ( lua );
+
+		g_slist_free_full ( lua_bgreads, lua_bgreads_destroy );
 		lua_bgreads = NULL;
 
-		g_slist_foreach (lua_timers, (GFunc) lua_timers_destroy, NULL);
-		g_slist_free (lua_timers);
+		g_slist_free_full ( lua_timers, lua_timers_destroy );
 		lua_timers = NULL;
 
-		g_slist_foreach (lua_events, (GFunc) lua_events_cancel, NULL);
-		g_slist_foreach (lua_events, (GFunc) lua_events_destroy, NULL);
-		g_slist_free (lua_events);
+		g_slist_free_full ( lua_events, lua_events_destroy );
 		lua_events = NULL;
 
-		g_slist_foreach (lua_added_features, (GFunc) lua_features_destroy, NULL);
-		g_slist_free (lua_added_features);
-		lua_added_features = NULL;
-
 #ifdef MCABBER_API_HAVE_CMD_ID
 		cmd_del (lua_cmdid);
 		lua_cmdid = NULL;
@@ -1883,8 +1839,10 @@
 		lua_close (lua);
 		lua = NULL;
 
-		g_slist_foreach (lua_added_categories, (GFunc) lua_categories_destroy, NULL);
-		g_slist_free (lua_added_categories);
+		g_slist_free_full ( lua_added_features, lua_features_destroy );
+		lua_added_features = NULL;
+
+		g_slist_free_full ( lua_added_categories, lua_categories_destroy );
 		lua_added_categories = NULL;
 
 #ifdef LLM_LOG_HANDLER