From a7be2bf160a7bd76915617b89662d240b70ad1d4 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch 
Date: Tue, 5 Jan 2016 23:05:06 +0100
Subject: degesch: refactor Lua
And fix handling of nil returns from filter callbacks.
---
 degesch.c | 155 +++++++++++++++++++++++++-------------------------------------
 1 file changed, 62 insertions(+), 93 deletions(-)
diff --git a/degesch.c b/degesch.c
index c8aa67f..d88b3bd 100644
--- a/degesch.c
+++ b/degesch.c
@@ -7601,7 +7601,7 @@ static luaL_Reg lua_hook_table[] =
 
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
-// Append a traceback to all errors so that we can later extract it
+/// Append a traceback to all errors so that we can later extract it
 static int
 lua_plugin_error_handler (lua_State *L)
 {
@@ -7632,16 +7632,33 @@ lua_plugin_process_error (struct lua_plugin *self, const char *message,
 	return false;
 }
 
-// Convenience function; replaces the "original" string or produces an error
+/// Call a Lua function and process errors using our special error handler
+static bool
+lua_plugin_call (struct lua_plugin *self,
+	int n_params, int n_results, struct error **e)
+{
+	lua_State *L = self->L;
+	lua_pushcfunction (L, lua_plugin_error_handler);
+
+	int error_handler_idx = -n_params - 2;
+	lua_insert (L, error_handler_idx);
+
+	if (!lua_pcall (L, n_params, n_results, error_handler_idx))
+		return true;
+
+	(void) lua_plugin_process_error (self, lua_tostring (L, -1), e);
+	lua_pop (L, 1);
+	return false;
+}
+
+/// Convenience function; replaces the "original" string or produces an error
 static bool
 lua_plugin_handle_string_filter_result (struct lua_plugin *self,
-	int result, char **original, bool utf8, struct error **e)
+	char **original, bool utf8, struct error **e)
 {
 	lua_State *L = self->L;
-	if (result)
-		return lua_plugin_process_error (self, lua_tostring (L, -1), e);
 	if (lua_isnil (L, -1))
-		return NULL;
+		return true;
 	if (!lua_isstring (L, -1))
 		FAIL ("must return either a string or nil");
 
@@ -7659,6 +7676,15 @@ lua_plugin_handle_string_filter_result (struct lua_plugin *self,
 	return true;
 }
 
+static void
+lua_plugin_log_error
+	(struct lua_plugin *self, const char *where, struct error *error)
+{
+	log_global_error (self->ctx, "Lua: plugin \"#s\": #s: #s",
+		self->super.name, where, error->message);
+	error_free (error);
+}
+
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
 static char *
@@ -7670,24 +7696,19 @@ lua_input_hook_filter (struct input_hook *self, struct buffer *buffer,
 	struct lua_plugin *plugin = hook->plugin;
 	lua_State *L = plugin->L;
 
-	lua_pushcfunction (L, lua_plugin_error_handler);
-
 	lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
 	lua_rawgetp (L, LUA_REGISTRYINDEX, hook);  // 1: hook
 	lua_plugin_push_buffer (plugin, buffer);   // 2: buffer
 	lua_pushstring (L, input);                 // 3: input
 
 	struct error *e = NULL;
-	bool failed = !lua_plugin_handle_string_filter_result
-		(plugin, lua_pcall (L, 3, 1, -5), &input, true, &e);
-	lua_pop (L, 1);
-
-	if (failed)
+	if (lua_plugin_call (plugin, 3, 1, &e))
 	{
-		log_global_error (plugin->ctx, "Lua: plugin \"#s\": #s: #s",
-			plugin->super.name, "input hook", e->message);
-		error_free (e);
+		lua_plugin_handle_string_filter_result (plugin, &input, true, &e);
+		lua_pop (L, 1);
 	}
+	if (e)
+		lua_plugin_log_error (plugin, "input hook", e);
 	return input;
 }
 
@@ -7706,24 +7727,19 @@ lua_irc_hook_filter (struct irc_hook *self, struct server *s, char *message)
 	struct lua_plugin *plugin = hook->plugin;
 	lua_State *L = plugin->L;
 
-	lua_pushcfunction (L, lua_plugin_error_handler);
-
 	lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
 	lua_rawgetp (L, LUA_REGISTRYINDEX, hook);  // 1: hook
 	lua_plugin_push_server (plugin, s);        // 2: server
 	lua_pushstring (L, message);               // 3: message
 
 	struct error *e = NULL;
-	bool failed = !lua_plugin_handle_string_filter_result
-		(plugin, lua_pcall (L, 3, 1, -5), &message, false, &e);
-	lua_pop (L, 1);
-
-	if (failed)
+	if (lua_plugin_call (plugin, 3, 1, &e))
 	{
-		log_global_error (plugin->ctx, "Lua: plugin \"#s\": #s: #s",
-			plugin->super.name, "IRC hook", e->message);
-		error_free (e);
+		lua_plugin_handle_string_filter_result (plugin, &message, false, &e);
+		lua_pop (L, 1);
 	}
+	if (e)
+		lua_plugin_log_error (plugin, "IRC hook", e);
 	return message;
 }
 
@@ -7741,21 +7757,12 @@ lua_timer_hook_dispatch (void *user_data)
 	struct lua_plugin *plugin = hook->plugin;
 	lua_State *L = plugin->L;
 
