From 21999ae2058e7b9e24c45ab34d6a37c7f207f4c3 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Sun, 2 Jul 2000 22:04:00 +0000 Subject: [PATCH] Implemented runtime loadable modules. /LOAD loads a module, /UNLOAD unloads it. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@420 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- src/core/modules.c | 137 ++++++++++++++++++++++++++++ src/core/modules.h | 18 ++++ src/fe-common/core/Makefile.am | 1 + src/fe-common/core/fe-common-core.c | 6 ++ src/fe-common/core/module-formats.c | 21 +++-- src/fe-common/core/module-formats.h | 9 ++ 6 files changed, 186 insertions(+), 6 deletions(-) diff --git a/src/core/modules.c b/src/core/modules.c index d850f60d..45b1f406 100644 --- a/src/core/modules.c +++ b/src/core/modules.c @@ -20,6 +20,11 @@ #include "module.h" #include "modules.h" +#include "signals.h" + +#define PLUGINSDIR "/usr/local/lib/irssi/plugins" /*FIXME: configurable*/ + +GSList *modules; static GHashTable *uniqids, *uniqstrids; static GHashTable *idlookup, *stridlookup; @@ -163,8 +168,140 @@ void module_uniq_destroy(const char *module) } } +MODULE_REC *module_find(const char *name) +{ + GSList *tmp; + + for (tmp = modules; tmp != NULL; tmp = tmp->next) { + MODULE_REC *rec = tmp->data; + + if (g_strcasecmp(rec->name, name) == 0) + return rec; + } + + return NULL; +} + +char *module_get_name(const char *path) +{ + const char *name; + char *module_name, *ptr; + + name = NULL; + if (g_path_is_absolute(path)) { + name = strrchr(path, G_DIR_SEPARATOR); + if (name != NULL) name++; + } + + if (name == NULL) + name = path; + + if (strncmp(name, "lib", 3) == 0) + name += 3; + + module_name = g_strdup(name); + ptr = strstr(module_name, ".so"); + if (ptr != NULL) *ptr = '\0'; + + return module_name; +} + +GModule *module_open(const char *name) +{ + GModule *module; + char *path, *str; + + if (g_path_is_absolute(name)) + path = g_strdup(name); + else { + path = g_module_build_path(PLUGINSDIR, name); + module = g_module_open(path, 0); + g_free(path); + if (module != NULL) return module; + + /* Plugin not found from global plugin dir, check from home dir */ + str = g_strdup_printf("%s/.irssi/plugins", g_get_home_dir()); + path = g_module_build_path(str, name); + g_free(str); + } + + module = g_module_open(path, 0); + g_free(path); + return module; +} + +int module_load(const char *path) +{ + void (*module_init) (void); + GModule *gmodule; + MODULE_REC *rec; + char *name, *initfunc; + + g_return_val_if_fail(path != NULL, FALSE); + + if (!g_module_supported()) + return FALSE; + + name = module_get_name(path); + if (module_find(name)) { + signal_emit("module error", 2, GINT_TO_POINTER(MODULE_ERROR_ALREADY_LOADED), name); + g_free(name); + return FALSE; + } + + gmodule = module_open(path); + if (gmodule == NULL) { + signal_emit("module error", 3, GINT_TO_POINTER(MODULE_ERROR_LOAD), name, g_module_error()); + g_free(name); + return FALSE; + } + + initfunc = g_strconcat(name, "_init", NULL); + if (!g_module_symbol(gmodule, initfunc, (gpointer *) &module_init)) { + signal_emit("module error", 2, GINT_TO_POINTER(MODULE_ERROR_INVALID), name); + g_module_close(gmodule); + g_free(initfunc); + g_free(name); + return FALSE; + } + g_free(initfunc); + + rec = g_new0(MODULE_REC, 1); + rec->name = name; + rec->gmodule = gmodule; + modules = g_slist_append(modules, rec); + + module_init(); + + signal_emit("module loaded", 1, rec); + return TRUE; +} + +void module_unload(MODULE_REC *module) +{ + void (*module_deinit) (void); + char *deinitfunc; + + g_return_if_fail(module != NULL); + + modules = g_slist_remove(modules, module); + + signal_emit("module unloaded", 1, module); + + deinitfunc = g_strconcat(module->name, "_deinit", NULL); + if (g_module_symbol(module->gmodule, deinitfunc, (gpointer *) &module_deinit)) + module_deinit(); + g_free(deinitfunc); + + g_module_close(module->gmodule); + g_free(module->name); + g_free(module); +} + void modules_init(void) { + modules = NULL; + idlookup = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal); uniqids = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal); diff --git a/src/core/modules.h b/src/core/modules.h index f175957b..6ced5387 100644 --- a/src/core/modules.h +++ b/src/core/modules.h @@ -1,6 +1,24 @@ #ifndef __MODULES_H #define __MODULES_H +enum { + MODULE_ERROR_ALREADY_LOADED, + MODULE_ERROR_LOAD, + MODULE_ERROR_INVALID +}; + +typedef struct { + char *name; + GModule *gmodule; +} MODULE_REC; + +extern GSList *modules; + +MODULE_REC *module_find(const char *name); + +int module_load(const char *path); +void module_unload(MODULE_REC *module); + #define MODULE_DATA_INIT(rec) \ (rec)->module_data = g_hash_table_new(g_str_hash, g_str_equal) diff --git a/src/fe-common/core/Makefile.am b/src/fe-common/core/Makefile.am index 093334ed..5a3bba07 100644 --- a/src/fe-common/core/Makefile.am +++ b/src/fe-common/core/Makefile.am @@ -13,6 +13,7 @@ libfe_common_core_la_SOURCES = \ fe-common-core.c \ fe-core-commands.c \ fe-log.c \ + fe-modules.c \ fe-server.c \ fe-settings.c \ hilight-text.c \ diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c index a402e6ae..ca337962 100644 --- a/src/fe-common/core/fe-common-core.c +++ b/src/fe-common/core/fe-common-core.c @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include "module.h" #include "module-formats.h" #include "levels.h" @@ -43,6 +44,9 @@ void fe_core_log_deinit(void); void fe_log_init(void); void fe_log_deinit(void); +void fe_modules_init(void); +void fe_modules_deinit(void); + void fe_server_init(void); void fe_server_deinit(void); @@ -87,6 +91,7 @@ void fe_common_core_init(void) keyboard_init(); printtext_init(); fe_log_init(); + fe_modules_init(); fe_server_init(); fe_settings_init(); translation_init(); @@ -106,6 +111,7 @@ void fe_common_core_deinit(void) keyboard_deinit(); printtext_deinit(); fe_log_deinit(); + fe_modules_deinit(); fe_server_deinit(); fe_settings_deinit(); translation_deinit(); diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c index 45a31ae5..497dab92 100644 --- a/src/fe-common/core/module-formats.c +++ b/src/fe-common/core/module-formats.c @@ -72,13 +72,13 @@ FORMAT_REC fecommon_core_formats[] = { /* ---- */ { NULL, "Logging", 0 }, - { "log_opened", "Log file %W$0%n opened", 1, { 0 } }, - { "log_closed", "Log file %W$0%n closed", 1, { 0 } }, + { "log_opened", "Log file %_$0%_ opened", 1, { 0 } }, + { "log_closed", "Log file %_$0%_ closed", 1, { 0 } }, { "log_create_failed", "Couldn't create log file %_$0%_: $1", 2, { 0, 0 } }, - { "log_locked", "Log file %W$0%n is locked, probably by another running Irssi", 1, { 0 } }, - { "log_not_open", "Log file %W$0%n not open", 1, { 0 } }, - { "log_started", "Started logging to file %W$0", 1, { 0 } }, - { "log_stopped", "Stopped logging to file %W$0", 1, { 0 } }, + { "log_locked", "Log file %_$0%_ is locked, probably by another running Irssi", 1, { 0 } }, + { "log_not_open", "Log file %_$0%_ not open", 1, { 0 } }, + { "log_started", "Started logging to file %_$0", 1, { 0 } }, + { "log_stopped", "Stopped logging to file %_$0", 1, { 0 } }, { "log_list_header", "Logs:", 0 }, { "log_list", "$0 $1: $2 $3$4$5", 6, { 1, 0, 0, 0, 0, 0 } }, { "log_list_footer", "", 0 }, @@ -87,6 +87,15 @@ FORMAT_REC fecommon_core_formats[] = { { "no_away_msgs", "No new messages in awaylog", 1, { 0 } }, { "away_msgs", "$1 new messages in awaylog:", 2, { 0, 1 } }, + /* ---- */ + { NULL, "Modules", 0 }, + + { "module_already_loaded", "Module %_$0%_ already loaded", 1, { 0 } }, + { "module_load_error", "Error loading module %_$0%_: $1", 2, { 0, 0 } }, + { "module_invalid", "%_$0%_ isn't Irssi module", 1, { 0 } }, + { "module_loaded", "Loaded module %_$0", 1, { 0 } }, + { "module_unloaded", "Unloaded module %_$0", 1, { 0 } }, + /* ---- */ { NULL, "Misc", 0 }, diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h index 416cb1cf..c88788c3 100644 --- a/src/fe-common/core/module-formats.h +++ b/src/fe-common/core/module-formats.h @@ -63,6 +63,14 @@ enum { IRCTXT_FILL_6, + IRCTXT_MODULE_ALREADY_LOADED, + IRCTXT_MODULE_LOAD_ERROR, + IRCTXT_MODULE_INVALID, + IRCTXT_MODULE_LOADED, + IRCTXT_MODULE_UNLOADED, + + IRCTXT_FILL_7, + IRCTXT_NOT_TOGGLE, IRCTXT_PERL_ERROR, IRCTXT_OPTION_UNKNOWN, @@ -76,6 +84,7 @@ enum { IRCTXT_CHAN_NOT_FOUND, IRCTXT_CHAN_NOT_SYNCED, IRCTXT_NOT_GOOD_IDEA + }; extern FORMAT_REC fecommon_core_formats[];