| |
1 #include "debug.h" |
| |
2 #include "value.h" |
| |
3 |
| |
4 #include "perl-common.h" |
| |
5 |
| |
6 extern PerlInterpreter *my_perl; |
| |
7 |
| |
8 static GHashTable *object_stashes = NULL; |
| |
9 |
| |
10 void purple_perl_normalize_script_name(char *name) |
| |
11 { |
| |
12 char *c; |
| |
13 |
| |
14 c = strrchr(name, '.'); |
| |
15 |
| |
16 if (c != NULL) |
| |
17 *c = '\0'; |
| |
18 |
| |
19 for (c = name; *c != '\0'; c++) { |
| |
20 if (*c != '_' && !g_ascii_isalnum(*c)) |
| |
21 *c = '_'; |
| |
22 } |
| |
23 } |
| |
24 |
| |
25 static int |
| |
26 magic_free_object(pTHX_ SV *sv, MAGIC *mg) |
| |
27 { |
| |
28 sv_setiv(sv, 0); |
| |
29 |
| |
30 return 0; |
| |
31 } |
| |
32 |
| |
33 static MGVTBL vtbl_free_object = |
| |
34 { |
| |
35 NULL, NULL, NULL, NULL, magic_free_object, NULL, NULL |
| |
36 }; |
| |
37 |
| |
38 static SV * |
| |
39 create_sv_ptr(void *object) |
| |
40 { |
| |
41 SV *sv; |
| |
42 |
| |
43 sv = newSViv((IV)object); |
| |
44 |
| |
45 sv_magic(sv, NULL, '~', NULL, 0); |
| |
46 |
| |
47 SvMAGIC(sv)->mg_private = 0x1551; /* HF */ |
| |
48 SvMAGIC(sv)->mg_virtual = &vtbl_free_object; |
| |
49 |
| |
50 return sv; |
| |
51 } |
| |
52 |
| |
53 SV * |
| |
54 newSVGChar(const char *str) |
| |
55 { |
| |
56 SV *sv; |
| |
57 |
| |
58 if (str == NULL) |
| |
59 return &PL_sv_undef; |
| |
60 |
| |
61 sv = newSVpv(str, 0); |
| |
62 SvUTF8_on(sv); |
| |
63 |
| |
64 return sv; |
| |
65 } |
| |
66 |
| |
67 SV * |
| |
68 purple_perl_bless_object(void *object, const char *stash_name) |
| |
69 { |
| |
70 HV *stash; |
| |
71 HV *hv; |
| |
72 |
| |
73 if (object == NULL) |
| |
74 return NULL; |
| |
75 |
| |
76 if (object_stashes == NULL) { |
| |
77 object_stashes = g_hash_table_new(g_direct_hash, g_direct_equal); |
| |
78 } |
| |
79 |
| |
80 stash = gv_stashpv(stash_name, 1); |
| |
81 |
| |
82 hv = newHV(); |
| |
83 hv_store(hv, "_purple", 5, create_sv_ptr(object), 0); |
| |
84 |
| |
85 return sv_bless(newRV_noinc((SV *)hv), stash); |
| |
86 } |
| |
87 |
| |
88 gboolean |
| |
89 purple_perl_is_ref_object(SV *o) |
| |
90 { |
| |
91 SV **sv; |
| |
92 HV *hv; |
| |
93 |
| |
94 hv = hvref(o); |
| |
95 |
| |
96 if (hv != NULL) { |
| |
97 sv = hv_fetch(hv, "_purple", 5, 0); |
| |
98 |
| |
99 if (sv != NULL) |
| |
100 return TRUE; |
| |
101 } |
| |
102 |
| |
103 return FALSE; |
| |
104 } |
| |
105 |
| |
106 void * |
| |
107 purple_perl_ref_object(SV *o) |
| |
108 { |
| |
109 SV **sv; |
| |
110 HV *hv; |
| |
111 void *p; |
| |
112 |
| |
113 if (o == NULL) |
| |
114 return NULL; |
| |
115 |
| |
116 hv = hvref(o); |
| |
117 |
| |
118 if (hv == NULL) |
| |
119 return NULL; |
| |
120 |
| |
121 sv = hv_fetch(hv, "_purple", 5, 0); |
| |
122 |
| |
123 if (sv == NULL) |
| |
124 croak("variable is damaged"); |
| |
125 |
| |
126 p = GINT_TO_POINTER(SvIV(*sv)); |
| |
127 |
| |
128 return p; |
| |
129 } |
| |
130 |
| |
131 /* |
| |
132 2003/02/06: execute_perl modified by Mark Doliner <mark@kingant.net> |
| |
133 Pass parameters by pushing them onto the stack rather than |
| |
134 passing an array of strings. This way, perl scripts can |
| |
135 modify the parameters and we can get the changed values |
| |
136 and then shoot ourselves. I mean, uh, use them. |
| |
137 |
| |
138 2001/06/14: execute_perl replaced by Martin Persson <mep@passagen.se> |
| |
139 previous use of perl_eval leaked memory, replaced with |
| |
140 a version that uses perl_call instead |
| |
141 |
| |
142 30/11/2002: execute_perl modified by Eric Timme <timothy@voidnet.com> |
| |
143 args changed to char** so that we can have preparsed |
| |
144 arguments again, and many headaches ensued! This essentially |
| |
145 means we replaced one hacked method with a messier hacked |
| |
146 method out of perceived necessity. Formerly execute_perl |
| |
147 required a single char_ptr, and it would insert it into an |
| |
148 array of character pointers and NULL terminate the new array. |
| |
149 Now we have to pass in pre-terminated character pointer arrays |
| |
150 to accomodate functions that want to pass in multiple arguments. |
| |
151 |
| |
152 Previously arguments were preparsed because an argument list |
| |
153 was constructed in the form 'arg one','arg two' and was |
| |
154 executed via a call like &funcname(arglist) (see .59.x), so |
| |
155 the arglist was magically pre-parsed because of the method. |
| |
156 With Martin Persson's change to perl_call we now need to |
| |
157 use a null terminated list of character pointers for arguments |
| |
158 if we wish them to be parsed. Lacking a better way to allow |
| |
159 for both single arguments and many I created a NULL terminated |
| |
160 array in every function that called execute_perl and passed |
| |
161 that list into the function. In the former version a single |
| |
162 character pointer was passed in, and was placed into an array |
| |
163 of character pointers with two elements, with a NULL element |
| |
164 tacked onto the back, but this method no longer seemed prudent. |
| |
165 |
| |
166 Enhancements in the future might be to get rid of pre-declaring |
| |
167 the array sizes? I am not comfortable enough with this |
| |
168 subject to attempt it myself and hope it to stand the test |
| |
169 of time. |
| |
170 */ |
| |
171 int |
| |
172 execute_perl(const char *function, int argc, char **args) |
| |
173 { |
| |
174 int count = 0, i, ret_value = 1; |
| |
175 SV *sv_args[argc]; |
| |
176 STRLEN na; |
| |
177 dSP; |
| |
178 PERL_SET_CONTEXT(my_perl); |
| |
179 /* |
| |
180 * Set up the perl environment, push arguments onto the |
| |
181 * perl stack, then call the given function |
| |
182 */ |
| |
183 SPAGAIN; |
| |
184 ENTER; |
| |
185 SAVETMPS; |
| |
186 PUSHMARK(sp); |
| |
187 |
| |
188 for (i = 0; i < argc; i++) { |
| |
189 if (args[i]) { |
| |
190 sv_args[i] = sv_2mortal(newSVpv(args[i], 0)); |
| |
191 XPUSHs(sv_args[i]); |
| |
192 } |
| |
193 } |
| |
194 |
| |
195 PUTBACK; |
| |
196 PERL_SET_CONTEXT(my_perl); |
| |
197 count = call_pv(function, G_EVAL | G_SCALAR); |
| |
198 SPAGAIN; |
| |
199 |
| |
200 /* |
| |
201 * Check for "die," make sure we have 1 argument, and set our |
| |
202 * return value. |
| |
203 */ |
| |
204 if (SvTRUE(ERRSV)) { |
| |
205 purple_debug(PURPLE_DEBUG_ERROR, "perl", |
| |
206 "Perl function %s exited abnormally: %s\n", |
| |
207 function, SvPV(ERRSV, na)); |
| |
208 POPs; |
| |
209 } else if (count != 1) { |
| |
210 /* |
| |
211 * This should NEVER happen. G_SCALAR ensures that we WILL |
| |
212 * have 1 parameter. |
| |
213 */ |
| |
214 purple_debug(PURPLE_DEBUG_ERROR, "perl", |
| |
215 "Perl error from %s: expected 1 return value, " |
| |
216 "but got %d\n", function, count); |
| |
217 } else |
| |
218 ret_value = POPi; |
| |
219 |
| |
220 /* Check for changed arguments */ |
| |
221 for (i = 0; i < argc; i++) { |
| |
222 if (args[i] && strcmp(args[i], SvPVX(sv_args[i]))) { |
| |
223 /* |
| |
224 * Shizzel. So the perl script changed one of the parameters, |
| |
225 * and we want this change to affect the original parameters. |
| |
226 * args[i] is just a temporary little list of pointers. We don't |
| |
227 * want to free args[i] here because the new parameter doesn't |
| |
228 * overwrite the data that args[i] points to. That is done by |
| |
229 * the function that called execute_perl. I'm not explaining this |
| |
230 * very well. See, it's aggregate... Oh, but if 2 perl scripts |
| |
231 * both modify the data, _that's_ a memleak. This is really kind |
| |
232 * of hackish. I should fix it. Look how long this comment is. |
| |
233 * Holy crap. |
| |
234 */ |
| |
235 args[i] = g_strdup(SvPV(sv_args[i], na)); |
| |
236 } |
| |
237 } |
| |
238 |
| |
239 PUTBACK; |
| |
240 FREETMPS; |
| |
241 LEAVE; |
| |
242 |
| |
243 return ret_value; |
| |
244 } |
| |
245 |
| |
246 #if 0 |
| |
247 gboolean |
| |
248 purple_perl_value_from_sv(PurpleValue *value, SV *sv) |
| |
249 { |
| |
250 switch (purple_value_get_type(value)) |
| |
251 { |
| |
252 case PURPLE_TYPE_CHAR: |
| |
253 if ((tmp = SvGChar(sv)) != NULL) |
| |
254 purple_value_set_char(value, tmp[0]); |
| |
255 else |
| |
256 return FALSE; |
| |
257 break; |
| |
258 |
| |
259 case PURPLE_TYPE_UCHAR: |
| |
260 if ((tmp = SvPV_nolen(sv)) != NULL) |
| |
261 purple_value_set_uchar(value, tmp[0]); |
| |
262 else |
| |
263 return FALSE; |
| |
264 break; |
| |
265 |
| |
266 case PURPLE_TYPE_BOOLEAN: |
| |
267 purple_value_set_boolean(value, SvTRUE(sv)); |
| |
268 break; |
| |
269 |
| |
270 case PURPLE_TYPE_INT: |
| |
271 purple_value_set_int(value, SvIV(sv)); |
| |
272 break; |
| |
273 |
| |
274 case PURPLE_TYPE_UINT: |
| |
275 purple_value_set_uint(value, SvIV(sv)); |
| |
276 break; |
| |
277 |
| |
278 case PURPLE_TYPE_LONG: |
| |
279 purple_value_set_long(value, SvIV(sv)); |
| |
280 break; |
| |
281 |
| |
282 case PURPLE_TYPE_ULONG: |
| |
283 purple_value_set_ulong(value, SvIV(sv)); |
| |
284 break; |
| |
285 |
| |
286 case PURPLE_TYPE_INT64: |
| |
287 purple_value_set_int64(value, SvIV(sv)); |
| |
288 break; |
| |
289 |
| |
290 case PURPLE_TYPE_UINT64: |
| |
291 purple_value_set_uint64(value, SvIV(sv)); |
| |
292 break; |
| |
293 |
| |
294 case PURPLE_TYPE_STRING: |
| |
295 purple_value_set_string(value, SvGChar(sv)); |
| |
296 break; |
| |
297 |
| |
298 case PURPLE_TYPE_POINTER: |
| |
299 purple_value_set_pointer(value, (void *)SvIV(sv)); |
| |
300 break; |
| |
301 |
| |
302 case PURPLE_TYPE_BOXED: |
| |
303 if (!strcmp(purple_value_get_specific_type(value), "SV")) |
| |
304 purple_value_set_boxed(value, (sv == &PL_sv_undef ? NULL : sv)); |
| |
305 else |
| |
306 purple_value_set_boxed(value, sv); |
| |
307 break; |
| |
308 |
| |
309 default: |
| |
310 return FALSE; |
| |
311 } |
| |
312 |
| |
313 return TRUE; |
| |
314 } |
| |
315 |
| |
316 SV * |
| |
317 purple_perl_sv_from_value(const PurpleValue *value, va_list list) |
| |
318 { |
| |
319 switch (purple_value_get_type(value)) |
| |
320 { |
| |
321 case PURPLE_TYPE_BOOLEAN: |
| |
322 return newSViv(purple_value_get_boolean(value)); |
| |
323 break; |
| |
324 |
| |
325 case PURPLE_TYPE_INT: |
| |
326 return newSViv(purple_value_get_int(value)); |
| |
327 break; |
| |
328 |
| |
329 case PURPLE_TYPE_UINT: |
| |
330 return newSVuv(purple_value_get_uint(value)); |
| |
331 break; |
| |
332 |
| |
333 case PURPLE_TYPE_LONG: |
| |
334 return newSViv(purple_value_get_long(value)); |
| |
335 break; |
| |
336 |
| |
337 case PURPLE_TYPE_ULONG: |
| |
338 return newSVuv(purple_value_get_ulong(value)); |
| |
339 break; |
| |
340 |
| |
341 case PURPLE_TYPE_INT64: |
| |
342 return newSViv(purple_value_get_int64(value)); |
| |
343 break; |
| |
344 |
| |
345 case PURPLE_TYPE_UINT64: |
| |
346 return newSVuv(purple_value_get_int64(value)); |
| |
347 break; |
| |
348 |
| |
349 case PURPLE_TYPE_STRING: |
| |
350 return newSVGChar(purple_value_get_string(value)); |
| |
351 break; |
| |
352 |
| |
353 case PURPLE_TYPE_POINTER: |
| |
354 return newSViv((IV)purple_value_get_pointer(value)); |
| |
355 break; |
| |
356 |
| |
357 case PURPLE_TYPE_BOXED: |
| |
358 if (!strcmp(purple_value_get_specific_type(value), "SV")) |
| |
359 { |
| |
360 SV *sv = (SV *)purple_perl_get_boxed(value); |
| |
361 |
| |
362 return (sv == NULL ? &PL_sv_undef : sv); |
| |
363 } |
| |
364 |
| |
365 /* Uh.. I dunno. Try this? */ |
| |
366 return sv_2mortal(purple_perl_bless_object( |
| |
367 purple_perl_get_boxed(value), |
| |
368 purple_value_get_specific_type(value))); |
| |
369 |
| |
370 default: |
| |
371 return FALSE; |
| |
372 } |
| |
373 |
| |
374 return TRUE; |
| |
375 } |
| |
376 #endif |
| |
377 |
| |
378 void * |
| |
379 purple_perl_data_from_sv(PurpleValue *value, SV *sv) |
| |
380 { |
| |
381 STRLEN na; |
| |
382 |
| |
383 switch (purple_value_get_type(value)) { |
| |
384 case PURPLE_TYPE_BOOLEAN: return (void *)SvIV(sv); |
| |
385 case PURPLE_TYPE_INT: return (void *)SvIV(sv); |
| |
386 case PURPLE_TYPE_UINT: return (void *)SvUV(sv); |
| |
387 case PURPLE_TYPE_LONG: return (void *)SvIV(sv); |
| |
388 case PURPLE_TYPE_ULONG: return (void *)SvUV(sv); |
| |
389 case PURPLE_TYPE_INT64: return (void *)SvIV(sv); |
| |
390 case PURPLE_TYPE_UINT64: return (void *)SvUV(sv); |
| |
391 case PURPLE_TYPE_STRING: return g_strdup((void *)SvPV(sv, na)); |
| |
392 case PURPLE_TYPE_POINTER: return (void *)SvIV(sv); |
| |
393 case PURPLE_TYPE_BOXED: return (void *)SvIV(sv); |
| |
394 |
| |
395 default: |
| |
396 return NULL; |
| |
397 } |
| |
398 |
| |
399 return NULL; |
| |
400 } |
| |
401 |
| |
402 static SV * |
| |
403 purple_perl_sv_from_subtype(const PurpleValue *value, void *arg) |
| |
404 { |
| |
405 const char *stash = NULL; |
| |
406 |
| |
407 switch (purple_value_get_subtype(value)) { |
| |
408 case PURPLE_SUBTYPE_ACCOUNT: |
| |
409 stash = "Purple::Account"; |
| |
410 break; |
| |
411 case PURPLE_SUBTYPE_BLIST: |
| |
412 stash = "Purple::BuddyList"; |
| |
413 break; |
| |
414 case PURPLE_SUBTYPE_BLIST_BUDDY: |
| |
415 stash = "Purple::BuddyList::Buddy"; |
| |
416 break; |
| |
417 case PURPLE_SUBTYPE_BLIST_GROUP: |
| |
418 stash = "Purple::BuddyList::Group"; |
| |
419 break; |
| |
420 case PURPLE_SUBTYPE_BLIST_CHAT: |
| |
421 stash = "Purple::BuddyList::Chat"; |
| |
422 break; |
| |
423 case PURPLE_SUBTYPE_BUDDY_ICON: |
| |
424 stash = "Purple::Buddy::Icon"; |
| |
425 break; |
| |
426 case PURPLE_SUBTYPE_CONNECTION: |
| |
427 stash = "Purple::Connection"; |
| |
428 break; |
| |
429 case PURPLE_SUBTYPE_CONVERSATION: |
| |
430 stash = "Purple::Conversation"; |
| |
431 break; |
| |
432 case PURPLE_SUBTYPE_PLUGIN: |
| |
433 stash = "Purple::Plugin"; |
| |
434 break; |
| |
435 case PURPLE_SUBTYPE_BLIST_NODE: |
| |
436 stash = "Purple::BuddyList::Node"; |
| |
437 break; |
| |
438 case PURPLE_SUBTYPE_CIPHER: |
| |
439 stash = "Purple::Cipher"; |
| |
440 break; |
| |
441 case PURPLE_SUBTYPE_STATUS: |
| |
442 stash = "Purple::Status"; |
| |
443 break; |
| |
444 case PURPLE_SUBTYPE_LOG: |
| |
445 stash = "Purple::Log"; |
| |
446 break; |
| |
447 case PURPLE_SUBTYPE_XFER: |
| |
448 stash = "Purple::Xfer"; |
| |
449 break; |
| |
450 case PURPLE_SUBTYPE_XMLNODE: |
| |
451 stash = "Purple::XMLNode"; |
| |
452 break; |
| |
453 |
| |
454 default: |
| |
455 stash = "Purple"; /* ? */ |
| |
456 } |
| |
457 |
| |
458 return sv_2mortal(purple_perl_bless_object(arg, stash)); |
| |
459 } |
| |
460 |
| |
461 SV * |
| |
462 purple_perl_sv_from_vargs(const PurpleValue *value, va_list *args, void ***copy_arg) |
| |
463 { |
| |
464 if (purple_value_is_outgoing(value)) { |
| |
465 switch (purple_value_get_type(value)) { |
| |
466 case PURPLE_TYPE_SUBTYPE: |
| |
467 if ((*copy_arg = va_arg(*args, void **)) == NULL) |
| |
468 return &PL_sv_undef; |
| |
469 |
| |
470 return purple_perl_sv_from_subtype(value, *(void **)*copy_arg); |
| |
471 |
| |
472 case PURPLE_TYPE_BOOLEAN: |
| |
473 if ((*copy_arg = (void *)va_arg(*args, gboolean *)) == NULL) |
| |
474 return &PL_sv_undef; |
| |
475 |
| |
476 return newSViv(*(gboolean *)*copy_arg); |
| |
477 |
| |
478 case PURPLE_TYPE_INT: |
| |
479 if ((*copy_arg = (void *)va_arg(*args, int *)) == NULL) |
| |
480 return &PL_sv_undef; |
| |
481 |
| |
482 return newSViv(*(int *)*copy_arg); |
| |
483 |
| |
484 case PURPLE_TYPE_UINT: |
| |
485 if ((*copy_arg = (void *)va_arg(*args, unsigned int *)) == NULL) |
| |
486 return &PL_sv_undef; |
| |
487 |
| |
488 return newSVuv(*(unsigned int *)*copy_arg); |
| |
489 |
| |
490 case PURPLE_TYPE_LONG: |
| |
491 if ((*copy_arg = (void *)va_arg(*args, long *)) == NULL) |
| |
492 return &PL_sv_undef; |
| |
493 |
| |
494 return newSViv(*(long *)*copy_arg); |
| |
495 |
| |
496 case PURPLE_TYPE_ULONG: |
| |
497 if ((*copy_arg = (void *)va_arg(*args, |
| |
498 unsigned long *)) == NULL) |
| |
499 return &PL_sv_undef; |
| |
500 |
| |
501 return newSVuv(*(unsigned long *)*copy_arg); |
| |
502 |
| |
503 case PURPLE_TYPE_INT64: |
| |
504 if ((*copy_arg = (void *)va_arg(*args, gint64 *)) == NULL) |
| |
505 return &PL_sv_undef; |
| |
506 |
| |
507 return newSViv(*(gint64 *)*copy_arg); |
| |
508 |
| |
509 case PURPLE_TYPE_UINT64: |
| |
510 if ((*copy_arg = (void *)va_arg(*args, guint64 *)) == NULL) |
| |
511 return &PL_sv_undef; |
| |
512 |
| |
513 return newSVuv(*(guint64 *)*copy_arg); |
| |
514 |
| |
515 case PURPLE_TYPE_STRING: |
| |
516 if ((*copy_arg = (void *)va_arg(*args, char **)) == NULL) |
| |
517 return &PL_sv_undef; |
| |
518 |
| |
519 return newSVGChar(*(char **)*copy_arg); |
| |
520 |
| |
521 case PURPLE_TYPE_POINTER: |
| |
522 if ((*copy_arg = va_arg(*args, void **)) == NULL) |
| |
523 return &PL_sv_undef; |
| |
524 |
| |
525 return newSViv((IV)*(void **)*copy_arg); |
| |
526 |
| |
527 case PURPLE_TYPE_BOXED: |
| |
528 /* Uh.. I dunno. Try this? */ |
| |
529 if ((*copy_arg = va_arg(*args, void **)) == NULL) |
| |
530 return &PL_sv_undef; |
| |
531 |
| |
532 return sv_2mortal(purple_perl_bless_object( |
| |
533 *(void **)*copy_arg, |
| |
534 purple_value_get_specific_type(value))); |
| |
535 |
| |
536 default: |
| |
537 /* If this happens, things are going to get screwed up... */ |
| |
538 return NULL; |
| |
539 } |
| |
540 } else { |
| |
541 switch (purple_value_get_type(value)) { |
| |
542 case PURPLE_TYPE_SUBTYPE: |
| |
543 if ((*copy_arg = va_arg(*args, void *)) == NULL) |
| |
544 return &PL_sv_undef; |
| |
545 |
| |
546 return purple_perl_sv_from_subtype(value, *copy_arg); |
| |
547 |
| |
548 case PURPLE_TYPE_BOOLEAN: |
| |
549 *copy_arg = GINT_TO_POINTER( va_arg(*args, gboolean) ); |
| |
550 |
| |
551 return newSViv((gboolean)GPOINTER_TO_INT(*copy_arg)); |
| |
552 |
| |
553 case PURPLE_TYPE_INT: |
| |
554 *copy_arg = GINT_TO_POINTER( va_arg(*args, int) ); |
| |
555 |
| |
556 return newSViv(GPOINTER_TO_INT(*copy_arg)); |
| |
557 |
| |
558 case PURPLE_TYPE_UINT: |
| |
559 *copy_arg = GUINT_TO_POINTER(va_arg(*args, unsigned int)); |
| |
560 |
| |
561 return newSVuv(GPOINTER_TO_UINT(*copy_arg)); |
| |
562 |
| |
563 case PURPLE_TYPE_LONG: |
| |
564 *copy_arg = (void *)va_arg(*args, long); |
| |
565 |
| |
566 return newSViv((long)*copy_arg); |
| |
567 |
| |
568 case PURPLE_TYPE_ULONG: |
| |
569 *copy_arg = (void *)va_arg(*args, unsigned long); |
| |
570 |
| |
571 return newSVuv((unsigned long)*copy_arg); |
| |
572 |
| |
573 case PURPLE_TYPE_INT64: |
| |
574 #if 0 |
| |
575 /* XXX This yells and complains. */ |
| |
576 *copy_arg = va_arg(*args, gint64); |
| |
577 |
| |
578 return newSViv(*copy_arg); |
| |
579 #endif |
| |
580 break; |
| |
581 |
| |
582 case PURPLE_TYPE_UINT64: |
| |
583 /* XXX This also yells and complains. */ |
| |
584 #if 0 |
| |
585 *copy_arg = (void *)va_arg(*args, guint64); |
| |
586 |
| |
587 return newSVuv(*copy_arg); |
| |
588 #endif |
| |
589 break; |
| |
590 |
| |
591 case PURPLE_TYPE_STRING: |
| |
592 if ((*copy_arg = (void *)va_arg(*args, char *)) == NULL) |
| |
593 return &PL_sv_undef; |
| |
594 |
| |
595 return newSVGChar((char *)*copy_arg); |
| |
596 |
| |
597 case PURPLE_TYPE_POINTER: |
| |
598 if ((*copy_arg = (void *)va_arg(*args, void *)) == NULL) |
| |
599 return &PL_sv_undef; |
| |
600 |
| |
601 return newSViv((IV)*copy_arg); |
| |
602 |
| |
603 case PURPLE_TYPE_BOXED: |
| |
604 /* Uh.. I dunno. Try this? */ |
| |
605 if ((*copy_arg = (void *)va_arg(*args, void *)) == NULL) |
| |
606 return &PL_sv_undef; |
| |
607 |
| |
608 return sv_2mortal(purple_perl_bless_object(*copy_arg, |
| |
609 purple_value_get_specific_type(value))); |
| |
610 |
| |
611 default: |
| |
612 /* If this happens, things are going to get screwed up... */ |
| |
613 return NULL; |
| |
614 } |
| |
615 } |
| |
616 |
| |
617 return NULL; |
| |
618 } |