diff --git a/configure.in b/configure.in index d54b6d6f..a988d2eb 100644 --- a/configure.in +++ b/configure.in @@ -477,19 +477,25 @@ if test "$want_perl" != "no"; then AC_DEFINE(HAVE_STATIC_PERL) dnl * build only static library of perl module - module_lib= - static_lib=libperl_static.la + perl_module_lib= + perl_module_fe_lib= + perl_static_lib=libperl_static.la + perl_static_fe_lib=libfe_perl_static.la PERL_LIBTOOL='$(SHELL) $(top_builddir)/libtool' else dnl * build dynamic library of perl module, dnl * use libtool-shared to prevent creating of dnl * libperl.a - module_lib=libperl.la - static_lib= + perl_module_lib=libperl_core.la + perl_module_fe_lib=libfe_perl.la + perl_static_lib= + perl_static_fe_lib= PERL_LIBTOOL='$(SHELL) $(top_builddir)/libtool-shared' fi - AC_SUBST(module_lib) - AC_SUBST(static_lib) + AC_SUBST(perl_module_lib) + AC_SUBST(perl_static_lib) + AC_SUBST(perl_module_fe_lib) + AC_SUBST(perl_static_fe_lib) AC_SUBST(PERL_LIBTOOL) AC_SUBST(PERL_LDFLAGS) @@ -544,7 +550,7 @@ for c in $CHAT_MODULES; do module_inits="$module_inits ${c}_${s}_init();" module_deinits="${c}_${s}_deinit(); $module_deinits" if test -d $srcdir/src/fe-common/$c/$s; then - FE_COMMON_LIBS="$FE_COMMON_LIBS../fe-common/$c/$s/${LIBDIR}libfe_common_${c}_$s.a " + FE_COMMON_LIBS="$FE_COMMON_LIBS../fe-common/$c/$s/${LIBDIR}libfe_${c}_$s.a " fe_module_inits="$fe_module_inits fe_${c}_${s}_init();" fe_module_deinits="fe_${c}_${s}_deinit(); $fe_module_deinits" fi diff --git a/src/core/modules.c b/src/core/modules.c index d0d27508..3a4c1f3e 100644 --- a/src/core/modules.c +++ b/src/core/modules.c @@ -215,7 +215,7 @@ MODULE_REC *module_find(const char *name) return NULL; } -char *module_get_name(const char *path) +static char *module_get_name(const char *path, int *start, int *end) { const char *name; char *module_name, *ptr; @@ -233,9 +233,13 @@ char *module_get_name(const char *path) name += 3; module_name = g_strdup(name); - ptr = strstr(module_name, ".so"); + ptr = strchr(module_name, '.'); if (ptr != NULL) *ptr = '\0'; + *start = (int) (name-path); + *end = *start + (ptr == NULL ? strlen(name) : + (int) (module_name-ptr)); + return module_name; } @@ -262,6 +266,7 @@ static GModule *module_open(const char *name) } /* module not found from home dir, try global module dir */ + g_free(path); path = g_module_build_path(MODULEDIR, name); } @@ -273,28 +278,27 @@ static GModule *module_open(const char *name) #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) +static int module_load_name(const char *path, const char *name, int silent) { void (*module_init) (void); GModule *gmodule; MODULE_REC *rec; char *initfunc; - if (module_find(name)) { - module_error(MODULE_ERROR_ALREADY_LOADED, name, NULL); - return FALSE; - } - gmodule = module_open(path); if (gmodule == NULL) { - module_error(MODULE_ERROR_LOAD, name, g_module_error()); + 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)) { - module_error(MODULE_ERROR_INVALID, name, NULL); + if (!silent) + module_error(MODULE_ERROR_INVALID, name, NULL); g_module_close(gmodule); g_free(initfunc); return FALSE; @@ -314,21 +318,55 @@ static int module_load_name(const char *path, const char *name) } #endif -int module_load(const char *path) +/* 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 - char *name; - int ret; + 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); - ret = module_load_name(path, name); - g_free(name); + name = module_get_name(path, &start, &end); + if (module_find(name)) { + module_error(MODULE_ERROR_ALREADY_LOADED, name, NULL); + 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; diff --git a/src/core/modules.h b/src/core/modules.h index 12730c53..7a83819f 100644 --- a/src/core/modules.h +++ b/src/core/modules.h @@ -30,7 +30,9 @@ extern GSList *modules; MODULE_REC *module_find(const char *name); -int module_load(const char *path); +/* 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); #define MODULE_CHECK_CAST(object, cast, type_field, id) \ diff --git a/src/fe-common/core/fe-modules.c b/src/fe-common/core/fe-modules.c index 5a33d39e..1ea78f1e 100644 --- a/src/fe-common/core/fe-modules.c +++ b/src/fe-common/core/fe-modules.c @@ -24,6 +24,7 @@ #include "signals.h" #include "commands.h" #include "levels.h" +#include "chat-protocols.h" #include "printtext.h" @@ -72,14 +73,54 @@ static void cmd_load_list(void) printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_MODULE_FOOTER); } +static char **module_prefixes_get(void) +{ + GSList *tmp; + char **list, *name; + int count; + + list = g_new(char *, 2 + 2*g_slist_length(chat_protocols)); + list[0] = "fe"; + + count = 1; + for (tmp = chat_protocols; tmp != NULL; tmp = tmp->next) { + CHAT_PROTOCOL_REC *rec = tmp->data; + + name = g_strdup(rec->name); + g_strdown(name); + + list[count++] = name; + list[count++] = g_strconcat("fe_", name, NULL); + } + list[count] = NULL; + + return list; +} + +static void module_prefixes_free(char **list) +{ + char **pos = list+1; + + while (*pos != NULL) { + g_free(*pos); + pos++; + } + g_free(list); +} + /* SYNTAX: LOAD */ static void cmd_load(const char *data) { + char **module_prefixes; + g_return_if_fail(data != NULL); if (*data == '\0') cmd_load_list(); - else - module_load(data); + else { + module_prefixes = module_prefixes_get(); + module_load(data, module_prefixes); + module_prefixes_free(module_prefixes); + } } /* SYNTAX: UNLOAD */ diff --git a/src/fe-common/irc/dcc/Makefile.am b/src/fe-common/irc/dcc/Makefile.am index dc4a540a..f8ac20ce 100644 --- a/src/fe-common/irc/dcc/Makefile.am +++ b/src/fe-common/irc/dcc/Makefile.am @@ -1,7 +1,7 @@ moduledir = $(libdir)/irssi/modules -module_LTLIBRARIES = libfe_common_irc_dcc.la +module_LTLIBRARIES = libfe_irc_dcc.la -libfe_common_irc_dcc_la_LDFLAGS = -avoid-version +libfe_irc_dcc_la_LDFLAGS = -avoid-version INCLUDES = \ $(GLIB_CFLAGS) \ @@ -13,7 +13,7 @@ INCLUDES = \ -DHELPDIR=\""$(datadir)/irssi/help"\" \ -DSYSCONFDIR=\""$(sysconfdir)"\" -libfe_common_irc_dcc_la_SOURCES = \ +libfe_irc_dcc_la_SOURCES = \ fe-dcc.c \ fe-dcc-chat.c \ fe-dcc-get.c \ diff --git a/src/fe-common/irc/flood/Makefile.am b/src/fe-common/irc/flood/Makefile.am index 575388b3..071d091c 100644 --- a/src/fe-common/irc/flood/Makefile.am +++ b/src/fe-common/irc/flood/Makefile.am @@ -1,7 +1,7 @@ moduledir = $(libdir)/irssi/modules -module_LTLIBRARIES = libfe_common_irc_flood.la +module_LTLIBRARIES = libfe_irc_flood.la -libfe_common_irc_flood_la_LDFLAGS = -avoid-version +libfe_irc_flood_la_LDFLAGS = -avoid-version INCLUDES = \ $(GLIB_CFLAGS) \ @@ -12,7 +12,7 @@ INCLUDES = \ -DHELPDIR=\""$(datadir)/irssi/help"\" \ -DSYSCONFDIR=\""$(sysconfdir)"\" -libfe_common_irc_flood_la_SOURCES = \ +libfe_irc_flood_la_SOURCES = \ fe-flood.c \ module-formats.c diff --git a/src/fe-common/irc/notifylist/Makefile.am b/src/fe-common/irc/notifylist/Makefile.am index 716d3fe4..595c948b 100644 --- a/src/fe-common/irc/notifylist/Makefile.am +++ b/src/fe-common/irc/notifylist/Makefile.am @@ -1,7 +1,7 @@ moduledir = $(libdir)/irssi/modules -module_LTLIBRARIES = libfe_common_irc_notifylist.la +module_LTLIBRARIES = libfe_irc_notifylist.la -libfe_common_irc_notifylist_la_LDFLAGS = -avoid-version +libfe_irc_notifylist_la_LDFLAGS = -avoid-version INCLUDES = \ $(GLIB_CFLAGS) \ @@ -12,7 +12,7 @@ INCLUDES = \ -DHELPDIR=\""$(datadir)/irssi/help"\" \ -DSYSCONFDIR=\""$(sysconfdir)"\" -libfe_common_irc_notifylist_la_SOURCES = \ +libfe_irc_notifylist_la_SOURCES = \ fe-notifylist.c \ module-formats.c diff --git a/src/fe-none/irssi.c b/src/fe-none/irssi.c index bd93edd8..ec729fc2 100644 --- a/src/fe-none/irssi.c +++ b/src/fe-none/irssi.c @@ -24,8 +24,8 @@ #include "core.h" #ifdef HAVE_STATIC_PERL -void perl_init(void); -void perl_deinit(void); +void perl_core_init(void); +void perl_core_deinit(void); #endif void irc_init(void); @@ -64,7 +64,7 @@ void noui_init(void) signal_add("gui exit", (SIGNAL_FUNC) sig_exit); #ifdef HAVE_STATIC_PERL - perl_init(); + perl_core_init(); #endif signal_emit("irssi init finished", 0); } @@ -72,7 +72,7 @@ void noui_init(void) void noui_deinit(void) { #ifdef HAVE_STATIC_PERL - perl_deinit(); + perl_core_deinit(); #endif signal_remove("reload", (SIGNAL_FUNC) sig_reload); diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c index a7aca87e..e9a484ae 100644 --- a/src/fe-text/irssi.c +++ b/src/fe-text/irssi.c @@ -42,8 +42,11 @@ #include #ifdef HAVE_STATIC_PERL -void perl_init(void); -void perl_deinit(void); +void perl_core_init(void); +void perl_core_deinit(void); + +void fe_perl_init(void); +void fe_perl_deinit(void); #endif void irc_init(void); @@ -135,7 +138,8 @@ static void textui_finish_init(void) fe_common_irc_finish_init(); #ifdef HAVE_STATIC_PERL - perl_init(); + perl_core_init(); + fe_perl_init(); #endif signal_emit("irssi init finished", 0); @@ -173,7 +177,8 @@ static void textui_deinit(void) deinit_screen(); #ifdef HAVE_STATIC_PERL - perl_deinit(); + fe_perl_deinit(); + perl_core_deinit(); #endif theme_unregister(); diff --git a/src/perl/Makefile.am b/src/perl/Makefile.am index 906fad79..5c31d908 100644 --- a/src/perl/Makefile.am +++ b/src/perl/Makefile.am @@ -2,11 +2,14 @@ LIBTOOL = $(PERL_LIBTOOL) moduledir = $(libdir)/irssi/modules -module_LTLIBRARIES = $(module_lib) -noinst_LTLIBRARIES = $(static_lib) -EXTRA_LTLIBRARIES = libperl.la libperl_static.la +module_LTLIBRARIES = $(perl_module_lib) $(perl_module_fe_lib) +noinst_LTLIBRARIES = $(perl_static_lib) $(perl_static_fe_lib) +EXTRA_LTLIBRARIES = \ + libperl_core.la libfe_perl.la \ + libperl_static.la libfe_perl_static.la -libperl_la_LDFLAGS = -avoid-version -rpath $(moduledir) +libperl_core_la_LDFLAGS = -avoid-version -rpath $(moduledir) +libfe_perl_la_LDFLAGS = -avoid-version -rpath $(moduledir) perl.c: perl-signals-list.h @@ -22,7 +25,9 @@ perl_sources = \ perl-signals.c \ xsinit.c -libperl_la_DEPENDENCIES = .libs/libperl_orig.a .libs/DynaLoader.a +perl_fe_sources = perl-fe.c + +libperl_core_la_DEPENDENCIES = .libs/libperl_orig.a .libs/DynaLoader.a .libs/libperl_orig.a: if [ ! -d .libs ]; then mkdir .libs; fi @@ -33,12 +38,18 @@ libperl_la_DEPENDENCIES = .libs/libperl_orig.a .libs/DynaLoader.a rm -f .libs/DynaLoader.a $(LN_S) $(DYNALOADER_A) .libs/DynaLoader.a -libperl_la_SOURCES = \ +libperl_core_la_SOURCES = \ $(perl_sources) libperl_static_la_SOURCES = \ $(perl_sources) +libfe_perl_la_SOURCES = \ + $(perl_fe_sources) + +libfe_perl_static_la_SOURCES = \ + $(perl_fe_sources) + perl-signals-list.h: $(top_srcdir)/docs/signals.txt $(srcdir)/get-signals.pl cat $(top_srcdir)/docs/signals.txt | $(perlpath) $(srcdir)/get-signals.pl > perl-signals-list.h @@ -96,4 +107,4 @@ install-exec-local: clean-generic: rm -f common/Irssi.c irc/Irc.c -libperl_la_LIBADD = $(PERL_LDFLAGS) +libperl_core_la_LIBADD = $(PERL_LDFLAGS) diff --git a/src/perl/module.h b/src/perl/module.h index 4e1d9b2f..46fb4548 100644 --- a/src/perl/module.h +++ b/src/perl/module.h @@ -15,3 +15,6 @@ #include "common.h" #define MODULE_NAME "irssi-perl" + +extern GSList *perl_scripts; +extern PerlInterpreter *my_perl; /* must be called my_perl or some perl implementations won't work */ diff --git a/src/perl/perl-common.c b/src/perl/perl-common.c index 7d53446b..bcbbae25 100644 --- a/src/perl/perl-common.c +++ b/src/perl/perl-common.c @@ -568,16 +568,6 @@ static void perl_unregister_protocol(CHAT_PROTOCOL_REC *rec) GINT_TO_POINTER(rec->id)); } -static void sig_protocol_created(CHAT_PROTOCOL_REC *rec) -{ - perl_register_protocol(rec); -} - -static void sig_protocol_destroyed(CHAT_PROTOCOL_REC *rec) -{ - perl_unregister_protocol(rec); -} - void perl_common_init(void) { static PLAIN_OBJECT_INIT_REC core_plains[] = { @@ -602,8 +592,8 @@ void perl_common_init(void) use_protocols = NULL; g_slist_foreach(chat_protocols, (GFunc) perl_register_protocol, NULL); - signal_add("chat protocol created", (SIGNAL_FUNC) sig_protocol_created); - signal_add("chat protocol destroyed", (SIGNAL_FUNC) sig_protocol_destroyed); + signal_add("chat protocol created", (SIGNAL_FUNC) perl_register_protocol); + signal_add("chat protocol destroyed", (SIGNAL_FUNC) perl_unregister_protocol); } void perl_common_deinit(void) @@ -617,6 +607,6 @@ void perl_common_deinit(void) g_slist_foreach(use_protocols, (GFunc) g_free, NULL); g_slist_free(use_protocols); - signal_remove("chat protocol created", (SIGNAL_FUNC) sig_protocol_created); - signal_remove("chat protocol destroyed", (SIGNAL_FUNC) sig_protocol_destroyed); + signal_remove("chat protocol created", (SIGNAL_FUNC) perl_register_protocol); + signal_remove("chat protocol destroyed", (SIGNAL_FUNC) perl_unregister_protocol); } diff --git a/src/perl/perl-common.h b/src/perl/perl-common.h index d01d014b..e6519681 100644 --- a/src/perl/perl-common.h +++ b/src/perl/perl-common.h @@ -1,8 +1,6 @@ #ifndef __PERL_COMMON_H #define __PERL_COMMON_H -extern PerlInterpreter *my_perl; /* must be called my_perl or some perl implementations won't work */ - /* helper defines */ #define new_pv(a) \ (newSVpv((a) == NULL ? "" : (a), (a) == NULL ? 0 : strlen(a))) diff --git a/src/perl/perl-fe.c b/src/perl/perl-fe.c new file mode 100644 index 00000000..f7ace310 --- /dev/null +++ b/src/perl/perl-fe.c @@ -0,0 +1,76 @@ +/* + perl-fe.c : irssi + + Copyright (C) 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 "signals.h" + +#include "fe-common/core/themes.h" +#include "fe-common/core/formats.h" + +#include "perl-common.h" + +static void perl_unregister_theme(const char *package) +{ + FORMAT_REC *formats; + int n; + + formats = g_hash_table_lookup(default_formats, package); + if (formats == NULL) return; + + for (n = 0; formats[n].def != NULL; n++) { + g_free(formats[n].tag); + g_free(formats[n].def); + } + g_free(formats); + theme_unregister_module(package); +} + +static void sig_script_destroy(const char *type, const char *name, + const char *package) +{ + if (strcmp(type, "PERL") == 0) + perl_unregister_theme(package); +} + +static void sig_perl_stop(void) +{ + GSList *tmp; + char *package; + + /* themes */ + for (tmp = perl_scripts; tmp != NULL; tmp = tmp->next) { + package = g_strdup_printf("Irssi::Script::%s", + (char *) tmp->data); + perl_unregister_theme(package); + g_free(package); + } +} + +void fe_perl_init(void) +{ + signal_add("script destroy", (SIGNAL_FUNC) sig_script_destroy); + signal_add("perl stop", (SIGNAL_FUNC) sig_perl_stop); +} + +void fe_perl_deinit(void) +{ + signal_remove("script destroy", (SIGNAL_FUNC) sig_script_destroy); + signal_remove("perl stop", (SIGNAL_FUNC) sig_perl_stop); +} diff --git a/src/perl/perl.c b/src/perl/perl.c index 072737b6..6239b9ed 100644 --- a/src/perl/perl.c +++ b/src/perl/perl.c @@ -1,7 +1,7 @@ /* perl.c : irssi - Copyright (C) 1999 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 @@ -23,9 +23,6 @@ #include "commands.h" #include "misc.h" -#include "fe-common/core/themes.h" -#include "fe-common/core/formats.h" - #include "perl-common.h" #include "perl-signals.h" @@ -43,7 +40,7 @@ typedef struct { } PERL_SOURCE_REC; static GSList *perl_sources; -static GSList *perl_scripts; +GSList *perl_scripts; PerlInterpreter *my_perl; static void perl_source_destroy(PERL_SOURCE_REC *rec) @@ -99,22 +96,6 @@ static void irssi_perl_start(void) perl_common_init(); } -static void perl_unregister_theme(const char *package) -{ - FORMAT_REC *formats; - int n; - - formats = g_hash_table_lookup(default_formats, package); - if (formats == NULL) return; - - for (n = 0; formats[n].def != NULL; n++) { - g_free(formats[n].tag); - g_free(formats[n].def); - } - g_free(formats); - theme_unregister_module(package); -} - static int perl_script_destroy(const char *name) { GSList *tmp, *next, *item; @@ -122,11 +103,14 @@ static int perl_script_destroy(const char *name) int package_len; item = gslist_find_string(perl_scripts, name); - if (item == NULL) return FALSE; + if (item == NULL) + return FALSE; package = g_strdup_printf("Irssi::Script::%s", name); package_len = strlen(package); + signal_emit("script destroy", 3, "PERL", name, package); + perl_signals_package_destroy(package); /* timeouts and input waits */ @@ -138,9 +122,6 @@ static int perl_script_destroy(const char *name) perl_source_destroy(rec); } - /* theme */ - perl_unregister_theme(package); - g_free(package); g_free(item->data); perl_scripts = g_slist_remove(perl_scripts, item->data); @@ -149,23 +130,15 @@ static int perl_script_destroy(const char *name) static void irssi_perl_stop(void) { - GSList *tmp; char *package; + signal_emit("perl stop", 0); perl_signals_stop(); /* timeouts and input waits */ while (perl_sources != NULL) perl_source_destroy(perl_sources->data); - /* themes */ - for (tmp = perl_scripts; tmp != NULL; tmp = tmp->next) { - package = g_strdup_printf("Irssi::Script::%s", - (char *) tmp->data); - perl_unregister_theme(package); - g_free(package); - } - /* scripts list */ g_slist_foreach(perl_scripts, (GFunc) g_free, NULL); g_slist_free(perl_scripts); @@ -221,14 +194,13 @@ static void cmd_run(const char *data) script_fix_name(name); perl_script_destroy(name); - perl_scripts = g_slist_append(perl_scripts, g_strdup(name)); ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(new_pv(fname))); g_free(fname); - XPUSHs(sv_2mortal(new_pv(name))); g_free(name); + XPUSHs(sv_2mortal(new_pv(name))); PUTBACK; retcount = perl_call_pv("Irssi::Load::eval_file", @@ -250,6 +222,10 @@ static void cmd_run(const char *data) PUTBACK; FREETMPS; LEAVE; + + perl_scripts = g_slist_append(perl_scripts, g_strdup(name)); + signal_emit("script new", 2, "PERL", name); + g_free(name); } static void cmd_perl(const char *data) @@ -403,7 +379,7 @@ static void irssi_perl_autorun(void) g_free(path); } -void perl_init(void) +void perl_core_init(void) { perl_scripts = NULL; command_bind("run", NULL, (SIGNAL_FUNC) cmd_run); @@ -417,7 +393,7 @@ void perl_init(void) irssi_perl_autorun(); } -void perl_deinit(void) +void perl_core_deinit(void) { perl_signals_deinit(); irssi_perl_stop();