mirror of
https://github.com/irssi/irssi.git
synced 2024-09-01 04:14:16 -04:00
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
This commit is contained in:
parent
f584c1013c
commit
803d805016
@ -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 \
|
||||
|
@ -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)
|
||||
|
388
src/core/modules-load.c
Normal file
388
src/core/modules-load.c
Normal file
@ -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
|
16
src/core/modules-load.h
Normal file
16
src/core/modules-load.h
Normal file
@ -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
|
@ -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,6 +198,36 @@ void module_uniq_destroy(const char *module)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
MODULE_REC *module;
|
||||
MODULE_FILE_REC *file;
|
||||
|
||||
module = module_find(name);
|
||||
if (module == NULL) {
|
||||
module = g_new0(MODULE_REC, 1);
|
||||
module->name = g_strdup(name);
|
||||
|
||||
modules = g_slist_append(modules, module);
|
||||
}
|
||||
|
||||
file = module_file_find(module, submodule);
|
||||
if (file != NULL)
|
||||
return file;
|
||||
|
||||
file = g_new0(MODULE_FILE_REC, 1);
|
||||
file->root = module;
|
||||
file->name = g_strdup(submodule);
|
||||
file->defined_module_name = g_strdup(defined_module_name);
|
||||
|
||||
module->files = g_slist_append(module->files, file);
|
||||
return file;
|
||||
}
|
||||
|
||||
MODULE_REC *module_find(const char *name)
|
||||
{
|
||||
GSList *tmp;
|
||||
@ -215,192 +242,18 @@ MODULE_REC *module_find(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GMODULE
|
||||
static char *module_get_name(const char *path, int *start, int *end)
|
||||
MODULE_FILE_REC *module_file_find(MODULE_REC *module, const char *name)
|
||||
{
|
||||
const char *name;
|
||||
char *module_name, *ptr;
|
||||
GSList *tmp;
|
||||
|
||||
name = NULL;
|
||||
if (g_path_is_absolute(path)) {
|
||||
name = strrchr(path, G_DIR_SEPARATOR);
|
||||
if (name != NULL) name++;
|
||||
for (tmp = module->files; tmp != NULL; tmp = tmp->next) {
|
||||
MODULE_FILE_REC *rec = tmp->data;
|
||||
|
||||
if (strcmp(rec->name, name) == 0)
|
||||
return rec;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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, module, text) \
|
||||
signal_emit("module error", 3, GINT_TO_POINTER(error), module, text)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
#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;
|
||||
|
||||
name = module_get_name(path, &start, &end);
|
||||
if (module_find(name)) {
|
||||
module_error(MODULE_ERROR_ALREADY_LOADED, name, NULL);
|
||||
g_free(name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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++;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_MODULE_HEADER);
|
||||
submodules = g_string_new(NULL);
|
||||
|
||||
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
|
||||
|
@ -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 },
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -34,6 +34,7 @@ perl_fe_sources = \
|
||||
|
||||
noinst_HEADERS = \
|
||||
module.h \
|
||||
module-fe.h \
|
||||
module-formats.h \
|
||||
perl-core.h \
|
||||
perl-common.h \
|
||||
|
4
src/perl/module-fe.h
Normal file
4
src/perl/module-fe.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include "module.h"
|
||||
|
||||
#undef MODULE_NAME
|
||||
#define MODULE_NAME "fe-common/perl"
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user