#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "xs_object_magic.h" STATIC MGVTBL null_mg_vtbl = { NULL, /* get */ NULL, /* set */ NULL, /* len */ NULL, /* clear */ NULL, /* free */ #if MGf_COPY NULL, /* copy */ #endif /* MGf_COPY */ #if MGf_DUP NULL, /* dup */ #endif /* MGf_DUP */ #if MGf_LOCAL NULL, /* local */ #endif /* MGf_LOCAL */ }; void xs_object_magic_attach_struct (pTHX_ SV *sv, void *ptr) { sv_magicext(sv, NULL, PERL_MAGIC_ext, &null_mg_vtbl, ptr, 0 ); } int xs_object_magic_detach_struct (pTHX_ SV *sv, void *ptr) { MAGIC *mg, *prevmagic, *moremagic = NULL; int removed = 0; if (SvTYPE(sv) < SVt_PVMG) return 0; /* find our magic, remembering the magic before and the magic after */ for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) { moremagic = mg->mg_moremagic; if (mg->mg_type == PERL_MAGIC_ext && mg->mg_virtual == &null_mg_vtbl && ( ptr == NULL || mg->mg_ptr == ptr )) { if(prevmagic != NULL) { prevmagic->mg_moremagic = moremagic; } else { SvMAGIC_set(sv, moremagic); } mg->mg_moremagic = NULL; Safefree(mg); mg = prevmagic; removed++; } } return removed; } int xs_object_magic_detach_struct_rv (pTHX_ SV *sv, void *ptr){ if(sv && SvROK(sv)) { sv = SvRV(sv); return xs_object_magic_detach_struct(aTHX_ sv, ptr); } return 0; } SV *xs_object_magic_create (pTHX_ void *ptr, HV *stash) { HV *hv = newHV(); SV *obj = newRV_noinc((SV *)hv); sv_bless(obj, stash); xs_object_magic_attach_struct(aTHX_ (SV *)hv, ptr); return obj; } MAGIC *xs_object_magic_get_mg (pTHX_ SV *sv) { MAGIC *mg; if (SvTYPE(sv) >= SVt_PVMG) { for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { if ( (mg->mg_type == PERL_MAGIC_ext) && (mg->mg_virtual == &null_mg_vtbl) ) { return mg; } } } return NULL; } int xs_object_magic_has_struct (pTHX_ SV *sv) { MAGIC *mg = xs_object_magic_get_mg(aTHX_ sv); return mg ? 1 : 0; } int xs_object_magic_has_struct_rv (pTHX_ SV *sv) { if( sv && SvROK(sv) ){ sv = SvRV(sv); MAGIC *mg = xs_object_magic_get_mg(aTHX_ sv); return mg ? 1 : 0; } return 0; } void *xs_object_magic_get_struct (pTHX_ SV *sv) { MAGIC *mg = xs_object_magic_get_mg(aTHX_ sv); if ( mg ) return mg->mg_ptr; else return NULL; } void *xs_object_magic_get_struct_rv_pretty (pTHX_ SV *sv, const char *name) { if ( sv && SvROK(sv) ) { MAGIC *mg = xs_object_magic_get_mg(aTHX_ SvRV(sv)); if ( mg ) return mg->mg_ptr; else croak("%s does not have a struct associated with it", name); } else { croak("%s is not a reference", name); } } void *xs_object_magic_get_struct_rv (pTHX_ SV *sv) { return xs_object_magic_get_struct_rv_pretty(aTHX_ sv, "argument"); } /* stuff for the test follows */ typedef struct { I32 i; } _xs_magic_object_test_t; static I32 destroyed = 0; static _xs_magic_object_test_t *test_new () { _xs_magic_object_test_t *t; Newx(t, 1, _xs_magic_object_test_t); t->i = 0; return t; } static int test_count (_xs_magic_object_test_t *t) { return ++t->i; } static void test_DESTROY (_xs_magic_object_test_t *t) { Safefree(t); destroyed++; } MODULE = XS::Object::Magic PACKAGE = XS::Object::Magic::Test PREFIX = test_ PROTOTYPES: DISABLE SV * new(char *class) CODE: RETVAL = xs_object_magic_create(aTHX_ (void *)test_new(), gv_stashpv(class, 0)); OUTPUT: RETVAL I32 test_count (self) _xs_magic_object_test_t *self; void test_has (self) SV *self; PPCODE: if (xs_object_magic_has_struct_rv(aTHX_ self)) XSRETURN_YES; XSRETURN_NO; void test_attach_again (self) SV *self void *s = xs_object_magic_get_struct_rv(aTHX_ self); CODE: xs_object_magic_attach_struct(aTHX_ SvRV(self), s ); int test_detach_null (self) SV *self; CODE: RETVAL = xs_object_magic_detach_struct_rv(aTHX_ self, NULL); OUTPUT: RETVAL int test_detach_struct (self) SV *self; void *s = xs_object_magic_get_struct_rv(aTHX_ self); CODE: RETVAL = xs_object_magic_detach_struct_rv(aTHX_ self, s); OUTPUT: RETVAL int test_detach_garbage (self) SV *self; void *s = (void *) 0x123456; CODE: RETVAL = xs_object_magic_detach_struct_rv(aTHX_ self, s); OUTPUT: RETVAL void test_DESTROY (self) _xs_magic_object_test_t *self; I32 destroyed () CODE: RETVAL = destroyed; OUTPUT: RETVAL