X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=XS.xs;h=ac7503885effd58a96beaa5240a8938f91876185;hb=HEAD;hp=2021e6d9497cba46c201f80ef55ce9abb31eea24;hpb=8860963a0ad7d3cc2e26593efd448054adc2fc4b;p=gitmo%2FPackage-Stash-XS.git diff --git a/XS.xs b/XS.xs index 2021e6d..ac75038 100644 --- a/XS.xs +++ b/XS.xs @@ -28,6 +28,14 @@ #define GvCV_set(gv, cv) (GvCV(gv) = (CV*)(cv)) #endif +#ifndef MUTABLE_PTR +#define MUTABLE_PTR(p) ((void *) (p)) +#endif + +#ifndef MUTABLE_SV +#define MUTABLE_SV(p) ((SV *)MUTABLE_PTR(p)) +#endif + #ifndef SVT_SCALAR #define SVT_SCALAR(svt) (svt <= SVt_PVLV) #endif @@ -96,7 +104,7 @@ } while (0) #define GvSetCV(g,v) do { \ SvREFCNT_dec(GvCV(g)); \ - if ((GvCV_set(g, v))) { \ + if ((GvCV_set(g, (CV*)(v)))) { \ GvIMPORTED_CV_on(g); \ GvASSUMECV_on(g); \ } \ @@ -324,18 +332,64 @@ static SV *_get_name(SV *self) return ret; } +static void _real_gv_init(GV *gv, HV *stash, SV *name) +{ + char *name_pv; + STRLEN name_len; + + name_pv = SvPV(name, name_len); + gv_init(gv, stash, name_pv, name_len, 1); + + /* XXX: copied and pasted from gv_fetchpvn_flags and such */ + /* ignoring the stuff for CORE:: and main:: for now, and also + * ignoring the GvMULTI_on bits, since we pass 1 to gv_init above */ + switch (name_pv[0]) { + case 'I': + if (strEQ(&name_pv[1], "SA")) { + AV *av; + + av = GvAVn(gv); + sv_magic(MUTABLE_SV(av), MUTABLE_SV(gv), PERL_MAGIC_isa, + NULL, 0); + } + break; + case 'O': + if (strEQ(&name_pv[1], "VERLOAD")) { + HV *hv; + + hv = GvHVn(gv); + hv_magic(hv, NULL, PERL_MAGIC_overload); + } + break; + default: + break; + } +} + static void _expand_glob(SV *self, SV *varname) { - SV *name; + HV *namespace; + HE *entry; + GV *glob; - name = newSVsv(_get_name(self)); - sv_catpvs(name, "::"); - sv_catsv(name, varname); + namespace = _get_namespace(self); - /* can't use gv_init here, because it screws up @ISA in a way that I - * can't reproduce, but that CMOP triggers */ - gv_fetchsv(name, GV_ADD, SVt_NULL); - SvREFCNT_dec(name); + if (entry = hv_fetch_ent(namespace, varname, 0, 0)) { + glob = (GV*)HeVAL(entry); + if (isGV(glob)) { + croak("_expand_glob called on stash slot with expanded glob"); + } + else { + SvREFCNT_inc(glob); + _real_gv_init(glob, namespace, varname); + if (!hv_store_ent(namespace, varname, (SV*)glob, 0)) { + croak("hv_store failed"); + } + } + } + else { + croak("_expand_glob called on nonexistent stash slot"); + } } static SV *_get_symbol(SV *self, varspec_t *variable, int vivify) @@ -493,22 +547,19 @@ add_symbol(self, variable, initial=NULL, ...) varspec_t variable SV *initial PREINIT: - SV *name; GV *glob; + HV *namespace; + HE *entry; CODE: if (initial && !_valid_for_type(initial, variable.type)) croak("%s is not of type %s", SvPV_nolen(initial), vartype_to_string(variable.type)); - name = newSVsv(_get_name(self)); - sv_catpvs(name, "::"); - sv_catsv(name, variable.name); - if (items > 2 && (PL_perldb & 0x10) && variable.type == VAR_CODE) { int i; char *filename = NULL; I32 first_line_num = -1, last_line_num = -1; - SV *dbval; + SV *dbval, *name; HV *dbsub; if ((items - 3) % 2) @@ -544,6 +595,10 @@ add_symbol(self, variable, initial=NULL, ...) if (last_line_num == -1) last_line_num = first_line_num; + name = newSVsv(_get_name(self)); + sv_catpvs(name, "::"); + sv_catsv(name, variable.name); + /* http://perldoc.perl.org/perldebguts.html#Debugger-Internals */ dbsub = get_hv("DB::sub", 1); dbval = newSVpvf("%s:%d-%d", filename, first_line_num, last_line_num); @@ -552,12 +607,25 @@ add_symbol(self, variable, initial=NULL, ...) SvPV_nolen(name)); SvREFCNT_dec(dbval); } + + SvREFCNT_dec(name); } /* GV_ADDMULTI rather than GV_ADD because otherwise you get 'used only * once' warnings in some situations... i can't reproduce this, but CMOP * triggers it */ - glob = gv_fetchsv(name, GV_ADDMULTI, vartype_to_svtype(variable.type)); + namespace = _get_namespace(self); + entry = hv_fetch_ent(namespace, variable.name, 0, 0); + if (entry) { + glob = (GV*)HeVAL(entry); + } + else { + glob = (GV*)newSV(0); + _real_gv_init(glob, namespace, variable.name); + if (!hv_store_ent(namespace, variable.name, (SV*)glob, 0)) { + croak("hv_store failed"); + } + } if (initial) { SV *val; @@ -589,8 +657,6 @@ add_symbol(self, variable, initial=NULL, ...) } } - SvREFCNT_dec(name); - void remove_glob(self, name) SV *self