diff --git a/src/perl/common/Core.xs b/src/perl/common/Core.xs index 8230e77f..10cd3936 100644 --- a/src/perl/common/Core.xs +++ b/src/perl/common/Core.xs @@ -142,6 +142,39 @@ CODE: else perl_signal_add_hash(SvIV(ST(0)), ST(1)); +void +signal_register(...) +PREINIT: + HV *hv; + HE *he; + I32 len, pos; + const char *arr[7]; +CODE: + if (items != 1 || !is_hvref(ST(0))) + croak("Usage: Irssi::signal_register(hash)"); + + hv = hvref(ST(0)); + hv_iterinit(hv); + while ((he = hv_iternext(hv)) != NULL) { + const char *key = hv_iterkey(he, &len); + SV *val = HeVAL(he); + AV *av; + + if (!SvROK(val) || SvTYPE(SvRV(val)) != SVt_PVAV) + croak("not array reference"); + + av = (AV *) SvRV(val); + len = av_len(av)+1; + if (len > 6) len = 6; + for (pos = 0; pos < len; pos++) { + SV **val = av_fetch(av, pos, 0); + arr[pos] = SvPV(*val, PL_na); + } + arr[pos] = NULL; + perl_signal_register(key, arr); + } + + int SIGNAL_PRIORITY_LOW() CODE: diff --git a/src/perl/perl-signals.c b/src/perl/perl-signals.c index 6dcde221..85e537de 100644 --- a/src/perl/perl-signals.c +++ b/src/perl/perl-signals.c @@ -39,6 +39,7 @@ typedef struct { typedef struct { char *signal; char *args[7]; + int dynamic; } PERL_SIGNAL_ARGS_REC; #include "perl-signals-list.h" @@ -388,6 +389,34 @@ void perl_signals_stop(void) signals = NULL; } +static void register_signal_rec(PERL_SIGNAL_ARGS_REC *rec) +{ + if (rec->signal[strlen(rec->signal)-1] == ' ') { + perl_signal_args_partial = + g_slist_append(perl_signal_args_partial, rec); + } else { + int signal_id = signal_get_uniq_id(rec->signal); + g_hash_table_insert(perl_signal_args_hash, + GINT_TO_POINTER(signal_id), rec); + } +} + +void perl_signal_register(const char *signal, const char **args) +{ + PERL_SIGNAL_ARGS_REC *rec; + int i; + + if (perl_signal_args_find(signal_get_uniq_id(signal)) != NULL) + return; + + rec = g_new0(PERL_SIGNAL_ARGS_REC, 1); + for (i = 0; i < 6 && args[i] != NULL; i++) + rec->args[i] = g_strdup(args[i]); + rec->dynamic = TRUE; + rec->signal = g_strdup(signal); + register_signal_rec(rec); +} + void perl_signals_init(void) { int n; @@ -396,23 +425,35 @@ void perl_signals_init(void) (GCompareFunc) g_direct_equal); perl_signal_args_partial = NULL; - for (n = 0; perl_signal_args[n].signal != NULL; n++) { - PERL_SIGNAL_ARGS_REC *rec = &perl_signal_args[n]; + for (n = 0; perl_signal_args[n].signal != NULL; n++) + register_signal_rec(&perl_signal_args[n]); +} - if (rec->signal[strlen(rec->signal)-1] == ' ') { - perl_signal_args_partial = - g_slist_append(perl_signal_args_partial, rec); - } else { - int signal_id = signal_get_uniq_id(rec->signal); - g_hash_table_insert(perl_signal_args_hash, - GINT_TO_POINTER(signal_id), - rec); - } - } +static void signal_args_free(PERL_SIGNAL_ARGS_REC *rec) +{ + int i; + + if (!rec->dynamic) + return; + + for (i = 0; i < 6 && rec->args[i] != NULL; i++) + g_free(rec->args[i]); + g_free(rec->signal); + g_free(rec); +} + +static void signal_args_hash_free(void *key, PERL_SIGNAL_ARGS_REC *rec) +{ + signal_args_free(rec); } void perl_signals_deinit(void) { - g_slist_free(perl_signal_args_partial); + g_slist_foreach(perl_signal_args_partial, + (GFunc) signal_args_free, NULL); + g_slist_free(perl_signal_args_partial); + + g_hash_table_foreach(perl_signal_args_hash, + (GHFunc) signal_args_hash_free, NULL); g_hash_table_destroy(perl_signal_args_hash); } diff --git a/src/perl/perl-signals.h b/src/perl/perl-signals.h index 60e6636e..f0b8e442 100644 --- a/src/perl/perl-signals.h +++ b/src/perl/perl-signals.h @@ -21,6 +21,8 @@ void perl_command_unbind(const char *cmd, SV *func); void perl_command_runsub(const char *cmd, const char *data, SERVER_REC *server, WI_ITEM_REC *item); +void perl_signal_register(const char *signal, const char **args); + void perl_signals_start(void); void perl_signals_stop(void);