summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2001-08-14 00:41:59 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2001-08-14 00:41:59 +0000
commit803d8050164eaaefdd52fd4ae967c1e038b3c571 (patch)
tree615ff88add7d3682beebed692f41f5135c799713
parentf584c1013c74a98bfb43b79280c4ee20b775970a (diff)
downloadirssi-803d8050164eaaefdd52fd4ae967c1e038b3c571.zip
Module loading updates - /LOAD shows now also the statically loaded modules.
You can't /LOAD the same module twice. Syntax changed to /LOAD <module> [<submodule>], /UNLOAD <module> [<submodule>]. NOTE: all modules now need to call register_module() in their init() function. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@1748 dbcabf3a-b0e7-0310-adc4-f8d773084564
-rw-r--r--src/core/Makefile.am2
-rw-r--r--src/core/core.c4
-rw-r--r--src/core/modules-load.c388
-rw-r--r--src/core/modules-load.h16
-rw-r--r--src/core/modules.c219
-rw-r--r--src/core/modules.h37
-rw-r--r--src/fe-common/core/fe-common-core.c2
-rw-r--r--src/fe-common/core/fe-modules.c155
-rw-r--r--src/fe-common/core/module-formats.c15
-rw-r--r--src/fe-common/core/module-formats.h1
-rw-r--r--src/fe-common/irc/dcc/fe-dcc.c1
-rw-r--r--src/fe-common/irc/fe-common-irc.c4
-rw-r--r--src/fe-common/irc/notifylist/fe-notifylist.c2
-rw-r--r--src/fe-text/irssi.c2
-rw-r--r--src/irc/core/irc-core.c2
-rw-r--r--src/irc/dcc/dcc.c2
-rw-r--r--src/irc/flood/flood.c1
-rw-r--r--src/irc/notifylist/notifylist.c2
-rw-r--r--src/perl/Makefile.am1
-rw-r--r--src/perl/module-fe.h4
-rw-r--r--src/perl/module.h2
-rw-r--r--src/perl/perl-core.c3
-rw-r--r--src/perl/perl-fe.c5
23 files changed, 642 insertions, 228 deletions
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 042ca8c6..ae932aa6 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -32,6 +32,7 @@ libcore_a_SOURCES = \
$(memdebug_src) \
misc.c \
modules.c \
+ modules-load.c \
net-disconnect.c \
net-nonblock.c \
net-sendbuffer.c \
@@ -78,6 +79,7 @@ noinst_HEADERS = \
misc.h \
module.h \
modules.h \
+ modules-load.h \
net-disconnect.h \
net-nonblock.h \
net-sendbuffer.h \
diff --git a/src/core/core.c b/src/core/core.c
index c4600993..e3d3bebc 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -211,7 +211,9 @@ void core_init(int argc, char *argv[])
signal_add("setup changed", (SIGNAL_FUNC) read_signals);
read_signals();
- settings_check();
+ settings_check();
+
+ module_register("core", "core");
}
void core_deinit(void)
diff --git a/src/core/modules-load.c b/src/core/modules-load.c
new file mode 100644
index 00000000..f55cdef3
--- /dev/null
+++ b/src/core/modules-load.c
@@ -0,0 +1,388 @@
+/*
+ modules-load.c : irssi
+
+ Copyright (C) 1999-2001 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ 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 "modules.h"
+#include "modules-load.h"
+#include "signals.h"
+
+#include "settings.h"
+#include "commands.h"
+
+#ifdef HAVE_GMODULE
+
+/* Returns the module name without path, "lib" prefix or ".so" suffix */
+static char *module_get_name(const char *path, int *start, int *end)
+{
+ 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 = strchr(module_name, '.');
+ if (ptr != NULL) *ptr = '\0';
+
+ *start = (int) (name-path);
+ *end = *start + (ptr == NULL ? strlen(name) :
+ (int) (ptr-module_name));
+
+ return module_name;
+}
+
+/* Returns the root module name for given submodule (eg. perl_core -> perl) */
+static char *module_get_root(const char *name, char **prefixes)
+{
+ int len;
+
+ /* skip any of the prefixes.. */
+ while (*prefixes != NULL) {
+ len = strlen(*prefixes);
+ if (strncmp(name, *prefixes, len) == 0 && name[len] == '_') {
+ name += len+1;
+ break;
+ }
+ prefixes++;
+ }
+
+ /* skip the _core part */
+ len = strlen(name);
+ if (len > 5 && strcmp(name+len-5, "_core") == 0)
+ return g_strndup(name, len-5);
+
+ return g_strdup(name);
+}
+
+/* Returns the sub module name for given submodule (eg. perl_core -> core) */
+static char *module_get_sub(const char *name, const char *root)
+{
+ int rootlen, namelen;
+
+ namelen = strlen(name);
+ rootlen = strlen(root);
+ g_return_val_if_fail(namelen >= rootlen, g_strdup(name));
+
+ if (strncmp(name, root, rootlen) == 0 &&
+ strcmp(name+rootlen, "_core") == 0)
+ return g_strdup("core");
+
+ if (namelen+1 > rootlen && name[namelen-rootlen-1] == '_' &&
+ strcmp(name+namelen-rootlen, root) == 0)
+ return g_strndup(name, namelen-rootlen-1);
+
+ return g_strdup(name);
+}
+
+static GModule *module_open(const char *name)
+{
+ struct stat statbuf;
+ GModule *module;
+ char *path, *str;
+
+ if (g_path_is_absolute(name) ||
+ (*name == '.' && name[1] == G_DIR_SEPARATOR))
+ path = g_strdup(name);
+ else {
+ /* first try from home dir */
+ str = g_strdup_printf("%s/modules", get_irssi_dir());
+ path = g_module_build_path(str, name);
+ g_free(str);
+
+ if (stat(path, &statbuf) == 0) {
+ module = g_module_open(path, (GModuleFlags) 0);
+ g_free(path);
+ return module;
+ }
+
+ /* module not found from home dir, try global module dir */
+ g_free(path);
+ path = g_module_build_path(MODULEDIR, name);
+ }
+
+ module = g_module_open(path, (GModuleFlags) 0);
+ g_free(path);
+ return module;
+}
+
+#define module_error(error, text, rootmodule, submodule) \
+ signal_emit("module error", 4, GINT_TO_POINTER(error), text, \
+ rootmodule, submodule)
+
+static int module_load_name(const char *path, const char *rootmodule,
+ const char *submodule, int silent)
+{
+ void (*module_init) (void);
+ GModule *gmodule;
+ MODULE_REC *module;
+ MODULE_FILE_REC *rec;
+ char *initfunc;
+
+ gmodule = module_open(path);
+ if (gmodule == NULL) {
+ if (!silent) {
+ module_error(MODULE_ERROR_LOAD, g_module_error(),
+ rootmodule, submodule);
+ }
+ return FALSE;
+ }
+
+ /* get the module's init() function */
+ if (strcmp(submodule, "core") == 0)
+ initfunc = g_strconcat(rootmodule, "_core_init", NULL);
+ else {
+ initfunc = g_strconcat(submodule, "_",
+ rootmodule, "_init", NULL);
+ }
+
+ if (!g_module_symbol(gmodule, initfunc, (gpointer *) &module_init)) {
+ if (!silent)
+ module_error(MODULE_ERROR_INVALID, NULL,
+ rootmodule, submodule);
+ g_module_close(gmodule);
+ g_free(initfunc);
+ return FALSE;
+ }
+ g_free(initfunc);
+
+ /* Call the module's init() function - it should register itself
+ with module_register() function, abort if it doesn't. */
+ module_init();
+
+ module = module_find(rootmodule);
+ rec = module == NULL ? NULL : module_file_find(module, submodule);
+ if (rec == NULL) {
+ rec = module_register_full(rootmodule, submodule, NULL);
+ rec->gmodule = gmodule;
+ module_file_unload(rec);
+
+ module_error(MODULE_ERROR_INVALID, NULL,
+ rootmodule, submodule);
+ return FALSE;
+ }
+
+ rec->gmodule = gmodule;
+ rec->initialized = TRUE;
+
+ settings_check_module(rec->defined_module_name);
+
+ signal_emit("module loaded", 2, rec->root, rec);
+ return TRUE;
+}
+
+static int module_load_prefixes(const char *path, const char *module,
+ int start, int end, char **prefixes)
+{
+ GString *realpath;
+ int ok;
+
+ /* load module_core */
+ realpath = g_string_new(path);
+ g_string_insert(realpath, end, "_core");
+
+ ok = module_load_name(realpath->str, module, "core", FALSE);
+ if (ok && prefixes != NULL) {
+ /* load all the "prefix modules", like the fe-common, irc,
+ etc. part of the module */
+ while (*prefixes != NULL) {
+ g_string_assign(realpath, path);
+ g_string_insert_c(realpath, start, '_');
+ g_string_insert(realpath, start, *prefixes);
+
+ module_load_name(realpath->str, module,
+ *prefixes, TRUE);
+
+ prefixes++;
+ }
+ }
+
+ g_string_free(realpath, TRUE);
+ return ok;
+}
+
+static int module_load_full(const char *path, const char *rootmodule,
+ const char *submodule, int start, int end,
+ char **prefixes)
+{
+ MODULE_REC *module;
+ int ok, try_prefixes;
+
+ if (!g_module_supported())
+ return FALSE;
+
+ module = module_find(rootmodule);
+ if (module != NULL && (strcmp(submodule, rootmodule) == 0 ||
+ module_file_find(module, submodule) != NULL)) {
+ /* module is already loaded */
+ module_error(MODULE_ERROR_ALREADY_LOADED, NULL,
+ rootmodule, submodule);
+ return FALSE;
+ }
+
+ /* check if the given module exists.. */
+ try_prefixes = strcmp(rootmodule, submodule) == 0;
+ ok = module_load_name(path, rootmodule, submodule, try_prefixes);
+ if (!ok && try_prefixes) {
+ /* nope, try loading the module_core,
+ fe_module, etc. */
+ ok = module_load_prefixes(path, rootmodule,
+ start, end, prefixes);
+ }
+
+ return ok;
+}
+
+/* Load module - automatically tries to load also the related non-core
+ modules given in `prefixes' (like irc, fe, fe_text, ..) */
+int module_load(const char *path, char **prefixes)
+{
+ char *name, *submodule, *rootmodule;
+ int start, end, ret;
+
+ g_return_val_if_fail(path != NULL, FALSE);
+
+ name = module_get_name(path, &start, &end);
+ rootmodule = module_get_root(name, prefixes);
+ submodule = module_get_sub(name, rootmodule);
+ g_free(name);
+
+ ret = module_load_full(path, rootmodule, submodule,
+ start, end, prefixes);
+
+ g_free(rootmodule);
+ g_free(submodule);
+ return ret;
+}
+
+/* Load a sub module. */
+int module_load_sub(const char *path, const char *submodule, char **prefixes)
+{
+ GString *full_path;
+ char *name, *rootmodule;
+ int start, end, ret;
+
+ g_return_val_if_fail(path != NULL, FALSE);
+ g_return_val_if_fail(submodule != NULL, FALSE);
+
+ name = module_get_name(path, &start, &end);
+ rootmodule = module_get_root(name, prefixes);
+ g_free(name);
+
+ full_path = g_string_new(path);
+ if (strcmp(submodule, "core") == 0)
+ g_string_insert(full_path, end, "_core");
+ else {
+ g_string_insert_c(full_path, start, '_');
+ g_string_insert(full_path, start, submodule);
+ }
+
+ ret = module_load_full(full_path->str, rootmodule, submodule,
+ start, end, NULL);
+
+ g_string_free(full_path, TRUE);
+ g_free(rootmodule);
+ return ret;
+}
+
+static void module_file_deinit_gmodule(MODULE_FILE_REC *file)
+{
+ void (*module_deinit) (void);
+ char *deinitfunc;
+
+ /* call the module's deinit() function */
+ if (strcmp(file->name, "core") == 0) {
+ deinitfunc = g_strconcat(file->root->name,
+ "_core_deinit", NULL);
+ } else {
+ deinitfunc = g_strconcat(file->name, "_",
+ file->root->name, "_deinit", NULL);
+ }
+
+ if (g_module_symbol(file->gmodule, deinitfunc,
+ (gpointer *) &module_deinit))
+ module_deinit();
+
+ g_free(deinitfunc);
+
+ if (file->defined_module_name != NULL) {
+ settings_remove_module(file->defined_module_name);
+ commands_remove_module(file->defined_module_name);
+ signals_remove_module(file->defined_module_name);
+ }
+
+ g_module_close(file->gmodule);
+}
+
+void module_file_unload(MODULE_FILE_REC *file)
+{
+ MODULE_REC *root;
+
+ root = file->root;
+ root->files = g_slist_remove(root->files, file);
+
+ if (file->initialized)
+ signal_emit("module unloaded", 2, file->root, file);
+
+ if (file->gmodule != NULL)
+ module_file_deinit_gmodule(file);
+
+ g_free(file->name);
+ g_free(file->defined_module_name);
+ g_free(file);
+
+ if (root->files == NULL && g_slist_find(modules, root) != NULL)
+ module_unload(root);
+}
+
+void module_unload(MODULE_REC *module)
+{
+ g_return_if_fail(module != NULL);
+
+ modules = g_slist_remove(modules, module);
+
+ signal_emit("module unloaded", 1, module);
+
+ while (module->files != NULL)
+ module_file_unload(module->files->data);
+
+ g_free(module);
+}
+
+#else /* !HAVE_GMODULE - modules are not supported */
+
+int module_load(const char *path, char **prefixes)
+{
+ return FALSE;
+}
+
+void module_unload(MODULE_REC *module)
+{
+}
+
+#endif
diff --git a/src/core/modules-load.h b/src/core/modules-load.h
new file mode 100644
index 00000000..42e14382
--- /dev/null
+++ b/src/core/modules-load.h
@@ -0,0 +1,16 @@
+#ifndef __MODULES_LOAD_H
+#define __MODULES_LOAD_H
+
+#include "modules.h"
+
+/* Load module - automatically tries to load also the related non-core
+ modules given in `prefixes' (like irc, fe, fe_text, ..) */
+int module_load(const char *path, char **prefixes);
+
+/* Load a sub module. */
+int module_load_sub(const char *path, const char *submodule, char **prefixes);
+
+void module_unload(MODULE_REC *module);
+void module_file_unload(MODULE_FILE_REC *file);
+
+#endif
diff --git a/src/core/modules.c b/src/core/modules.c
index f450f39d..dc373189 100644
--- a/src/core/modules.c
+++ b/src/core/modules.c
@@ -1,7 +1,7 @@
/*
modules.c : irssi
- Copyright (C) 1999-2000 Timo Sirainen
+ Copyright (C) 1999-2001 Timo Sirainen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,9 +22,6 @@
#include "modules.h"
#include "signals.h"
-#include "commands.h"
-#include "settings.h"
-
GSList *modules;
static GHashTable *uniqids, *uniqstrids;
@@ -201,206 +198,62 @@ void module_uniq_destroy(const char *module)
}
}
-MODULE_REC *module_find(const char *name)
+/* Register a new module. The `name' is the root module name, `submodule'
+ specifies the current module to be registered (eg. "perl", "fe").
+ The module is registered as statically loaded by default. */
+MODULE_FILE_REC *module_register_full(const char *name, const char *submodule,
+ const char *defined_module_name)
{
- GSList *tmp;
+ MODULE_REC *module;
+ MODULE_FILE_REC *file;
- for (tmp = modules; tmp != NULL; tmp = tmp->next) {
- MODULE_REC *rec = tmp->data;
+ module = module_find(name);
+ if (module == NULL) {
+ module = g_new0(MODULE_REC, 1);
+ module->name = g_strdup(name);
- if (g_strcasecmp(rec->name, name) == 0)
- return rec;
+ modules = g_slist_append(modules, module);
}
- return NULL;
-}
-
-#ifdef HAVE_GMODULE
-static char *module_get_name(const char *path, int *start, int *end)
-{
- const char *name;
- char *module_name, *ptr;
+ file = module_file_find(module, submodule);
+ if (file != NULL)
+ return file;
- name = NULL;
- if (g_path_is_absolute(path)) {
- name = strrchr(path, G_DIR_SEPARATOR);
- if (name != NULL) name++;
- }
+ file = g_new0(MODULE_FILE_REC, 1);
+ file->root = module;
+ file->name = g_strdup(submodule);
+ file->defined_module_name = g_strdup(defined_module_name);
- if (name == NULL)
- name = path;
-
- if (strncmp(name, "lib", 3) == 0)
- name += 3;
-
- module_name = g_strdup(name);
- ptr = strchr(module_name, '.');
- if (ptr != NULL) *ptr = '\0';
-
- *start = (int) (name-path);
- *end = *start + (ptr == NULL ? strlen(name) :
- (int) (ptr-module_name));
-
- return module_name;
+ module->files = g_slist_append(module->files, file);
+ return file;
}
-static GModule *module_open(const char *name)
+MODULE_REC *module_find(const char *name)
{
- struct stat statbuf;
- GModule *module;
- char *path, *str;
-
- if (g_path_is_absolute(name) ||
- (*name == '.' && name[1] == G_DIR_SEPARATOR))
- path = g_strdup(name);
- else {
- /* first try from home dir */
- str = g_strdup_printf("%s/modules", get_irssi_dir());
- path = g_module_build_path(str, name);
- g_free(str);
-
- if (stat(path, &statbuf) == 0) {
- module = g_module_open(path, (GModuleFlags) 0);
- g_free(path);
- return module;
- }
-
- /* module not found from home dir, try global module dir */
- g_free(path);
- path = g_module_build_path(MODULEDIR, name);
- }
-
- module = g_module_open(path, (GModuleFlags) 0);
- g_free(path);
- return module;
-}
-
-#define module_error(error, module, text) \
- signal_emit("module error", 3, GINT_TO_POINTER(error), module, text)
+ GSList *tmp;
-static int module_load_name(const char *path, const char *name, int silent)
-{
- void (*module_init) (void);
- GModule *gmodule;
- MODULE_REC *rec;
- char *initfunc;
-
- gmodule = module_open(path);
- if (gmodule == NULL) {
- if (!silent) {
- module_error(MODULE_ERROR_LOAD, name,
- g_module_error());
- }
- return FALSE;
- }
+ for (tmp = modules; tmp != NULL; tmp = tmp->next) {
+ MODULE_REC *rec = tmp->data;
- /* get the module's init() function */
- initfunc = g_strconcat(name, "_init", NULL);
- if (!g_module_symbol(gmodule, initfunc, (gpointer *) &module_init)) {
- if (!silent)
- module_error(MODULE_ERROR_INVALID, name, NULL);
- g_module_close(gmodule);
- g_free(initfunc);
- return FALSE;
+ if (g_strcasecmp(rec->name, name) == 0)
+ return rec;
}
- g_free(initfunc);
-
- rec = g_new0(MODULE_REC, 1);
- rec->name = g_strdup(name);
- rec->gmodule = gmodule;
- modules = g_slist_append(modules, rec);
- module_init();
- settings_check_module(name);
-
- signal_emit("module loaded", 1, rec);
- return TRUE;
+ return NULL;
}
-#endif
-/* Load module - automatically tries to load also the related non-core
- modules given in `prefixes' (like irc, fe, fe_text, ..) */
-int module_load(const char *path, char **prefixes)
+MODULE_FILE_REC *module_file_find(MODULE_REC *module, const char *name)
{
-#ifdef HAVE_GMODULE
- GString *realpath;
- char *name, *pname;
- int ret, start, end;
-
- g_return_val_if_fail(path != NULL, FALSE);
-
- if (!g_module_supported())
- return FALSE;
+ GSList *tmp;
- name = module_get_name(path, &start, &end);
- if (module_find(name)) {
- module_error(MODULE_ERROR_ALREADY_LOADED, name, NULL);
- g_free(name);
- return FALSE;
- }
+ for (tmp = module->files; tmp != NULL; tmp = tmp->next) {
+ MODULE_FILE_REC *rec = tmp->data;
- /* load "module_core" instead of "module" if it exists */
- realpath = g_string_new(path);
- g_string_insert(realpath, end, "_core");
-
- pname = g_strconcat(name, "_core", NULL);
- ret = module_load_name(realpath->str, pname, TRUE);
- g_free(pname);
-
- if (!ret) {
- /* load "module" - complain if it's not found */
- ret = module_load_name(path, name, FALSE);
- } else if (prefixes != NULL) {
- /* load all the "prefix modules", like the fe-common, irc,
- etc. part of the module */
- while (*prefixes != NULL) {
- g_string_assign(realpath, path);
- g_string_insert(realpath, start, "_");
- g_string_insert(realpath, start, *prefixes);
-
- pname = g_strconcat(*prefixes, "_", name, NULL);
- module_load_name(realpath->str, pname, TRUE);
- g_free(pname);
-
- prefixes++;
- }
+ if (strcmp(rec->name, name) == 0)
+ return rec;
}
- g_string_free(realpath, TRUE);
- g_free(name);
- return ret;
-#else
- return FALSE;
-#endif
-}
-
-void module_unload(MODULE_REC *module)
-{
-#ifdef HAVE_GMODULE
- void (*module_deinit) (void);
- char *deinitfunc;
-
- g_return_if_fail(module != NULL);
-
- modules = g_slist_remove(modules, module);
-
- signal_emit("module unloaded", 1, module);
-
- /* call the module's deinit() function */
- deinitfunc = g_strconcat(module->name, "_deinit", NULL);
- if (g_module_symbol(module->gmodule, deinitfunc,
- (gpointer *) &module_deinit))
- module_deinit();
- g_free(deinitfunc);
-
- settings_remove_module(module->name);
- commands_remove_module(module->name);
- signals_remove_module(module->name);
-
- g_module_close(module->gmodule);
- g_free(module->name);
- g_free(module);
-#endif
+ return NULL;
}
static void uniq_get_modules(char *key, void *value, GSList **list)
diff --git a/src/core/modules.h b/src/core/modules.h
index 7a83819f..bf2dba31 100644
--- a/src/core/modules.h
+++ b/src/core/modules.h
@@ -13,27 +13,50 @@
#define MODULE_DATA(rec) \
g_hash_table_lookup((rec)->module_data, MODULE_NAME)
+
+#ifdef HAVE_GMODULE
+# define MODULE_IS_STATIC(rec) \
+ ((rec)->gmodule == NULL)
+#else
+# define MODULE_IS_STATIC(rec) TRUE
+#endif
+
enum {
MODULE_ERROR_ALREADY_LOADED,
MODULE_ERROR_LOAD,
MODULE_ERROR_INVALID
};
+typedef struct _MODULE_REC MODULE_REC;
+
typedef struct {
+ MODULE_REC *root;
char *name;
+ char *defined_module_name;
+
#ifdef HAVE_GMODULE
- GModule *gmodule;
+ GModule *gmodule; /* static, if NULL */
#endif
-} MODULE_REC;
+ unsigned int initialized:1;
+} MODULE_FILE_REC;
+
+struct _MODULE_REC {
+ char *name;
+ GSList *files; /* list of modules that belong to this root module */
+};
extern GSList *modules;
-MODULE_REC *module_find(const char *name);
+/* Register a new module. The `name' is the root module name, `submodule'
+ specifies the current module to be registered (eg. "perl", "fe").
+ The module is registered as statically loaded by default. */
+MODULE_FILE_REC *module_register_full(const char *name, const char *submodule,
+ const char *defined_module_name);
+#define module_register(name, submodule) \
+ module_register_full(name, submodule, MODULE_NAME)
-/* Load module - automatically tries to load also the related non-core
- modules given in `prefixes' (like irc, fe, fe_text, ..) */
-int module_load(const char *path, char **prefixes);
-void module_unload(MODULE_REC *module);
+MODULE_REC *module_find(const char *name);
+MODULE_FILE_REC *module_file_find(MODULE_REC *module, const char *name);
#define MODULE_CHECK_CAST(object, cast, type_field, id) \
((cast *) module_check_cast(object, offsetof(cast, type_field), id))
diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c
index 66a2e602..0f5ce6ea 100644
--- a/src/fe-common/core/fe-common-core.c
+++ b/src/fe-common/core/fe-common-core.c
@@ -206,6 +206,8 @@ void fe_common_core_init(void)
signal_add_last("server disconnected", (SIGNAL_FUNC) sig_disconnected);
signal_add_first("channel created", (SIGNAL_FUNC) sig_channel_created);
signal_add_last("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
+
+ module_register("core", "fe");
}
void fe_common_core_deinit(void)
diff --git a/src/fe-common/core/fe-modules.c b/src/fe-common/core/fe-modules.c
index e351dc71..5bbcf0b5 100644
--- a/src/fe-common/core/fe-modules.c
+++ b/src/fe-common/core/fe-modules.c
@@ -20,6 +20,7 @@
#include "module.h"
#include "modules.h"
+#include "modules-load.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
@@ -28,49 +29,99 @@
#include "printtext.h"
-static void sig_module_error(void *number, const char *module,
- const char *data)
+#ifdef HAVE_GMODULE
+
+static void sig_module_error(void *number, const char *data,
+ const char *rootmodule, const char *submodule)
{
switch (GPOINTER_TO_INT(number)) {
case MODULE_ERROR_ALREADY_LOADED:
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
- TXT_MODULE_ALREADY_LOADED, module);
+ TXT_MODULE_ALREADY_LOADED, rootmodule, submodule);
break;
case MODULE_ERROR_LOAD:
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
- TXT_MODULE_LOAD_ERROR, module, data);
+ TXT_MODULE_LOAD_ERROR, rootmodule, submodule, data);
break;
case MODULE_ERROR_INVALID:
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
- TXT_MODULE_INVALID, module);
+ TXT_MODULE_INVALID, rootmodule, submodule);
break;
}
}
-static void sig_module_loaded(MODULE_REC *rec)
+static void sig_module_loaded(MODULE_REC *module, MODULE_FILE_REC *file)
{
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
- TXT_MODULE_LOADED, rec->name);
+ TXT_MODULE_LOADED, module->name, file->name);
}
-static void sig_module_unloaded(MODULE_REC *rec)
+static void sig_module_unloaded(MODULE_REC *module, MODULE_FILE_REC *file)
{
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
- TXT_MODULE_UNLOADED, rec->name);
+ if (file != NULL && file->gmodule != NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ TXT_MODULE_UNLOADED, module->name, file->name);
+ }
+}
+
+static int module_list_sub(MODULE_REC *module, int mark_type,
+ GString *submodules)
+{
+ GSList *tmp;
+ int all_dynamic, dynamic;
+
+ g_string_truncate(submodules, 0);
+
+ all_dynamic = -1;
+ for (tmp = module->files; tmp != NULL; tmp = tmp->next) {
+ MODULE_FILE_REC *file = tmp->data;
+
+ /* if there's dynamic and static modules mixed, we'll need
+ to specify them separately */
+ if (!mark_type) {
+ dynamic = file->gmodule != NULL;
+ if (all_dynamic != -1 && all_dynamic != dynamic) {
+ return module_list_sub(module, TRUE,
+ submodules);
+ }
+ all_dynamic = dynamic;
+ }
+
+ if (submodules->len > 0)
+ g_string_append_c(submodules, ' ');
+ g_string_append(submodules, file->name);
+ if (mark_type) {
+ g_string_append(submodules, file->gmodule == NULL ?
+ " (static)" : " (dynamic)");
+ }
+ }
+
+ return all_dynamic;
}
static void cmd_load_list(void)
{
GSList *tmp;
+ GString *submodules;
+ const char *type;
+ int dynamic;
+
+ submodules = g_string_new(NULL);
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_MODULE_HEADER);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_MODULE_HEADER);
for (tmp = modules; tmp != NULL; tmp = tmp->next) {
MODULE_REC *rec = tmp->data;
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
- TXT_MODULE_LINE, rec->name);
+ dynamic = module_list_sub(rec, FALSE, submodules);
+ type = dynamic == -1 ? "mixed" :
+ dynamic ? "dynamic" : "static";
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_MODULE_LINE, rec->name, type, submodules->str);
}
- printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_MODULE_FOOTER);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_MODULE_FOOTER);
+
+ g_string_free(submodules, TRUE);
}
static char **module_prefixes_get(void)
@@ -108,36 +159,67 @@ static void module_prefixes_free(char **list)
g_free(list);
}
-/* SYNTAX: LOAD <module> */
+/* SYNTAX: LOAD <module> [<submodule>] */
static void cmd_load(const char *data)
{
-#ifdef HAVE_GMODULE
+ char *rootmodule, *submodule;
char **module_prefixes;
+ void *free_arg;
g_return_if_fail(data != NULL);
- if (*data == '\0')
+
+ if (!cmd_get_params(data, &free_arg, 2 , &rootmodule, &submodule))
+ return;
+
+ if (*rootmodule == '\0')
cmd_load_list();
else {
module_prefixes = module_prefixes_get();
- module_load(data, module_prefixes);
+ if (*submodule == '\0')
+ module_load(rootmodule, module_prefixes);
+ else {
+ module_load_sub(rootmodule, submodule,
+ module_prefixes);
+ }
module_prefixes_free(module_prefixes);
}
-#else
- printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
- "Dynamic modules loading not supported");
-#endif
+
+ cmd_params_free(free_arg);
}
-/* SYNTAX: UNLOAD <module> */
+/* SYNTAX: UNLOAD <module> [<submodule>] */
static void cmd_unload(const char *data)
{
- MODULE_REC *rec;
+ MODULE_REC *module;
+ MODULE_FILE_REC *file;
+ char *rootmodule, *submodule;
+ void *free_arg;
g_return_if_fail(data != NULL);
- if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
- rec = module_find(data);
- if (rec != NULL) module_unload(rec);
+ if (!cmd_get_params(data, &free_arg, 2 , &rootmodule, &submodule))
+ return;
+ if (*rootmodule == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ module = module_find(rootmodule);
+ if (module != NULL) {
+ if (*submodule == '\0')
+ module_unload(module);
+ else {
+ file = module_file_find(module, submodule);
+ if (file != NULL)
+ module_file_unload(file);
+ else
+ module = NULL;
+ }
+ }
+
+ if (module == NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ TXT_MODULE_NOT_LOADED, rootmodule, submodule);
+ }
+
+ cmd_params_free(free_arg);
}
void fe_modules_init(void)
@@ -159,3 +241,22 @@ void fe_modules_deinit(void)
command_unbind("load", (SIGNAL_FUNC) cmd_load);
command_unbind("unload", (SIGNAL_FUNC) cmd_unload);
}
+
+#else /* !HAVE_GMODULE */
+
+static void cmd_load(const char *data)
+{
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ "Dynamic modules loading not supported");
+}
+
+void fe_modules_init(void)
+{
+ command_bind("load", NULL, (SIGNAL_FUNC) cmd_load);
+}
+
+void fe_modules_deinit(void)
+{
+ command_unbind("load", (SIGNAL_FUNC) cmd_load);
+}
+#endif
diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c
index 46fe4de0..dbb8bb3e 100644
--- a/src/fe-common/core/module-formats.c
+++ b/src/fe-common/core/module-formats.c
@@ -179,14 +179,15 @@ FORMAT_REC fecommon_core_formats[] = {
/* ---- */
{ NULL, "Modules", 0 },
- { "module_header", "Loaded modules:", 0, },
- { "module_line", " $0", 1, { 0 } },
+ { "module_header", "Module Type Submodules", 0, },
+ { "module_line", "$[!20]0 $[7]1 $2", 3, { 0, 0, 0 } },
{ "module_footer", "", 0, },
- { "module_already_loaded", "Module {hilight $0} already loaded", 1, { 0 } },
- { "module_load_error", "Error loading module {hilight $0}: $1", 2, { 0, 0 } },
- { "module_invalid", "{hilight $0} isn't Irssi module", 1, { 0 } },
- { "module_loaded", "Loaded module {hilight $0}", 1, { 0 } },
- { "module_unloaded", "Unloaded module {hilight $0}", 1, { 0 } },
+ { "module_already_loaded", "Module {hilight $0/$1} already loaded", 2, { 0, 0 } },
+ { "module_not_loaded", "Module {hilight $0/$1} is not loaded", 2, { 0, 0 } },
+ { "module_load_error", "Error loading module {hilight $0/$1}: $2", 3, { 0, 0, 0 } },
+ { "module_invalid", "{hilight $0/$1} isn't Irssi module", 2, { 0, 0 } },
+ { "module_loaded", "Loaded module {hilight $0/$1}", 2, { 0, 0 } },
+ { "module_unloaded", "Unloaded module {hilight $0/$1}", 2, { 0, 0 } },
/* ---- */
{ NULL, "Commands", 0 },
diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h
index eacbc8aa..6e93f70c 100644
--- a/src/fe-common/core/module-formats.h
+++ b/src/fe-common/core/module-formats.h
@@ -153,6 +153,7 @@ enum {
TXT_MODULE_LINE,
TXT_MODULE_FOOTER,
TXT_MODULE_ALREADY_LOADED,
+ TXT_MODULE_NOT_LOADED,
TXT_MODULE_LOAD_ERROR,
TXT_MODULE_INVALID,
TXT_MODULE_LOADED,
diff --git a/src/fe-common/irc/dcc/fe-dcc.c b/src/fe-common/irc/dcc/fe-dcc.c
index 2989e3ab..afe230ec 100644
--- a/src/fe-common/irc/dcc/fe-dcc.c
+++ b/src/fe-common/irc/dcc/fe-dcc.c
@@ -139,6 +139,7 @@ void fe_irc_dcc_init(void)
command_bind("dcc list", NULL, (SIGNAL_FUNC) cmd_dcc_list);
theme_register(fecommon_irc_dcc_formats);
+ module_register("dcc", "fe-irc");
}
void fe_irc_dcc_deinit(void)
diff --git a/src/fe-common/irc/fe-common-irc.c b/src/fe-common/irc/fe-common-irc.c
index aed6afac..5dfc2a25 100644
--- a/src/fe-common/irc/fe-common-irc.c
+++ b/src/fe-common/irc/fe-common-irc.c
@@ -85,8 +85,10 @@ void fe_common_irc_init(void)
fe_netsplit_init();
fe_netjoin_init();
- fe_irc_modules_init();
settings_check();
+ module_register("core", "fe-irc");
+
+ fe_irc_modules_init();
}
void fe_common_irc_deinit(void)
diff --git a/src/fe-common/irc/notifylist/fe-notifylist.c b/src/fe-common/irc/notifylist/fe-notifylist.c
index 7253a042..b4532fb8 100644
--- a/src/fe-common/irc/notifylist/fe-notifylist.c
+++ b/src/fe-common/irc/notifylist/fe-notifylist.c
@@ -250,6 +250,8 @@ void fe_irc_notifylist_init(void)
signal_add("notifylist unidle", (SIGNAL_FUNC) notifylist_unidle);
command_set_options("notify", "list");
+
+ module_register("notifylist", "fe-irc");
}
void fe_irc_notifylist_deinit(void)
diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c
index cf6f974b..22f2b8d7 100644
--- a/src/fe-text/irssi.c
+++ b/src/fe-text/irssi.c
@@ -20,6 +20,7 @@
#include "module.h"
#include "module-formats.h"
+#include "modules-load.h"
#include "args.h"
#include "signals.h"
#include "levels.h"
@@ -135,6 +136,7 @@ static void textui_finish_init(void)
screen_refresh_thaw();
settings_check();
+ module_register("core", "fe-text");
fe_common_core_finish_init();
diff --git a/src/irc/core/irc-core.c b/src/irc/core/irc-core.c
index b036d244..b203fe35 100644
--- a/src/irc/core/irc-core.c
+++ b/src/irc/core/irc-core.c
@@ -103,6 +103,8 @@ void irc_core_init(void)
netsplit_init();
irc_rawlog_init();
irc_expandos_init();
+
+ module_register("core", "irc");
}
void irc_core_deinit(void)
diff --git a/src/irc/dcc/dcc.c b/src/irc/dcc/dcc.c
index fa0853fb..49c68eb8 100644
--- a/src/irc/dcc/dcc.c
+++ b/src/irc/dcc/dcc.c
@@ -446,6 +446,8 @@ void irc_dcc_init(void)
dcc_send_init();
dcc_resume_init();
dcc_autoget_init();
+
+ module_register("dcc", "irc");
}
void irc_dcc_deinit(void)
diff --git a/src/irc/flood/flood.c b/src/irc/flood/flood.c
index 5381b1cc..aa383554 100644
--- a/src/irc/flood/flood.c
+++ b/src/irc/flood/flood.c
@@ -309,6 +309,7 @@ void irc_flood_init(void)
signal_add("server disconnected", (SIGNAL_FUNC) flood_deinit_server);
autoignore_init();
+ module_register("flood", "irc");
}
void irc_flood_deinit(void)
diff --git a/src/irc/notifylist/notifylist.c b/src/irc/notifylist/notifylist.c
index 2836d586..09a6f7c7 100644
--- a/src/irc/notifylist/notifylist.c
+++ b/src/irc/notifylist/notifylist.c
@@ -352,6 +352,8 @@ void irc_notifylist_init(void)
signal_add("event join", (SIGNAL_FUNC) event_join);
signal_add("channel wholist", (SIGNAL_FUNC) sig_channel_wholist);
signal_add("setup reread", (SIGNAL_FUNC) notifylist_read_config);
+
+ module_register("notifylist", "irc");
}
void irc_notifylist_deinit(void)
diff --git a/src/perl/Makefile.am b/src/perl/Makefile.am
index 8ac1ffa7..e6208352 100644
--- a/src/perl/Makefile.am
+++ b/src/perl/Makefile.am
@@ -34,6 +34,7 @@ perl_fe_sources = \
noinst_HEADERS = \
module.h \
+ module-fe.h \
module-formats.h \
perl-core.h \
perl-common.h \
diff --git a/src/perl/module-fe.h b/src/perl/module-fe.h
new file mode 100644
index 00000000..2dc8c283
--- /dev/null
+++ b/src/perl/module-fe.h
@@ -0,0 +1,4 @@
+#include "module.h"
+
+#undef MODULE_NAME
+#define MODULE_NAME "fe-common/perl"
diff --git a/src/perl/module.h b/src/perl/module.h
index 9c9f7399..0e95f13d 100644
--- a/src/perl/module.h
+++ b/src/perl/module.h
@@ -18,4 +18,4 @@ extern PerlInterpreter *my_perl; /* must be called my_perl or some perl implemen
#include "common.h"
-#define MODULE_NAME "irssi-perl"
+#define MODULE_NAME "perl/core"
diff --git a/src/perl/perl-core.c b/src/perl/perl-core.c
index 0807fc72..914f6eff 100644
--- a/src/perl/perl-core.c
+++ b/src/perl/perl-core.c
@@ -20,6 +20,7 @@
#define NEED_PERL_H
#include "module.h"
+#include "modules.h"
#include "signals.h"
#include "misc.h"
@@ -363,6 +364,8 @@ void perl_core_init(void)
perl_scripts_init();
perl_scripts_autorun();
+
+ module_register("perl", "core");
}
void perl_core_deinit(void)
diff --git a/src/perl/perl-fe.c b/src/perl/perl-fe.c
index cbdad663..27ac154b 100644
--- a/src/perl/perl-fe.c
+++ b/src/perl/perl-fe.c
@@ -18,7 +18,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "module.h"
+#include "module-fe.h"
+#include "modules.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
@@ -230,6 +231,8 @@ void fe_perl_init(void)
signal_add("script error", (SIGNAL_FUNC) sig_script_error);
signal_add("complete command script load", (SIGNAL_FUNC) sig_complete_load);
signal_add("complete command script unload", (SIGNAL_FUNC) sig_complete_unload);
+
+ module_register("perl", "fe");
}
void fe_perl_deinit(void)