This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
run/locale.t: Add explanation for when tests fail
[perl5.git] / universal.c
index b217c14..65e02df 100644 (file)
@@ -29,7 +29,7 @@
 #define PERL_IN_UNIVERSAL_C
 #include "perl.h"
 
-#ifdef USE_PERLIO
+#if defined(USE_PERLIO)
 #include "perliol.h" /* For the PERLIO_F_XXX */
 #endif
 
@@ -67,7 +67,7 @@ S_isa_lookup(pTHX_ HV *stash, const char * const name, STRLEN len, U32 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))) {
@@ -294,7 +294,7 @@ 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:
+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");
 
@@ -328,6 +328,7 @@ Perl_croak_xs_usage(const CV *const cv, const char *const params)
     }
 }
 
+XS(XS_UNIVERSAL_isa); /* prototype to pass -Wmissing-prototypes */
 XS(XS_UNIVERSAL_isa)
 {
     dVAR;
@@ -348,6 +349,7 @@ XS(XS_UNIVERSAL_isa)
     }
 }
 
+XS(XS_UNIVERSAL_can); /* prototype to pass -Wmissing-prototypes */
 XS(XS_UNIVERSAL_can)
 {
     dVAR;
@@ -399,6 +401,7 @@ XS(XS_UNIVERSAL_can)
     XSRETURN(1);
 }
 
+XS(XS_UNIVERSAL_DOES); /* prototype to pass -Wmissing-prototypes */
 XS(XS_UNIVERSAL_DOES)
 {
     dVAR;
@@ -416,382 +419,7 @@ XS(XS_UNIVERSAL_DOES)
     }
 }
 
