diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/perl/common/Core.xs | 63 | ||||
-rw-r--r-- | src/perl/perl-signals.c | 169 | ||||
-rw-r--r-- | src/perl/perl-signals.h | 3 |
3 files changed, 190 insertions, 45 deletions
diff --git a/src/perl/common/Core.xs b/src/perl/common/Core.xs index c1e526bb..4032340a 100644 --- a/src/perl/common/Core.xs +++ b/src/perl/common/Core.xs @@ -65,6 +65,15 @@ static void add_tuple(gpointer key_, gpointer value_, gpointer user_data) hv_store(hash, key, strlen(key), new_pv(value), 0); } +static void wrap_signal_emit(void *signal, void **p) { + signal_emit(signal, 6, p[0], p[1], p[2], p[3], p[4], p[5]); +} + +static void wrap_signal_continue(void *dummy, void **p) { + (void)dummy; + signal_continue(6, p[0], p[1], p[2], p[3], p[4], p[5]); +} + MODULE = Irssi::Core PACKAGE = Irssi PROTOTYPES: ENABLE @@ -72,44 +81,34 @@ void signal_emit(signal, ...) char *signal CODE: - void *p[SIGNAL_MAX_ARGUMENTS]; - int n; - - memset(p, 0, sizeof(p)); - for (n = 1; n < items && n < SIGNAL_MAX_ARGUMENTS+1; n++) { - if (SvPOKp(ST(n))) - p[n-1] = SvPV(ST(n), PL_na); - else if (irssi_is_ref_object(ST(n))) - p[n-1] = irssi_ref_object(ST(n)); - else if (SvROK(ST(n))) - p[n-1] = (void *) SvIV((SV*)SvRV(ST(n))); - else if (SvIOK(ST(n))) - p[n-1] = (void *)SvIV(ST(n)); - else - p[n-1] = NULL; + int signal_id; + SV *args[SIGNAL_MAX_ARGUMENTS]; + int n, used; + + signal_id = signal_get_uniq_id(signal); + used = items - 1; + if (used > SIGNAL_MAX_ARGUMENTS) { + used = SIGNAL_MAX_ARGUMENTS; + } + for (n = 0; n < used; ++n) { + args[n] = ST(n + 1); } - signal_emit(signal, items-1, p[0], p[1], p[2], p[3], p[4], p[5]); + perl_signal_args_to_c(wrap_signal_emit, signal, signal_id, args, used); void signal_continue(...) CODE: - void *p[SIGNAL_MAX_ARGUMENTS]; - int n; - - memset(p, 0, sizeof(p)); - for (n = 0; n < items && n < SIGNAL_MAX_ARGUMENTS; n++) { - if (SvPOKp(ST(n))) - p[n] = SvPV(ST(n), PL_na); - else if (irssi_is_ref_object(ST(n))) - p[n] = irssi_ref_object(ST(n)); - else if (SvROK(ST(n))) - p[n] = (void *) SvIV((SV*)SvRV(ST(n))); - else if (SvIOK(ST(n))) - p[n] = (void *) SvIV(ST(n)); - else - p[n] = NULL; + SV *args[SIGNAL_MAX_ARGUMENTS]; + int n, used; + + used = items; + if (used > SIGNAL_MAX_ARGUMENTS) { + used = SIGNAL_MAX_ARGUMENTS; + } + for (n = 0; n < used; ++n) { + args[n] = ST(n); } - signal_continue(items, p[0], p[1], p[2], p[3], p[4], p[5]); + perl_signal_args_to_c(wrap_signal_continue, NULL, signal_get_emitted_id(), args, used); void signal_add(...) diff --git a/src/perl/perl-signals.c b/src/perl/perl-signals.c index 65a39e62..4986c12c 100644 --- a/src/perl/perl-signals.c +++ b/src/perl/perl-signals.c @@ -70,6 +70,150 @@ static PERL_SIGNAL_ARGS_REC *perl_signal_args_find(int signal_id) return NULL; } +void perl_signal_args_to_c( + void (*callback)(void *, void **), void *cb_arg, + int signal_id, SV **args, size_t n_args) +{ + union { + int v_int; + unsigned long v_ulong; + GSList *v_gslist; + GList *v_glist; + } saved_args[SIGNAL_MAX_ARGUMENTS]; + void *p[SIGNAL_MAX_ARGUMENTS]; + PERL_SIGNAL_ARGS_REC *rec; + size_t n; + + if (!(rec = perl_signal_args_find(signal_id))) { + const char *name = signal_get_id_str(signal_id); + if (!name) { + croak("%d is not a known signal id", signal_id); + } + croak("\"%s\" is not a registered signal", name); + } + + for (n = 0; n < SIGNAL_MAX_ARGUMENTS && n < n_args && rec->args[n] != NULL; ++n) { + void *c_arg; + SV *arg = args[n]; + + if (!SvOK(arg)) { + c_arg = NULL; + } else if (strcmp(rec->args[n], "string") == 0) { + c_arg = SvPV_nolen(arg); + } else if (strcmp(rec->args[n], "int") == 0) { + c_arg = (void *)SvIV(arg); + } else if (strcmp(rec->args[n], "ulongptr") == 0) { + saved_args[n].v_ulong = SvUV(arg); + c_arg = &saved_args[n].v_ulong; + } else if (strcmp(rec->args[n], "intptr") == 0) { + saved_args[n].v_int = SvIV(SvRV(arg)); + c_arg = &saved_args[n].v_int; + } else if (strncmp(rec->args[n], "glistptr_", 9) == 0) { + GList *gl; + int is_str; + AV *av; + SV *t; + int count; + + t = SvRV(arg); + if (SvTYPE(t) != SVt_PVAV) { + croak("Not an ARRAY reference"); + } + av = (AV *)t; + + is_str = strcmp(rec->args[n]+9, "char*") == 0; + + gl = NULL; + count = av_len(av) + 1; + while (count-- > 0) { + SV **px = av_fetch(av, count, 0); + SV *x = px ? *px : NULL; + gl = g_list_prepend( + gl, + x == NULL ? NULL : + is_str ? g_strdup(SvPV_nolen(x)) : + irssi_ref_object(x) + ); + } + saved_args[n].v_glist = gl; + c_arg = &saved_args[n].v_glist; + } else if (strncmp(rec->args[n], "gslist_", 7) == 0) { + GSList *gsl; + AV *av; + SV *t; + int count; + + t = SvRV(arg); + if (SvTYPE(t) != SVt_PVAV) { + croak("Not an ARRAY reference"); + } + av = (AV *)t; + + gsl = NULL; + count = av_len(av) + 1; + while (count-- > 0) { + SV **x = av_fetch(av, count, 0); + gsl = g_slist_prepend( + gsl, + x == NULL ? NULL : + irssi_ref_object(*x) + ); + } + c_arg = saved_args[n].v_gslist = gsl; + } else { + c_arg = irssi_ref_object(arg); + } + + p[n] = c_arg; + } + + for (; n < SIGNAL_MAX_ARGUMENTS; ++n) { + p[n] = NULL; + } + + callback(cb_arg, p); + + for (n = 0; n < SIGNAL_MAX_ARGUMENTS && n < n_args && rec->args[n] != NULL; ++n) { + SV *arg = args[n]; + + if (!SvOK(arg)) { + continue; + } + + if (strcmp(rec->args[n], "intptr") == 0) { + SV *t = SvRV(arg); + SvIOK_only(t); + SvIV_set(t, saved_args[n].v_int); + } else if (strncmp(rec->args[n], "gslist_", 7) == 0) { + g_slist_free(saved_args[n].v_gslist); + } else if (strncmp(rec->args[n], "glistptr_", 9) == 0) { + int is_iobject, is_str; + AV *av; + GList *gl, *tmp; + + is_iobject = strcmp(rec->args[n]+9, "iobject") == 0; + is_str = strcmp(rec->args[n]+9, "char*") == 0; + + av = (AV *)SvRV(arg); + av_clear(av); + + gl = saved_args[n].v_glist; + for (tmp = gl; tmp != NULL; tmp = tmp->next) { + av_push(av, + is_iobject ? iobject_bless((SERVER_REC *)tmp->data) : + is_str ? new_pv(tmp->data) : + irssi_bless_plain(rec->args[n]+9, tmp->data) + ); + } + + if (is_str) { + g_list_foreach(gl, (GFunc)g_free, NULL); + } + g_list_free(gl); + } + } +} + static void perl_call_signal(PERL_SCRIPT_REC *script, SV *func, int signal_id, gconstpointer *args) { @@ -95,15 +239,7 @@ static void perl_call_signal(PERL_SCRIPT_REC *script, SV *func, rec != NULL && rec->args[n] != NULL; n++) { arg = (void *) args[n]; - if (strcmp(rec->args[n], "string") == 0) - perlarg = new_pv(arg); - else if (strcmp(rec->args[n], "int") == 0) - perlarg = newSViv((IV)arg); - else if (strcmp(rec->args[n], "ulongptr") == 0) - perlarg = newSViv(*(unsigned long *) arg); - else if (strcmp(rec->args[n], "intptr") == 0) - saved_args[n] = perlarg = newRV_noinc(newSViv(*(int *) arg)); - else if (strncmp(rec->args[n], "glistptr_", 9) == 0) { + if (strncmp(rec->args[n], "glistptr_", 9) == 0) { /* pointer to linked list - push as AV */ GList *tmp, **ptr; int is_iobject, is_str; @@ -121,7 +257,17 @@ static void perl_call_signal(PERL_SCRIPT_REC *script, SV *func, } saved_args[n] = perlarg = newRV_noinc((SV *) av); - } else if (strncmp(rec->args[n], "gslist_", 7) == 0) { + } else if (strcmp(rec->args[n], "int") == 0) + perlarg = newSViv((IV)arg); + else if (arg == NULL) + perlarg = &PL_sv_undef; + else if (strcmp(rec->args[n], "string") == 0) + perlarg = new_pv(arg); + else if (strcmp(rec->args[n], "ulongptr") == 0) + perlarg = newSViv(*(unsigned long *) arg); + else if (strcmp(rec->args[n], "intptr") == 0) + saved_args[n] = perlarg = newRV_noinc(newSViv(*(int *) arg)); + else if (strncmp(rec->args[n], "gslist_", 7) == 0) { /* linked list - push as AV */ GSList *tmp; int is_iobject; @@ -135,9 +281,6 @@ static void perl_call_signal(PERL_SCRIPT_REC *script, SV *func, } perlarg = newRV_noinc((SV *) av); - } else if (arg == NULL) { - /* don't bless NULL arguments */ - perlarg = newSViv(0); } else if (strcmp(rec->args[n], "iobject") == 0) { /* "irssi object" - any struct that has "int type; int chat_type" as it's first diff --git a/src/perl/perl-signals.h b/src/perl/perl-signals.h index f0b8e442..e2c3db61 100644 --- a/src/perl/perl-signals.h +++ b/src/perl/perl-signals.h @@ -1,6 +1,9 @@ #ifndef __PERL_SIGNALS_H #define __PERL_SIGNALS_H +void perl_signal_args_to_c(void (*callback)(void *, void **), void *cb_arg, + int signal_id, SV **args, size_t n_args); + void perl_signal_add_full(const char *signal, SV *func, int priority); void perl_signal_remove(const char *signal, SV *func); |