-	lua_pushcfunction (L, lua_plugin_error_handler);
-
 	lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
 	lua_rawgetp (L, LUA_REGISTRYINDEX, hook);  // 1: hook
 
-	if (lua_pcall (L, 1, 0, -3))
-	{
-		struct error *e = NULL;
-		(void) lua_plugin_process_error (plugin, lua_tostring (L, -1), &e);
-		lua_pop (L, 1);
-
-		log_global_error (plugin->ctx, "Lua: plugin \"#s\": #s: #s",
-			plugin->super.name, "timer hook", e->message);
-		error_free (e);
-	}
+	struct error *e = NULL;
+	if (!lua_plugin_call (plugin, 1, 0, &e))
+		lua_plugin_log_error (plugin, "timer hook", e);
 
 	// There's no need to keep the hook around once the timer is dispatched
 	lua_cache_invalidate (L, hook);
@@ -7929,21 +7936,12 @@ lua_schema_item_validate (const struct config_item *item, struct error **e)
 	if (self->ref_validate == LUA_REFNIL)
 		return true;
 
-	struct lua_plugin *plugin = self->plugin;
-	lua_State *L = plugin->L;
-
-	lua_pushcfunction (L, lua_plugin_error_handler);
+	lua_State *L = self->plugin->L;
 	lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_validate);
 	lua_plugin_push_config_item (L, item);
 
 	// The callback can make use of error("...", 0) to produce nice messages
-	if (lua_pcall (L, 1, 0, -3))
-	{
-		(void) lua_plugin_process_error (plugin, lua_tostring (L, -1), e);
-		lua_pop (L, 1);
-		return false;
-	}
-	return true;
+	return lua_plugin_call (self->plugin, 1, 0, e);
 }
 
 static void
@@ -7953,23 +7951,13 @@ lua_schema_item_on_change (struct config_item *item)
 	if (self->ref_on_change == LUA_REFNIL)
 		return;
 
-	struct lua_plugin *plugin = self->plugin;
-	lua_State *L = plugin->L;
-
-	lua_pushcfunction (L, lua_plugin_error_handler);
+	lua_State *L = self->plugin->L;
 	lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_on_change);
 	lua_plugin_push_config_item (L, item);
 
-	if (lua_pcall (L, 1, 0, -3))
-	{
-		struct error *e = NULL;
-		(void) lua_plugin_process_error (plugin, lua_tostring (L, -1), &e);
-		lua_pop (L, 1);
-
-		log_global_error (plugin->ctx, "Lua: plugin \"#s\": #s: #s",
-			plugin->super.name, "schema on_change", e->message);
-		error_free (e);
-	}
+	struct error *e = NULL;
+	if (!lua_plugin_call (self->plugin, 1, 0, &e))
+		lua_plugin_log_error (self->plugin, "schema on_change", e);
 }
 
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -8244,30 +8232,21 @@ static void
 lua_connector_on_connected (void *user_data, int socket, const char *hostname)
 {
 	struct lua_connector *self = user_data;
-	struct lua_plugin *plugin = self->plugin;
-	lua_State *L = plugin->L;
 
 	// TODO: use this for SNI once TLS is implemented
 	(void) hostname;
 
 	if (self->ref_on_success != LUA_REFNIL)
 	{
-		lua_pushcfunction (L, lua_plugin_error_handler);
-
+		lua_State *L = self->plugin->L;
 		lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_on_success);
-		lua_plugin_push_connection (plugin, socket);  // 1: connection
+		lua_plugin_push_connection (self->plugin, socket);  // 1: connection
 
-		if (lua_pcall (L, 1, 0, -3))
-		{
-			struct error *e = NULL;
-			(void) lua_plugin_process_error (plugin, lua_tostring (L, -1), &e);
-			lua_pop (L, 1);
-
-			log_global_error (plugin->ctx, "Lua: plugin \"#s\": #s: #s",
-				plugin->super.name, "connector on_success", e->message);
-			error_free (e);
-		}
+		struct error *e = NULL;
+		if (!lua_plugin_call (self->plugin, 1, 0, &e))
+			lua_plugin_log_error (self->plugin, "connector on_success", e);
 	}
+
 	lua_connector_discard (self);
 }
 
@@ -8275,27 +8254,17 @@ static void
 lua_connector_on_failure (void *user_data)
 {
 	struct lua_connector *self = user_data;
-	struct lua_plugin *plugin = self->plugin;
-	lua_State *L = plugin->L;
-
 	if (self->ref_on_error != LUA_REFNIL)
 	{
-		lua_pushcfunction (L, lua_plugin_error_handler);
-
+		lua_State *L = self->plugin->L;
 		lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_on_error);
 		lua_pushstring (L, self->last_error);  // 1: error string
 
-		if (lua_pcall (L, 1, 0, -3))
-		{
-			struct error *e = NULL;
-			(void) lua_plugin_process_error (plugin, lua_tostring (L, -1), &e);
-			lua_pop (L, 1);
-
-			log_global_error (plugin->ctx, "Lua: plugin \"#s\": #s: #s",
-				plugin->super.name, "connector on_error", e->message);
-			error_free (e);
-		}
+		struct error *e = NULL;
+		if (!lua_plugin_call (self->plugin, 1, 0, &e))
+			lua_plugin_log_error (self->plugin, "connector on_error", e);
 	}
+
 	lua_connector_discard (self);
 }
 
-- 
cgit v1.2.3-70-g09d2