Mercurial > pidgin
comparison src/perl.c @ 3551:cd938f18f3f8
[gaim-migrate @ 3626]
In the interest of continued progress, I pulled what's usable out of my
development tree and am committing it.
Here, we have gotten rid of the plugins dialog and perl menu under Tools and
put them both in preferences. Perl scripts now work like plugins--you have
to load them explicitly (it will probe $prefix/lib/gaim and $HOME/.gaim for
them) and you can unload them (although right now, this is entirely unreliable)
Oh, and I broke all your perl scripts. Sorry about that. Don't try fixing
them yet, though--I'm gonna make unloading single scripts more reliable
tommorow.
I should also finish Phase Two tommorow as well.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Thu, 26 Sep 2002 07:37:52 +0000 |
parents | 6b0cb60162f4 |
children | 4d70a24c0fd6 |
comparison
equal
deleted
inserted
replaced
3550:e9b2003ee562 | 3551:cd938f18f3f8 |
---|---|
71 }; | 71 }; |
72 | 72 |
73 struct _perl_event_handlers { | 73 struct _perl_event_handlers { |
74 char *event_type; | 74 char *event_type; |
75 char *handler_name; | 75 char *handler_name; |
76 char *handle; | |
76 }; | 77 }; |
77 | 78 |
78 struct _perl_timeout_handlers { | 79 struct _perl_timeout_handlers { |
79 char *handler_name; | 80 char *handler_name; |
80 char *handler_args; | 81 char *handler_args; |
81 gint iotag; | 82 gint iotag; |
83 char *handle; | |
82 }; | 84 }; |
83 | 85 |
84 static GList *perl_list = NULL; /* should probably extern this at some point */ | 86 static GList *perl_list = NULL; /* should probably extern this at some point */ |
85 static GList *perl_timeout_handlers = NULL; | 87 static GList *perl_timeout_handlers = NULL; |
86 static GList *perl_event_handlers = NULL; | 88 static GList *perl_event_handlers = NULL; |
113 XS(XS_GAIM_play_sound); /*play a sound*/ | 115 XS(XS_GAIM_play_sound); /*play a sound*/ |
114 | 116 |
115 void xs_init() | 117 void xs_init() |
116 { | 118 { |
117 char *file = __FILE__; | 119 char *file = __FILE__; |
120 | |
121 /* This one allows dynamic loading of perl modules in perl | |
122 scripts by the 'use perlmod;' construction*/ | |
118 newXS ("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); | 123 newXS ("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); |
124 | |
125 /* load up all the custom Gaim perl functions */ | |
126 newXS ("GAIM::register", XS_GAIM_register, "GAIM"); | |
127 newXS ("GAIM::get_info", XS_GAIM_get_info, "GAIM"); | |
128 newXS ("GAIM::print", XS_GAIM_print, "GAIM"); | |
129 newXS ("GAIM::write_to_conv", XS_GAIM_write_to_conv, "GAIM"); | |
130 | |
131 newXS ("GAIM::buddy_list", XS_GAIM_buddy_list, "GAIM"); | |
132 newXS ("GAIM::online_list", XS_GAIM_online_list, "GAIM"); | |
133 | |
134 newXS ("GAIM::command", XS_GAIM_command, "GAIM"); | |
135 newXS ("GAIM::user_info", XS_GAIM_user_info, "GAIM"); | |
136 newXS ("GAIM::print_to_conv", XS_GAIM_print_to_conv, "GAIM"); | |
137 newXS ("GAIM::print_to_chat", XS_GAIM_print_to_chat, "GAIM"); | |
138 newXS ("GAIM::serv_send_im", XS_GAIM_serv_send_im, "GAIM"); | |
139 | |
140 newXS ("GAIM::add_event_handler", XS_GAIM_add_event_handler, "GAIM"); | |
141 newXS ("GAIM::remove_event_handler", XS_GAIM_remove_event_handler, "GAIM"); | |
142 newXS ("GAIM::add_timeout_handler", XS_GAIM_add_timeout_handler, "GAIM"); | |
143 | |
144 newXS ("GAIM::play_sound", XS_GAIM_play_sound, "GAIM"); | |
119 } | 145 } |
120 | 146 |
121 static char *escape_quotes(char *buf) | 147 static char *escape_quotes(char *buf) |
122 { | 148 { |
123 static char *tmp_buf = NULL; | 149 static char *tmp_buf = NULL; |
134 *j = '\0'; | 160 *j = '\0'; |
135 | 161 |
136 return (tmp_buf); | 162 return (tmp_buf); |
137 } | 163 } |
138 | 164 |
139 static SV *execute_perl(char *function, char *args) | 165 /* |
140 { | 166 2001/06/14: execute_perl replaced by Martin Persson <mep@passagen.se> |
141 static char *perl_cmd = NULL; | 167 previous use of perl_eval leaked memory, replaced with |
142 SV *i; | 168 a version that uses perl_call instead |
143 | 169 */ |
144 if (perl_cmd) | 170 |
145 g_free(perl_cmd); | 171 static int |
146 perl_cmd = g_malloc(strlen(function) + strlen(args) + 4); | 172 execute_perl(char *function, char *args) |
147 sprintf(perl_cmd, "&%s(%s)", function, args); | 173 { |
148 #ifndef HAVE_PERL_EVAL_PV | 174 char *perl_args[2] = { args, NULL }, buf[512]; |
149 i = (perl_eval_pv(perl_cmd, TRUE)); | 175 int count, ret_value = 1; |
150 #else | 176 SV *sv; |
151 i = (Perl_eval_pv(perl_cmd, TRUE)); | 177 |
152 #endif | 178 dSP; |
153 return i; | 179 ENTER; |
180 SAVETMPS; | |
181 PUSHMARK(sp); | |
182 count = perl_call_argv(function, G_EVAL | G_SCALAR, perl_args); | |
183 SPAGAIN; | |
184 | |
185 sv = GvSV(gv_fetchpv("@", TRUE, SVt_PV)); | |
186 if (SvTRUE(sv)) { | |
187 snprintf(buf, 512, "Perl error: %s\n", SvPV(sv, count)); | |
188 debug_printf(buf); | |
189 POPs; | |
190 } else if (count != 1) { | |
191 snprintf(buf, 512, "Perl error: expected 1 value from %s, " | |
192 "got: %d\n", function, count); | |
193 debug_printf(buf); | |
194 } else { | |
195 ret_value = POPi; | |
196 } | |
197 | |
198 PUTBACK; | |
199 FREETMPS; | |
200 LEAVE; | |
201 | |
202 return ret_value; | |
203 | |
204 } | |
205 | |
206 /* This function is so incredibly broken and should never, ever, ever | |
207 be trusted to work */ | |
208 void perl_unload_file(struct gaim_plugin *plug) { | |
209 struct perlscript *scp = NULL; | |
210 struct _perl_timeout_handlers *thn; | |
211 struct _perl_event_handlers *ehn; | |
212 | |
213 GList *pl = perl_list; | |
214 | |
215 debug_printf("Unloading %s\n", plug->handle); | |
216 while (pl) { | |
217 scp = pl->data; | |
218 /* This is so broken */ | |
219 if (!strcmp(scp->name, plug->desc.name) && | |
220 !strcmp(scp->version, plug->desc.version)) | |
221 break; | |
222 pl = pl->next; | |
223 scp = NULL; | |
224 } | |
225 if (scp) { | |
226 perl_list = g_list_remove(perl_list, scp); | |
227 if (scp->shutdowncallback[0]) | |
228 execute_perl(scp->shutdowncallback, ""); | |
229 perl_list = g_list_remove(perl_list, scp); | |
230 g_free(scp->name); | |
231 g_free(scp->version); | |
232 g_free(scp->shutdowncallback); | |
233 g_free(scp); | |
234 } | |
235 | |
236 pl = perl_timeout_handlers; | |
237 while (pl) { | |
238 thn = pl->data; | |
239 if (thn && thn->handle == plug->handle) { | |
240 g_list_remove(perl_timeout_handlers, thn); | |
241 g_source_remove(thn->iotag); | |
242 g_free(thn->handler_args); | |
243 g_free(thn->handler_name); | |
244 g_free(thn); | |
245 } | |
246 pl = pl->next; | |
247 } | |
248 | |
249 pl = perl_event_handlers; | |
250 while (pl) { | |
251 ehn = pl->data; | |
252 if (ehn && ehn->handle == plug->handle) { | |
253 perl_event_handlers = g_list_remove(perl_event_handlers, ehn); | |
254 g_free(ehn->event_type); | |
255 g_free(ehn->handler_name); | |
256 g_free(ehn); | |
257 } | |
258 pl = pl->next; | |
259 } | |
260 | |
261 plug->handle=NULL; | |
154 } | 262 } |
155 | 263 |
156 int perl_load_file(char *script_name) | 264 int perl_load_file(char *script_name) |
157 { | 265 { |
158 char *name = g_strdup_printf("'%s'", escape_quotes(script_name)); | 266 struct gaim_plugin *plug; |
159 SV *return_val; | 267 GList *p = probed_plugins; |
268 GList *e = perl_event_handlers; | |
269 GList *t = perl_timeout_handlers; | |
270 int num_e, num_t, ret; | |
271 | |
160 if (my_perl == NULL) | 272 if (my_perl == NULL) |
161 perl_init(); | 273 perl_init(); |
162 return_val = execute_perl("load_file", name); | 274 |
163 g_free(name); | 275 while (p) { |
164 return SvNV (return_val); | 276 plug = (struct gaim_plugin *)p->data; |
165 } | 277 if (!strcmp(script_name, plug->path)) |
166 | 278 break; |
167 static int is_pl_file(char *filename) | 279 p = p->next; |
168 { | 280 } |
169 int len; | 281 |
170 if (!filename) return 0; | 282 if (!plug) { |
171 if (!filename[0]) return 0; | 283 probe_perl(script_name); |
172 len = strlen(filename); | 284 } |
173 len -= 3; | 285 |
174 if (len < 0) return 0; | 286 plug->handle = plug->path; |
175 return (!strncmp(filename + len, ".pl", 3)); | 287 |
176 } | 288 /* This is such a terrible hack-- if I weren't tired and annoyed |
177 | 289 * with perl, I'm sure I wouldn't even be considering this. */ |
178 void perl_autoload() | 290 num_e=g_list_length(e); |
179 { | 291 num_t=g_list_length(t); |
180 DIR *dir; | 292 |
181 struct dirent *ent; | 293 ret = execute_perl("load_n_eval", script_name); |
182 struct dirent dirent_buf; | 294 |
183 char *buf; | 295 t = g_list_nth(perl_timeout_handlers, num_t++); |
184 char *path; | 296 while (t) { |
185 | 297 struct _perl_timeout_handlers *h = t->data; |
186 path = gaim_user_dir(); | 298 h->handle = plug->handle; |
187 dir = opendir(path); | 299 t = t->next; |
188 if (dir) { | 300 } |
189 while ((readdir_r(dir,&dirent_buf,&ent),ent)) { | 301 |
190 if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) { | 302 e = g_list_nth(perl_event_handlers, num_e++); |
191 if (is_pl_file(ent->d_name)) { | 303 while (e) { |
192 buf = g_malloc(strlen(path) + strlen(ent->d_name) + 2); | 304 struct _perl_event_handlers *h = e->data; |
193 sprintf(buf, "%s/%s", path, ent->d_name); | 305 h->handle = plug->handle; |
194 perl_load_file(buf); | 306 e = e->next; |
195 g_free(buf); | 307 } |
196 } | 308 return ret; |
197 } | 309 } |
198 } | 310 |
199 closedir(dir); | 311 struct gaim_plugin *probe_perl(const char *filename) { |
200 } | 312 |
201 g_free(path); | 313 /* XXX This woulld be much faster if I didn't create a new |
314 * PerlInterpreter every time I did probed a plugin */ | |
315 | |
316 PerlInterpreter *prober = perl_alloc(); | |
317 struct gaim_plugin * plug = NULL; | |
318 char *argv[] = {"", filename}; | |
319 int count; | |
320 perl_construct(prober); | |
321 perl_parse(prober, NULL, 2, argv, NULL); | |
322 | |
323 { | |
324 dSP; | |
325 ENTER; | |
326 SAVETMPS; | |
327 PUSHMARK(SP); | |
328 count =perl_call_pv("description", G_NOARGS | G_ARRAY); | |
329 SPAGAIN; | |
330 | |
331 if (count = sizeof(struct gaim_plugin_description) / sizeof(char*)) { | |
332 plug = g_new0(struct gaim_plugin, 1); | |
333 plug->type = perl_script; | |
334 g_snprintf(plug->path, sizeof(plug->path), filename); | |
335 plug->desc.iconfile = g_strdup(POPp); | |
336 plug->desc.url = g_strdup(POPp); | |
337 plug->desc.authors = g_strdup(POPp); | |
338 plug->desc.description = g_strdup(POPp); | |
339 plug->desc.version = g_strdup(POPp); | |
340 plug->desc.name = g_strdup(POPp); | |
341 } | |
342 | |
343 PUTBACK; | |
344 FREETMPS; | |
345 LEAVE; | |
346 } | |
347 perl_destruct(prober); | |
348 perl_free(prober); | |
349 return plug; | |
202 } | 350 } |
203 | 351 |
204 static void perl_init() | 352 static void perl_init() |
205 { | 353 { /*changed the name of the variable from load_file to |
206 char *perl_args[] = {"", "-e", "0", "-w"}; | 354 perl_definitions since now it does much more than defining |
207 char load_file[] = | 355 the load_file sub. Moreover, deplaced the initialisation to |
208 "sub load_file()\n" | 356 the xs_init function. (TheHobbit)*/ |
209 "{\n" | 357 char *perl_args[] = { "", "-e", "0", "-w" }; |
210 " (my $file_name) = @_;\n" | 358 char perl_definitions[] = |
211 " open FH, $file_name or return 2;\n" | 359 { |
212 " my $is = $/;\n" | 360 /* We use to function one to load a file the other to |
213 " local($/) = undef;\n" | 361 execute the string obtained from the first and holding |
214 " $file = <FH>;\n" | 362 the file conents. This allows to have a realy local $/ |
215 " close FH;\n" | 363 without introducing temp variables to hold the old |
216 " $/ = $is;\n" | 364 value. Just a question of style:) */ |
217 " $file = \"\\@ISA = qw(Exporter DynaLoader);\\n\" . $file;\n" | 365 "sub load_file{" |
218 " eval $file;\n" | 366 "my $f_name=shift;" |
219 " eval $file if $@;\n" | 367 "local $/=undef;" |
220 " return 1 if $@;\n" | 368 "open FH,$f_name or return \"__FAILED__\";" |
221 " return 0;\n" | 369 "$_=<FH>;" |
222 "}"; | 370 "close FH;" |
371 "return $_;" | |
372 "}" | |
373 "sub load_n_eval{" | |
374 "my $f_name=shift;" | |
375 "my $strin=load_file($f_name);" | |
376 "return 2 if($strin eq \"__FAILED__\");" | |
377 "eval $strin;" | |
378 "if($@){" | |
379 /*" #something went wrong\n"*/ | |
380 "GAIM::print\"Errors loading file $f_name:\\n\";" | |
381 "GAIM::print\"$@\\n\";" | |
382 "return 1;" | |
383 "}" | |
384 "return 0;" | |
385 "}" | |
386 }; | |
223 | 387 |
224 my_perl = perl_alloc(); | 388 my_perl = perl_alloc(); |
225 perl_construct(my_perl); | 389 perl_construct(my_perl); |
390 #ifdef DEBUG | |
226 perl_parse(my_perl, xs_init, 4, perl_args, NULL); | 391 perl_parse(my_perl, xs_init, 4, perl_args, NULL); |
392 #else | |
393 perl_parse(my_perl, xs_init, 3, perl_args, NULL); | |
394 #endif | |
227 #ifndef HAVE_PERL_EVAL_PV | 395 #ifndef HAVE_PERL_EVAL_PV |
228 perl_eval_pv(load_file, TRUE); | 396 eval_pv(perl_definitions, TRUE); |
229 #else | 397 #else |
230 Perl_eval_pv(load_file, TRUE); | 398 perl_eval_pv(perl_definitions, TRUE); /* deprecated */ |
231 #endif | 399 #endif |
232 | 400 |
233 newXS ("GAIM::register", XS_GAIM_register, "GAIM"); | 401 |
234 newXS ("GAIM::get_info", XS_GAIM_get_info, "GAIM"); | |
235 newXS ("GAIM::print", XS_GAIM_print, "GAIM"); | |
236 newXS ("GAIM::write_to_conv", XS_GAIM_write_to_conv, "GAIM"); | |
237 | |
238 newXS ("GAIM::buddy_list", XS_GAIM_buddy_list, "GAIM"); | |
239 newXS ("GAIM::online_list", XS_GAIM_online_list, "GAIM"); | |
240 | |
241 newXS ("GAIM::command", XS_GAIM_command, "GAIM"); | |
242 newXS ("GAIM::user_info", XS_GAIM_user_info, "GAIM"); | |
243 newXS ("GAIM::print_to_conv", XS_GAIM_print_to_conv, "GAIM"); | |
244 newXS ("GAIM::print_to_chat", XS_GAIM_print_to_chat, "GAIM"); | |
245 newXS ("GAIM::serv_send_im", XS_GAIM_serv_send_im, "GAIM"); | |
246 | |
247 newXS ("GAIM::add_event_handler", XS_GAIM_add_event_handler, "GAIM"); | |
248 newXS ("GAIM::remove_event_handler", XS_GAIM_remove_event_handler, "GAIM"); | |
249 newXS ("GAIM::add_timeout_handler", XS_GAIM_add_timeout_handler, "GAIM"); | |
250 | |
251 newXS ("GAIM::play_sound", XS_GAIM_play_sound, "GAIM"); | |
252 } | 402 } |
253 | 403 |
254 void perl_end() | 404 void perl_end() |
255 { | 405 { |
256 struct perlscript *scp; | 406 struct perlscript *scp; |
279 | 429 |
280 while (perl_event_handlers) { | 430 while (perl_event_handlers) { |
281 ehn = perl_event_handlers->data; | 431 ehn = perl_event_handlers->data; |
282 perl_event_handlers = g_list_remove(perl_event_handlers, ehn); | 432 perl_event_handlers = g_list_remove(perl_event_handlers, ehn); |
283 g_free(ehn->event_type); | 433 g_free(ehn->event_type); |
434 debug_printf("handler_name: %s\n", ehn->handler_name); | |
284 g_free(ehn->handler_name); | 435 g_free(ehn->handler_name); |
285 g_free(ehn); | 436 g_free(ehn); |
286 } | 437 } |
287 | 438 |
288 if (my_perl != NULL) { | 439 if (my_perl != NULL) { |
410 dXSARGS; | 561 dXSARGS; |
411 items = 0; | 562 items = 0; |
412 | 563 |
413 title = SvPV(ST(0), junk); | 564 title = SvPV(ST(0), junk); |
414 message = SvPV(ST(1), junk); | 565 message = SvPV(ST(1), junk); |
415 do_error_dialog(message, NULL, GAIM_INFO); | 566 do_error_dialog(title, message, GAIM_INFO); |
416 XSRETURN(0); | 567 XSRETURN(0); |
417 } | 568 } |
418 | 569 |
419 XS (XS_GAIM_buddy_list) | 570 XS (XS_GAIM_buddy_list) |
420 { | 571 { |