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