#define PERL_IN_UNIVERSAL_C
#include "perl.h"
-#ifdef USE_PERLIO
+#if defined(USE_PERLIO)
#include "perliol.h" /* For the PERLIO_F_XXX */
#endif
STATIC bool
S_isa_lookup(pTHX_ HV *stash, const char * const name, STRLEN len, U32 flags)
{
- dVAR;
const struct mro_meta *const meta = HvMROMETA(stash);
HV *isa = meta->isa;
const HV *our_stash;
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))) {
bool
Perl_sv_derived_from_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, U32 flags)
{
- dVAR;
HV *stash;
PERL_ARGS_ASSERT_SV_DERIVED_FROM_PVN;
SvGETMAGIC(sv);
- if (SvROK(sv)) { /* hugdo: */
+ if (SvROK(sv)) {
const char *type;
sv = SvRV(sv);
type = sv_reftype(sv,0);
if (type && strEQ(type,name))
return TRUE;
- stash = SvOBJECT(sv) ? SvSTASH(sv) : NULL;
+ if (!SvOBJECT(sv))
+ return FALSE;
+ stash = SvSTASH(sv);
}
else {
stash = gv_stashsv(sv, 0);
}
- return stash ? isa_lookup(stash, name, len, flags) : FALSE;
+ if (stash && isa_lookup(stash, name, len, flags))
+ return TRUE;
+
+ stash = gv_stashpvs("UNIVERSAL", 0);
+ return stash && isa_lookup(stash, name, len, flags);
}
/*
SvGETMAGIC(sv);
- if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))
- || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv)))) {
+ if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv)))) {
LEAVE;
return FALSE;
}
- if (sv_isobject(sv)) {
+ if (SvROK(sv) && SvOBJECT(SvRV(sv))) {
classname = sv_ref(NULL,SvRV(sv),TRUE);
} else {
classname = sv;
croak_xs_usage(cv, "eee_yow");
works out the package name and subroutine name from C<cv>, and then calls
-C<croak()>. Hence if C<cv> is C<&ouch::awk>, it would call C<croak> as:
+C<croak()>. Hence if C<cv> is C<&ouch::awk>, it would call C<croak> as:
- Perl_croak(aTHX_ "Usage: %"SVf"::%"SVf"(%s)", "ouch" "awk", "eee_yow");
+ Perl_croak(aTHX_ "Usage: %"SVf"::%"SVf"(%s)", "ouch" "awk",
+ "eee_yow");
=cut
*/
void
-Perl_croak_xs_usage(pTHX_ const CV *const cv, const char *const params)
+Perl_croak_xs_usage(const CV *const cv, const char *const params)
{
- const GV *const gv = CvGV(cv);
+ /* Avoid CvGV as it requires aTHX. */
+ const GV *gv = CvNAMED(cv) ? NULL : cv->sv_any->xcv_gv_u.xcv_gv;
PERL_ARGS_ASSERT_CROAK_XS_USAGE;
- if (gv) {
+ if (gv) got_gv: {
const HV *const stash = GvSTASH(gv);
if (HvNAME_get(stash))
- Perl_croak(aTHX_ "Usage: %"HEKf"::%"HEKf"(%s)",
+ /* diag_listed_as: SKIPME */
+ Perl_croak_nocontext("Usage: %"HEKf"::%"HEKf"(%s)",
HEKfARG(HvNAME_HEK(stash)),
HEKfARG(GvNAME_HEK(gv)),
params);
else
- Perl_croak(aTHX_ "Usage: %"HEKf"(%s)",
+ /* 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);
}
}
+XS(XS_UNIVERSAL_isa); /* prototype to pass -Wmissing-prototypes */
XS(XS_UNIVERSAL_isa)
{
- dVAR;
dXSARGS;
if (items != 2)
SvGETMAGIC(sv);
- if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))
- || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv))))
+ if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))))
XSRETURN_UNDEF;
ST(0) = boolSV(sv_derived_from_sv(sv, ST(1), 0));
}
}
+XS(XS_UNIVERSAL_can); /* prototype to pass -Wmissing-prototypes */
XS(XS_UNIVERSAL_can)
{
- dVAR;
dXSARGS;
SV *sv;
SV *rv;
HV *pkg = NULL;
+ GV *iogv;
if (items != 2)
croak_xs_usage(cv, "object-ref, method");
SvGETMAGIC(sv);
- if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))
- || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv))))
+ /* Reject undef and empty string. Note that the string form takes
+ 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;
rv = &PL_sv_undef;
sv = MUTABLE_SV(SvRV(sv));
if (SvOBJECT(sv))
pkg = SvSTASH(sv);
+ else if (isGV_with_GP(sv) && GvIO(sv))
+ pkg = SvSTASH(GvIO(sv));
}
+ else if (isGV_with_GP(sv) && GvIO(sv))
+ pkg = SvSTASH(GvIO(sv));
+ else if ((iogv = gv_fetchsv_nomg(sv, 0, SVt_PVIO)) && GvIO(iogv))
+ pkg = SvSTASH(GvIO(iogv));
else {
pkg = gv_stashsv(sv, 0);
+ if (!pkg)
+ pkg = gv_stashpvs("UNIVERSAL", 0);
}
if (pkg) {
XSRETURN(1);
}
+XS(XS_UNIVERSAL_DOES); /* prototype to pass -Wmissing-prototypes */
XS(XS_UNIVERSAL_DOES)
{
- dVAR;
dXSARGS;
PERL_UNUSED_ARG(cv);
}
}
-XS(XS_UNIVERSAL_VERSION)
-{
- dVAR;
- dXSARGS;
- HV *pkg;
- GV **gvp;
- GV *gv;
- SV *sv;
- SV *ret;
- const char *undef;
- PERL_UNUSED_ARG(cv);
-
- if (SvROK(ST(0))) {
- sv = MUTABLE_SV(SvRV(ST(0)));
- if (!SvOBJECT(sv))
- Perl_croak(aTHX_ "Cannot find version of an unblessed reference");
- pkg = SvSTASH(sv);
- }
- else {
- pkg = gv_stashsv(ST(0), 0);
- }
-
- gvp = pkg ? (GV**)hv_fetchs(pkg, "VERSION", FALSE) : NULL;
-
- if (gvp && isGV(gv = *gvp) && (sv = GvSV(gv)) && SvOK(sv)) {
- ret = sv_newmortal();
- sv_setsv(ret, sv);
- undef = NULL;
- }
- else {
- sv = ret = &PL_sv_undef;
- undef = "(undef)";
- }
-
- if (items > 1) {
- SV *req = ST(1);
-
- if (undef) {
- if (pkg) {
- const HEK * const name = HvNAME_HEK(pkg);
- Perl_croak(aTHX_
- "%"HEKf" does not define $%"HEKf
- "::VERSION--version check failed",
- HEKfARG(name), HEKfARG(name));
- } else {
- Perl_croak(aTHX_
- "%"SVf" defines neither package nor VERSION--version check failed",
- SVfARG(ST(0)) );
- }
- }
-
- if ( !sv_derived_from(sv, "version"))
- upg_version(sv, FALSE);
-
- if ( !sv_derived_from(req, "version")) {
- /* req may very well be R/O, so create a new object */
- req = sv_2mortal( new_version(req) );
- }
-
- if ( vcmp( req, sv ) > 0 ) {
- if ( hv_exists(MUTABLE_HV(SvRV(req)), "qv", 2 ) ) {
- Perl_croak(aTHX_ "%"HEKf" version %"SVf" required--"
- "this is only version %"SVf"",
- HEKfARG(HvNAME_HEK(pkg)),
- SVfARG(sv_2mortal(vnormal(req))),
- SVfARG(sv_2mortal(vnormal(sv))));
- } else {
- Perl_croak(aTHX_ "%"HEKf" version %"SVf" required--"
- "this is only version %"SVf,
- HEKfARG(HvNAME_HEK(pkg)),
- SVfARG(sv_2mortal(vstringify(req))),
- SVfARG(sv_2mortal(vstringify(sv))));
- }
- }
-
- }
-
- ST(0) = ret;
-
- XSRETURN(1);
-}
-
-XS(XS_version_new)
-{
- dVAR;
- dXSARGS;
- if (items > 3)
- croak_xs_usage(cv, "class, version");
- SP -= items;
- {
- SV *vs = ST(1);
- SV *rv;
- STRLEN len;
- const char *classname;
- U32 flags;
- if ( sv_isobject(ST(0)) ) { /* get the class if called as an object method */
- const HV * stash = SvSTASH(SvRV(ST(0)));
- classname = HvNAME(stash);
- len = HvNAMELEN(stash);
- flags = HvNAMEUTF8(stash) ? SVf_UTF8 : 0;
- }
- else {
- classname = SvPV(ST(0), len);
- flags = SvUTF8(ST(0));
- }
-
- if ( items == 1 || ! SvOK(vs) ) { /* no param or explicit undef */
- /* create empty object */
- vs = sv_newmortal();
- sv_setpvs(vs, "0");
- }
- else if ( items == 3 ) {
- vs = sv_newmortal();
- Perl_sv_setpvf(aTHX_ vs,"v%s",SvPV_nolen_const(ST(2)));
- }
-
- rv = new_version(vs);
- if ( strnNE(classname,"version", len) ) /* inherited new() */
- sv_bless(rv, gv_stashpvn(classname, len, GV_ADD | flags));
-
- mPUSHs(rv);
- PUTBACK;
- return;
- }
-}
-
-XS(XS_version_stringify)
-{
- dVAR;
- dXSARGS;
- if (items < 1)
- croak_xs_usage(cv, "lobj, ...");
- SP -= items;
- {
- SV * lobj = ST(0);
-
- if (sv_derived_from(lobj, "version") && SvROK(lobj)) {
- lobj = SvRV(lobj);
- }
- else
- Perl_croak(aTHX_ "lobj is not of type version");
-
- mPUSHs(vstringify(lobj));
-
- PUTBACK;
- return;
- }
-}
-
-XS(XS_version_numify)
-{
- dVAR;
- dXSARGS;
- if (items < 1)
- croak_xs_usage(cv, "lobj, ...");
- SP -= items;
- {
- SV * lobj = ST(0);
-
- if (sv_derived_from(lobj, "version") && SvROK(lobj)) {
- lobj = SvRV(lobj);
- }
- else
- Perl_croak(aTHX_ "lobj is not of type version");
-
- mPUSHs(vnumify(lobj));
-
- PUTBACK;
- return;
- }
-}
-
-XS(XS_version_normal)
-{
- dVAR;
- dXSARGS;
- if (items < 1)
- croak_xs_usage(cv, "lobj, ...");
- SP -= items;
- {
- SV * lobj = ST(0);
-
- if (sv_derived_from(lobj, "version") && SvROK(lobj)) {
- lobj = SvRV(lobj);
- }
- else
- Perl_croak(aTHX_ "lobj is not of type version");
-
- mPUSHs(vnormal(lobj));
-
- PUTBACK;
- return;
- }
-}
-
-XS(XS_version_vcmp)
-{
- dVAR;
- dXSARGS;
- if (items < 1)
- croak_xs_usage(cv, "lobj, ...");
- SP -= items;
- {
- SV * lobj = ST(0);
-
- if (sv_derived_from(lobj, "version") && SvROK(lobj)) {
- lobj = SvRV(lobj);
- }
- else
- Perl_croak(aTHX_ "lobj is not of type version");
-
- {
- SV *rs;
- SV *rvs;
- SV * robj = ST(1);
- const IV swap = (IV)SvIV(ST(2));
-
- if ( ! sv_derived_from(robj, "version") )
- {
- robj = new_version(SvOK(robj) ? robj : newSVpvs_flags("0", SVs_TEMP));
- sv_2mortal(robj);
- }
- rvs = SvRV(robj);
-
- if ( swap )
- {
- rs = newSViv(vcmp(rvs,lobj));
- }
- else
- {
- rs = newSViv(vcmp(lobj,rvs));
- }
-
- mPUSHs(rs);
- }
-
- PUTBACK;
- return;
- }
-}
-
-XS(XS_version_boolean)
-{
- dVAR;
- dXSARGS;
- if (items < 1)
- croak_xs_usage(cv, "lobj, ...");
- SP -= items;
- if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) {
- SV * const lobj = SvRV(ST(0));
- SV * const rs = newSViv( vcmp(lobj,new_version(newSVpvs("0"))) );
- mPUSHs(rs);
- PUTBACK;
- return;
- }
- else
- Perl_croak(aTHX_ "lobj is not of type version");
-}
-
-XS(XS_version_noop)
-{
- dVAR;
- dXSARGS;
- if (items < 1)
- croak_xs_usage(cv, "lobj, ...");
- if (sv_derived_from(ST(0), "version") && SvROK(ST(0)))
- Perl_croak(aTHX_ "operation not supported with version object");
- else
- Perl_croak(aTHX_ "lobj is not of type version");
-#ifndef HASATTRIBUTE_NORETURN
- XSRETURN_EMPTY;
-#endif
-}
-
-XS(XS_version_is_alpha)
-{
- dVAR;
- dXSARGS;
- if (items != 1)
- croak_xs_usage(cv, "lobj");
- SP -= items;
- if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) {
- SV * const lobj = ST(0);
- if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "alpha", 5 ) )
- XSRETURN_YES;
- else
- XSRETURN_NO;
- PUTBACK;
- return;
- }
- else
- Perl_croak(aTHX_ "lobj is not of type version");
-}
-
-XS(XS_version_qv)
-{
- dVAR;
- dXSARGS;
- PERL_UNUSED_ARG(cv);
- SP -= items;
- {
- SV * ver = ST(0);
- SV * rv;
- STRLEN len = 0;
- const char * classname = "";
- U32 flags = 0;
- if ( items == 2 && SvOK(ST(1)) ) {
- ver = ST(1);
- if ( sv_isobject(ST(0)) ) { /* class called as an object method */
- const HV * stash = SvSTASH(SvRV(ST(0)));
- classname = HvNAME(stash);
- len = HvNAMELEN(stash);
- flags = HvNAMEUTF8(stash) ? SVf_UTF8 : 0;
- }
- else {
- classname = SvPV(ST(0), len);
- flags = SvUTF8(ST(0));
- }
- }
- if ( !SvVOK(ver) ) { /* not already a v-string */
- rv = sv_newmortal();
- sv_setsv(rv,ver); /* make a duplicate */
- upg_version(rv, TRUE);
- } else {
- rv = sv_2mortal(new_version(ver));
- }
- if ( items == 2
- && strnNE(classname,"version", len) ) { /* inherited new() */
- sv_bless(rv, gv_stashpvn(classname, len, GV_ADD | flags));
- }
- PUSHs(rv);
- }
- PUTBACK;
- return;
-}
-
-XS(XS_version_is_qv)
-{
- dVAR;
- dXSARGS;
- if (items != 1)
- croak_xs_usage(cv, "lobj");
- SP -= items;
- if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) {
- SV * const lobj = ST(0);
- if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "qv", 2 ) )
- XSRETURN_YES;
- else
- XSRETURN_NO;
- PUTBACK;
- return;
- }
- else
- Perl_croak(aTHX_ "lobj is not of type version");
-}
-
+XS(XS_utf8_is_utf8); /* prototype to pass -Wmissing-prototypes */
XS(XS_utf8_is_utf8)
{
- dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "sv");
XSRETURN_EMPTY;
}
+XS(XS_utf8_valid); /* prototype to pass -Wmissing-prototypes */
XS(XS_utf8_valid)
{
- dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "sv");
XSRETURN_EMPTY;
}
+XS(XS_utf8_encode); /* prototype to pass -Wmissing-prototypes */
XS(XS_utf8_encode)
{
- dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "sv");
sv_utf8_encode(ST(0));
+ SvSETMAGIC(ST(0));
XSRETURN_EMPTY;
}
+XS(XS_utf8_decode); /* prototype to pass -Wmissing-prototypes */
XS(XS_utf8_decode)
{
- dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "sv");
else {
SV * const sv = ST(0);
bool RETVAL;
- if (SvIsCOW(sv)) sv_force_normal(sv);
+ SvPV_force_nolen(sv);
RETVAL = sv_utf8_decode(sv);
+ SvSETMAGIC(sv);
ST(0) = boolSV(RETVAL);
}
XSRETURN(1);
}
+XS(XS_utf8_upgrade); /* prototype to pass -Wmissing-prototypes */
XS(XS_utf8_upgrade)
{
- dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "sv");
XSRETURN(1);
}
+XS(XS_utf8_downgrade); /* prototype to pass -Wmissing-prototypes */
XS(XS_utf8_downgrade)
{
- dVAR;
dXSARGS;
if (items < 1 || items > 2)
croak_xs_usage(cv, "sv, failok=0");
else {
SV * const sv = ST(0);
- const bool failok = (items < 2) ? 0 : (int)SvIV(ST(1));
+ const bool failok = (items < 2) ? 0 : SvTRUE(ST(1)) ? 1 : 0;
const bool RETVAL = sv_utf8_downgrade(sv, failok);
ST(0) = boolSV(RETVAL);
XSRETURN(1);
}
+XS(XS_utf8_native_to_unicode); /* prototype to pass -Wmissing-prototypes */
XS(XS_utf8_native_to_unicode)
{
- dVAR;
dXSARGS;
const UV uv = SvUV(ST(0));
if (items > 1)
croak_xs_usage(cv, "sv");
- ST(0) = sv_2mortal(newSViv(NATIVE_TO_UNI(uv)));
+ ST(0) = sv_2mortal(newSVuv(NATIVE_TO_UNI(uv)));
XSRETURN(1);
}
+XS(XS_utf8_unicode_to_native); /* prototype to pass -Wmissing-prototypes */
XS(XS_utf8_unicode_to_native)
{
- dVAR;
dXSARGS;
const UV uv = SvUV(ST(0));
if (items > 1)
croak_xs_usage(cv, "sv");
- ST(0) = sv_2mortal(newSViv(UNI_TO_NATIVE(uv)));
+ ST(0) = sv_2mortal(newSVuv(UNI_TO_NATIVE(uv)));
XSRETURN(1);
}
+XS(XS_Internals_SvREADONLY); /* prototype to pass -Wmissing-prototypes */
XS(XS_Internals_SvREADONLY) /* This is dangerous stuff. */
{
- dVAR;
dXSARGS;
SV * const svz = ST(0);
SV * sv;
sv = SvRV(svz);
if (items == 1) {
- if (SvREADONLY(sv) && !SvIsCOW(sv))
+ if (SvREADONLY(sv))
XSRETURN_YES;
else
XSRETURN_NO;
}
else if (items == 2) {
if (SvTRUE(ST(1))) {
- if (SvIsCOW(sv)) sv_force_normal(sv);
- SvREADONLY_on(sv);
+ SvFLAGS(sv) |= SVf_READONLY;
XSRETURN_YES;
}
else {
/* I hope you really know what you are doing. */
- if (!SvIsCOW(sv)) SvREADONLY_off(sv);
+ SvFLAGS(sv) &=~ SVf_READONLY;
XSRETURN_NO;
}
}
XSRETURN_UNDEF; /* Can't happen. */
}
+XS(XS_constant__make_const); /* prototype to pass -Wmissing-prototypes */
+XS(XS_constant__make_const) /* This is dangerous stuff. */
+{
+ dXSARGS;
+ SV * const svz = ST(0);
+ SV * sv;
+ PERL_UNUSED_ARG(cv);
+
+ /* [perl #77776] - called as &foo() not foo() */
+ if (!SvROK(svz) || items != 1)
+ croak_xs_usage(cv, "SCALAR");
+
+ sv = SvRV(svz);
+
+ 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);
+ }
+ XSRETURN(0);
+}
+
+XS(XS_Internals_SvREFCNT); /* prototype to pass -Wmissing-prototypes */
XS(XS_Internals_SvREFCNT) /* This is dangerous stuff. */
{
- dVAR;
dXSARGS;
SV * const svz = ST(0);
SV * sv;
+ U32 refcnt;
PERL_UNUSED_ARG(cv);
/* [perl #77776] - called as &foo() not foo() */
- if (!SvROK(svz))
+ if ((items != 1 && items != 2) || !SvROK(svz))
croak_xs_usage(cv, "SCALAR[, REFCOUNT]");
sv = SvRV(svz);
- if (items == 1)
- XSRETURN_IV(SvREFCNT(sv) - 1); /* Minus the ref created for us. */
- else if (items == 2) {
/* I hope you really know what you are doing. */
- SvREFCNT(sv) = SvIV(ST(1));
- XSRETURN_IV(SvREFCNT(sv));
- }
- XSRETURN_UNDEF; /* Can't happen. */
+ /* idea is for SvREFCNT(sv) to be accessed only once */
+ refcnt = items == 2 ?
+ /* we free one ref on exit */
+ (SvREFCNT(sv) = SvUV(ST(1)) + 1)
+ : SvREFCNT(sv);
+ XSRETURN_UV(refcnt - 1); /* Minus the ref created for us. */
+
}
+XS(XS_Internals_hv_clear_placehold); /* prototype to pass -Wmissing-prototypes */
XS(XS_Internals_hv_clear_placehold)
{
- dVAR;
dXSARGS;
if (items != 1 || !SvROK(ST(0)))
}
}
+XS(XS_PerlIO_get_layers); /* prototype to pass -Wmissing-prototypes */
XS(XS_PerlIO_get_layers)
{
- dVAR;
dXSARGS;
if (items < 1 || items % 2 == 0)
croak_xs_usage(cv, "filehandle[,args]");
-#ifdef USE_PERLIO
+#if defined(USE_PERLIO)
{
SV * sv;
GV * gv;
}
sv = POPs;
- gv = MUTABLE_GV(sv);
+ gv = MAYBE_DEREF_GV(sv);
- if (!isGV(sv)) {
- if (SvROK(sv) && isGV(SvRV(sv)))
- gv = MUTABLE_GV(SvRV(sv));
- else if (SvPOKp(sv))
- gv = gv_fetchsv(sv, 0, SVt_PVIO);
- }
+ 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));
- I32 i;
- const I32 last = av_len(av);
- I32 nitem = 0;
+ 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);
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. */
- XPUSHs(namok
+ PUSHs(namok
? sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp))
: &PL_sv_undef);
- XPUSHs(argok
+ PUSHs(argok
? newSVpvn_flags(SvPVX_const(*argsvp),
SvCUR(*argsvp),
(SvUTF8(*argsvp) ? SVf_UTF8 : 0)
| SVs_TEMP)
: &PL_sv_undef);
- XPUSHs(flgok
+ PUSHs(flgok
? sv_2mortal(SvREFCNT_inc_simple_NN(*flgsvp))
: &PL_sv_undef);
nitem += 3;
}
else {
if (namok && argok)
- XPUSHs(sv_2mortal(Perl_newSVpvf(aTHX_ "%"SVf"(%"SVf")",
+ PUSHs(sv_2mortal(Perl_newSVpvf(aTHX_ "%"SVf"(%"SVf")",
SVfARG(*namsvp),
SVfARG(*argsvp))));
else if (namok)
- XPUSHs(sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp)));
+ PUSHs(sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp)));
else
- XPUSHs(&PL_sv_undef);
+ PUSHs(&PL_sv_undef);
nitem++;
if (flgok) {
const IV flags = SvIVX(*flgsvp);
if (flags & PERLIO_F_UTF8) {
- XPUSHs(newSVpvs_flags("utf8", SVs_TEMP));
+ PUSHs(newSVpvs_flags("utf8", SVs_TEMP));
nitem++;
}
}
XSRETURN(0);
}
-XS(XS_Internals_hash_seed)
-{
- dVAR;
- /* Using dXSARGS would also have dITEM and dSP,
- * which define 2 unused local variables. */
- dAXMARK;
- PERL_UNUSED_ARG(cv);
- PERL_UNUSED_VAR(mark);
- XSRETURN_UV(PERL_HASH_SEED);
-}
-
-XS(XS_Internals_rehash_seed)
-{
- dVAR;
- /* Using dXSARGS would also have dITEM and dSP,
- * which define 2 unused local variables. */
- dAXMARK;
- PERL_UNUSED_ARG(cv);
- PERL_UNUSED_VAR(mark);
- XSRETURN_UV(PL_rehash_seed);
-}
-
-XS(XS_Internals_HvREHASH) /* Subject to change */
-{
- dVAR;
- dXSARGS;
- PERL_UNUSED_ARG(cv);
- if (SvROK(ST(0))) {
- const HV * const hv = (const HV *) SvRV(ST(0));
- if (items == 1 && SvTYPE(hv) == SVt_PVHV) {
- if (HvREHASH(hv))
- XSRETURN_YES;
- else
- XSRETURN_NO;
- }
- }
- Perl_croak(aTHX_ "Internals::HvREHASH $hashref");
-}
-
+XS(XS_re_is_regexp); /* prototype to pass -Wmissing-prototypes */
XS(XS_re_is_regexp)
{
- dVAR;
dXSARGS;
PERL_UNUSED_VAR(cv);
}
}
+XS(XS_re_regnames_count); /* prototype to pass -Wmissing-prototypes */
XS(XS_re_regnames_count)
{
REGEXP *rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
SV * ret;
- dVAR;
dXSARGS;
if (items != 0)
croak_xs_usage(cv, "");
- SP -= items;
- PUTBACK;
-
if (!rx)
XSRETURN_UNDEF;
XSRETURN(1);
}
+XS(XS_re_regname); /* prototype to pass -Wmissing-prototypes */
XS(XS_re_regname)
{
- dVAR;
dXSARGS;
REGEXP * rx;
U32 flags;
}
+XS(XS_re_regnames); /* prototype to pass -Wmissing-prototypes */
XS(XS_re_regnames)
{
- dVAR;
dXSARGS;
REGEXP * rx;
U32 flags;
SV *ret;
AV *av;
- I32 length;
- I32 i;
+ SSize_t length;
+ SSize_t i;
SV **entry;
if (items > 1)
XSRETURN_UNDEF;
av = MUTABLE_AV(SvRV(ret));
- length = av_len(av);
+ length = av_tindex(av);
+ EXTEND(SP, length+1); /* better extend stack just once */
for (i = 0; i <= length; i++) {
entry = av_fetch(av, i, FALSE);
if (!entry)
Perl_croak(aTHX_ "NULL array element in re::regnames()");
- mXPUSHs(SvREFCNT_inc_simple_NN(*entry));
+ mPUSHs(SvREFCNT_inc_simple_NN(*entry));
}
SvREFCNT_dec(ret);
return;
}
+XS(XS_re_regexp_pattern); /* prototype to pass -Wmissing-prototypes */
XS(XS_re_regexp_pattern)
{
- dVAR;
dXSARGS;
REGEXP *re;
+ U8 const gimme = GIMME_V;
+ EXTEND(SP, 2);
+ SP -= items;
if (items != 1)
croak_xs_usage(cv, "sv");
- SP -= items;
-
/*
Checks if a reference is a regex or not. If the parameter is
not a ref, or is not the result of a qr// then returns false
/* Houston, we have a regex! */
SV *pattern;
- if ( GIMME_V == G_ARRAY ) {
+ if ( gimme == G_ARRAY ) {
STRLEN left = 0;
char reflags[sizeof(INT_PAT_MODS) + MAX_CHARSET_NAME_LENGTH];
const char *fptr;
(RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP);
/* return the pattern and the modifiers */
- XPUSHs(pattern);
- XPUSHs(newSVpvn_flags(reflags, left, SVs_TEMP));
+ PUSHs(pattern);
+ PUSHs(newSVpvn_flags(reflags, left, SVs_TEMP));
XSRETURN(2);
} else {
/* Scalar, so use the string that Perl would return */
- /* return the pattern in (?msix:..) format */
+ /* return the pattern in (?msixn:..) format */
#if PERL_VERSION >= 11
pattern = sv_2mortal(newSVsv(MUTABLE_SV(re)));
#else
pattern = newSVpvn_flags(RX_WRAPPED(re), RX_WRAPLEN(re),
(RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP);
#endif
- XPUSHs(pattern);
+ PUSHs(pattern);
XSRETURN(1);
}
} else {
/* It ain't a regexp folks */
- if ( GIMME_V == G_ARRAY ) {
+ if ( gimme == G_ARRAY ) {
/* return the empty list */
- XSRETURN_UNDEF;
+ XSRETURN_EMPTY;
} else {
/* Because of the (?:..) wrapping involved in a
stringified pattern it is impossible to get a
XSRETURN_NO;
}
}
- /* NOT-REACHED */
+ NOT_REACHED; /* NOTREACHED */
}
+#include "vutil.h"
+#include "vxs.inc"
+
struct xsub_details {
const char *name;
XSUBADDR_t xsub;
const char *proto;
};
-struct xsub_details details[] = {
+static const struct xsub_details details[] = {
{"UNIVERSAL::isa", XS_UNIVERSAL_isa, NULL},
{"UNIVERSAL::can", XS_UNIVERSAL_can, NULL},
{"UNIVERSAL::DOES", XS_UNIVERSAL_DOES, NULL},
- {"UNIVERSAL::VERSION", XS_UNIVERSAL_VERSION, NULL},
- {"version::()", XS_version_noop, NULL},
- {"version::new", XS_version_new, NULL},
- {"version::parse", XS_version_new, NULL},
- {"version::(\"\"", XS_version_stringify, NULL},
- {"version::stringify", XS_version_stringify, NULL},
- {"version::(0+", XS_version_numify, NULL},
- {"version::numify", XS_version_numify, NULL},
- {"version::normal", XS_version_normal, NULL},
- {"version::(cmp", XS_version_vcmp, NULL},
- {"version::(<=>", XS_version_vcmp, NULL},
- {"version::vcmp", XS_version_vcmp, NULL},
- {"version::(bool", XS_version_boolean, NULL},
- {"version::boolean", XS_version_boolean, NULL},
- {"version::(nomethod", XS_version_noop, NULL},
- {"version::noop", XS_version_noop, NULL},
- {"version::is_alpha", XS_version_is_alpha, NULL},
- {"version::qv", XS_version_qv, NULL},
- {"version::declare", XS_version_qv, NULL},
- {"version::is_qv", XS_version_is_qv, NULL},
+#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},
{"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, "*;@"},
- {"Internals::hash_seed", XS_Internals_hash_seed, ""},
- {"Internals::rehash_seed", XS_Internals_rehash_seed, ""},
- {"Internals::HvREHASH", XS_Internals_HvREHASH, "\\%"},
{"re::is_regexp", XS_re_is_regexp, "$"},
{"re::regname", XS_re_regname, ";$$"},
{"re::regnames", XS_re_regnames, ";$"},
{"re::regexp_pattern", XS_re_regexp_pattern, "$"},
};
+STATIC OP*
+optimize_out_native_convert_function(pTHX_ OP* entersubop,
+ GV* namegv,
+ SV* protosv)
+{
+ /* Optimizes out an identity function, i.e., one that just returns its
+ * argument. The passed in function is assumed to be an identity function,
+ * with no checking. This is designed to be called for utf8_to_native()
+ * and native_to_utf8() on ASCII platforms, as they just return their
+ * arguments, but it could work on any such function.
+ *
+ * The code is mostly just cargo-culted from Memoize::Lift */
+
+ OP *pushop, *argop;
+ OP *parent;
+ SV* prototype = newSVpvs("$");
+
+ PERL_UNUSED_ARG(protosv);
+
+ assert(entersubop->op_type == OP_ENTERSUB);
+
+ entersubop = ck_entersub_args_proto(entersubop, namegv, prototype);
+ parent = entersubop;
+
+ SvREFCNT_dec(prototype);
+
+ pushop = cUNOPx(entersubop)->op_first;
+ if (! OpHAS_SIBLING(pushop)) {
+ parent = pushop;
+ pushop = cUNOPx(pushop)->op_first;
+ }
+ argop = OpSIBLING(pushop);
+
+ /* Carry on without doing the optimization if it is not something we're
+ * expecting, so continues to work */
+ if ( ! argop
+ || ! OpHAS_SIBLING(argop)
+ || OpHAS_SIBLING(OpSIBLING(argop))
+ ) {
+ return entersubop;
+ }
+
+ /* cut argop from the subtree */
+ (void)op_sibling_splice(parent, pushop, 1, NULL);
+
+ op_free(entersubop);
+ return argop;
+}
+
void
Perl_boot_core_UNIVERSAL(pTHX)
{
- dVAR;
static const char file[] = __FILE__;
- struct xsub_details *xsub = details;
- const struct xsub_details *end
- = details + sizeof(details) / sizeof(details[0]);
+ const struct xsub_details *xsub = details;
+ const struct xsub_details *end = C_ARRAY_END(details);
do {
newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0);
} while (++xsub < end);
- /* register the overloading (type 'A') magic */
- PL_amagic_generation++;
+#ifndef EBCDIC
+ { /* On ASCII platforms these functions just return their argument, so can
+ be optimized away */
+
+ 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,
+ optimize_out_native_convert_function,
+ (SV*) to_native_cv);
+ cv_set_call_checker(to_unicode_cv,
+ optimize_out_native_convert_function,
+ (SV*) to_unicode_cv);
+ }
+#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);
- Safefree(CvFILE(cv));
- CvFILE(cv) = (char *)file;
+ char ** cvfile = &CvFILE(cv);
+ char * oldfile = *cvfile;
CvDYNFILE_off(cv);
+ *cvfile = (char *)file;
+ Safefree(oldfile);
}
}
/*
- * Local variables:
- * c-indentation-style: bsd
- * c-basic-offset: 4
- * indent-tabs-mode: t
- * End:
- *
- * ex: set ts=8 sts=4 sw=4 noet:
+ * ex: set ts=8 sts=4 sw=4 et:
*/