diff --git a/degesch.c b/degesch.c index 6bd0449..3a80c3f 100644 --- a/degesch.c +++ b/degesch.c @@ -1390,12 +1390,45 @@ plugin_destroy (struct plugin *self) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// This is a bit ugly since insertion is O(n) and the need to get rid of the +// specific type because of list macros, however I don't currently posses any +// strictly better, ordered data structure + +struct hook +{ + LIST_HEADER (struct hook) + int priority; ///< The lesser the sooner +}; + +static struct hook * +hook_insert (struct hook *list, struct hook *item) +{ + // Corner cases: list is empty or we precede everything + if (!list || item->priority < list->priority) + { + LIST_PREPEND (list, item); + return list; + } + + // Otherwise fast-forward to the last entry that precedes us + struct hook *before = list; + while (before->next && before->next->priority < item->next->priority) + before = before->next; + + // And link ourselves in between it and its successor + if ((item->next = before->next)) + item->next->prev = item; + before->next = item; + item->prev = before; + return list; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + struct input_hook { - LIST_HEADER (struct input_hook) - + struct hook super; ///< Common hook fields struct input_hook_vtable *vtable; ///< Methods - int priority; ///< The lesser the sooner }; struct input_hook_vtable @@ -1410,10 +1443,8 @@ struct input_hook_vtable struct irc_hook { - LIST_HEADER (struct irc_hook) - + struct hook super; ///< Common hook fields struct irc_hook_vtable *vtable; ///< Methods - int priority; ///< The lesser the sooner }; struct irc_hook_vtable @@ -1487,8 +1518,8 @@ struct app_context int terminal_suspended; ///< Terminal suspension level struct plugin *plugins; ///< Loaded plugins - struct input_hook *input_hooks; ///< Input hooks - struct irc_hook *irc_hooks; ///< IRC hooks + struct hook *input_hooks; ///< Input hooks + struct hook *irc_hooks; ///< IRC hooks } *g_ctx; @@ -4116,8 +4147,9 @@ static char * irc_process_hooks (struct server *s, char *input) { log_server_debug (s, "#a>> \"#S\"#r", ATTR_JOIN, input); - LIST_FOR_EACH (struct irc_hook, hook, s->ctx->irc_hooks) + LIST_FOR_EACH (struct hook, iter, s->ctx->irc_hooks) { + struct irc_hook *hook = (struct irc_hook *) iter; char *processed = hook->vtable->filter (hook, s, input); if (input == processed) continue; @@ -7219,73 +7251,6 @@ server_rename (struct app_context *ctx, struct server *s, const char *new_name) } } -// --- Ordered linked lists ---------------------------------------------------- - -// This is a bit ugly since there's no way to force a guarantee that the list -// members are going to be the first ones in the structure, plus insertion is -// O(n), however I don't currently posses any better ordered data structure - -struct list_header -{ - LIST_HEADER (struct list_header) -}; - -static struct list_header * -list_insert_ordered (struct list_header *list, struct list_header *item, - bool (*less) (const void *, const void *)) -{ - // Corner cases: list is empty or we precede everything - if (!list || less (item, list)) - { - LIST_PREPEND (list, item); - return list; - } - - // Otherwise fast-worward to the last entry that precedes us - struct list_header *before = list; - while (before->next && less (before->next, item)) - before = before->next; - - // And link ourselves in between it and its successor - if ((item->next = before->next)) - item->next->prev = item; - before->next = item; - item->prev = before; - return list; -} - -// --- Hooks ------------------------------------------------------------------- - -static bool -input_hook_less (const void *a, const void *b) -{ - return ((const struct input_hook *) a)->priority - < ((const struct input_hook *) b)->priority; -} - -static void -input_hook_insert (struct app_context *ctx, struct input_hook *hook) -{ - ctx->input_hooks = (struct input_hook *) list_insert_ordered ( - (struct list_header *) ctx->input_hooks, - (struct list_header *) hook, input_hook_less); -} - -static bool -irc_hook_less (const void *a, const void *b) -{ - return ((const struct irc_hook *) a)->priority - < ((const struct irc_hook *) b)->priority; -} - -static void -irc_hook_insert (struct app_context *ctx, struct irc_hook *hook) -{ - ctx->irc_hooks = (struct irc_hook *) list_insert_ordered ( - (struct list_header *) ctx->irc_hooks, - (struct list_header *) hook, irc_hook_less); -} - // --- Lua --------------------------------------------------------------------- // Each plugin has its own Lua state object, so that a/ they don't disturb each @@ -7501,6 +7466,7 @@ struct lua_hook enum lua_hook_type type; ///< Type of the hook union { + struct hook hook; ///< Base structure struct input_hook input_hook; ///< Input hook struct irc_hook irc_hook; ///< IRC hook } @@ -7514,10 +7480,10 @@ lua_hook_unhook (lua_State *L) switch (hook->type) { case XLUA_HOOK_INPUT: - LIST_UNLINK (hook->plugin->ctx->input_hooks, &hook->data.input_hook); + LIST_UNLINK (hook->plugin->ctx->input_hooks, &hook->data.hook); break; case XLUA_HOOK_IRC: - LIST_UNLINK (hook->plugin->ctx->irc_hooks, &hook->data.irc_hook); + LIST_UNLINK (hook->plugin->ctx->irc_hooks, &hook->data.hook); break; default: hard_assert (!"invalid hook type"); @@ -7679,13 +7645,16 @@ struct irc_hook_vtable lua_irc_hook_vtable = // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static struct lua_hook * -lua_plugin_push_hook - (struct lua_plugin *plugin, int callback_index, enum lua_hook_type type) +lua_plugin_push_hook (struct lua_plugin *plugin, int callback_index, + enum lua_hook_type type, int priority) { lua_State *L = plugin->L; + luaL_checktype (L, callback_index, LUA_TFUNCTION); + struct lua_hook *hook = lua_newuserdata (L, sizeof *hook); luaL_setmetatable (L, XLUA_HOOK_METATABLE); memset (hook, 0, sizeof *hook); + hook->data.hook.priority = priority; hook->type = type; hook->plugin = plugin; @@ -7702,13 +7671,11 @@ static int lua_plugin_hook_input (lua_State *L) { struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1)); - luaL_checktype (L, 1, LUA_TFUNCTION); - lua_Integer priority = luaL_optinteger (L, 2, 0); - - struct lua_hook *hook = lua_plugin_push_hook (plugin, 1, XLUA_HOOK_INPUT); + struct lua_hook *hook = lua_plugin_push_hook + (plugin, 1, XLUA_HOOK_INPUT, luaL_optinteger (L, 2, 0)); hook->data.input_hook.vtable = &lua_input_hook_vtable; - hook->data.input_hook.priority = priority; - input_hook_insert (plugin->ctx, &hook->data.input_hook); + plugin->ctx->input_hooks = + hook_insert (plugin->ctx->input_hooks, &hook->data.hook); return 1; } @@ -7716,13 +7683,11 @@ static int lua_plugin_hook_irc (lua_State *L) { struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1)); - luaL_checktype (L, 1, LUA_TFUNCTION); - lua_Integer priority = luaL_optinteger (L, 2, 0); - - struct lua_hook *hook = lua_plugin_push_hook (plugin, 1, XLUA_HOOK_IRC); + struct lua_hook *hook = lua_plugin_push_hook + (plugin, 1, XLUA_HOOK_IRC, luaL_optinteger (L, 2, 0)); hook->data.irc_hook.vtable = &lua_irc_hook_vtable; - hook->data.irc_hook.priority = priority; - irc_hook_insert (plugin->ctx, &hook->data.irc_hook); + plugin->ctx->irc_hooks = + hook_insert (plugin->ctx->irc_hooks, &hook->data.hook); return 1; } @@ -9520,8 +9485,9 @@ static char * process_input_hooks (struct app_context *ctx, struct buffer *buffer, char *input) { - LIST_FOR_EACH (struct input_hook, hook, ctx->input_hooks) + LIST_FOR_EACH (struct hook, iter, ctx->input_hooks) { + struct input_hook *hook = (struct input_hook *) iter; char *processed = hook->vtable->filter (hook, buffer, input); if (input == processed) continue;