Added SILC Thread Queue API
[crypto.git] / apps / irssi / src / perl / common / Expando.xs
1 #include "module.h"
2 #include "expandos.h"
3
4 typedef struct {
5         PERL_SCRIPT_REC *script;
6         SV *func;
7 } PerlExpando;
8
9 static GHashTable *perl_expando_defs;
10
11 static char *sig_perl_expando(SERVER_REC *server, void *item, int *free_ret);
12
13 static int check_expando_destroy(char *key, PerlExpando *rec,
14                                  PERL_SCRIPT_REC *script)
15 {
16         if (rec->script == script) {
17                 expando_destroy(key, sig_perl_expando);
18                 SvREFCNT_dec(rec->func);
19                 g_free(key);
20                 g_free(rec);
21                 return TRUE;
22         }
23
24         return FALSE;
25 }
26
27 static void script_unregister_expandos(PERL_SCRIPT_REC *script)
28 {
29         g_hash_table_foreach_remove(perl_expando_defs,
30                                     (GHRFunc) check_expando_destroy, script);
31 }
32
33 void perl_expando_init(void)
34 {
35         perl_expando_defs = g_hash_table_new((GHashFunc) g_str_hash,
36                                              (GCompareFunc) g_str_equal);
37         signal_add("script destroyed", (SIGNAL_FUNC) script_unregister_expandos);
38 }
39
40 static void expando_def_destroy(char *key, PerlExpando *rec)
41 {
42         SvREFCNT_dec(rec->func);
43         g_free(key);
44         g_free(rec);
45 }
46
47 void perl_expando_deinit(void)
48 {
49         signal_remove("script destroyed", (SIGNAL_FUNC) script_unregister_expandos);
50
51         g_hash_table_foreach(perl_expando_defs,
52                              (GHFunc) expando_def_destroy, NULL);
53         g_hash_table_destroy(perl_expando_defs);
54 }
55
56 static char *perl_expando_event(PerlExpando *rec, SERVER_REC *server,
57                                 WI_ITEM_REC *item, int *free_ret)
58 {
59         dSP;
60         char *ret;
61         int retcount;
62
63         ENTER;
64         SAVETMPS;
65
66         PUSHMARK(SP);
67         XPUSHs(sv_2mortal(iobject_bless(server)));
68         XPUSHs(sv_2mortal(iobject_bless(item)));
69         PUTBACK;
70
71         retcount = perl_call_sv(rec->func, G_EVAL|G_SCALAR);
72         SPAGAIN;
73
74         ret = NULL;
75         if (SvTRUE(ERRSV)) {
76                 /* make sure we don't get back here */
77                 if (rec->script != NULL)
78                         script_unregister_expandos(rec->script);
79
80                 signal_emit("script error", 2, rec->script, SvPV(ERRSV, PL_na));
81         } else if (retcount > 0) {
82                 ret = g_strdup(POPp);
83                 *free_ret = TRUE;
84         }
85
86         PUTBACK;
87         FREETMPS;
88         LEAVE;
89
90         return ret;
91 }
92
93 static char *sig_perl_expando(SERVER_REC *server, void *item, int *free_ret)
94 {
95         PerlExpando *rec;
96
97         rec = g_hash_table_lookup(perl_expando_defs, current_expando);
98         if (rec != NULL)
99                 return perl_expando_event(rec, server, item, free_ret);
100         return NULL;
101 }
102
103 void expando_signals_add_hash(const char *key, SV *signals)
104 {
105         HV *hv;
106         HE *he;
107         I32 len;
108         const char *argstr;
109         ExpandoArg arg;
110
111         if (!is_hvref(signals)) {
112                 croak("Usage: Irssi::expando_create(key, func, hash)");
113                 return;
114         }
115
116         hv = hvref(signals);
117         hv_iterinit(hv);
118         while ((he = hv_iternext(hv)) != NULL) {
119                 SV *argsv = HeVAL(he);
120                 argstr = SvPV(argsv, PL_na);
121
122                 if (strcasecmp(argstr, "none") == 0)
123                         arg = EXPANDO_ARG_NONE;
124                 else if (strcasecmp(argstr, "server") == 0)
125                         arg = EXPANDO_ARG_SERVER;
126                 else if (strcasecmp(argstr, "window") == 0)
127                         arg = EXPANDO_ARG_WINDOW;
128                 else if (strcasecmp(argstr, "windowitem") == 0)
129                         arg = EXPANDO_ARG_WINDOW_ITEM;
130                 else if (strcasecmp(argstr, "never") == 0)
131                         arg = EXPANDO_NEVER;
132                 else {
133                         croak("Unknown signal type: %s", argstr);
134                         break;
135                 }
136                 expando_add_signal(key, hv_iterkey(he, &len), arg);
137         }
138 }
139
140 MODULE = Irssi::Expando  PACKAGE = Irssi
141 PROTOTYPES: ENABLE
142
143 void
144 expando_create(key, func, signals)
145         char *key
146         SV *func
147         SV *signals
148 PREINIT:
149         PerlExpando *rec;
150 CODE:
151         rec = g_new0(PerlExpando, 1);
152         rec->script = perl_script_find_package(perl_get_package());
153         rec->func = perl_func_sv_inc(func, perl_get_package());
154
155         expando_create(key, sig_perl_expando, NULL);
156         g_hash_table_insert(perl_expando_defs, g_strdup(key), rec);
157         expando_signals_add_hash(key, signals);
158
159 void
160 expando_destroy(name)
161         char *name
162 PREINIT:
163         gpointer key, value;
164 CODE:
165         if (g_hash_table_lookup_extended(perl_expando_defs, name, &key, &value)) {
166                 g_hash_table_remove(perl_expando_defs, name);
167                 g_free(key);
168                 SvREFCNT_dec((SV *) value);
169         }
170         expando_destroy(name, sig_perl_expando);