/* universal.c
*
* Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- * 2005, 2006, 2007 by Larry Wall and others
+ * 2005, 2006, 2007, 2008 by Larry Wall and others
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
*/
/*
- * "The roots of those mountains must be roots indeed; there must be
- * great secrets buried there which have not been discovered since the
- * beginning." --Gandalf, relating Gollum's story
+ * '"The roots of those mountains must be roots indeed; there must be
+ * great secrets buried there which have not been discovered since the
+ * beginning."' --Gandalf, relating Gollum's history
+ *
+ * [p.54 of _The Lord of the Rings_, I/ii: "The Shadow of the Past"]
*/
/* This file contains the code that implements the functions in Perl's
*
* 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.
*/
*/
STATIC bool
-S_isa_lookup(pTHX_ HV *stash, const char * const name, const HV* const name_stash)
+S_isa_lookup(pTHX_ HV *stash, const char * const name)
{
dVAR;
- AV* stash_linear_isa;
- SV** svp;
- const char *hvname;
- I32 items;
+ const struct mro_meta *const meta = HvMROMETA(stash);
+ HV *isa = meta->isa;
+ STRLEN len = strlen(name);
+ const HV *our_stash;
- /* A stash/class can go by many names (ie. User == main::User), so
- we compare the stash itself just in case */
- if (name_stash && ((const HV *)stash == name_stash))
- return TRUE;
+ PERL_ARGS_ASSERT_ISA_LOOKUP;
- hvname = HvNAME_get(stash);
+ if (!isa) {
+ (void)mro_get_linear_isa(stash);
+ isa = meta->isa;
+ }
- if (strEQ(hvname, name))
+ if (hv_common(isa, NULL, name, len, 0 /* No "UTF-8" flag possible with only
+ a char * argument*/,
+ HV_FETCH_ISEXISTS, NULL, 0)) {
+ /* Direct name lookup worked. */
return TRUE;
+ }
- if (strEQ(name, "UNIVERSAL"))
- 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, 0);
- stash_linear_isa = mro_get_linear_isa(stash);
- svp = AvARRAY(stash_linear_isa) + 1;
- items = AvFILLp(stash_linear_isa);
- while (items--) {
- SV* const basename_sv = *svp++;
- HV* const basestash = gv_stashsv(basename_sv, 0);
- if (!basestash) {
- if (ckWARN(WARN_SYNTAX))
- Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
- "Can't locate package %"SVf" for the parents of %s",
- SVfARG(basename_sv), hvname);
- continue;
- }
- if(name_stash == basestash || strEQ(name, SvPVX(basename_sv)))
+ if (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),
+ HV_FETCH_ISEXISTS, NULL, HEK_HASH(canon_name))) {
return TRUE;
+ }
}
return FALSE;
dVAR;
HV *stash;
+ PERL_ARGS_ASSERT_SV_DERIVED_FROM;
+
SvGETMAGIC(sv);
if (SvROK(sv)) {
stash = gv_stashsv(sv, 0);
}
- if (stash) {
- HV * const name_stash = gv_stashpv(name, 0);
- return isa_lookup(stash, name, name_stash);
- }
- else
- return FALSE;
-
+ return stash ? isa_lookup(stash, name) : FALSE;
}
/*
const char *classname;
bool does_it;
SV *methodname;
-
dSP;
+
+ PERL_ARGS_ASSERT_SV_DOES;
+
ENTER;
SAVETMPS;
SvGETMAGIC(sv);
if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))
- || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv))))
+ || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv)))) {
+ LEAVE;
return FALSE;
+ }
if (sv_isobject(sv)) {
classname = sv_reftype(SvRV(sv),TRUE);
classname = SvPV_nolen(sv);
}
- if (strEQ(name,classname))
+ if (strEQ(name,classname)) {
+ LEAVE;
return TRUE;
+ }
PUSHMARK(SP);
XPUSHs(sv);
return does_it;
}
-PERL_XS_EXPORT_C void XS_UNIVERSAL_isa(pTHX_ CV *cv);
-PERL_XS_EXPORT_C void XS_UNIVERSAL_can(pTHX_ CV *cv);
-PERL_XS_EXPORT_C void XS_UNIVERSAL_DOES(pTHX_ CV *cv);
-PERL_XS_EXPORT_C void XS_UNIVERSAL_VERSION(pTHX_ CV *cv);
-XS(XS_version_new);
-XS(XS_version_stringify);
-XS(XS_version_numify);
-XS(XS_version_normal);
-XS(XS_version_vcmp);
-XS(XS_version_boolean);
-#ifdef HASATTRIBUTE_NORETURN
-XS(XS_version_noop) __attribute__noreturn__;
-#else
-XS(XS_version_noop);
-#endif
-XS(XS_version_is_alpha);
-XS(XS_version_qv);
-XS(XS_utf8_is_utf8);
-XS(XS_utf8_valid);
-XS(XS_utf8_encode);
-XS(XS_utf8_decode);
-XS(XS_utf8_upgrade);
-XS(XS_utf8_downgrade);
-XS(XS_utf8_unicode_to_native);
-XS(XS_utf8_native_to_unicode);
-XS(XS_Internals_SvREADONLY);
-XS(XS_Internals_SvREFCNT);
-XS(XS_Internals_hv_clear_placehold);
-XS(XS_PerlIO_get_layers);
-XS(XS_Regexp_DESTROY);
-XS(XS_Internals_hash_seed);
-XS(XS_Internals_rehash_seed);
-XS(XS_Internals_HvREHASH);
-XS(XS_Internals_inc_sub_generation);
-XS(XS_re_is_regexp);
-XS(XS_re_regname);
-XS(XS_re_regnames);
-XS(XS_re_regnames_count);
-XS(XS_re_regexp_pattern);
-XS(XS_Tie_Hash_NamedCapture_FETCH);
-XS(XS_Tie_Hash_NamedCapture_STORE);
-XS(XS_Tie_Hash_NamedCapture_DELETE);
-XS(XS_Tie_Hash_NamedCapture_CLEAR);
-XS(XS_Tie_Hash_NamedCapture_EXISTS);
-XS(XS_Tie_Hash_NamedCapture_FIRSTK);
-XS(XS_Tie_Hash_NamedCapture_NEXTK);
-XS(XS_Tie_Hash_NamedCapture_SCALAR);
-XS(XS_Tie_Hash_NamedCapture_flags);
+/*
+=for apidoc croak_xs_usage
+
+A specialised variant of C<croak()> for emitting the usage message for xsubs
+
+ 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:
+
+ Perl_croak(aTHX_ "Usage: %s::%s(%s)", "ouch" "awk", "eee_yow");
+
+=cut
+*/
void
-Perl_boot_core_UNIVERSAL(pTHX)
+Perl_croak_xs_usage(pTHX_ const CV *const cv, const char *const params)
{
- dVAR;
- static const char file[] = __FILE__;
+ const GV *const gv = CvGV(cv);
- newXS("UNIVERSAL::isa", XS_UNIVERSAL_isa, file);
- newXS("UNIVERSAL::can", XS_UNIVERSAL_can, file);
- newXS("UNIVERSAL::DOES", XS_UNIVERSAL_DOES, file);
- newXS("UNIVERSAL::VERSION", XS_UNIVERSAL_VERSION, file);
- {
- /* register the overloading (type 'A') magic */
- PL_amagic_generation++;
- /* Make it findable via fetchmethod */
- newXS("version::()", XS_version_noop, file);
- newXS("version::new", XS_version_new, file);
- newXS("version::(\"\"", XS_version_stringify, file);
- newXS("version::stringify", XS_version_stringify, file);
- newXS("version::(0+", XS_version_numify, file);
- newXS("version::numify", XS_version_numify, file);
- newXS("version::normal", XS_version_normal, file);
- newXS("version::(cmp", XS_version_vcmp, file);
- newXS("version::(<=>", XS_version_vcmp, file);
- newXS("version::vcmp", XS_version_vcmp, file);
- newXS("version::(bool", XS_version_boolean, file);
- newXS("version::boolean", XS_version_boolean, file);
- newXS("version::(nomethod", XS_version_noop, file);
- newXS("version::noop", XS_version_noop, file);
- newXS("version::is_alpha", XS_version_is_alpha, file);
- newXS("version::qv", XS_version_qv, file);
+ 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);
+ else
+ Perl_croak(aTHX_ "Usage: %s(%s)", gvname, 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);
}
- newXS("utf8::is_utf8", XS_utf8_is_utf8, file);
- newXS("utf8::valid", XS_utf8_valid, file);
- newXS("utf8::encode", XS_utf8_encode, file);
- newXS("utf8::decode", XS_utf8_decode, file);
- newXS("utf8::upgrade", XS_utf8_upgrade, file);
- newXS("utf8::downgrade", XS_utf8_downgrade, file);
- newXS("utf8::native_to_unicode", XS_utf8_native_to_unicode, file);
- newXS("utf8::unicode_to_native", XS_utf8_unicode_to_native, file);
- newXSproto("Internals::SvREADONLY",XS_Internals_SvREADONLY, file, "\\[$%@];$");
- newXSproto("Internals::SvREFCNT",XS_Internals_SvREFCNT, file, "\\[$%@];$");
- newXSproto("Internals::hv_clear_placeholders",
- XS_Internals_hv_clear_placehold, file, "\\%");
- newXSproto("PerlIO::get_layers",
- XS_PerlIO_get_layers, file, "*;@");
- newXS("Regexp::DESTROY", XS_Regexp_DESTROY, file);
- newXSproto("Internals::hash_seed",XS_Internals_hash_seed, file, "");
- newXSproto("Internals::rehash_seed",XS_Internals_rehash_seed, file, "");
- newXSproto("Internals::HvREHASH", XS_Internals_HvREHASH, file, "\\%");
- newXSproto("re::is_regexp", XS_re_is_regexp, file, "$");
- newXSproto("re::regname", XS_re_regname, file, ";$$");
- newXSproto("re::regnames", XS_re_regnames, file, ";$");
- newXSproto("re::regnames_count", XS_re_regnames_count, file, "");
- newXSproto("re::regexp_pattern", XS_re_regexp_pattern, file, "$");
- newXS("Tie::Hash::NamedCapture::FETCH", XS_Tie_Hash_NamedCapture_FETCH, file);
- newXS("Tie::Hash::NamedCapture::STORE", XS_Tie_Hash_NamedCapture_STORE, file);
- newXS("Tie::Hash::NamedCapture::DELETE", XS_Tie_Hash_NamedCapture_DELETE, file);
- newXS("Tie::Hash::NamedCapture::CLEAR", XS_Tie_Hash_NamedCapture_CLEAR, file);
- newXS("Tie::Hash::NamedCapture::EXISTS", XS_Tie_Hash_NamedCapture_EXISTS, file);
- newXS("Tie::Hash::NamedCapture::FIRSTKEY", XS_Tie_Hash_NamedCapture_FIRSTK, file);
- newXS("Tie::Hash::NamedCapture::NEXTKEY", XS_Tie_Hash_NamedCapture_NEXTK, file);
- newXS("Tie::Hash::NamedCapture::SCALAR", XS_Tie_Hash_NamedCapture_SCALAR, file);
- newXS("Tie::Hash::NamedCapture::flags", XS_Tie_Hash_NamedCapture_flags, file);
}
-
XS(XS_UNIVERSAL_isa)
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items != 2)
- Perl_croak(aTHX_ "Usage: UNIVERSAL::isa(reference, kind)");
+ croak_xs_usage(cv, "reference, kind");
else {
SV * const sv = ST(0);
const char *name;
const char *name;
SV *rv;
HV *pkg = NULL;
- PERL_UNUSED_ARG(cv);
if (items != 2)
- Perl_croak(aTHX_ "Usage: UNIVERSAL::can(object-ref, method)");
+ croak_xs_usage(cv, "object-ref, method");
sv = ST(0);
rv = &PL_sv_undef;
if (SvROK(sv)) {
- sv = (SV*)SvRV(sv);
+ sv = MUTABLE_SV(SvRV(sv));
if (SvOBJECT(sv))
pkg = SvSTASH(sv);
}
if (pkg) {
GV * const gv = gv_fetchmethod_autoload(pkg, name, FALSE);
if (gv && isGV(gv))
- rv = sv_2mortal(newRV((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: invocand->DOES(kind)");
else {
SV * const sv = ST(0);
const char *name;
PERL_UNUSED_ARG(cv);
if (SvROK(ST(0))) {
- sv = (SV*)SvRV(ST(0));
+ sv = MUTABLE_SV(SvRV(ST(0)));
if (!SvOBJECT(sv))
Perl_croak(aTHX_ "Cannot find version of an unblessed reference");
pkg = SvSTASH(sv);
undef = NULL;
}
else {
- sv = (SV*)&PL_sv_undef;
+ sv = &PL_sv_undef;
undef = "(undef)";
}
}
if ( vcmp( req, sv ) > 0 ) {
- if ( hv_exists((HV*)SvRV(req), "qv", 2 ) ) {
+ 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)));
+ 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)));
+ 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;
}
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items > 3)
- Perl_croak(aTHX_ "Usage: version::new(class, version)");
+ croak_xs_usage(cv, "class, version");
SP -= items;
{
SV *vs = ST(1);
? HvNAME(SvSTASH(SvRV(ST(0))))
: (char *)SvPV_nolen(ST(0));
- if ( items == 1 || vs == &PL_sv_undef ) { /* no param or explicit undef */
+ if ( items == 1 || ! SvOK(vs) ) { /* no param or explicit undef */
/* create empty object */
vs = sv_newmortal();
- sv_setpvn(vs,"",0);
+ sv_setpvs(vs, "0");
}
else if ( items == 3 ) {
vs = sv_newmortal();
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items < 1)
- Perl_croak(aTHX_ "Usage: version::stringify(lobj, ...)");
+ 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_derived_from(lobj, "version") && SvROK(lobj)) {
+ lobj = SvRV(lobj);
}
else
Perl_croak(aTHX_ "lobj is not of type version");
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items < 1)
- Perl_croak(aTHX_ "Usage: version::numify(lobj, ...)");
+ 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_derived_from(lobj, "version") && SvROK(lobj)) {
+ lobj = SvRV(lobj);
}
else
Perl_croak(aTHX_ "lobj is not of type version");
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items < 1)
- Perl_croak(aTHX_ "Usage: version::normal(lobj, ...)");
+ 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_derived_from(lobj, "version") && SvROK(lobj)) {
+ lobj = SvRV(lobj);
}
else
Perl_croak(aTHX_ "lobj is not of type version");
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items < 1)
- Perl_croak(aTHX_ "Usage: version::vcmp(lobj, ...)");
+ 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_derived_from(lobj, "version") && SvROK(lobj)) {
+ lobj = SvRV(lobj);
}
else
Perl_croak(aTHX_ "lobj is not of type version");
if ( ! sv_derived_from(robj, "version") )
{
- robj = new_version(robj);
+ robj = new_version(SvOK(robj) ? robj : newSVpvs_flags("0", SVs_TEMP));
+ sv_2mortal(robj);
}
rvs = SvRV(robj);
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items < 1)
- Perl_croak(aTHX_ "Usage: version::boolean(lobj, ...)");
+ croak_xs_usage(cv, "lobj, ...");
SP -= items;
- if (sv_derived_from(ST(0), "version")) {
+ 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);
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items < 1)
- Perl_croak(aTHX_ "Usage: version::noop(lobj, ...)");
- if (sv_derived_from(ST(0), "version"))
+ 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");
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items != 1)
- Perl_croak(aTHX_ "Usage: version::is_alpha(lobj)");
+ croak_xs_usage(cv, "lobj");
SP -= items;
- if (sv_derived_from(ST(0), "version")) {
+ if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) {
SV * const lobj = ST(0);
- if ( hv_exists((HV*)SvRV(lobj), "alpha", 5 ) )
+ if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "alpha", 5 ) )
XSRETURN_YES;
else
XSRETURN_NO;
dVAR;
dXSARGS;
PERL_UNUSED_ARG(cv);
- if (items != 1)
- Perl_croak(aTHX_ "Usage: version::qv(ver)");
SP -= items;
{
- SV * ver = ST(0);
- if ( !SvVOK(ver) ) { /* only need to do with if not already v-string */
- SV * const rv = sv_newmortal();
+ 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));
+ }
+ if ( !SvVOK(ver) ) { /* not already a v-string */
+ rv = sv_newmortal();
sv_setsv(rv,ver); /* make a duplicate */
upg_version(rv, TRUE);
- PUSHs(rv);
+ } else {
+ rv = sv_2mortal(new_version(ver));
}
- else
- {
- mPUSHs(new_version(ver));
+ if ( items == 2 && strcmp(classname,"version") ) { /* inherited new() */
+ sv_bless(rv, gv_stashpv(classname, GV_ADD));
}
+ 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)
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items != 1)
- Perl_croak(aTHX_ "Usage: utf8::is_utf8(sv)");
+ croak_xs_usage(cv, "sv");
else {
- const SV * const sv = ST(0);
+ SV * const sv = ST(0);
+ SvGETMAGIC(sv);
if (SvUTF8(sv))
XSRETURN_YES;
else
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items != 1)
- Perl_croak(aTHX_ "Usage: utf8::valid(sv)");
+ croak_xs_usage(cv, "sv");
else {
SV * const sv = ST(0);
STRLEN len;
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items != 1)
- Perl_croak(aTHX_ "Usage: utf8::encode(sv)");
+ croak_xs_usage(cv, "sv");
sv_utf8_encode(ST(0));
XSRETURN_EMPTY;
}
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items != 1)
- Perl_croak(aTHX_ "Usage: utf8::decode(sv)");
+ croak_xs_usage(cv, "sv");
else {
SV * const sv = ST(0);
const bool RETVAL = sv_utf8_decode(sv);
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items != 1)
- Perl_croak(aTHX_ "Usage: utf8::upgrade(sv)");
+ croak_xs_usage(cv, "sv");
else {
SV * const sv = ST(0);
STRLEN RETVAL;
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items < 1 || items > 2)
- Perl_croak(aTHX_ "Usage: utf8::downgrade(sv, failok=0)");
+ croak_xs_usage(cv, "sv, failok=0");
else {
SV * const sv = ST(0);
const bool failok = (items < 2) ? 0 : (int)SvIV(ST(1));
dVAR;
dXSARGS;
const UV uv = SvUV(ST(0));
- PERL_UNUSED_ARG(cv);
if (items > 1)
- Perl_croak(aTHX_ "Usage: utf8::native_to_unicode(sv)");
+ croak_xs_usage(cv, "sv");
ST(0) = sv_2mortal(newSViv(NATIVE_TO_UNI(uv)));
XSRETURN(1);
dVAR;
dXSARGS;
const UV uv = SvUV(ST(0));
- PERL_UNUSED_ARG(cv);
if (items > 1)
- Perl_croak(aTHX_ "Usage: utf8::unicode_to_native(sv)");
+ croak_xs_usage(cv, "sv");
ST(0) = sv_2mortal(newSViv(UNI_TO_NATIVE(uv)));
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))
XSRETURN_YES;
{
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[, REFCOUNT]");
+
+ sv = SvRV(svz);
+
if (items == 1)
XSRETURN_IV(SvREFCNT(sv) - 1); /* Minus the ref created for us. */
else if (items == 2) {
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
- if (items != 1)
- Perl_croak(aTHX_ "Usage: UNIVERSAL::hv_clear_placeholders(hv)");
+ if (items != 1 || !SvROK(ST(0)))
+ croak_xs_usage(cv, "hv");
else {
- HV * const hv = (HV *) SvRV(ST(0));
+ HV * const hv = MUTABLE_HV(SvRV(ST(0)));
hv_clear_placeholders(hv);
XSRETURN(0);
}
}
-XS(XS_Regexp_DESTROY)
-{
- PERL_UNUSED_CONTEXT;
- PERL_UNUSED_ARG(cv);
-}
-
XS(XS_PerlIO_get_layers)
{
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items < 1 || items % 2 == 0)
- Perl_croak(aTHX_ "Usage: PerlIO_get_layers(filehandle[,args])");
+ croak_xs_usage(cv, "filehandle[,args]");
#ifdef USE_PERLIO
{
SV * sv;
}
sv = POPs;
- gv = (GV*)sv;
+ gv = MUTABLE_GV(sv);
if (!isGV(sv)) {
if (SvROK(sv) && isGV(SvRV(sv)))
- gv = (GV*)SvRV(sv);
+ gv = MUTABLE_GV(SvRV(sv));
else if (SvPOKp(sv))
gv = gv_fetchsv(sv, 0, SVt_PVIO);
}
const bool flgok = flgsvp && *flgsvp && SvIOK(*flgsvp);
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
- ? sv_2mortal(newSVpvn(SvPVX_const(*namsvp), SvCUR(*namsvp)))
+ ? sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp))
: &PL_sv_undef);
XPUSHs(argok
- ? sv_2mortal(newSVpvn(SvPVX_const(*argsvp), SvCUR(*argsvp)))
+ ? newSVpvn_flags(SvPVX_const(*argsvp),
+ SvCUR(*argsvp),
+ (SvUTF8(*argsvp) ? SVf_UTF8 : 0)
+ | SVs_TEMP)
+ : &PL_sv_undef);
+ XPUSHs(flgok
+ ? sv_2mortal(SvREFCNT_inc_simple_NN(*flgsvp))
: &PL_sv_undef);
- if (flgok)
- mXPUSHi(SvIVX(*flgsvp));
- else
- XPUSHs(&PL_sv_undef);
nitem += 3;
}
else {
SVfARG(*namsvp),
SVfARG(*argsvp))));
else if (namok)
- XPUSHs(sv_2mortal(Perl_newSVpvf(aTHX_ "%"SVf,
- SVfARG(*namsvp))));
+ XPUSHs(sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp)));
else
XPUSHs(&PL_sv_undef);
nitem++;
dXSARGS;
PERL_UNUSED_ARG(cv);
if (SvROK(ST(0))) {
- const HV * const hv = (HV *) SvRV(ST(0));
+ const HV * const hv = (const HV *) SvRV(ST(0));
if (items == 1 && SvTYPE(hv) == SVt_PVHV) {
if (HvREHASH(hv))
XSRETURN_YES;
PERL_UNUSED_VAR(cv);
if (items != 1)
- Perl_croak(aTHX_ "Usage: %s(%s)", "re::is_regexp", "sv");
-
- SP -= items;
+ croak_xs_usage(cv, "sv");
if (SvRXOK(ST(0))) {
XSRETURN_YES;
SV * ret;
dVAR;
dXSARGS;
- PERL_UNUSED_ARG(cv);
if (items != 0)
- Perl_croak(aTHX_ "Usage: %s(%s)", "re::regnames_count", "");
+ croak_xs_usage(cv, "");
SP -= items;
+ PUTBACK;
if (!rx)
XSRETURN_UNDEF;
ret = CALLREG_NAMED_BUFF_COUNT(rx);
SPAGAIN;
-
- if (ret) {
- XPUSHs(ret);
- PUTBACK;
- return;
- } else {
- XSRETURN_UNDEF;
- }
+ PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
+ XSRETURN(1);
}
XS(XS_re_regname)
REGEXP * rx;
U32 flags;
SV * ret;
- PERL_UNUSED_ARG(cv);
if (items < 1 || items > 2)
- Perl_croak(aTHX_ "Usage: %s(%s)", "re::regname", "name[, all ]");
+ 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) {
- if (SvROK(ret))
- XPUSHs(ret);
- else
- XPUSHs(SvREFCNT_inc(ret));
- XSRETURN(1);
- }
- XSRETURN_UNDEF;
+ SPAGAIN;
+ PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
+ XSRETURN(1);
}
I32 length;
I32 i;
SV **entry;
- PERL_UNUSED_ARG(cv);
if (items > 1)
- Perl_croak(aTHX_ "Usage: %s(%s)", "re::regnames", "[all]");
+ croak_xs_usage(cv, "[all]");
rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
}
SP -= items;
+ PUTBACK;
ret = CALLREG_NAMED_BUFF_ALL(rx, (flags | RXapif_REGNAMES));
SPAGAIN;
- SP -= items;
-
if (!ret)
XSRETURN_UNDEF;
- av = (AV*)SvRV(ret);
+ av = MUTABLE_AV(SvRV(ret));
length = av_len(av);
for (i = 0; i <= length; i++) {
if (!entry)
Perl_croak(aTHX_ "NULL array element in re::regnames()");
- XPUSHs(*entry);
+ mXPUSHs(SvREFCNT_inc_simple_NN(*entry));
}
+
+ SvREFCNT_dec(ret);
+
PUTBACK;
return;
}
dVAR;
dXSARGS;
REGEXP *re;
- PERL_UNUSED_ARG(cv);
if (items != 1)
- Perl_croak(aTHX_ "Usage: %s(%s)", "re::regexp_pattern", "sv");
+ croak_xs_usage(cv, "sv");
SP -= items;
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.
*/
if ((re = SvRX(ST(0)))) /* assign deliberate */
{
- /* Housten, we have a regex! */
+ /* 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++)) {
match_flags >>= 1;
}
- pattern = sv_2mortal(newSVpvn(RX_PRECOMP(re),RX_PRELEN(re)));
- if (RX_UTF8(re))
- SvUTF8_on(pattern);
+ pattern = newSVpvn_flags(RX_PRECOMP(re),RX_PRELEN(re),
+ (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP);
/* return the pattern and the modifiers */
XPUSHs(pattern);
- XPUSHs(sv_2mortal(newSVpvn(reflags,left)));
+ XPUSHs(newSVpvn_flags(reflags, left, SVs_TEMP));
XSRETURN(2);
} else {
/* Scalar, so use the string that Perl would return */
/* return the pattern in (?msix:..) format */
#if PERL_VERSION >= 11
- pattern = sv_2mortal(newSVsv((SV*)re));
+ pattern = sv_2mortal(newSVsv(MUTABLE_SV(re)));
#else
- pattern = sv_2mortal(newSVpvn(RX_WRAPPED(re),RX_WRAPLEN(re)));
- if (RX_UTF8(re))
- SvUTF8_on(pattern);
+ pattern = newSVpvn_flags(RX_WRAPPED(re), RX_WRAPLEN(re),
+ (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP);
#endif
XPUSHs(pattern);
XSRETURN(1);
/* NOT-REACHED */
}
-XS(XS_Tie_Hash_NamedCapture_FETCH)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- SV * ret;
- PERL_UNUSED_ARG(cv);
-
- if (items != 2)
- Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::STORE($key, $flags)");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx)
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
- ret = CALLREG_NAMED_BUFF_FETCH(rx, ST(1), flags);
-
- SPAGAIN;
-
- if (ret) {
- if (SvROK(ret))
- XPUSHs(ret);
- else
- XPUSHs(SvREFCNT_inc(ret));
- PUTBACK;
- return;
- }
- XSRETURN_UNDEF;
-}
-
-XS(XS_Tie_Hash_NamedCapture_STORE)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- PERL_UNUSED_ARG(cv);
-
- if (items != 3)
- Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::STORE($key, $value, $flags)");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx) {
- if (!PL_localizing)
- Perl_croak(aTHX_ PL_no_modify);
- else
- XSRETURN_UNDEF;
- }
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV((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;
- PERL_UNUSED_ARG(cv);
-
- if (items != 2)
- Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::DELETE($key, $flags)");
-
- if (!rx)
- Perl_croak(aTHX_ PL_no_modify);
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
- CALLREG_NAMED_BUFF_DELETE(rx, ST(1), flags);
-}
-
-XS(XS_Tie_Hash_NamedCapture_CLEAR)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- PERL_UNUSED_ARG(cv);
-
- if (items != 1)
- Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::CLEAR($flags)");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx)
- Perl_croak(aTHX_ PL_no_modify);
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
- CALLREG_NAMED_BUFF_CLEAR(rx, flags);
-}
-
-XS(XS_Tie_Hash_NamedCapture_EXISTS)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- SV * ret;
- PERL_UNUSED_ARG(cv);
-
- if (items != 2)
- Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::EXISTS($key, $flags)");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx)
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV((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;
- PERL_UNUSED_ARG(cv);
-
- if (items != 1)
- Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::FIRSTKEY()");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx)
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
- ret = CALLREG_NAMED_BUFF_FIRSTKEY(rx, flags);
-
- SPAGAIN;
-
- if (ret) {
- XPUSHs(SvREFCNT_inc(ret));
- PUTBACK;
- } else {
- XSRETURN_UNDEF;
- }
-
-}
-
-XS(XS_Tie_Hash_NamedCapture_NEXTK)
-{
- dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- SV * ret;
- PERL_UNUSED_ARG(cv);
-
- if (items != 2)
- Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::NEXTKEY($lastkey)");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx)
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
- ret = CALLREG_NAMED_BUFF_NEXTKEY(rx, ST(1), flags);
-
- SPAGAIN;
-
- if (ret) {
- XPUSHs(ret);
- } else {
- XSRETURN_UNDEF;
- }
- PUTBACK;
-}
+struct xsub_details {
+ const char *name;
+ XSUBADDR_t xsub;
+ const char *proto;
+};
+
+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},
+ {"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, "\\%"},
+ {"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, "$"},
+};
-XS(XS_Tie_Hash_NamedCapture_SCALAR)
+void
+Perl_boot_core_UNIVERSAL(pTHX)
{
dVAR;
- dXSARGS;
- REGEXP * rx;
- U32 flags;
- SV * ret;
- PERL_UNUSED_ARG(cv);
-
- if (items != 1)
- Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::SCALAR()");
-
- rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
-
- if (!rx)
- XSRETURN_UNDEF;
-
- SP -= items;
-
- flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
- ret = CALLREG_NAMED_BUFF_SCALAR(rx, flags);
-
- SPAGAIN;
-
- if (ret) {
- XPUSHs(ret);
- PUTBACK;
- return;
- } else {
- XSRETURN_UNDEF;
- }
-}
+ static const char file[] = __FILE__;
+ struct xsub_details *xsub = details;
+ const struct xsub_details *end
+ = details + sizeof(details) / sizeof(details[0]);
-XS(XS_Tie_Hash_NamedCapture_flags)
-{
- dVAR;
- dXSARGS;
- PERL_UNUSED_ARG(cv);
+ do {
+ newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0);
+ } while (++xsub < end);
- if (items != 0)
- Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::flags()");
+ /* register the overloading (type 'A') magic */
+ PL_amagic_generation++;
- mXPUSHu(RXapif_ONE);
- mXPUSHu(RXapif_ALL);
- PUTBACK;
- return;
+ /* Providing a Regexp::DESTROY fixes #21347. See test in t/op/ref.t */
+ CvFILE(newCONSTSUB(get_hv("Regexp::", GV_ADD), "DESTROY", NULL))
+ = (char *)file;
}
-
/*
* Local variables:
* c-indentation-style: bsd