+++ /dev/null
-/*
- 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"
-#include "misc.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 (*path == '~' || 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.. */
- if (prefixes != NULL) {
- 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 > 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, int *found)
-{
- struct stat statbuf;
- GModule *module;
- char *path, *str;
-
- if (g_path_is_absolute(name) || *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);
- *found = TRUE;
- return module;
- }
-
- /* module not found from home dir, try global module dir */
- g_free(path);
- path = g_module_build_path(MODULEDIR, name);
- }
-
- *found = stat(path, &statbuf) == 0;
- module = g_module_open(path, (GModuleFlags) 0);
- g_free(path);
- return module;
-}
-
-static char *module_get_func(const char *rootmodule, const char *submodule,
- const char *function)
-{
- if (strcmp(submodule, "core") == 0)
- return g_strconcat(rootmodule, "_core_", function, NULL);
-
- if (strcmp(rootmodule, submodule) == 0)
- return g_strconcat(rootmodule, "_", function, NULL);
-
- return g_strconcat(submodule, "_", rootmodule, "_", function, NULL);
-}
-
-#define module_error(error, text, rootmodule, submodule) \
- signal_emit("module error", 4, GINT_TO_POINTER(error), text, \
- rootmodule, submodule)
-
-/* Returns 1 if ok, 0 if error in module and
- -1 if module wasn't found */
-static int module_load_name(const char *path, const char *rootmodule,
- const char *submodule, int silent)
-{
- void (*module_init) (void);
- void (*module_deinit) (void);
- GModule *gmodule;
- MODULE_REC *module;
- MODULE_FILE_REC *rec;
- gpointer value1, value2;
- char *initfunc, *deinitfunc;
- int found;
-
- gmodule = module_open(path, &found);
- if (gmodule == NULL) {
- if (!silent || found) {
- module_error(MODULE_ERROR_LOAD, g_module_error(),
- rootmodule, submodule);
- }
- return found ? 0 : -1;
- }
-
- /* get the module's init() and deinit() functions */
- initfunc = module_get_func(rootmodule, submodule, "init");
- deinitfunc = module_get_func(rootmodule, submodule, "deinit");
- found = g_module_symbol(gmodule, initfunc, &value1) &&
- g_module_symbol(gmodule, deinitfunc, &value2);
- g_free(initfunc);
- g_free(deinitfunc);
-
- module_init = value1;
- module_deinit = value2;
-
- if (!found) {
- module_error(MODULE_ERROR_INVALID, NULL,
- rootmodule, submodule);
- g_module_close(gmodule);
- return 0;
- }
-
- /* 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 :
- strcmp(rootmodule, submodule) == 0 ?
- module_file_find(module, "core") :
- 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 0;
- }
-
- rec->module_deinit = module_deinit;
- rec->gmodule = gmodule;
- rec->initialized = TRUE;
-
- settings_check_module(rec->defined_module_name);
-
- signal_emit("module loaded", 2, rec->root, rec);
- return 1;
-}
-
-static int module_load_prefixes(const char *path, const char *module,
- int start, int end, char **prefixes)
-{
- GString *realpath;
- int status, ok;
-
- /* load module_core */
- realpath = g_string_new(path);
- g_string_insert(realpath, end, "_core");
-
- /* Don't print the error message the first time, since the module
- may not have the core part at all. */
- status = module_load_name(realpath->str, module, "core", TRUE);
- ok = status > 0;
-
- 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_c(realpath, start, '_');
- g_string_insert(realpath, start, *prefixes);
-
- status = module_load_name(realpath->str, module,
- *prefixes, TRUE);
- if (status > 0)
- ok = TRUE;
-
- prefixes++;
- }
- }
-
- if (!ok) {
- /* error loading module, print the error message */
- g_string_assign(realpath, path);
- g_string_insert(realpath, end, "_core");
- module_load_name(realpath->str, module, "core", FALSE);
- }
-
- 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 status, 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;
- status = module_load_name(path, rootmodule, submodule, try_prefixes);
- if (status == -1 && try_prefixes) {
- /* nope, try loading the module_core,
- fe_module, etc. */
- status = module_load_prefixes(path, rootmodule,
- start, end, prefixes);
- }
-
- return status > 0;
-}
-
-/* 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 *exppath, *name, *submodule, *rootmodule;
- int start, end, ret;
-
- g_return_val_if_fail(path != NULL, FALSE);
-
- exppath = convert_home(path);
-
- name = module_get_name(exppath, &start, &end);
- rootmodule = module_get_root(name, prefixes);
- submodule = module_get_sub(name, rootmodule);
- g_free(name);
-
- ret = module_load_full(exppath, rootmodule, submodule,
- start, end, prefixes);
-
- g_free(rootmodule);
- g_free(submodule);
- g_free(exppath);
- return ret;
-}
-
-/* Load a sub module. */
-int module_load_sub(const char *path, const char *submodule, char **prefixes)
-{
- GString *full_path;
- char *exppath, *name, *rootmodule;
- int start, end, ret;
-
- g_return_val_if_fail(path != NULL, FALSE);
- g_return_val_if_fail(submodule != NULL, FALSE);
-
- exppath = convert_home(path);
-
- name = module_get_name(exppath, &start, &end);
- rootmodule = module_get_root(name, prefixes);
- g_free(name);
-
- full_path = g_string_new(exppath);
- 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);
- g_free(exppath);
- return ret;
-}
-
-static void module_file_deinit_gmodule(MODULE_FILE_REC *file)
-{
- /* call the module's deinit() function */
- if (file->module_deinit != NULL)
- file->module_deinit();
-
- 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);
-}
-
-#else /* !HAVE_GMODULE - modules are not supported */
-
-int module_load(const char *path, char **prefixes)
-{
- return FALSE;
-}
-
-#endif
-
-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);
-
-#ifdef HAVE_GMODULE
- if (file->gmodule != NULL)
- module_file_deinit_gmodule(file);
-#endif
-
- 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->name);
- g_free(module);
-}