This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
In lib/File/stat.t, test everything with and without use filetest "access".
[perl5.git] / universal.c
index 855942e..384d307 100644 (file)
@@ -154,7 +154,7 @@ Perl_sv_derived_from_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len,
 
     SvGETMAGIC(sv);
 
-    if (SvROK(sv)) { /* hugdo: */
+    if (SvROK(sv)) {
        const char *type;
         sv = SvRV(sv);
         type = sv_reftype(sv,0);
@@ -252,8 +252,7 @@ Perl_sv_does(pTHX_ SV *sv, const char *const name)
 /*
 =for apidoc sv_does_pv
 
-Like L</sv_does_pvn>, but takes a nul-terminated string 
-instead of a string/length pair.
+Like L</sv_does_sv>, but takes a nul-terminated string instead of an SV.
 
 =cut
 */
@@ -266,6 +265,14 @@ Perl_sv_does_pv(pTHX_ SV *sv, const char *const name, U32 flags)
     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)
 {
@@ -284,7 +291,7 @@ 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
 */
@@ -297,14 +304,16 @@ Perl_croak_xs_usage(pTHX_ const CV *const cv, const char *const params)
     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(aTHX_ "Usage: %"HEKf"::%"HEKf"(%s)",
+                                HEKfARG(HvNAME_HEK(stash)),
+                                HEKfARG(GvNAME_HEK(gv)),
+                                params);
        else
-           Perl_croak(aTHX_ "Usage: %s(%s)", gvname, params);
+           Perl_croak(aTHX_ "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);
@@ -347,8 +356,8 @@ XS(XS_UNIVERSAL_can)
 
     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))
+       || (SvGMAGICAL(sv) && (SvNIOKp(sv) || (SvPOKp(sv) && SvCUR(sv))))))
        XSRETURN_UNDEF;
 
     rv = &PL_sv_undef;
@@ -397,7 +406,6 @@ XS(XS_UNIVERSAL_VERSION)
     GV **gvp;
     GV *gv;
     SV *sv;
-    SV *ret;
     const char *undef;
     PERL_UNUSED_ARG(cv);
 
@@ -414,12 +422,16 @@ XS(XS_UNIVERSAL_VERSION)
     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);
+        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 = ret = &PL_sv_undef;
+        sv = &PL_sv_undef;
         undef = "(undef)";
     }
 
@@ -428,34 +440,34 @@ XS(XS_UNIVERSAL_VERSION)
 
        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(sv, "version"))
-           upg_version(sv, FALSE);
-
-       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),
+               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),
+               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))));
            }
@@ -463,7 +475,11 @@ XS(XS_UNIVERSAL_VERSION)
 
     }
 
-    ST(0) = ret;
+    if ( SvOK(sv) && sv_derived_from(sv, "version") ) {
+       ST(0) = sv_2mortal(vstringify(sv));
+    } else {
+       ST(0) = sv;
+    }
 
     XSRETURN(1);
 }
@@ -478,10 +494,19 @@ XS(XS_version_new)
     {
         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 */
@@ -494,8 +519,8 @@ XS(XS_version_new)
        }
 
        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;
@@ -513,7 +538,7 @@ XS(XS_version_stringify)
      {
          SV *  lobj = ST(0);
 
-         if (sv_derived_from(lobj, "version") && SvROK(lobj)) {
+         if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) {
               lobj = SvRV(lobj);
          }
          else
@@ -536,7 +561,7 @@ XS(XS_version_numify)
      {
          SV *  lobj = ST(0);
 
-         if (sv_derived_from(lobj, "version") && SvROK(lobj)) {
+         if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) {
               lobj = SvRV(lobj);
          }
          else
@@ -559,7 +584,7 @@ XS(XS_version_normal)
      {
          SV *  lobj = ST(0);
 
-         if (sv_derived_from(lobj, "version") && SvROK(lobj)) {
+         if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) {
               lobj = SvRV(lobj);
          }
          else
@@ -582,7 +607,7 @@ XS(XS_version_vcmp)
      {
          SV *  lobj = ST(0);
 
-         if (sv_derived_from(lobj, "version") && SvROK(lobj)) {
+         if (sv_isobject(lobj) && sv_derived_from(lobj, "version")) {
               lobj = SvRV(lobj);
          }
          else
@@ -594,7 +619,7 @@ XS(XS_version_vcmp)
               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_flags("0", SVs_TEMP));
                    sv_2mortal(robj);
@@ -625,9 +650,15 @@ XS(XS_version_boolean)
     if (items < 1)
        croak_xs_usage(cv, "lobj, ...");
     SP -= items;
-    if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) {
+    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;
@@ -642,7 +673,7 @@ XS(XS_version_noop)
     dXSARGS;
     if (items < 1)
        croak_xs_usage(cv, "lobj, ...");
-    if (sv_derived_from(ST(0), "version") && SvROK(ST(0)))
+    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");
@@ -658,7 +689,7 @@ XS(XS_version_is_alpha)
     if (items != 1)
        croak_xs_usage(cv, "lobj");
     SP -= items;
-    if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) {
+    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;
@@ -680,15 +711,22 @@ XS(XS_version_qv)
     {
        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 */
@@ -696,9 +734,10 @@ XS(XS_version_qv)
        } 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;
@@ -712,7 +751,7 @@ XS(XS_version_is_qv)
     if (items != 1)
        croak_xs_usage(cv, "lobj");
     SP -= items;
-    if (sv_derived_from(ST(0), "version") && SvROK(ST(0))) {
+    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;
@@ -779,7 +818,7 @@ XS(XS_utf8_decode)
     else {
        SV * const sv = ST(0);
        bool RETVAL;
-       if (SvIsCOW(sv)) sv_force_normal(sv);
+       SvPV_force_nolen(sv);
        RETVAL = sv_utf8_decode(sv);
        ST(0) = boolSV(RETVAL);
     }
@@ -895,11 +934,11 @@ XS(XS_Internals_SvREFCNT) /* This is dangerous stuff. */
     sv = SvRV(svz);
 
     if (items == 1)
-        XSRETURN_IV(SvREFCNT(sv) - 1); /* Minus the ref created for us. */
+        XSRETURN_UV(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));
+        SvREFCNT(sv) = SvUV(ST(1)) + 1; /* we free one ref on exit */
+        XSRETURN_UV(SvREFCNT(sv) - 1);
     }
     XSRETURN_UNDEF; /* Can't happen. */
 }
@@ -971,14 +1010,10 @@ XS(XS_PerlIO_get_layers)
        }
 
        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 ?
@@ -1334,6 +1369,15 @@ struct xsub_details details[] = {
     {"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},
@@ -1375,9 +1419,6 @@ Perl_boot_core_UNIVERSAL(pTHX)
        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  */
     {
        CV * const cv =
@@ -1392,8 +1433,8 @@ Perl_boot_core_UNIVERSAL(pTHX)
  * 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:
  */