summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/perl/common/Core.xs63
-rw-r--r--src/perl/perl-signals.c169
-rw-r--r--src/perl/perl-signals.h3
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);