Added missing.
authorPekka Riikonen <priikone@silcnet.org>
Thu, 31 Oct 2002 17:48:41 +0000 (17:48 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 31 Oct 2002 17:48:41 +0000 (17:48 +0000)
apps/irssi/src/perl/common/Expando.xs [new file with mode: 0644]

diff --git a/apps/irssi/src/perl/common/Expando.xs b/apps/irssi/src/perl/common/Expando.xs
new file mode 100644 (file)
index 0000000..d3a232f
--- /dev/null
@@ -0,0 +1,170 @@
+#include "module.h"
+#include "expandos.h"
+
+typedef struct {
+       PERL_SCRIPT_REC *script;
+       SV *func;
+} PerlExpando;
+
+static GHashTable *perl_expando_defs;
+
+static char *sig_perl_expando(SERVER_REC *server, void *item, int *free_ret);
+
+static int check_expando_destroy(char *key, PerlExpando *rec,
+                                PERL_SCRIPT_REC *script)
+{
+       if (rec->script == script) {
+                expando_destroy(key, sig_perl_expando);
+               SvREFCNT_dec(rec->func);
+               g_free(key);
+               g_free(rec);
+               return TRUE;
+       }
+
+        return FALSE;
+}
+
+static void script_unregister_expandos(PERL_SCRIPT_REC *script)
+{
+       g_hash_table_foreach_remove(perl_expando_defs,
+                                   (GHRFunc) check_expando_destroy, script);
+}
+
+void perl_expando_init(void)
+{
+       perl_expando_defs = g_hash_table_new((GHashFunc) g_str_hash,
+                                            (GCompareFunc) g_str_equal);
+       signal_add("script destroyed", (SIGNAL_FUNC) script_unregister_expandos);
+}
+
+static void expando_def_destroy(char *key, PerlExpando *rec)
+{
+       SvREFCNT_dec(rec->func);
+       g_free(key);
+       g_free(rec);
+}
+
+void perl_expando_deinit(void)
+{
+       signal_remove("script destroyed", (SIGNAL_FUNC) script_unregister_expandos);
+
+       g_hash_table_foreach(perl_expando_defs,
+                            (GHFunc) expando_def_destroy, NULL);
+       g_hash_table_destroy(perl_expando_defs);
+}
+
+static char *perl_expando_event(PerlExpando *rec, SERVER_REC *server,
+                               WI_ITEM_REC *item, int *free_ret)
+{
+       dSP;
+       char *ret;
+       int retcount;
+
+       ENTER;
+       SAVETMPS;
+
+       PUSHMARK(SP);
+       XPUSHs(sv_2mortal(iobject_bless(server)));
+       XPUSHs(sv_2mortal(iobject_bless(item)));
+       PUTBACK;
+
+       retcount = perl_call_sv(rec->func, G_EVAL|G_SCALAR);
+       SPAGAIN;
+
+       if (SvTRUE(ERRSV)) {
+               /* make sure we don't get back here */
+               if (rec->script != NULL)
+                       script_unregister_expandos(rec->script);
+
+               signal_emit("script error", 2, rec->script, SvPV(ERRSV, PL_na));
+               ret = NULL;
+       } else if (retcount > 0) {
+               ret = g_strdup(POPp);
+               *free_ret = TRUE;
+       }
+
+       PUTBACK;
+       FREETMPS;
+       LEAVE;
+
+       return ret;
+}
+
+static char *sig_perl_expando(SERVER_REC *server, void *item, int *free_ret)
+{
+        PerlExpando *rec;
+
+       rec = g_hash_table_lookup(perl_expando_defs, current_expando);
+       if (rec != NULL)
+               return perl_expando_event(rec, server, item, free_ret);
+       return NULL;
+}
+
+void expando_signals_add_hash(const char *key, SV *signals)
+{
+       HV *hv;
+        HE *he;
+       I32 len;
+       const char *argstr;
+       ExpandoArg arg;
+
+       if (!is_hvref(signals)) {
+               croak("Usage: Irssi::expando_create(key, func, hash)");
+               return;
+       }
+
+        hv = hvref(signals);
+       hv_iterinit(hv);
+       while ((he = hv_iternext(hv)) != NULL) {
+               SV *argsv = HeVAL(he);
+               argstr = SvPV(argsv, PL_na);
+
+               if (strcasecmp(argstr, "none") == 0)
+                       arg = EXPANDO_ARG_NONE;
+               else if (strcasecmp(argstr, "server") == 0)
+                       arg = EXPANDO_ARG_SERVER;
+               else if (strcasecmp(argstr, "window") == 0)
+                       arg = EXPANDO_ARG_WINDOW;
+               else if (strcasecmp(argstr, "windowitem") == 0)
+                       arg = EXPANDO_ARG_WINDOW_ITEM;
+               else if (strcasecmp(argstr, "never") == 0)
+                       arg = EXPANDO_NEVER;
+               else {
+                       croak("Unknown signal type: %s", argstr);
+                       break;
+               }
+               expando_add_signal(key, hv_iterkey(he, &len), arg);
+       }
+}
+
+MODULE = Irssi::Expando  PACKAGE = Irssi
+PROTOTYPES: ENABLE
+
+void
+expando_create(key, func, signals)
+       char *key
+       SV *func
+       SV *signals
+PREINIT:
+        PerlExpando *rec;
+CODE:
+       rec = g_new0(PerlExpando, 1);
+       rec->script = perl_script_find_package(perl_get_package());
+        rec->func = perl_func_sv_inc(func, perl_get_package());
+
+       expando_create(key, sig_perl_expando, NULL);
+       g_hash_table_insert(perl_expando_defs, g_strdup(key), rec);
+        expando_signals_add_hash(key, signals);
+
+void
+expando_destroy(name)
+       char *name
+PREINIT:
+        gpointer key, value;
+CODE:
+       if (g_hash_table_lookup_extended(perl_expando_defs, name, &key, &value)) {
+                g_hash_table_remove(perl_expando_defs, name);
+               g_free(key);
+               SvREFCNT_dec((SV *) value);
+       }
+       expando_destroy(name, sig_perl_expando);