*
* It is also used to store XS functions that need to be present in
* miniperl for a lack of a better place to put them. It might be
- * clever to move them to seperate XS files which would then be pulled
+ * clever to move them to separate XS files which would then be pulled
* in by some to-be-written build process.
*/
#include "perliol.h" /* For the PERLIO_F_XXX */
#endif
-static HV *
-S_get_isa_hash(pTHX_ HV *const stash)
-{
- dVAR;
- struct mro_meta *const meta = HvMROMETA(stash);
-
- PERL_ARGS_ASSERT_GET_ISA_HASH;
-
- if (!meta->isa) {
- AV *const isa = mro_get_linear_isa(stash);
- if (!meta->isa) {
- HV *const isa_hash = newHV();
- /* Linearisation didn't build it for us, so do it here. */
- SV *const *svp = AvARRAY(isa);
- SV *const *const svp_end = svp + AvFILLp(isa) + 1;
- const HEK *const canon_name = HvNAME_HEK(stash);
-
- while (svp < svp_end) {
- (void) hv_store_ent(isa_hash, *svp++, &PL_sv_undef, 0);
- }
-
- (void) hv_common(isa_hash, NULL, HEK_KEY(canon_name),
- HEK_LEN(canon_name), HEK_FLAGS(canon_name),
- HV_FETCH_ISSTORE, &PL_sv_undef,
- HEK_HASH(canon_name));
- (void) hv_store(isa_hash, "UNIVERSAL", 9, &PL_sv_undef, 0);
-
- SvREADONLY_on(isa_hash);
-
- meta->isa = isa_hash;
- }
- }
- return meta->isa;
-}
-
/*
* Contributed by Graham Barr <Graham.Barr@tiuk.ti.com>
* The main guts of traverse_isa was actually copied from gv_fetchmeth
*/
STATIC bool
-S_isa_lookup(pTHX_ HV *stash, const char * const name)
+S_isa_lookup(pTHX_ HV *stash, const char * const name, STRLEN len, U32 flags)
{
dVAR;
const struct mro_meta *const meta = HvMROMETA(stash);
- HV *const isa = meta->isa ? meta->isa : S_get_isa_hash(aTHX_ stash);
- STRLEN len = strlen(name);
+ HV *isa = meta->isa;
const HV *our_stash;
PERL_ARGS_ASSERT_ISA_LOOKUP;
- if (hv_common(isa, NULL, name, len, 0 /* No "UTF-8" flag possible with only
- a char * argument*/,
+ if (!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;
}
/* A stash/class can go by many names (ie. User == main::User), so
- we use the name in the stash itself, which is canonical. */
- our_stash = gv_stashpvn(name, len, 0);
+ we use the HvENAME in the stash itself, which is canonical, falling
+ back to HvNAME if necessary. */
+ our_stash = gv_stashpvn(name, len, flags);
if (our_stash) {
- HEK *const canon_name = HvNAME_HEK(our_stash);
+ HEK *canon_name = HvENAME_HEK(our_stash);
+ if (!canon_name) canon_name = HvNAME_HEK(our_stash);
if (hv_common(isa, NULL, HEK_KEY(canon_name), HEK_LEN(canon_name),
HEK_FLAGS(canon_name),
/*
=head1 SV Manipulation Functions
-=for apidoc sv_derived_from
+=for apidoc sv_derived_from_pvn
Returns a boolean indicating whether the SV is derived from the specified class
I<at the C level>. To check derivation at the Perl level, call C<isa()> as a
normal Perl method.
+Currently, the only significant value for C<flags> is SVf_UTF8.
+
+=cut
+
+=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.
+
+=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);
+}
+
+/*
+=for apidoc sv_derived_from
+
+Exactly like L</sv_derived_from_pv>, but doesn't take a C<flags> parameter.
+
=cut
*/
bool
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);
+}
+
+/*
+=for apidoc sv_derived_from_pv
+
+Exactly like L</sv_derived_from_pvn>, but takes a nul-terminated string
+instead of a string/length pair.
+
+=cut
+*/
+
+
+bool
+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);
+}
+
+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;
+ PERL_ARGS_ASSERT_SV_DERIVED_FROM_PVN;
SvGETMAGIC(sv);
}
else {
stash = gv_stashsv(sv, 0);
+ if (!stash)
+ stash = gv_stashpvs("UNIVERSAL", 0);
}
- return stash ? isa_lookup(stash, name) : FALSE;
+ return stash ? isa_lookup(stash, name, len, flags) : FALSE;
}
/*
-=for apidoc sv_does
+=for apidoc sv_does_sv
Returns a boolean indicating whether the SV performs a specific, named role.
The SV can be a Perl object or the name of a Perl class.
#include "XSUB.h"
bool
-Perl_sv_does(pTHX_ SV *sv, const char *const name)
+Perl_sv_does_sv(pTHX_ SV *sv, SV *namesv, U32 flags)
{
- const char *classname;
+ SV *classname;
bool does_it;
SV *methodname;
dSP;
- PERL_ARGS_ASSERT_SV_DOES;
+ PERL_ARGS_ASSERT_SV_DOES_SV;
+ PERL_UNUSED_ARG(flags);
ENTER;
SAVETMPS;
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)) {
- classname = sv_reftype(SvRV(sv),TRUE);
+ classname = sv_ref(NULL,SvRV(sv),TRUE);
} else {
- classname = SvPV_nolen(sv);
+ classname = sv;
}
- if (strEQ(name,classname)) {
+ if (sv_eq(classname, namesv)) {
LEAVE;
return TRUE;
}
PUSHMARK(SP);
- XPUSHs(sv);
- mXPUSHs(newSVpv(name, 0));
+ EXTEND(SP, 2);
+ PUSHs(sv);
+ PUSHs(namesv);
PUTBACK;
methodname = newSVpvs_flags("isa", SVs_TEMP);
}
/*
+=for apidoc sv_does
+
+Like L</sv_does_pv>, but doesn't take a C<flags> parameter.
+
+=cut
+*/
+
+bool
+Perl_sv_does(pTHX_ SV *sv, const char *const name)
+{
+ PERL_ARGS_ASSERT_SV_DOES;
+ return sv_does_sv(sv, newSVpvn_flags(name, strlen(name), SVs_TEMP), 0);
+}
+
+/*
+=for apidoc sv_does_pv
+
+Like L</sv_does_sv>, but takes a nul-terminated string instead of an SV.
+
+=cut
+*/
+
+
+bool
+Perl_sv_does_pv(pTHX_ SV *sv, const char *const name, U32 flags)
+{
+ PERL_ARGS_ASSERT_SV_DOES_PV;
+ return sv_does_sv(sv, newSVpvn_flags(name, strlen(name), SVs_TEMP | flags), flags);
+}
+
+/*
+=for apidoc sv_does_pvn
+
+Like L</sv_does_sv>, but takes a string/length pair instead of an SV.
+
+=cut
+*/
+
+bool
+Perl_sv_does_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, U32 flags)
+{
+ PERL_ARGS_ASSERT_SV_DOES_PVN;
+
+ return sv_does_sv(sv, newSVpvn_flags(name, len, flags | SVs_TEMP), flags);
+}
+
+/*
=for apidoc croak_xs_usage
A specialised variant of C<croak()> for emitting the usage message for xsubs
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:
- Perl_croak(aTHX_ "Usage %s::%s(%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);
PERL_ARGS_ASSERT_CROAK_XS_USAGE;
if (gv) {
- const char *const gvname = GvNAME(gv);
const HV *const stash = GvSTASH(gv);
- const char *const hvname = stash ? HvNAME_get(stash) : NULL;
- if (hvname)
- Perl_croak(aTHX_ "Usage: %s::%s(%s)", hvname, gvname, params);
+ if (HvNAME_get(stash))
+ Perl_croak_nocontext("Usage: %"HEKf"::%"HEKf"(%s)",
+ HEKfARG(HvNAME_HEK(stash)),
+ HEKfARG(GvNAME_HEK(gv)),
+ params);
else
- Perl_croak(aTHX_ "Usage: %s(%s)", gvname, params);
+ Perl_croak_nocontext("Usage: %"HEKf"(%s)",
+ HEKfARG(GvNAME_HEK(gv)), params);
} else {
/* Pants. I don't think that it should be possible to get here. */
- Perl_croak(aTHX_ "Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
+ Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
}
}
croak_xs_usage(cv, "reference, kind");
else {
SV * const sv = ST(0);
- const char *name;
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;
- name = SvPV_nolen_const(ST(1));
-
- ST(0) = boolSV(sv_derived_from(sv, name));
+ ST(0) = boolSV(sv_derived_from_sv(sv, ST(1), 0));
XSRETURN(1);
}
}
dVAR;
dXSARGS;
SV *sv;
- const char *name;
SV *rv;
HV *pkg = NULL;
SvGETMAGIC(sv);
- if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))
- || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv))))
+ if (!SvOK(sv) || !(SvROK(sv) || SvNIOK(sv) || (SvPOK(sv) && SvCUR(sv))
+ ))
XSRETURN_UNDEF;
- name = SvPV_nolen_const(ST(1));
rv = &PL_sv_undef;
if (SvROK(sv)) {
}
else {
pkg = gv_stashsv(sv, 0);
+ if (!pkg)
+ pkg = gv_stashpv("UNIVERSAL", 0);
}
if (pkg) {
- GV * const gv = gv_fetchmethod_autoload(pkg, name, FALSE);
+ GV * const gv = gv_fetchmethod_sv_flags(pkg, ST(1), 0);
if (gv && isGV(gv))
rv = sv_2mortal(newRV(MUTABLE_SV(GvCV(gv))));
}
Perl_croak(aTHX_ "Usage: invocant->DOES(kind)");
else {
SV * const sv = ST(0);
- const char *name;
-
- name = SvPV_nolen_const(ST(1));
- if (sv_does( sv, name ))
+ if (sv_does_sv( sv, ST(1), 0 ))
XSRETURN_YES;
XSRETURN_NO;
SV * const nsv = sv_newmortal();
sv_setsv(nsv, sv);
sv = nsv;
- if ( !sv_derived_from(sv, "version"))
+ if ( !sv_isobject(sv) || !sv_derived_from(sv, "version"))
upg_version(sv, FALSE);
+
undef = NULL;
}
else {
if (undef) {
if (pkg) {
- const char * const name = HvNAME_get(pkg);
+ const HEK * const name = HvNAME_HEK(pkg);
Perl_croak(aTHX_
- "%s does not define $%s::VERSION--version check failed",
- name, name);
+ "%"HEKf" does not define $%"HEKf
+ "::VERSION--version check failed",
+ HEKfARG(name), HEKfARG(name));
} else {
Perl_croak(aTHX_
- "%s defines neither package nor VERSION--version check failed",
- SvPVx_nolen_const(ST(0)) );
+ "%"SVf" defines neither package nor VERSION--version check failed",
+ SVfARG(ST(0)) );
}
}
- if ( !sv_derived_from(req, "version")) {
+ if ( !sv_isobject(req) || !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_ "%s version %"SVf" required--"
- "this is only version %"SVf"", HvNAME_get(pkg),
- SVfARG(vnormal(req)),
- SVfARG(vnormal(sv)));
+ 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_ "%s version %"SVf" required--"
- "this is only version %"SVf"", HvNAME_get(pkg),
- SVfARG(vstringify(req)),
- SVfARG(vstringify(sv)));
+ 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))));
}
}
}
if ( SvOK(sv) && sv_derived_from(sv, "version") ) {
- ST(0) = vstringify(sv);
+ ST(0) = sv_2mortal(vstringify(sv));
} else {
ST(0) = sv;
}
{
SV *vs = ST(1);
SV *rv;
- const char * const classname =
- sv_isobject(ST(0)) /* get the class if called as an object method */
- ? HvNAME(SvSTASH(SvRV(ST(0))))
- : (char *)SvPV_nolen(ST(0));
+ 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 */
}
rv = new_version(vs);
- if ( strcmp(classname,"version") != 0 ) /* inherited new() */
- sv_bless(rv, gv_stashpv(classname, GV_ADD));
+ if ( strnNE(classname,"version", len) ) /* inherited new() */
+ sv_bless(rv, gv_stashpvn(classname, len, GV_ADD | flags));
mPUSHs(rv);
PUTBACK;
croak_xs_usage(cv, "lobj, ...");
SP -= items;
{
- SV * lobj;
+ SV * lobj = ST(0);
- if (sv_derived_from(ST(0), "version")) {
- lobj = SvRV(ST(0));
+ if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) {
+ lobj = SvRV(lobj);
}
else
Perl_croak(aTHX_ "lobj is not of type version");
croak_xs_usage(cv, "lobj, ...");
SP -= items;
{
- SV * lobj;
+ SV * lobj = ST(0);
- if (sv_derived_from(ST(0), "version")) {
- lobj = SvRV(ST(0));
+ if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) {
+ lobj = SvRV(lobj);
}
else
Perl_croak(aTHX_ "lobj is not of type version");
croak_xs_usage(cv, "lobj, ...");
SP -= items;
{
- SV * lobj;
+ SV * lobj = ST(0);
- if (sv_derived_from(ST(0), "version")) {
- lobj = SvRV(ST(0));
+ if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) {
+ lobj = SvRV(lobj);
}
else
Perl_croak(aTHX_ "lobj is not of type version");
croak_xs_usage(cv, "lobj, ...");
SP -= items;
{
- SV * lobj;
+ SV * lobj = ST(0);
- if (sv_derived_from(ST(0), "version")) {
- lobj = SvRV(ST(0));
+ if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) {
+ lobj = SvRV(lobj);
}
else
Perl_croak(aTHX_ "lobj is not of type version");
SV * robj = ST(1);
const IV swap = (IV)SvIV(ST(2));
- if ( ! sv_derived_from(robj, "version") )
+ if ( !sv_isobject(robj) || !sv_derived_from(robj, "version") )
{
- robj = new_version(SvOK(robj) ? robj : newSVpvs("0"));
+ robj = new_version(SvOK(robj) ? robj : newSVpvs_flags("0", SVs_TEMP));
+ sv_2mortal(robj);
}
rvs = SvRV(robj);
if (items < 1)
croak_xs_usage(cv, "lobj, ...");
SP -= items;
- if (sv_derived_from(ST(0), "version")) {
+ if (sv_isobject(ST(0)) && sv_derived_from(ST(0), "version")) {
SV * const lobj = SvRV(ST(0));
- SV * const rs = newSViv( vcmp(lobj,new_version(newSVpvs("0"))) );
+ SV * const rs =
+ newSViv( vcmp(lobj,
+ sv_2mortal(new_version(
+ sv_2mortal(newSVpvs("0"))
+ ))
+ )
+ );
mPUSHs(rs);
PUTBACK;
return;
dXSARGS;
if (items < 1)
croak_xs_usage(cv, "lobj, ...");
- if (sv_derived_from(ST(0), "version"))
+ if (sv_isobject(ST(0)) && sv_derived_from(ST(0), "version"))
Perl_croak(aTHX_ "operation not supported with version object");
else
Perl_croak(aTHX_ "lobj is not of type version");
if (items != 1)
croak_xs_usage(cv, "lobj");
SP -= items;
- if (sv_derived_from(ST(0), "version")) {
+ if (sv_isobject(ST(0)) && sv_derived_from(ST(0), "version")) {
SV * const lobj = ST(0);
if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "alpha", 5 ) )
XSRETURN_YES;
{
SV * ver = ST(0);
SV * rv;
- const char * classname = "";
- if ( items == 2 && SvOK(ST(1)) ) {
- /* getting called as object or class method */
- ver = ST(1);
- classname =
- sv_isobject(ST(0)) /* class called as an object method */
- ? HvNAME_get(SvSTASH(SvRV(ST(0))))
- : (char *)SvPV_nolen(ST(0));
- }
+ 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 */
} else {
rv = sv_2mortal(new_version(ver));
}
- if ( items == 2 && strcmp(classname,"version") ) { /* inherited new() */
- sv_bless(rv, gv_stashpv(classname, GV_ADD));
- }
+ if ( items == 2
+ && strnNE(classname,"version", len) ) { /* inherited new() */
+ sv_bless(rv, gv_stashpvn(classname, len, GV_ADD | flags));
+ }
PUSHs(rv);
}
PUTBACK;
if (items != 1)
croak_xs_usage(cv, "lobj");
SP -= items;
- if (sv_derived_from(ST(0), "version")) {
+ if (sv_isobject(ST(0)) && sv_derived_from(ST(0), "version")) {
SV * const lobj = ST(0);
if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "qv", 2 ) )
XSRETURN_YES;
if (items != 1)
croak_xs_usage(cv, "sv");
sv_utf8_encode(ST(0));
+ SvSETMAGIC(ST(0));
XSRETURN_EMPTY;
}
croak_xs_usage(cv, "sv");
else {
SV * const sv = ST(0);
- const bool RETVAL = sv_utf8_decode(sv);
+ bool RETVAL;
+ SvPV_force_nolen(sv);
+ RETVAL = sv_utf8_decode(sv);
+ SvSETMAGIC(sv);
ST(0) = boolSV(RETVAL);
- sv_2mortal(ST(0));
}
XSRETURN(1);
}
const bool RETVAL = sv_utf8_downgrade(sv, failok);
ST(0) = boolSV(RETVAL);
- sv_2mortal(ST(0));
}
XSRETURN(1);
}
{
dVAR;
dXSARGS;
- SV * const sv = SvRV(ST(0));
+ SV * const svz = ST(0);
+ SV * sv;
PERL_UNUSED_ARG(cv);
+ /* [perl #77776] - called as &foo() not foo() */
+ if (!SvROK(svz))
+ croak_xs_usage(cv, "SCALAR[, ON]");
+
+ sv = SvRV(svz);
+
if (items == 1) {
- if (SvREADONLY(sv))
+ if (SvREADONLY(sv) && !SvIsCOW(sv))
XSRETURN_YES;
else
XSRETURN_NO;
}
else if (items == 2) {
if (SvTRUE(ST(1))) {
+ if (SvIsCOW(sv)) sv_force_normal(sv);
SvREADONLY_on(sv);
XSRETURN_YES;
}
else {
/* I hope you really know what you are doing. */
- SvREADONLY_off(sv);
+ if (!SvIsCOW(sv)) SvREADONLY_off(sv);
XSRETURN_NO;
}
}
XSRETURN_UNDEF; /* Can't happen. */
}
-
XS(XS_Internals_SvREFCNT) /* This is dangerous stuff. */
{
dVAR;
dXSARGS;
- SV * const sv = SvRV(ST(0));
+ SV * const svz = ST(0);
+ SV * sv;
+ U32 refcnt;
PERL_UNUSED_ARG(cv);
- if (items == 1)
- XSRETURN_IV(SvREFCNT(sv) - 1); /* Minus the ref created for us. */
- else if (items == 2) {
+ /* [perl #77776] - called as &foo() not foo() */
+ if ((items != 1 && items != 2) || !SvROK(svz))
+ croak_xs_usage(cv, "SCALAR[, REFCOUNT]");
+
+ sv = SvRV(svz);
+
/* 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)
dVAR;
dXSARGS;
- if (items != 1)
+ if (items != 1 || !SvROK(ST(0)))
croak_xs_usage(cv, "hv");
else {
HV * const hv = MUTABLE_HV(SvRV(ST(0)));
}
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 ?
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)
{
if (items != 1)
croak_xs_usage(cv, "sv");
- SP -= items;
-
if (SvRXOK(ST(0))) {
XSRETURN_YES;
} else {
croak_xs_usage(cv, "");
SP -= items;
+ PUTBACK;
if (!rx)
XSRETURN_UNDEF;
ret = CALLREG_NAMED_BUFF_COUNT(rx);
SPAGAIN;
-
- if (ret) {
- mXPUSHs(ret);
- PUTBACK;
- return;
- } else {
- XSRETURN_UNDEF;
- }
+ PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
+ XSRETURN(1);
}
XS(XS_re_regname)
croak_xs_usage(cv, "name[, all ]");
SP -= items;
+ PUTBACK;
rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
}
ret = CALLREG_NAMED_BUFF_FETCH(rx, ST(0), (flags | RXapif_REGNAME));
- if (ret) {
- mXPUSHs(ret);
- XSRETURN(1);
- }
- XSRETURN_UNDEF;
+ SPAGAIN;
+ PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
+ XSRETURN(1);
}
}
SP -= items;
+ PUTBACK;
ret = CALLREG_NAMED_BUFF_ALL(rx, (flags | RXapif_REGNAMES));
SPAGAIN;
- SP -= items;
-
if (!ret)
XSRETURN_UNDEF;
av = MUTABLE_AV(SvRV(ret));
length = av_len(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);
dXSARGS;
REGEXP *re;
+ 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
Otherwise in list context it returns the pattern and the
modifiers, in scalar context it returns the pattern just as it
would if the qr// was stringified normally, regardless as
- to the class of the variable and any strigification overloads
+ to the class of the variable and any stringification overloads
on the object.
*/
{
/* Houston, we have a regex! */
SV *pattern;
- STRLEN left = 0;
- char reflags[6];
if ( GIMME_V == G_ARRAY ) {
+ STRLEN left = 0;
+ char reflags[sizeof(INT_PAT_MODS) + MAX_CHARSET_NAME_LENGTH];
+ const char *fptr;
+ char ch;
+ U16 match_flags;
+
/*
we are in list context so stringify
the modifiers that apply. We ignore "negative
- modifiers" in this scenario.
+ modifiers" in this scenario, and the default character set
*/
- const char *fptr = INT_PAT_MODS;
- char ch;
- U16 match_flags = (U16)((RX_EXTFLAGS(re) & PMf_COMPILETIME)
+ 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);
while((ch = *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 */
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 {
/* NOT-REACHED */
}
-XS(XS_Tie_Hash_NamedCapture_FETCH)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- SV * ret;
-
- if (items != 2)
- croak_xs_usage(cv, "$key, $flags");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx || !SvROK(ST(0)))
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0)))));
- ret = CALLREG_NAMED_BUFF_FETCH(rx, ST(1), flags);
-
- SPAGAIN;
-
- if (ret) {
- mXPUSHs(ret);
- PUTBACK;
- return;
- }
- XSRETURN_UNDEF;
-}
-
-XS(XS_Tie_Hash_NamedCapture_STORE)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
-
- if (items != 3)
- croak_xs_usage(cv, "$key, $value, $flags");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx || !SvROK(ST(0))) {
- if (!PL_localizing)
- Perl_croak(aTHX_ "%s", PL_no_modify);
- else
- XSRETURN_UNDEF;
- }
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0)))));
- CALLREG_NAMED_BUFF_STORE(rx,ST(1), ST(2), flags);
-}
-
-XS(XS_Tie_Hash_NamedCapture_DELETE)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
- U32 flags;
-
- if (items != 2)
- croak_xs_usage(cv, "$key, $flags");
-
- if (!rx || !SvROK(ST(0)))
- Perl_croak(aTHX_ "%s", PL_no_modify);
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0)))));
- CALLREG_NAMED_BUFF_DELETE(rx, ST(1), flags);
-}
-
-XS(XS_Tie_Hash_NamedCapture_CLEAR)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
-
- if (items != 1)
- croak_xs_usage(cv, "$flags");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx || !SvROK(ST(0)))
- Perl_croak(aTHX_ "%s", PL_no_modify);
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0)))));
- CALLREG_NAMED_BUFF_CLEAR(rx, flags);
-}
-
-XS(XS_Tie_Hash_NamedCapture_EXISTS)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- SV * ret;
-
- if (items != 2)
- croak_xs_usage(cv, "$key, $flags");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx || !SvROK(ST(0)))
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0)))));
- ret = CALLREG_NAMED_BUFF_EXISTS(rx, ST(1), flags);
-
- SPAGAIN;
-
- XPUSHs(ret);
- PUTBACK;
- return;
-}
-
-XS(XS_Tie_Hash_NamedCapture_FIRSTK)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- SV * ret;
-
- if (items != 1)
- croak_xs_usage(cv, "");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx || !SvROK(ST(0)))
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0)))));
- ret = CALLREG_NAMED_BUFF_FIRSTKEY(rx, flags);
-
- SPAGAIN;
-
- if (ret) {
- mXPUSHs(ret);
- PUTBACK;
- } else {
- XSRETURN_UNDEF;
- }
-
-}
-
-XS(XS_Tie_Hash_NamedCapture_NEXTK)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- SV * ret;
-
- if (items != 2)
- croak_xs_usage(cv, "$lastkey");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx || !SvROK(ST(0)))
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0)))));
- ret = CALLREG_NAMED_BUFF_NEXTKEY(rx, ST(1), flags);
-
- SPAGAIN;
-
- if (ret) {
- mXPUSHs(ret);
- } else {
- XSRETURN_UNDEF;
- }
- PUTBACK;
-}
-
-XS(XS_Tie_Hash_NamedCapture_SCALAR)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- SV * ret;
-
- if (items != 1)
- croak_xs_usage(cv, "");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx || !SvROK(ST(0)))
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV(MUTABLE_SV(ST(0)))));
- ret = CALLREG_NAMED_BUFF_SCALAR(rx, flags);
-
- SPAGAIN;
-
- if (ret) {
- mXPUSHs(ret);
- PUTBACK;
- return;
- } else {
- XSRETURN_UNDEF;
- }
-}
-
-XS(XS_Tie_Hash_NamedCapture_flags)
-{
- dVAR;
- dXSARGS;
-
- if (items != 0)
- croak_xs_usage(cv, "");
-
- mXPUSHu(RXapif_ONE);
- mXPUSHu(RXapif_ALL);
- PUTBACK;
- return;
-}
-
struct xsub_details {
const char *name;
XSUBADDR_t xsub;
const char *proto;
};
-struct xsub_details details[] = {
+const struct xsub_details details[] = {
{"UNIVERSAL::isa", XS_UNIVERSAL_isa, NULL},
{"UNIVERSAL::can", XS_UNIVERSAL_can, NULL},
{"UNIVERSAL::DOES", XS_UNIVERSAL_DOES, NULL},
{"version::vcmp", XS_version_vcmp, NULL},
{"version::(bool", XS_version_boolean, NULL},
{"version::boolean", XS_version_boolean, NULL},
+ {"version::(+", XS_version_noop, NULL},
+ {"version::(-", XS_version_noop, NULL},
+ {"version::(*", XS_version_noop, NULL},
+ {"version::(/", XS_version_noop, NULL},
+ {"version::(+=", XS_version_noop, NULL},
+ {"version::(-=", XS_version_noop, NULL},
+ {"version::(*=", XS_version_noop, NULL},
+ {"version::(/=", XS_version_noop, NULL},
+ {"version::(abs", XS_version_noop, NULL},
{"version::(nomethod", XS_version_noop, NULL},
{"version::noop", XS_version_noop, NULL},
{"version::is_alpha", XS_version_is_alpha, NULL},
{"Internals::SvREFCNT", XS_Internals_SvREFCNT, "\\[$%@];$"},
{"Internals::hv_clear_placeholders", XS_Internals_hv_clear_placehold, "\\%"},
{"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::regnames_count", XS_re_regnames_count, ""},
{"re::regexp_pattern", XS_re_regexp_pattern, "$"},
- {"Tie::Hash::NamedCapture::FETCH", XS_Tie_Hash_NamedCapture_FETCH, NULL},
- {"Tie::Hash::NamedCapture::STORE", XS_Tie_Hash_NamedCapture_STORE, NULL},
- {"Tie::Hash::NamedCapture::DELETE", XS_Tie_Hash_NamedCapture_DELETE, NULL},
- {"Tie::Hash::NamedCapture::CLEAR", XS_Tie_Hash_NamedCapture_CLEAR, NULL},
- {"Tie::Hash::NamedCapture::EXISTS", XS_Tie_Hash_NamedCapture_EXISTS, NULL},
- {"Tie::Hash::NamedCapture::FIRSTKEY", XS_Tie_Hash_NamedCapture_FIRSTK, NULL},
- {"Tie::Hash::NamedCapture::NEXTKEY", XS_Tie_Hash_NamedCapture_NEXTK, NULL},
- {"Tie::Hash::NamedCapture::SCALAR", XS_Tie_Hash_NamedCapture_SCALAR, NULL},
- {"Tie::Hash::NamedCapture::flags", XS_Tie_Hash_NamedCapture_flags, NULL}
};
void
{
dVAR;
static const char file[] = __FILE__;
- struct xsub_details *xsub = details;
+ const struct xsub_details *xsub = details;
const struct xsub_details *end
= details + sizeof(details) / sizeof(details[0]);
newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0);
} while (++xsub < end);
- /* register the overloading (type 'A') magic */
- PL_amagic_generation++;
-
/* Providing a Regexp::DESTROY fixes #21347. See test in t/op/ref.t */
- CvFILE(newCONSTSUB(get_hv("Regexp::", GV_ADD), "DESTROY", NULL))
- = (char *)file;
+ {
+ CV * const cv =
+ newCONSTSUB(get_hv("Regexp::", GV_ADD), "DESTROY", NULL);
+ Safefree(CvFILE(cv));
+ CvFILE(cv) = (char *)file;
+ CvDYNFILE_off(cv);
+ }
}
/*
* Local variables:
* c-indentation-style: bsd
* c-basic-offset: 4
- * indent-tabs-mode: t
+ * indent-tabs-mode: nil
* End:
*
- * ex: set ts=8 sts=4 sw=4 noet:
+ * ex: set ts=8 sts=4 sw=4 et:
*/