* The main guts of traverse_isa was actually copied from gv_fetchmeth
*/
+#define PERL_ARGS_ASSERT_ISA_LOOKUP \
+ assert(stash); \
+ assert(namesv || name)
+
+
STATIC bool
-S_isa_lookup(pTHX_ HV *stash, const char * const name, STRLEN len, U32 flags)
+S_isa_lookup(pTHX_ HV *stash, SV *namesv, const char * name, STRLEN len, U32 flags)
{
const struct mro_meta *const meta = HvMROMETA(stash);
HV *isa = meta->isa;
PERL_ARGS_ASSERT_ISA_LOOKUP;
if (!isa) {
- (void)mro_get_linear_isa(stash);
- isa = meta->isa;
+ (void)mro_get_linear_isa(stash);
+ isa = meta->isa;
}
- if (hv_common(isa, NULL, name, len, ( flags & SVf_UTF8 ? HVhek_UTF8 : 0),
- HV_FETCH_ISEXISTS, NULL, 0)) {
- /* Direct name lookup worked. */
- return TRUE;
+ if (hv_common(isa, namesv, name, len, ( flags & SVf_UTF8 ? HVhek_UTF8 : 0),
+ HV_FETCH_ISEXISTS, NULL, 0)) {
+ /* Direct name lookup worked. */
+ return TRUE;
}
/* A stash/class can go by many names (ie. User == main::User), so
we use the HvENAME in the stash itself, which is canonical, falling
back to HvNAME if necessary. */
- our_stash = gv_stashpvn(name, len, flags);
+ our_stash = gv_stashsvpvn_cached(namesv, name, len, flags);
if (our_stash) {
- HEK *canon_name = HvENAME_HEK(our_stash);
- if (!canon_name) canon_name = HvNAME_HEK(our_stash);
- assert(canon_name);
- if (hv_common(isa, NULL, HEK_KEY(canon_name), HEK_LEN(canon_name),
- HEK_FLAGS(canon_name),
- HV_FETCH_ISEXISTS, NULL, HEK_HASH(canon_name))) {
- return TRUE;
- }
+ HEK *canon_name = HvENAME_HEK(our_stash);
+ if (!canon_name) canon_name = HvNAME_HEK(our_stash);
+ assert(canon_name);
+ if (hv_common(isa, NULL, HEK_KEY(canon_name), HEK_LEN(canon_name),
+ HEK_FLAGS(canon_name),
+ HV_FETCH_ISEXISTS, NULL, HEK_HASH(canon_name))) {
+ return TRUE;
+ }
}
return FALSE;
}
+#define PERL_ARGS_ASSERT_SV_DERIVED_FROM_SVPVN \
+ assert(sv); \
+ assert(namesv || name)
+
+STATIC bool
+S_sv_derived_from_svpvn(pTHX_ SV *sv, SV *namesv, const char * name, const STRLEN len, U32 flags)
+{
+ HV* stash;
+
+ PERL_ARGS_ASSERT_SV_DERIVED_FROM_SVPVN;
+ SvGETMAGIC(sv);
+
+ if (SvROK(sv)) {
+ const char *type;
+ sv = SvRV(sv);
+ type = sv_reftype(sv,0);
+ if (type) {
+ if (namesv)
+ name = SvPV_nolen(namesv);
+ if (strEQ(name, type))
+ return TRUE;
+ }
+ if (!SvOBJECT(sv))
+ return FALSE;
+ stash = SvSTASH(sv);
+ }
+ else {
+ stash = gv_stashsv(sv, 0);
+ }
+
+ if (stash && isa_lookup(stash, namesv, name, len, flags))
+ return TRUE;
+
+ stash = gv_stashpvs("UNIVERSAL", 0);
+ return stash && isa_lookup(stash, namesv, name, len, flags);
+}
+
/*
-=head1 SV Manipulation Functions
+=for apidoc_section $SV
=for apidoc sv_derived_from_pvn
=for apidoc sv_derived_from_sv
Exactly like L</sv_derived_from_pvn>, but takes the name string in the form
-of an SV instead of a string/length pair.
+of an SV instead of a string/length pair. This is the advised form.
=cut
bool
Perl_sv_derived_from_sv(pTHX_ SV *sv, SV *namesv, U32 flags)
{
- char *namepv;
- STRLEN namelen;
PERL_ARGS_ASSERT_SV_DERIVED_FROM_SV;
- namepv = SvPV(namesv, namelen);
- if (SvUTF8(namesv))
- flags |= SVf_UTF8;
- return sv_derived_from_pvn(sv, namepv, namelen, flags);
+ return sv_derived_from_svpvn(sv, namesv, NULL, 0, flags);
}
/*
Perl_sv_derived_from(pTHX_ SV *sv, const char *const name)
{
PERL_ARGS_ASSERT_SV_DERIVED_FROM;
- return sv_derived_from_pvn(sv, name, strlen(name), 0);
+ return sv_derived_from_svpvn(sv, NULL, name, strlen(name), 0);
}
/*
Perl_sv_derived_from_pv(pTHX_ SV *sv, const char *const name, U32 flags)
{
PERL_ARGS_ASSERT_SV_DERIVED_FROM_PV;
- return sv_derived_from_pvn(sv, name, strlen(name), flags);
+ return sv_derived_from_svpvn(sv, NULL, name, strlen(name), flags);
}
bool
Perl_sv_derived_from_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, U32 flags)
{
- HV *stash;
-
PERL_ARGS_ASSERT_SV_DERIVED_FROM_PVN;
+ return sv_derived_from_svpvn(sv, NULL, name, len, flags);
+}
- SvGETMAGIC(sv);
+/*
+=for apidoc sv_isa_sv
- if (SvROK(sv)) {
- const char *type;
- sv = SvRV(sv);
- type = sv_reftype(sv,0);
- if (type && strEQ(type,name))
- return TRUE;
- if (!SvOBJECT(sv))
- return FALSE;
- stash = SvSTASH(sv);
- }
- else {
- stash = gv_stashsv(sv, 0);
+Returns a boolean indicating whether the SV is an object reference and is
+derived from the specified class, respecting any C<isa()> method overloading
+it may have. Returns false if C<sv> is not a reference to an object, or is
+not derived from the specified class.
+
+This is the function used to implement the behaviour of the C<isa> operator.
+
+Does not invoke magic on C<sv>.
+
+Not to be confused with the older C<sv_isa> function, which does not use an
+overloaded C<isa()> method, nor will check subclassing.
+
+=cut
+
+*/
+
+bool
+Perl_sv_isa_sv(pTHX_ SV *sv, SV *namesv)
+{
+ GV *isagv;
+
+ PERL_ARGS_ASSERT_SV_ISA_SV;
+
+ if(!SvROK(sv) || !SvOBJECT(SvRV(sv)))
+ return FALSE;
+
+ isagv = gv_fetchmeth_pvn(SvSTASH(SvRV(sv)), "isa", 3, -1, GV_NOUNIVERSAL);
+ if(isagv) {
+ dSP;
+ CV *isacv = isGV(isagv) ? GvCV(isagv) : (CV *)isagv;
+ SV *retsv;
+ bool ret;
+
+ PUTBACK;
+
+ ENTER;
+ SAVETMPS;
+
+ EXTEND(SP, 2);
+ PUSHMARK(SP);
+ PUSHs(sv);
+ PUSHs(namesv);
+ PUTBACK;
+
+ call_sv((SV *)isacv, G_SCALAR);
+
+ SPAGAIN;
+ retsv = POPs;
+ ret = SvTRUE(retsv);
+ PUTBACK;
+
+ FREETMPS;
+ LEAVE;
+
+ return ret;
}
- if (stash && isa_lookup(stash, name, len, flags))
- return TRUE;
+ /* TODO: Support namesv being an HV ref to the stash directly? */
- stash = gv_stashpvs("UNIVERSAL", 0);
- return stash && isa_lookup(stash, name, len, flags);
+ return sv_derived_from_sv(sv, namesv, 0);
}
/*
SvGETMAGIC(sv);
if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv)))) {
- LEAVE;
- return FALSE;
+ LEAVE;
+ return FALSE;
}
if (SvROK(sv) && SvOBJECT(SvRV(sv))) {
- classname = sv_ref(NULL,SvRV(sv),TRUE);
+ classname = sv_ref(NULL,SvRV(sv),TRUE);
} else {
- classname = sv;
+ classname = sv;
}
if (sv_eq(classname, namesv)) {
- LEAVE;
- return TRUE;
+ LEAVE;
+ return TRUE;
}
PUSHMARK(SP);
/* create a PV with value "isa", but with a special address
* so that perl knows we're really doing "DOES" instead */
methodname = newSV_type(SVt_PV);
- SvLEN(methodname) = 0;
- SvCUR(methodname) = strlen(PL_isa_DOES);
+ SvLEN_set(methodname, 0);
+ SvCUR_set(methodname, strlen(PL_isa_DOES));
SvPVX(methodname) = (char *)PL_isa_DOES; /* discard 'const' qualifier */
SvPOK_on(methodname);
sv_2mortal(methodname);
call_sv(methodname, G_SCALAR | G_METHOD);
SPAGAIN;
- does_it = SvTRUE( TOPs );
+ does_it = SvTRUE_NN( TOPs );
FREETMPS;
LEAVE;
PERL_ARGS_ASSERT_CROAK_XS_USAGE;
if (gv) got_gv: {
- const HV *const stash = GvSTASH(gv);
+ const HV *const stash = GvSTASH(gv);
- if (HvNAME_get(stash))
- /* diag_listed_as: SKIPME */
- Perl_croak_nocontext("Usage: %" HEKf "::%" HEKf "(%s)",
+ if (HvNAME_get(stash))
+ /* diag_listed_as: SKIPME */
+ Perl_croak_nocontext("Usage: %" HEKf "::%" HEKf "(%s)",
HEKfARG(HvNAME_HEK(stash)),
HEKfARG(GvNAME_HEK(gv)),
params);
- else
- /* diag_listed_as: SKIPME */
- Perl_croak_nocontext("Usage: %" HEKf "(%s)",
+ else
+ /* diag_listed_as: SKIPME */
+ Perl_croak_nocontext("Usage: %" HEKf "(%s)",
HEKfARG(GvNAME_HEK(gv)), params);
} else {
dTHX;
if ((gv = CvGV(cv))) goto got_gv;
- /* Pants. I don't think that it should be possible to get here. */
- /* diag_listed_as: SKIPME */
- Perl_croak(aTHX_ "Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
+ /* Pants. I don't think that it should be possible to get here. */
+ /* diag_listed_as: SKIPME */
+ Perl_croak(aTHX_ "Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
}
}
dXSARGS;
if (items != 2)
- croak_xs_usage(cv, "reference, kind");
+ croak_xs_usage(cv, "reference, kind");
else {
- SV * const sv = ST(0);
+ SV * const sv = ST(0);
- SvGETMAGIC(sv);
+ SvGETMAGIC(sv);
- if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))))
- XSRETURN_UNDEF;
+ if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))))
+ XSRETURN_UNDEF;
- ST(0) = boolSV(sv_derived_from_sv(sv, ST(1), 0));
- XSRETURN(1);
+ ST(0) = boolSV(sv_derived_from_sv(sv, ST(1), 0));
+ XSRETURN(1);
}
}
GV *iogv;
if (items != 2)
- croak_xs_usage(cv, "object-ref, method");
+ croak_xs_usage(cv, "object-ref, method");
sv = ST(0);
precedence here over the numeric form, as (!1)->foo treats the
invocant as the empty string, though it is a dualvar. */
if (!SvOK(sv) || (SvPOK(sv) && !SvCUR(sv)))
- XSRETURN_UNDEF;
+ XSRETURN_UNDEF;
rv = &PL_sv_undef;
if (SvOBJECT(sv))
pkg = SvSTASH(sv);
else if (isGV_with_GP(sv) && GvIO(sv))
- pkg = SvSTASH(GvIO(sv));
+ pkg = SvSTASH(GvIO(sv));
}
else if (isGV_with_GP(sv) && GvIO(sv))
pkg = SvSTASH(GvIO(sv));
}
if (pkg) {
- GV * const gv = gv_fetchmethod_sv_flags(pkg, ST(1), 0);
+ GV * const gv = gv_fetchmethod_sv_flags(pkg, ST(1), 0);
if (gv && isGV(gv))
- rv = sv_2mortal(newRV(MUTABLE_SV(GvCV(gv))));
+ rv = sv_2mortal(newRV(MUTABLE_SV(GvCV(gv))));
}
ST(0) = rv;
PERL_UNUSED_ARG(cv);
if (items != 2)
- Perl_croak(aTHX_ "Usage: invocant->DOES(kind)");
+ Perl_croak(aTHX_ "Usage: invocant->DOES(kind)");
else {
- SV * const sv = ST(0);
- if (sv_does_sv( sv, ST(1), 0 ))
- XSRETURN_YES;
+ SV * const sv = ST(0);
+ if (sv_does_sv( sv, ST(1), 0 ))
+ XSRETURN_YES;
- XSRETURN_NO;
+ XSRETURN_NO;
}
}
{
dXSARGS;
if (items != 1)
- croak_xs_usage(cv, "sv");
+ croak_xs_usage(cv, "sv");
else {
- SV * const sv = ST(0);
- SvGETMAGIC(sv);
- if (SvUTF8(sv))
- XSRETURN_YES;
- else
- XSRETURN_NO;
+ SV * const sv = ST(0);
+ SvGETMAGIC(sv);
+ if (SvUTF8(sv))
+ XSRETURN_YES;
+ else
+ XSRETURN_NO;
}
XSRETURN_EMPTY;
}
{
dXSARGS;
if (items != 1)
- croak_xs_usage(cv, "sv");
+ croak_xs_usage(cv, "sv");
else {
- SV * const sv = ST(0);
- STRLEN len;
- const char * const s = SvPV_const(sv,len);
- if (!SvUTF8(sv) || is_utf8_string((const U8*)s,len))
- XSRETURN_YES;
- else
- XSRETURN_NO;
+ SV * const sv = ST(0);
+ STRLEN len;
+ const char * const s = SvPV_const(sv,len);
+ if (!SvUTF8(sv) || is_utf8_string((const U8*)s,len))
+ XSRETURN_YES;
+ else
+ XSRETURN_NO;
}
XSRETURN_EMPTY;
}
{
dXSARGS;
if (items != 1)
- croak_xs_usage(cv, "sv");
+ croak_xs_usage(cv, "sv");
sv_utf8_encode(ST(0));
SvSETMAGIC(ST(0));
XSRETURN_EMPTY;
{
dXSARGS;
if (items != 1)
- croak_xs_usage(cv, "sv");
+ croak_xs_usage(cv, "sv");
else {
- SV * const sv = ST(0);
- bool RETVAL;
- SvPV_force_nolen(sv);
- RETVAL = sv_utf8_decode(sv);
- SvSETMAGIC(sv);
- ST(0) = boolSV(RETVAL);
+ SV * const sv = ST(0);
+ bool RETVAL;
+ SvPV_force_nolen(sv);
+ RETVAL = sv_utf8_decode(sv);
+ SvSETMAGIC(sv);
+ ST(0) = boolSV(RETVAL);
}
XSRETURN(1);
}
{
dXSARGS;
if (items != 1)
- croak_xs_usage(cv, "sv");
+ croak_xs_usage(cv, "sv");
else {
- SV * const sv = ST(0);
- STRLEN RETVAL;
- dXSTARG;
+ SV * const sv = ST(0);
+ STRLEN RETVAL;
+ dXSTARG;
- RETVAL = sv_utf8_upgrade(sv);
- XSprePUSH; PUSHi((IV)RETVAL);
+ RETVAL = sv_utf8_upgrade(sv);
+ XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
}
{
dXSARGS;
if (items < 1 || items > 2)
- croak_xs_usage(cv, "sv, failok=0");
+ croak_xs_usage(cv, "sv, failok=0");
else {
- SV * const sv = ST(0);
- const bool failok = (items < 2) ? 0 : SvTRUE(ST(1)) ? 1 : 0;
- const bool RETVAL = sv_utf8_downgrade(sv, failok);
+ SV * const sv0 = ST(0);
+ SV * const sv1 = ST(1);
+ const bool failok = (items < 2) ? 0 : SvTRUE_NN(sv1) ? 1 : 0;
+ const bool RETVAL = sv_utf8_downgrade(sv0, failok);
- ST(0) = boolSV(RETVAL);
+ ST(0) = boolSV(RETVAL);
}
XSRETURN(1);
}
sv = SvRV(svz);
if (items == 1) {
- if (SvREADONLY(sv))
- XSRETURN_YES;
- else
- XSRETURN_NO;
+ if (SvREADONLY(sv))
+ XSRETURN_YES;
+ else
+ XSRETURN_NO;
}
else if (items == 2) {
- if (SvTRUE(ST(1))) {
- SvFLAGS(sv) |= SVf_READONLY;
- XSRETURN_YES;
- }
- else {
- /* I hope you really know what you are doing. */
- SvFLAGS(sv) &=~ SVf_READONLY;
- XSRETURN_NO;
- }
+ SV *sv1 = ST(1);
+ if (SvTRUE_NN(sv1)) {
+ SvFLAGS(sv) |= SVf_READONLY;
+ XSRETURN_YES;
+ }
+ else {
+ /* I hope you really know what you are doing. */
+ SvFLAGS(sv) &=~ SVf_READONLY;
+ XSRETURN_NO;
+ }
}
XSRETURN_UNDEF; /* Can't happen. */
}
SvREADONLY_on(sv);
if (SvTYPE(sv) == SVt_PVAV && AvFILLp(sv) != -1) {
- /* for constant.pm; nobody else should be calling this
- on arrays anyway. */
- SV **svp;
- for (svp = AvARRAY(sv) + AvFILLp(sv)
- ; svp >= AvARRAY(sv)
- ; --svp)
- if (*svp) SvPADTMP_on(*svp);
+ /* for constant.pm; nobody else should be calling this
+ on arrays anyway. */
+ SV **svp;
+ for (svp = AvARRAY(sv) + AvFILLp(sv)
+ ; svp >= AvARRAY(sv)
+ ; --svp)
+ if (*svp) SvPADTMP_on(*svp);
}
XSRETURN(0);
}
dXSARGS;
if (items != 1 || !SvROK(ST(0)))
- croak_xs_usage(cv, "hv");
+ croak_xs_usage(cv, "hv");
else {
- HV * const hv = MUTABLE_HV(SvRV(ST(0)));
- hv_clear_placeholders(hv);
- XSRETURN(0);
+ HV * const hv = MUTABLE_HV(SvRV(ST(0)));
+ hv_clear_placeholders(hv);
+ XSRETURN(0);
}
}
{
dXSARGS;
if (items < 1 || items % 2 == 0)
- croak_xs_usage(cv, "filehandle[,args]");
+ croak_xs_usage(cv, "filehandle[,args]");
#if defined(USE_PERLIO)
{
- SV * sv;
- GV * gv;
- IO * io;
- bool input = TRUE;
- bool details = FALSE;
-
- if (items > 1) {
- SV * const *svp;
- for (svp = MARK + 2; svp <= SP; svp += 2) {
- SV * const * const varp = svp;
- SV * const * const valp = svp + 1;
- STRLEN klen;
- const char * const key = SvPV_const(*varp, klen);
-
- switch (*key) {
- case 'i':
+ SV * sv;
+ GV * gv;
+ IO * io;
+ bool input = TRUE;
+ bool details = FALSE;
+
+ if (items > 1) {
+ SV * const *svp;
+ for (svp = MARK + 2; svp <= SP; svp += 2) {
+ SV * const * const varp = svp;
+ SV * const * const valp = svp + 1;
+ STRLEN klen;
+ const char * const key = SvPV_const(*varp, klen);
+
+ switch (*key) {
+ case 'i':
if (memEQs(key, klen, "input")) {
- input = SvTRUE(*valp);
- break;
- }
- goto fail;
- case 'o':
+ input = SvTRUE(*valp);
+ break;
+ }
+ goto fail;
+ case 'o':
if (memEQs(key, klen, "output")) {
- input = !SvTRUE(*valp);
- break;
- }
- goto fail;
- case 'd':
+ input = !SvTRUE(*valp);
+ break;
+ }
+ goto fail;
+ case 'd':
if (memEQs(key, klen, "details")) {
- details = SvTRUE(*valp);
- break;
- }
- goto fail;
- default:
- fail:
- Perl_croak(aTHX_
- "get_layers: unknown argument '%s'",
- key);
- }
- }
-
- SP -= (items - 1);
- }
-
- sv = POPs;
- gv = MAYBE_DEREF_GV(sv);
-
- if (!gv && !SvROK(sv))
- gv = gv_fetchsv_nomg(sv, 0, SVt_PVIO);
-
- if (gv && (io = GvIO(gv))) {
- AV* const av = PerlIO_get_layers(aTHX_ input ?
- IoIFP(io) : IoOFP(io));
- SSize_t i;
- const SSize_t last = av_tindex(av);
- SSize_t nitem = 0;
-
- for (i = last; i >= 0; i -= 3) {
- SV * const * const namsvp = av_fetch(av, i - 2, FALSE);
- SV * const * const argsvp = av_fetch(av, i - 1, FALSE);
- SV * const * const flgsvp = av_fetch(av, i, FALSE);
-
- const bool namok = namsvp && *namsvp && SvPOK(*namsvp);
- const bool argok = argsvp && *argsvp && SvPOK(*argsvp);
- const bool flgok = flgsvp && *flgsvp && SvIOK(*flgsvp);
-
- EXTEND(SP, 3); /* Three is the max in all branches: better check just once */
- if (details) {
- /* Indents of 5? Yuck. */
- /* We know that PerlIO_get_layers creates a new SV for
- the name and flags, so we can just take a reference
- and "steal" it when we free the AV below. */
- PUSHs(namok
- ? sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp))
- : &PL_sv_undef);
- PUSHs(argok
- ? newSVpvn_flags(SvPVX_const(*argsvp),
- SvCUR(*argsvp),
- (SvUTF8(*argsvp) ? SVf_UTF8 : 0)
- | SVs_TEMP)
- : &PL_sv_undef);
- PUSHs(flgok
- ? sv_2mortal(SvREFCNT_inc_simple_NN(*flgsvp))
- : &PL_sv_undef);
- nitem += 3;
- }
- else {
- if (namok && argok)
- PUSHs(sv_2mortal(Perl_newSVpvf(aTHX_ "%" SVf "(%" SVf ")",
- SVfARG(*namsvp),
- SVfARG(*argsvp))));
- else if (namok)
- PUSHs(sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp)));
- else
- PUSHs(&PL_sv_undef);
- nitem++;
- if (flgok) {
- const IV flags = SvIVX(*flgsvp);
-
- if (flags & PERLIO_F_UTF8) {
- PUSHs(newSVpvs_flags("utf8", SVs_TEMP));
- nitem++;
- }
- }
- }
- }
-
- SvREFCNT_dec(av);
-
- XSRETURN(nitem);
- }
+ details = SvTRUE(*valp);
+ break;
+ }
+ goto fail;
+ default:
+ fail:
+ Perl_croak(aTHX_
+ "get_layers: unknown argument '%s'",
+ key);
+ }
+ }
+
+ SP -= (items - 1);
+ }
+
+ sv = POPs;
+ gv = MAYBE_DEREF_GV(sv);
+
+ if (!gv && !SvROK(sv))
+ gv = gv_fetchsv_nomg(sv, 0, SVt_PVIO);
+
+ if (gv && (io = GvIO(gv))) {
+ AV* const av = PerlIO_get_layers(aTHX_ input ?
+ IoIFP(io) : IoOFP(io));
+ SSize_t i;
+ const SSize_t last = av_top_index(av);
+ SSize_t nitem = 0;
+
+ for (i = last; i >= 0; i -= 3) {
+ SV * const * const namsvp = av_fetch(av, i - 2, FALSE);
+ SV * const * const argsvp = av_fetch(av, i - 1, FALSE);
+ SV * const * const flgsvp = av_fetch(av, i, FALSE);
+
+ const bool namok = namsvp && *namsvp && SvPOK(*namsvp);
+ const bool argok = argsvp && *argsvp && SvPOK(*argsvp);
+ const bool flgok = flgsvp && *flgsvp && SvIOK(*flgsvp);
+
+ EXTEND(SP, 3); /* Three is the max in all branches: better check just once */
+ if (details) {
+ /* Indents of 5? Yuck. */
+ /* We know that PerlIO_get_layers creates a new SV for
+ the name and flags, so we can just take a reference
+ and "steal" it when we free the AV below. */
+ PUSHs(namok
+ ? sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp))
+ : &PL_sv_undef);
+ PUSHs(argok
+ ? newSVpvn_flags(SvPVX_const(*argsvp),
+ SvCUR(*argsvp),
+ (SvUTF8(*argsvp) ? SVf_UTF8 : 0)
+ | SVs_TEMP)
+ : &PL_sv_undef);
+ PUSHs(flgok
+ ? sv_2mortal(SvREFCNT_inc_simple_NN(*flgsvp))
+ : &PL_sv_undef);
+ nitem += 3;
+ }
+ else {
+ if (namok && argok)
+ PUSHs(sv_2mortal(Perl_newSVpvf(aTHX_ "%" SVf "(%" SVf ")",
+ SVfARG(*namsvp),
+ SVfARG(*argsvp))));
+ else if (namok)
+ PUSHs(sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp)));
+ else
+ PUSHs(&PL_sv_undef);
+ nitem++;
+ if (flgok) {
+ const IV flags = SvIVX(*flgsvp);
+
+ if (flags & PERLIO_F_UTF8) {
+ PUSHs(newSVpvs_flags("utf8", SVs_TEMP));
+ nitem++;
+ }
+ }
+ }
+ }
+
+ SvREFCNT_dec(av);
+
+ XSRETURN(nitem);
+ }
}
#endif
dXSARGS;
if (items != 1)
- croak_xs_usage(cv, "sv");
+ croak_xs_usage(cv, "sv");
if (SvRXOK(ST(0))) {
XSRETURN_YES;
dXSARGS;
if (items != 0)
- croak_xs_usage(cv, "");
+ croak_xs_usage(cv, "");
if (!rx)
XSRETURN_UNDEF;
SV * ret;
if (items < 1 || items > 2)
- croak_xs_usage(cv, "name[, all ]");
+ croak_xs_usage(cv, "name[, all ]");
SP -= items;
PUTBACK;
if (!rx)
XSRETURN_UNDEF;
- if (items == 2 && SvTRUE(ST(1))) {
+ if (items == 2 && SvTRUE_NN(ST(1))) {
flags = RXapif_ALL;
} else {
flags = RXapif_ONE;
SV **entry;
if (items > 1)
- croak_xs_usage(cv, "[all]");
+ croak_xs_usage(cv, "[all]");
rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
if (!rx)
XSRETURN_UNDEF;
- if (items == 1 && SvTRUE(ST(0))) {
+ if (items == 1 && SvTRUE_NN(ST(0))) {
flags = RXapif_ALL;
} else {
flags = RXapif_ONE;
XSRETURN_UNDEF;
av = MUTABLE_AV(SvRV(ret));
- length = av_tindex(av);
+ length = av_count(av);
- EXTEND(SP, length+1); /* better extend stack just once */
- for (i = 0; i <= length; i++) {
+ EXTEND(SP, length); /* better extend stack just once */
+ for (i = 0; i < length; i++) {
entry = av_fetch(av, i, FALSE);
if (!entry)
EXTEND(SP, 2);
SP -= items;
if (items != 1)
- croak_xs_usage(cv, "sv");
+ croak_xs_usage(cv, "sv");
/*
Checks if a reference is a regex or not. If the parameter is
SV *pattern;
if ( gimme == G_ARRAY ) {
- STRLEN left = 0;
- char reflags[sizeof(INT_PAT_MODS) + MAX_CHARSET_NAME_LENGTH];
+ STRLEN left = 0;
+ char reflags[sizeof(INT_PAT_MODS) + MAX_CHARSET_NAME_LENGTH];
const char *fptr;
char ch;
U16 match_flags;
modifiers" in this scenario, and the default character set
*/
- if (get_regex_charset(RX_EXTFLAGS(re)) != REGEX_DEPENDS_CHARSET) {
- STRLEN len;
- const char* const name = get_regex_charset_name(RX_EXTFLAGS(re),
- &len);
- Copy(name, reflags + left, len, char);
- left += len;
- }
+ if (get_regex_charset(RX_EXTFLAGS(re)) != REGEX_DEPENDS_CHARSET) {
+ STRLEN len;
+ const char* const name = get_regex_charset_name(RX_EXTFLAGS(re),
+ &len);
+ Copy(name, reflags + left, len, char);
+ left += len;
+ }
fptr = INT_PAT_MODS;
match_flags = (U16)((RX_EXTFLAGS(re) & RXf_PMf_COMPILETIME)
>> RXf_PMf_STD_PMMOD_SHIFT);
}
pattern = newSVpvn_flags(RX_PRECOMP(re),RX_PRELEN(re),
- (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP);
+ (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP);
/* return the pattern and the modifiers */
PUSHs(pattern);
NOT_REACHED; /* NOTREACHED */
}
+#ifdef HAS_GETCWD
+
+XS(XS_Internals_getcwd)
+{
+ dXSARGS;
+ SV *sv = sv_newmortal();
+
+ if (items != 0)
+ croak_xs_usage(cv, "");
+
+ (void)getcwd_sv(sv);
+
+ SvTAINTED_on(sv);
+ PUSHs(sv);
+ XSRETURN(1);
+}
+
+#endif
+
+XS(XS_NamedCapture_tie_it)
+{
+ dXSARGS;
+
+ if (items != 1)
+ croak_xs_usage(cv, "sv");
+ {
+ SV *sv = ST(0);
+ GV * const gv = (GV *)sv;
+ HV * const hv = GvHVn(gv);
+ SV *rv = newSV_type(SVt_IV);
+ const char *gv_name = GvNAME(gv);
+
+ SvRV_set(rv, newSVuv(
+ strEQ(gv_name, "-") || strEQ(gv_name, "\003APTURE_ALL")
+ ? RXapif_ALL : RXapif_ONE));
+ SvROK_on(rv);
+ sv_bless(rv, GvSTASH(CvGV(cv)));
+
+ sv_unmagic((SV *)hv, PERL_MAGIC_tied);
+ sv_magic((SV *)hv, rv, PERL_MAGIC_tied, NULL, 0);
+ SvREFCNT_dec(rv); /* As sv_magic increased it by one. */
+ }
+ XSRETURN_EMPTY;
+}
+
+XS(XS_NamedCapture_TIEHASH)
+{
+ dXSARGS;
+ if (items < 1)
+ croak_xs_usage(cv, "package, ...");
+ {
+ const char * package = (const char *)SvPV_nolen(ST(0));
+ UV flag = RXapif_ONE;
+ mark += 2;
+ while(mark < sp) {
+ STRLEN len;
+ const char *p = SvPV_const(*mark, len);
+ if(memEQs(p, len, "all"))
+ flag = SvTRUE(mark[1]) ? RXapif_ALL : RXapif_ONE;
+ mark += 2;
+ }
+ ST(0) = sv_2mortal(newSV_type(SVt_IV));
+ sv_setuv(newSVrv(ST(0), package), flag);
+ }
+ XSRETURN(1);
+}
+
+/* These are tightly coupled to the RXapif_* flags defined in regexp.h */
+#define UNDEF_FATAL 0x80000
+#define DISCARD 0x40000
+#define EXPECT_SHIFT 24
+#define ACTION_MASK 0x000FF
+
+#define FETCH_ALIAS (RXapif_FETCH | (2 << EXPECT_SHIFT))
+#define STORE_ALIAS (RXapif_STORE | (3 << EXPECT_SHIFT) | UNDEF_FATAL | DISCARD)
+#define DELETE_ALIAS (RXapif_DELETE | (2 << EXPECT_SHIFT) | UNDEF_FATAL)
+#define CLEAR_ALIAS (RXapif_CLEAR | (1 << EXPECT_SHIFT) | UNDEF_FATAL | DISCARD)
+#define EXISTS_ALIAS (RXapif_EXISTS | (2 << EXPECT_SHIFT))
+#define SCALAR_ALIAS (RXapif_SCALAR | (1 << EXPECT_SHIFT))
+
+XS(XS_NamedCapture_FETCH)
+{
+ dXSARGS;
+ dXSI32;
+ PERL_UNUSED_VAR(cv); /* -W */
+ PERL_UNUSED_VAR(ax); /* -Wall */
+ SP -= items;
+ {
+ REGEXP *const rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
+ U32 flags;
+ SV *ret;
+ const U32 action = ix & ACTION_MASK;
+ const int expect = ix >> EXPECT_SHIFT;
+ if (items != expect)
+ croak_xs_usage(cv, expect == 2 ? "$key"
+ : (expect == 3 ? "$key, $value"
+ : ""));
+
+ if (!rx || !SvROK(ST(0))) {
+ if (ix & UNDEF_FATAL)
+ Perl_croak_no_modify();
+ else
+ XSRETURN_UNDEF;
+ }
+
+ flags = (U32)SvUV(SvRV(MUTABLE_SV(ST(0))));
+
+ PUTBACK;
+ ret = RX_ENGINE(rx)->named_buff(aTHX_ (rx), expect >= 2 ? ST(1) : NULL,
+ expect >= 3 ? ST(2) : NULL, flags | action);
+ SPAGAIN;
+
+ if (ix & DISCARD) {
+ /* Called with G_DISCARD, so our return stack state is thrown away.
+ Hence if we were returned anything, free it immediately. */
+ SvREFCNT_dec(ret);
+ } else {
+ PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
+ }
+ PUTBACK;
+ return;
+ }
+}
+
+
+XS(XS_NamedCapture_FIRSTKEY)
+{
+ dXSARGS;
+ dXSI32;
+ PERL_UNUSED_VAR(cv); /* -W */
+ PERL_UNUSED_VAR(ax); /* -Wall */
+ SP -= items;
+ {
+ REGEXP *const rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
+ U32 flags;
+ SV *ret;
+ const int expect = ix ? 2 : 1;
+ const U32 action = ix ? RXapif_NEXTKEY : RXapif_FIRSTKEY;
+ if (items != expect)
+ croak_xs_usage(cv, expect == 2 ? "$lastkey" : "");
+
+ if (!rx || !SvROK(ST(0)))
+ XSRETURN_UNDEF;
+
+ flags = (U32)SvUV(SvRV(MUTABLE_SV(ST(0))));
+
+ PUTBACK;
+ ret = RX_ENGINE(rx)->named_buff_iter(aTHX_ (rx),
+ expect >= 2 ? ST(1) : NULL,
+ flags | action);
+ SPAGAIN;
+
+ PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
+ PUTBACK;
+ return;
+ }
+}
+
+/* is this still needed? */
+XS(XS_NamedCapture_flags)
+{
+ dXSARGS;
+ PERL_UNUSED_VAR(cv); /* -W */
+ PERL_UNUSED_VAR(ax); /* -Wall */
+ SP -= items;
+ {
+ EXTEND(SP, 2);
+ mPUSHu(RXapif_ONE);
+ mPUSHu(RXapif_ALL);
+ PUTBACK;
+ return;
+ }
+}
+
#include "vutil.h"
#include "vxs.inc"
const char *name;
XSUBADDR_t xsub;
const char *proto;
+ int ix;
};
-static const struct xsub_details details[] = {
- {"UNIVERSAL::isa", XS_UNIVERSAL_isa, NULL},
- {"UNIVERSAL::can", XS_UNIVERSAL_can, NULL},
- {"UNIVERSAL::DOES", XS_UNIVERSAL_DOES, NULL},
+static const struct xsub_details these_details[] = {
+ {"UNIVERSAL::isa", XS_UNIVERSAL_isa, NULL, 0 },
+ {"UNIVERSAL::can", XS_UNIVERSAL_can, NULL, 0 },
+ {"UNIVERSAL::DOES", XS_UNIVERSAL_DOES, NULL, 0 },
#define VXS_XSUB_DETAILS
#include "vxs.inc"
#undef VXS_XSUB_DETAILS
- {"utf8::is_utf8", XS_utf8_is_utf8, NULL},
- {"utf8::valid", XS_utf8_valid, NULL},
- {"utf8::encode", XS_utf8_encode, NULL},
- {"utf8::decode", XS_utf8_decode, NULL},
- {"utf8::upgrade", XS_utf8_upgrade, NULL},
- {"utf8::downgrade", XS_utf8_downgrade, NULL},
- {"utf8::native_to_unicode", XS_utf8_native_to_unicode, NULL},
- {"utf8::unicode_to_native", XS_utf8_unicode_to_native, NULL},
- {"Internals::SvREADONLY", XS_Internals_SvREADONLY, "\\[$%@];$"},
- {"Internals::SvREFCNT", XS_Internals_SvREFCNT, "\\[$%@];$"},
- {"Internals::hv_clear_placeholders", XS_Internals_hv_clear_placehold, "\\%"},
- {"constant::_make_const", XS_constant__make_const, "\\[$@]"},
- {"PerlIO::get_layers", XS_PerlIO_get_layers, "*;@"},
- {"re::is_regexp", XS_re_is_regexp, "$"},
- {"re::regname", XS_re_regname, ";$$"},
- {"re::regnames", XS_re_regnames, ";$"},
- {"re::regnames_count", XS_re_regnames_count, ""},
- {"re::regexp_pattern", XS_re_regexp_pattern, "$"},
+ {"utf8::is_utf8", XS_utf8_is_utf8, NULL, 0 },
+ {"utf8::valid", XS_utf8_valid, NULL, 0 },
+ {"utf8::encode", XS_utf8_encode, NULL, 0 },
+ {"utf8::decode", XS_utf8_decode, NULL, 0 },
+ {"utf8::upgrade", XS_utf8_upgrade, NULL, 0 },
+ {"utf8::downgrade", XS_utf8_downgrade, NULL, 0 },
+ {"utf8::native_to_unicode", XS_utf8_native_to_unicode, NULL, 0 },
+ {"utf8::unicode_to_native", XS_utf8_unicode_to_native, NULL, 0 },
+ {"Internals::SvREADONLY", XS_Internals_SvREADONLY, "\\[$%@];$", 0 },
+ {"Internals::SvREFCNT", XS_Internals_SvREFCNT, "\\[$%@];$", 0 },
+ {"Internals::hv_clear_placeholders", XS_Internals_hv_clear_placehold, "\\%", 0 },
+ {"constant::_make_const", XS_constant__make_const, "\\[$@]", 0 },
+ {"PerlIO::get_layers", XS_PerlIO_get_layers, "*;@", 0 },
+ {"re::is_regexp", XS_re_is_regexp, "$", 0 },
+ {"re::regname", XS_re_regname, ";$$", 0 },
+ {"re::regnames", XS_re_regnames, ";$", 0 },
+ {"re::regnames_count", XS_re_regnames_count, "", 0 },
+ {"re::regexp_pattern", XS_re_regexp_pattern, "$", 0 },
+#ifdef HAS_GETCWD
+ {"Internals::getcwd", XS_Internals_getcwd, "", 0 },
+#endif
+ {"Tie::Hash::NamedCapture::_tie_it", XS_NamedCapture_tie_it, NULL, 0 },
+ {"Tie::Hash::NamedCapture::TIEHASH", XS_NamedCapture_TIEHASH, NULL, 0 },
+ {"Tie::Hash::NamedCapture::FETCH", XS_NamedCapture_FETCH, NULL, FETCH_ALIAS },
+ {"Tie::Hash::NamedCapture::STORE", XS_NamedCapture_FETCH, NULL, STORE_ALIAS },
+ {"Tie::Hash::NamedCapture::DELETE", XS_NamedCapture_FETCH, NULL, DELETE_ALIAS },
+ {"Tie::Hash::NamedCapture::CLEAR", XS_NamedCapture_FETCH, NULL, CLEAR_ALIAS },
+ {"Tie::Hash::NamedCapture::EXISTS", XS_NamedCapture_FETCH, NULL, EXISTS_ALIAS },
+ {"Tie::Hash::NamedCapture::SCALAR", XS_NamedCapture_FETCH, NULL, SCALAR_ALIAS },
+ {"Tie::Hash::NamedCapture::FIRSTKEY", XS_NamedCapture_FIRSTKEY, NULL, 0 },
+ {"Tie::Hash::NamedCapture::NEXTKEY", XS_NamedCapture_FIRSTKEY, NULL, 1 },
+ {"Tie::Hash::NamedCapture::flags", XS_NamedCapture_flags, NULL, 0 },
};
STATIC OP*
Perl_boot_core_UNIVERSAL(pTHX)
{
static const char file[] = __FILE__;
- const struct xsub_details *xsub = details;
- const struct xsub_details *end = C_ARRAY_END(details);
+ const struct xsub_details *xsub = these_details;
+ const struct xsub_details *end = C_ARRAY_END(these_details);
do {
- newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0);
+ CV *cv = newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0);
+ XSANY.any_i32 = xsub->ix;
} while (++xsub < end);
#ifndef EBCDIC
CV* to_native_cv = get_cv("utf8::unicode_to_native", 0);
CV* to_unicode_cv = get_cv("utf8::native_to_unicode", 0);
- cv_set_call_checker(to_native_cv,
+ cv_set_call_checker_flags(to_native_cv,
optimize_out_native_convert_function,
- (SV*) to_native_cv);
- cv_set_call_checker(to_unicode_cv,
+ (SV*) to_native_cv, 0);
+ cv_set_call_checker_flags(to_unicode_cv,
optimize_out_native_convert_function,
- (SV*) to_unicode_cv);
+ (SV*) to_unicode_cv, 0);
}
#endif
/* Providing a Regexp::DESTROY fixes #21347. See test in t/op/ref.t */
{
- CV * const cv =
- newCONSTSUB(get_hv("Regexp::", GV_ADD), "DESTROY", NULL);
- char ** cvfile = &CvFILE(cv);
- char * oldfile = *cvfile;
- CvDYNFILE_off(cv);
- *cvfile = (char *)file;
- Safefree(oldfile);
+ CV * const cv =
+ newCONSTSUB(get_hv("Regexp::", GV_ADD), "DESTROY", NULL);
+ char ** cvfile = &CvFILE(cv);
+ char * oldfile = *cvfile;
+ CvDYNFILE_off(cv);
+ *cvfile = (char *)file;
+ Safefree(oldfile);
}
}