]> git.vpit.fr Git - perl/modules/Variable-Magic.git/blob - Magic.xs
fd22ffa81f9e9fc04e8804c043ee47f03a8efdb5
[perl/modules/Variable-Magic.git] / Magic.xs
1 /* This file is part of the Variable::Magic Perl module.
2  * See http://search.cpan.org/dist/Variable-Magic/ */
3
4 #include <stdio.h>  /* sprintf() */
5
6 #define PERL_NO_GET_CONTEXT
7 #include "EXTERN.h"
8 #include "perl.h"
9 #include "XSUB.h"
10
11 #define __PACKAGE__ "Variable::Magic"
12
13 #define R(S) fprintf(stderr, "R(" #S ") = %d\n", SvREFCNT(S))
14
15 #define PERL_VERSION_LE(R, V, S) (PERL_REVISION < (R) || (PERL_REVISION == (R) && (PERL_VERSION < (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION <= (S))))))
16
17 #define PERL_API_VERSION_GE(R, V, S) (PERL_API_REVISION > (R) || (PERL_API_REVISION == (R) && (PERL_API_VERSION > (V) || (PERL_API_VERSION == (V) && (PERL_API_SUBVERSION >= (S))))))
18
19 /* --- Compatibility ------------------------------------------------------- */
20
21 #ifndef Newx
22 # define Newx(v, n, c) New(0, v, n, c)
23 #endif
24
25 #ifndef SvMAGIC_set
26 # define SvMAGIC_set(sv, val) (SvMAGIC(sv) = (val))
27 #endif
28
29 #ifndef dMY_CXT
30 # define MY_CXT vmg_globaldata
31 # define dMY_CXT
32 # define START_MY_CXT STATIC my_cxt_t MY_CXT;
33 # define MY_CXT_INIT
34 #endif
35
36 #ifndef PERL_MAGIC_ext
37 # define PERL_MAGIC_ext '~'
38 #endif
39
40 #ifndef MGf_COPY
41 # define MGf_COPY 0
42 #endif /* !MGf_COPY */
43
44 #ifndef MGf_DUP
45 # define MGf_DUP 0
46 #endif /* !MGf_DUP */
47
48 #ifndef MGf_LOCAL
49 # define MGf_LOCAL 0
50 #endif /* !MGf_LOCAL */
51
52 /* --- Our sv_magicext ----------------------------------------------------- */
53
54 #ifdef sv_magicext
55 STATIC MAGIC *vmg_sv_magicext(pTHX_ SV *sv, SV *obj, MGVTBL *vtbl, SV *obj2, I32 flag) {
56  return sv_magicext(sv, obj, PERL_MAGIC_ext, vtbl, (const char *) obj2, flag);
57 }
58 #else /* Stub inspired from 5.7.3's sv_magicext */
59 STATIC MAGIC *vmg_sv_magicext(pTHX_ SV *sv, SV *obj, MGVTBL *vtbl, SV *obj2, I32 flag) {
60  MAGIC* mg;
61
62  if (SvTYPE(sv) < SVt_PVMG) {
63   SvUPGRADE(sv, SVt_PVMG);
64  }
65  Newx(mg, 1, MAGIC);
66  mg->mg_moremagic = SvMAGIC(sv);
67  SvMAGIC_set(sv, mg);
68
69  if (!obj || obj == sv ||
70      (SvTYPE(obj) == SVt_PVGV &&
71         (GvSV(obj) == sv || GvHV(obj) == (HV *) sv || GvAV(obj) == (AV *) sv ||
72                             GvCV(obj) == (CV *) sv || GvIOp(obj) == (IO *) sv ||
73                             GvFORM(obj) == (CV *) sv))) {
74   mg->mg_obj = obj;
75  } else {
76   mg->mg_obj = SvREFCNT_inc(obj);
77   mg->mg_flags |= MGf_REFCOUNTED;
78  }
79
80  mg->mg_type = PERL_MAGIC_ext;
81  mg->mg_len  = flag;
82  if (obj2) {
83   if (flag == HEf_SVKEY) {
84    mg->mg_ptr = (char *) SvREFCNT_inc((SV *) obj2);
85   } else {
86    mg->mg_ptr = (char *) obj2;
87   }
88  }
89  mg->mg_virtual = vtbl;
90
91  mg_magical(sv);
92  if (SvGMAGICAL(sv)) {
93   SvFLAGS(sv) &= ~(SVf_IOK | SVf_NOK | SVf_POK);
94  }
95
96  return mg;
97 }
98 #endif
99 #define vmg_sv_magicext(S, O, V, OO, F) vmg_sv_magicext(aTHX_ (S), (O), (V), (OO), (F))
100
101 /* --- Context-safe global data -------------------------------------------- */
102
103 #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
104
105 typedef struct {
106  HV *wizz;
107  U16 count;
108 } my_cxt_t;
109
110 START_MY_CXT
111
112 /* --- Signatures ---------------------------------------------------------- */
113
114 #define SIG_MIN ((U16) (1u << 8))
115 #define SIG_MAX ((U16) (1u << 16 - 1))
116 #define SIG_NBR (SIG_MAX - SIG_MIN + 1)
117 #define SIG_WIZ ((U16) (1u << 8 - 1))
118
119 /* ... Generate signatures ................................................. */
120
121 STATIC U16 vmg_gensig(pTHX) {
122 #define vmg_gensig() vmg_gensig(aTHX)
123  U16 sig;
124  char buf[8];
125  dMY_CXT;
126
127  do {
128   sig = SIG_NBR * Drand01() + SIG_MIN;
129  } while (hv_exists(MY_CXT.wizz, buf, sprintf(buf, "%u", sig)));
130
131  return sig;
132 }
133
134 /* --- MGWIZ structure ----------------------------------------------------- */
135
136 typedef struct {
137  MGVTBL *vtbl;
138  U16 sig;
139  SV *cb_get, *cb_set, *cb_len, *cb_clear, *cb_free;
140 #if MGf_COPY
141  SV *cb_copy;
142 #endif /* MGf_COPY */
143 #if MGf_DUP
144  SV *cb_dup;
145 #endif /* MGf_DUP */
146 #if MGf_LOCAL
147  SV *cb_local;
148 #endif /* MGf_LOCAL */
149  SV *cb_data;
150 } MGWIZ;
151
152 #define MGWIZ2SV(W) (newSVuv(PTR2UV(W)))
153 #define SV2MGWIZ(S) (INT2PTR(MGWIZ*, SvUVX((SV *) (S))))
154
155 /* ... Construct private data .............................................. */
156
157 STATIC SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, AV *args) {
158 #define vmg_data_new(C, S, A) vmg_data_new(aTHX_ (C), (S), (A))
159  SV *nsv;
160
161  dSP;
162  int count;
163
164  ENTER;
165  SAVETMPS;
166
167  PUSHMARK(SP);
168  XPUSHs(sv_2mortal(newRV_inc(sv)));
169  if (args != NULL) {
170   I32 i, alen = av_len(args);
171   for (i = 0; i < alen; ++i) { XPUSHs(*av_fetch(args, i, 0)); }
172  }
173  PUTBACK;
174
175  count = call_sv(ctor, G_SCALAR);
176
177  SPAGAIN;
178
179  if (count != 1) { croak("Callback needs to return 1 scalar\n"); }
180  nsv = POPs;
181 #if PERL_VERSION_LE(5, 8, 2)
182  nsv = sv_newref(nsv); /* Workaround some bug in SvREFCNT_inc() */
183 #else
184  SvREFCNT_inc(nsv);    /* Or it will be destroyed in FREETMPS */
185 #endif
186
187  PUTBACK;
188
189  FREETMPS;
190  LEAVE;
191
192  return nsv;
193 }
194
195 STATIC SV *vmg_data_get(SV *sv, U16 sig) {
196  MAGIC *mg, *moremagic;
197  MGWIZ *w;
198
199  if (SvTYPE(sv) >= SVt_PVMG) {
200   for (mg = SvMAGIC(sv); mg; mg = moremagic) {
201    moremagic = mg->mg_moremagic;
202    if ((mg->mg_type == PERL_MAGIC_ext) && (mg->mg_private == sig)) { break; }
203   }
204   if (mg) { return mg->mg_obj; }
205  }
206
207  return NULL;
208
209
210 /* ... Magic cast/dispell .................................................. */
211
212 STATIC UV vmg_cast(pTHX_ SV *sv, SV *wiz, AV *args) {
213 #define vmg_cast(S, W, A) vmg_cast(aTHX_ (S), (W), (A))
214  MAGIC *mg = NULL, *moremagic = NULL;
215  MGWIZ *w;
216  SV *data;
217
218  w = SV2MGWIZ(wiz);
219
220  if (SvTYPE(sv) >= SVt_PVMG) {
221   for (mg = SvMAGIC(sv); mg; mg = moremagic) {
222    moremagic = mg->mg_moremagic;
223    if ((mg->mg_type == PERL_MAGIC_ext) && (mg->mg_private == w->sig)) { break; }
224   }
225   if (mg) { return 1; }
226  }
227
228  data = (w->cb_data) ? vmg_data_new(w->cb_data, sv, args) : NULL;
229  mg = vmg_sv_magicext(sv, data, w->vtbl, wiz, HEf_SVKEY);
230  mg->mg_private = w->sig;
231  mg->mg_flags   = mg->mg_flags
232 #if MGf_COPY
233                 | MGf_COPY
234 #endif /* MGf_COPY */
235 #if MGf_DUP
236                 | MGf_DUP
237 #endif /* MGf_DUP */
238 #if MGf_LOCAL
239                 | MGf_LOCAL
240 #endif /* MGf_LOCAL */
241  ;
242
243  return 1;
244 }
245
246 STATIC UV vmg_dispell(pTHX_ SV *sv, U16 sig) {
247 #define vmg_dispell(S, Z) vmg_dispell(aTHX_ (S), (Z))
248  MAGIC *mg, *prevmagic, *moremagic = NULL;
249  MGWIZ *w;
250
251  if (SvTYPE(sv) < SVt_PVMG) { return 0; }
252
253  for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) {
254   moremagic = mg->mg_moremagic;
255   if ((mg->mg_type == PERL_MAGIC_ext) && (mg->mg_private == sig)) { break; }
256  }
257  if (!mg) { return 0; }
258
259  if (prevmagic) {
260   prevmagic->mg_moremagic = moremagic;
261  } else {
262   SvMAGIC_set(sv, moremagic);
263  }
264  mg->mg_moremagic = NULL;
265
266  if (mg->mg_obj != sv) { SvREFCNT_dec(mg->mg_obj); } /* Destroy private data */
267  SvREFCNT_dec((SV *) mg->mg_ptr); /* Unreference the wizard */
268  Safefree(mg);
269
270  return 1;
271 }
272
273 /* ... svt callbacks ....................................................... */
274
275 STATIC int vmg_cb_call(pTHX_ SV *cb, SV *sv, SV *data) {
276 #define vmg_cb_call(I, S, D) vmg_cb_call(aTHX_ (I), (S), (D))
277  int ret;
278
279  dSP;
280  int count;
281
282  ENTER;
283  SAVETMPS;
284
285  PUSHMARK(SP);
286  XPUSHs(sv_2mortal(newRV_inc(sv)));
287  if (data) { XPUSHs(data); }
288  PUTBACK;
289
290  count = call_sv(cb, G_SCALAR);
291
292  SPAGAIN;
293
294  if (count != 1) { croak("Callback needs to return 1 scalar\n"); }
295  ret = POPi;
296
297  PUTBACK;
298
299  FREETMPS;
300  LEAVE;
301
302  return ret;
303 }
304
305 STATIC int vmg_svt_get(pTHX_ SV *sv, MAGIC *mg) {
306  return vmg_cb_call(SV2MGWIZ(mg->mg_ptr)->cb_get, sv, mg->mg_obj);
307 }
308
309 STATIC int vmg_svt_set(pTHX_ SV *sv, MAGIC *mg) {
310  return vmg_cb_call(SV2MGWIZ(mg->mg_ptr)->cb_set, sv, mg->mg_obj);
311 }
312
313 STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) {
314  U32 ret;
315
316  dSP;
317  int count;
318
319  ENTER;
320  SAVETMPS;
321
322  PUSHMARK(SP);
323  XPUSHs(sv_2mortal(newRV_inc(sv)));
324  XPUSHs((mg->mg_obj) ? (mg->mg_obj) : &PL_sv_undef);
325  if (SvTYPE(sv) == SVt_PVAV) {
326   XPUSHs(sv_2mortal(newSViv(av_len((AV *) sv) + 1)));
327  }
328  PUTBACK;
329
330  count = call_sv(SV2MGWIZ(mg->mg_ptr)->cb_len, G_SCALAR);
331
332  SPAGAIN;
333
334  if (count != 1) { croak("Callback needs to return 1 scalar\n"); }
335  ret = POPi;
336
337  PUTBACK;
338
339  FREETMPS;
340  LEAVE;
341
342  return ret - 1;
343 }
344
345 STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) {
346  return vmg_cb_call(SV2MGWIZ(mg->mg_ptr)->cb_clear, sv, mg->mg_obj);
347 }
348
349 STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) {
350  /* So that it can survive tmp cleanup in vmg_cb_call */
351  SvREFCNT_inc(sv);
352  /* Perl_mg_free will get rid of the magic and decrement mg->mg_obj and
353   * mg->mg_ptr reference count */
354  return vmg_cb_call(SV2MGWIZ(mg->mg_ptr)->cb_free, sv, mg->mg_obj);
355 }
356
357 #if MGf_COPY
358 STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *name, int namelen) {
359  int ret;
360
361  dSP;
362  int count;
363
364  ENTER;
365  SAVETMPS;
366
367  PUSHMARK(SP);
368  XPUSHs(sv_2mortal(newRV_inc(sv)));
369  XPUSHs((mg->mg_obj) ? (mg->mg_obj) : &PL_sv_undef);
370  XPUSHs(sv_mortalcopy(nsv));
371  PUTBACK;
372
373  count = call_sv(SV2MGWIZ(mg->mg_ptr)->cb_copy, G_SCALAR);
374
375  SPAGAIN;
376
377  if (count != 1) { croak("Callback needs to return 1 scalar\n"); }
378  ret = POPi;
379
380  PUTBACK;
381
382  FREETMPS;
383  LEAVE;
384
385  return ret;
386 }
387 #endif /* MGf_COPY */
388
389 #if MGf_DUP
390 STATIC int vmg_svt_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *p) {
391  return 0;
392 }
393 #endif /* MGf_DUP */
394
395 #if MGf_LOCAL
396 STATIC int vmg_svt_local(pTHX_ SV *nsv, MAGIC *mg) {
397  return vmg_cb_call(SV2MGWIZ(mg->mg_ptr)->cb_local, nsv, mg->mg_obj);
398 }
399 #endif /* MGf_LOCAL */
400
401 /* ... Wizard destructor ................................................... */
402
403 STATIC int vmg_wizard_free(pTHX_ SV *wiz, MAGIC *mg) {
404  char buf[8];
405  MGWIZ *w;
406  dMY_CXT;
407
408  w = SV2MGWIZ(wiz);
409
410  SvREFCNT_inc(wiz); /* Fake survival - it's gonna be deleted anyway */
411 #if PERL_API_VERSION_GE(5, 9, 5)
412  SvREFCNT_inc(wiz); /* One more push */
413 #endif
414  if (hv_delete(MY_CXT.wizz, buf, sprintf(buf, "%u", w->sig), 0)) {
415   --MY_CXT.count;
416  }
417
418  if (w->cb_get   != NULL) { SvREFCNT_dec(SvRV(w->cb_get)); }
419  if (w->cb_set   != NULL) { SvREFCNT_dec(SvRV(w->cb_set)); }
420  if (w->cb_len   != NULL) { SvREFCNT_dec(SvRV(w->cb_len)); }
421  if (w->cb_clear != NULL) { SvREFCNT_dec(SvRV(w->cb_clear)); }
422  if (w->cb_free  != NULL) { SvREFCNT_dec(SvRV(w->cb_free)); }
423 #if MGf_COPY
424  if (w->cb_copy  != NULL) { SvREFCNT_dec(SvRV(w->cb_copy)); }
425 #endif /* MGf_COPY */
426 #if MGf_DUP
427  if (w->cb_dup   != NULL) { SvREFCNT_dec(SvRV(w->cb_dup)); }
428 #endif /* MGf_DUP */
429 #if MGf_LOCAL
430  if (w->cb_local != NULL) { SvREFCNT_dec(SvRV(w->cb_local)); }
431 #endif /* MGf_LOCAL */
432  if (w->cb_data  != NULL) { SvREFCNT_dec(SvRV(w->cb_data)); }
433  Safefree(w->vtbl);
434  Safefree(w);
435
436  return 0;
437 }
438
439 STATIC MGVTBL vmg_wizard_vtbl = {
440  NULL,            /* get */
441  NULL,            /* set */
442  NULL,            /* len */
443  NULL,            /* clear */
444  vmg_wizard_free, /* free */
445 #if MGf_COPY
446  NULL,            /* copy */
447 #endif /* MGf_COPY */
448 #if MGf_DUP
449  NULL,            /* dup */
450 #endif /* MGf_DUP */
451 #if MGf_LOCAL
452  NULL,            /* local */
453 #endif /* MGf_LOCAL */
454 };
455
456 /* --- Error messages and misc helpers ------------------------------------- */
457
458 STATIC const char vmg__wizard_args[]   = "_wizard() called with a wrong number of arguments - use wizard() instead";
459 STATIC const char vmg_invalid_wiz[]    = "Invalid wizard object";
460 STATIC const char vmg_invalid_sv[]     = "Invalid variable";
461 STATIC const char vmg_invalid_sig[]    = "Invalid numeric signature";
462 STATIC const char vmg_toomanysigs[]    = "Too many magic signatures used";
463 STATIC const char vmg_argstorefailed[] = "Error while storing arguments";
464
465 STATIC U16 vmg_sv2sig(pTHX_ SV *sv) {
466 #define vmg_sv2sig(S) vmg_sv2sig(aTHX_ (S))
467  U16 sig;
468
469  if (SvIOK(sv)) {
470   sig = SvUVX(sv);
471  } else if (SvNOK(sv)) {
472   sig = SvNVX(sv);
473  } else if ((SvPOK(sv) && grok_number(SvPVX(sv), SvCUR(sv), NULL))) {
474   sig = SvUV(sv);
475  } else {
476   croak(vmg_invalid_sig);
477  }
478  if (sig < SIG_MIN) { sig += SIG_MIN; }
479  if (sig > SIG_MAX) { sig %= SIG_MAX + 1; }
480
481  return sig;
482 }
483
484 #define VMG_SET_CB(T, V, M, CB) \
485  cb = (CB); \
486  if (SvROK(cb)) { \
487   (V)->svt_##T = vmg_svt_##T; (M)->cb_##T = newRV_inc(SvRV(cb)); \
488  } else { \
489   (V)->svt_##T = NULL;        (M)->cb_##T = NULL; \
490  }
491
492 /* --- XS ------------------------------------------------------------------ */
493
494 MODULE = Variable::Magic            PACKAGE = Variable::Magic
495
496 PROTOTYPES: ENABLE
497
498 BOOT:
499 {
500  HV *stash;
501  MY_CXT_INIT;
502  MY_CXT.wizz = newHV();
503  MY_CXT.count = 0;
504  stash = gv_stashpv(__PACKAGE__, 1);
505  newCONSTSUB(stash, "SIG_MIN",   newSVuv(SIG_MIN));
506  newCONSTSUB(stash, "SIG_MAX",   newSVuv(SIG_MAX));
507  newCONSTSUB(stash, "SIG_NBR",   newSVuv(SIG_NBR));
508  newCONSTSUB(stash, "MGf_COPY",  newSVuv(MGf_COPY));
509  newCONSTSUB(stash, "MGf_DUP",   newSVuv(MGf_DUP));
510  newCONSTSUB(stash, "MGf_LOCAL", newSVuv(MGf_LOCAL));
511 }
512
513 SV *_wizard(SV *svsig, ...)
514 PROTOTYPE: $@
515 PREINIT:
516  U16 sig;
517  I32 i;
518  char buf[8];
519  MGWIZ *w;
520  MGVTBL *t;
521  MAGIC *mg;
522  SV *cb, *sv;
523 CODE:
524  dMY_CXT;
525
526  if (items != 7
527 #if MGf_COPY
528              + 1
529 #endif /* MGf_COPY */
530 #if MGf_DUP
531              + 1
532 #endif /* MGf_DUP */
533 #if MGf_LOCAL
534              + 1
535 #endif /* MGf_LOCAL */
536                 ) { croak(vmg__wizard_args); }
537
538  if (SvOK(svsig)) {
539   SV **old;
540   sig = vmg_sv2sig(svsig);
541   if (old = hv_fetch(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), 0)) {
542    ST(0) = sv_2mortal(newRV_inc(*old));
543    XSRETURN(1);
544   }
545  } else {
546   if (MY_CXT.count >= SIG_NBR) { croak(vmg_toomanysigs); }
547   sig = vmg_gensig();
548  }
549
550  Newx(t, 1, MGVTBL);
551  Newx(w, 1, MGWIZ);
552  w->vtbl = t;
553  w->sig  = sig;
554
555  cb = ST(1); w->cb_data = SvROK(cb) ? newRV_inc(SvRV(cb)) : NULL;
556  VMG_SET_CB(get,   t, w, ST(2));
557  VMG_SET_CB(set,   t, w, ST(3));
558  VMG_SET_CB(len,   t, w, ST(4));
559  VMG_SET_CB(clear, t, w, ST(5));
560  VMG_SET_CB(free,  t, w, ST(6));
561 #if MGf_COPY
562  VMG_SET_CB(copy,  t, w, ST(7));
563 #endif /* MGf_COPY */
564 #if MGf_DUP
565  VMG_SET_CB(dup,   t, w, ST(8));
566 #endif /* MGf_DUP */
567 #if MGf_LOCAL
568  VMG_SET_CB(local, t, w, ST(9));
569 #endif /* MGf_LOCAL */
570
571  sv = MGWIZ2SV(w);
572  mg = vmg_sv_magicext(sv, NULL, &vmg_wizard_vtbl, NULL, -1);
573  mg->mg_private = SIG_WIZ;
574 #if MGf_COPY
575  if (t->svt_copy)  { mg->mg_flags |= MGf_COPY; }
576 #endif /* MGf_COPY */
577 #if MGf_DUP
578  if (t->svt_dup)   { mg->mg_flags |= MGf_DUP; }
579 #endif /* MGf_DUP */
580 #if MGf_LOCAL
581  if (t->svt_local) { mg->mg_flags |= MGf_LOCAL; }
582 #endif /* MGf_LOCAL */
583
584  hv_store(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), sv, 0);
585  ++MY_CXT.count;
586  
587  RETVAL = newRV_noinc(sv);
588 OUTPUT:
589  RETVAL
590
591 SV *gensig()
592 PROTOTYPE:
593 CODE:
594  dMY_CXT;
595  if (MY_CXT.count >= SIG_NBR) { croak(vmg_toomanysigs); }
596  RETVAL = newSVuv(vmg_gensig());
597 OUTPUT:
598  RETVAL
599
600 SV *getsig(SV *wiz)
601 PROTOTYPE: $
602 CODE:
603  if (!SvROK(wiz)) { croak(vmg_invalid_wiz); }
604  RETVAL = newSVuv(SV2MGWIZ(SvRV(wiz))->sig);
605 OUTPUT:
606  RETVAL
607
608 SV *cast(SV *sv, SV *wiz, ...)
609 PROTOTYPE: \[$@%&*]$@
610 PREINIT:
611  AV *args = NULL;
612  SV *ret;
613 CODE:
614  dMY_CXT;
615  if (SvROK(wiz)) {
616   wiz = SvRV(wiz);
617  } else if (SvOK(wiz)) {
618   char buf[8];
619   SV **old;
620   U16 sig = vmg_sv2sig(wiz);
621   if (old = hv_fetch(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), 0)) {
622    wiz = *old;
623   } else {
624    XSRETURN_UNDEF;
625   }
626  } else {
627   croak(vmg_invalid_sig);
628  }
629  if (items > 2) {
630   I32 i;
631   args = newAV();
632   av_fill(args, items - 2);
633   for (i = 2; i < items; ++i) {
634    SV *arg = ST(i);
635    SvREFCNT_inc(arg);
636    if (av_store(args, i - 2, arg) == NULL) { croak(vmg_argstorefailed); }
637   }
638  }
639  ret = newSVuv(vmg_cast(SvRV(sv), wiz, args));
640  SvREFCNT_dec(args);
641  RETVAL = ret;
642 OUTPUT:
643  RETVAL
644
645 SV *getdata(SV *sv, SV *wiz)
646 PROTOTYPE: \[$@%&*]$
647 PREINIT:
648  SV *data;
649  U16 sig;
650 CODE:
651  dMY_CXT;
652  if (SvROK(wiz)) {
653   sig = SV2MGWIZ(SvRV(wiz))->sig;
654  } else if (SvOK(wiz)) {
655   char buf[8];
656   sig = vmg_sv2sig(wiz);
657   if (!hv_fetch(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), 0)) {
658    XSRETURN_UNDEF;
659   }
660  } else {
661   croak(vmg_invalid_wiz);
662  }
663  data = vmg_data_get(SvRV(sv), sig);
664  if (!data) { XSRETURN_UNDEF; }
665  ST(0) = newSVsv(data);
666  XSRETURN(1);
667
668 SV *dispell(SV *sv, SV *wiz)
669 PROTOTYPE: \[$@%&*]$
670 PREINIT:
671  U16 sig;
672 CODE:
673  dMY_CXT;
674  if (SvROK(wiz)) {
675   sig = SV2MGWIZ(SvRV(wiz))->sig;
676  } else if (SvOK(wiz)) {
677   char buf[8];
678   sig = vmg_sv2sig(wiz);
679   if (!hv_fetch(MY_CXT.wizz, buf, sprintf(buf, "%u", sig), 0)) {
680    XSRETURN_UNDEF;
681   }
682  } else {
683   croak(vmg_invalid_wiz);
684  }
685  RETVAL = newSVuv(vmg_dispell(SvRV(sv), sig));
686 OUTPUT:
687  RETVAL