-XS(XS_UNIVERSAL_VERSION)
-{
-    dVAR;
-    dXSARGS;
-    HV *pkg;
-    GV **gvp;
-    GV *gv;
-    SV *sv;
-    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)) {
-        SV * const nsv = sv_newmortal();
-        sv_setsv(nsv, sv);
-        sv = nsv;
-       if ( !sv_isobject(sv) || !sv_derived_from(sv, "version"))
-           upg_version(sv, FALSE);
-
-        undef = NULL;
-    }
-    else {
-        sv = &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_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_ "%"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))));
-           }
-       }
-
-    }
-
-    if ( SvOK(sv) && sv_derived_from(sv, "version") ) {
-       ST(0) = sv_2mortal(vstringify(sv));
-    } else {
-       ST(0) = sv;
-    }
-
-    XSRETURN(1);
-}
-
-XS(XS_version_new)
-{
-    dVAR;
-    dXSARGS;
-    if (items > 3 || items < 1)
-       croak_xs_usage(cv, "class, version");
-    SP -= items;
-    {
-        SV *vs = ST(1);
-       SV *rv;
-        STRLEN len;
-        const char *classname;
-        U32 flags;
-
-       /* Just in case this is something like a tied hash */
-       SvGETMAGIC(vs);
-
-        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_isobject(lobj) && sv_derived_from(lobj, "version")) {
-              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_isobject(lobj) && sv_derived_from(lobj, "version")) {
-              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_isobject(lobj) && sv_derived_from(lobj, "version")) {
-              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_isobject(lobj) && sv_derived_from(lobj, "version")) {
-              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_isobject(robj) || !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_isobject(ST(0)) && sv_derived_from(ST(0), "version")) {
-       SV * const lobj = SvRV(ST(0));
-       SV * const rs =
-           newSViv( vcmp(lobj,
-                         sv_2mortal(new_version(
-                                       sv_2mortal(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_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");
-#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_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;
-       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 ) {
-           SvGETMAGIC(ST(1));
-           if (SvOK(ST(1))) {
-               ver = ST(1);
-           }
-           else {
-               Perl_croak(aTHX_ "Invalid version format (version required)");
-           }
-            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_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;
-       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;
@@ -809,6 +437,7 @@ XS(XS_utf8_is_utf8)
      XSRETURN_EMPTY;
 }
 
+XS(XS_utf8_valid); /* prototype to pass -Wmissing-prototypes */
 XS(XS_utf8_valid)
 {
      dVAR;
@@ -827,6 +456,7 @@ XS(XS_utf8_valid)
      XSRETURN_EMPTY;
 }
 
+XS(XS_utf8_encode); /* prototype to pass -Wmissing-prototypes */
 XS(XS_utf8_encode)
 {
     dVAR;
@@ -838,6 +468,7 @@ XS(XS_utf8_encode)
     XSRETURN_EMPTY;
 }
 
+XS(XS_utf8_decode); /* prototype to pass -Wmissing-prototypes */
 XS(XS_utf8_decode)
 {
     dVAR;
@@ -855,6 +486,7 @@ XS(XS_utf8_decode)
     XSRETURN(1);
 }
 
+XS(XS_utf8_upgrade); /* prototype to pass -Wmissing-prototypes */
 XS(XS_utf8_upgrade)
 {
     dVAR;
@@ -872,6 +504,7 @@ XS(XS_utf8_upgrade)
     XSRETURN(1);
 }
 
+XS(XS_utf8_downgrade); /* prototype to pass -Wmissing-prototypes */
 XS(XS_utf8_downgrade)
 {
     dVAR;
@@ -888,6 +521,7 @@ XS(XS_utf8_downgrade)
     XSRETURN(1);
 }
 
+XS(XS_utf8_native_to_unicode); /* prototype to pass -Wmissing-prototypes */
 XS(XS_utf8_native_to_unicode)
 {
  dVAR;
@@ -901,6 +535,7 @@ XS(XS_utf8_native_to_unicode)
  XSRETURN(1);
 }
 
+XS(XS_utf8_unicode_to_native); /* prototype to pass -Wmissing-prototypes */
 XS(XS_utf8_unicode_to_native)
 {
  dVAR;
@@ -914,6 +549,7 @@ XS(XS_utf8_unicode_to_native)
  XSRETURN(1);
 }
 
+XS(XS_Internals_SvREADONLY); /* prototype to pass -Wmissing-prototypes */
 XS(XS_Internals_SvREADONLY)    /* This is dangerous stuff. */
 {
     dVAR;
@@ -951,6 +587,7 @@ XS(XS_Internals_SvREADONLY) /* This is dangerous stuff. */
     XSRETURN_UNDEF; /* Can't happen. */
 }
 
+XS(XS_constant__make_const); /* prototype to pass -Wmissing-prototypes */
 XS(XS_constant__make_const)    /* This is dangerous stuff. */
 {
     dVAR;
@@ -981,6 +618,7 @@ XS(XS_constant__make_const) /* This is dangerous stuff. */
     XSRETURN(0);
 }
 
+XS(XS_Internals_SvREFCNT); /* prototype to pass -Wmissing-prototypes */
 XS(XS_Internals_SvREFCNT)      /* This is dangerous stuff. */
 {
     dVAR;
@@ -1006,6 +644,7 @@ XS(XS_Internals_SvREFCNT)  /* This is dangerous stuff. */
 
 }
 
+XS(XS_Internals_hv_clear_placehold); /* prototype to pass -Wmissing-prototypes */
 XS(XS_Internals_hv_clear_placehold)
 {
     dVAR;
@@ -1020,13 +659,14 @@ XS(XS_Internals_hv_clear_placehold)
     }
 }
 
+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;
@@ -1082,7 +722,7 @@ XS(XS_PerlIO_get_layers)
             AV* const av = PerlIO_get_layers(aTHX_ input ?
                                        IoIFP(io) : IoOFP(io));
             SSize_t i;
-            const SSize_t last = av_len(av);
+            const SSize_t last = av_tindex(av);
             SSize_t nitem = 0;
             
             for (i = last; i >= 0; i -= 3) {
@@ -1146,6 +786,7 @@ XS(XS_PerlIO_get_layers)
 }
 
 
+XS(XS_re_is_regexp); /* prototype to pass -Wmissing-prototypes */
 XS(XS_re_is_regexp)
 {
     dVAR; 
@@ -1162,6 +803,7 @@ XS(XS_re_is_regexp)
     }
 }
 
+XS(XS_re_regnames_count); /* prototype to pass -Wmissing-prototypes */
 XS(XS_re_regnames_count)
 {
     REGEXP *rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
@@ -1185,6 +827,7 @@ XS(XS_re_regnames_count)
     XSRETURN(1);
 }
 
+XS(XS_re_regname); /* prototype to pass -Wmissing-prototypes */
 XS(XS_re_regname)
 {
     dVAR;
@@ -1217,6 +860,7 @@ XS(XS_re_regname)
 }
 
 
+XS(XS_re_regnames); /* prototype to pass -Wmissing-prototypes */
 XS(XS_re_regnames)
 {
     dVAR;
@@ -1254,7 +898,7 @@ XS(XS_re_regnames)
         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++) {
@@ -1272,6 +916,7 @@ XS(XS_re_regnames)
     return;
 }
 
+XS(XS_re_regexp_pattern); /* prototype to pass -Wmissing-prototypes */
 XS(XS_re_regexp_pattern)
 {
     dVAR;
@@ -1372,6 +1017,9 @@ XS(XS_re_regexp_pattern)
     /* NOT-REACHED */
 }
 
+#include "vutil.h"
+#include "vxs.inc"
+
 struct xsub_details {
     const char *name;
     XSUBADDR_t xsub;
@@ -1382,35 +1030,9 @@ 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::(+", 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},
-    {"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},
@@ -1437,8 +1059,7 @@ Perl_boot_core_UNIVERSAL(pTHX)
     dVAR;
     static const char file[] = __FILE__;
     const struct xsub_details *xsub = details;
-    const struct xsub_details *end
-       = details + sizeof(details) / sizeof(details[0]);
+    const struct xsub_details *end = C_ARRAY_END(details);
 
     do {
        newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0);