#17171: ld flag for shrplib on OpenBSD
[p5sagit/p5-mst-13.2.git] / universal.c
index b92bd7a..533d843 100644 (file)
@@ -160,6 +160,12 @@ Perl_sv_derived_from(pTHX_ SV *sv, const char *name)
 void XS_UNIVERSAL_isa(pTHX_ CV *cv);
 void XS_UNIVERSAL_can(pTHX_ CV *cv);
 void XS_UNIVERSAL_VERSION(pTHX_ CV *cv);
+XS(XS_version_new);
+XS(XS_version_stringify);
+XS(XS_version_numify);
+XS(XS_version_vcmp);
+XS(XS_version_boolean);
+XS(XS_version_noop);
 XS(XS_utf8_valid);
 XS(XS_utf8_encode);
 XS(XS_utf8_decode);
@@ -179,6 +185,24 @@ Perl_boot_core_UNIVERSAL(pTHX)
     newXS("UNIVERSAL::isa",             XS_UNIVERSAL_isa,         file);
     newXS("UNIVERSAL::can",             XS_UNIVERSAL_can,         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::(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("utf8::valid", XS_utf8_valid, file);
     newXS("utf8::encode", XS_utf8_encode, file);
     newXS("utf8::decode", XS_utf8_decode, file);
@@ -307,53 +331,186 @@ XS(XS_UNIVERSAL_VERSION)
                             "%s defines neither package nor VERSION--version check failed", str);
             }
        }
-       if (!SvNIOK(sv) && SvPOK(sv)) {
-           char *str = SvPVx(sv,len);
-           while (len) {
-               --len;
-               /* XXX could DWIM "1.2.3" here */
-               if (!isDIGIT(str[len]) && str[len] != '.' && str[len] != '_')
-                   break;
-           }
-           if (len) {
-               if (SvNOK(req) && SvPOK(req)) {
-                   /* they said C<use Foo v1.2.3> and $Foo::VERSION
-                    * doesn't look like a float: do string compare */
-                   if (sv_cmp(req,sv) == 1) {
-                       Perl_croak(aTHX_ "%s v%"VDf" required--"
-                                  "this is only v%"VDf,
-                                  HvNAME(pkg), req, sv);
-                   }
-                   goto finish;
-               }
-               /* they said C<use Foo 1.002_003> and $Foo::VERSION
-                * doesn't look like a float: force numeric compare */
-               (void)SvUPGRADE(sv, SVt_PVNV);
-               SvNVX(sv) = str_to_version(sv);
-               SvPOK_off(sv);
-               SvNOK_on(sv);
-           }
-       }
-       /* if we get here, we're looking for a numeric comparison,
-        * so force the required version into a float, even if they
-        * said C<use Foo v1.2.3> */
-       if (SvNOK(req) && SvPOK(req)) {
-           NV n = SvNV(req);
-           req = sv_newmortal();
-           sv_setnv(req, n);
-       }
+       if ( !sv_derived_from(sv, "version"))
+           sv = new_version(sv);
+
+       if ( !sv_derived_from(req, "version"))
+           req = new_version(req);
 
-       if (SvNV(req) > SvNV(sv))
+       if ( vcmp( SvRV(req), SvRV(sv) ) > 0 )
            Perl_croak(aTHX_ "%s version %s required--this is only version %s",
-                      HvNAME(pkg), SvPV_nolen(req), SvPV_nolen(sv));
+               HvNAME(pkg), SvPV(req,PL_na), SvPV(sv,PL_na));
     }
 
-finish:
     ST(0) = sv;
 
     XSRETURN(1);
 }
 
+XS(XS_version_new)
+{
+    dXSARGS;
+    if (items != 2)
+       Perl_croak(aTHX_ "Usage: version::new(class, version)");
+    SP -= items;
+    {
+/*     char *  class = (char *)SvPV_nolen(ST(0)); */
+       SV *    version = ST(1);
+
+{
+    PUSHs(new_version(version));
+}
+
+       PUTBACK;
+       return;
+    }
+}
+
+XS(XS_version_stringify)
+{
+    dXSARGS;
+    if (items < 1)
+       Perl_croak(aTHX_ "Usage: version::stringify(lobj, ...)");
+    SP -= items;
+    {
+       SV *    lobj;
+
+        if (sv_derived_from(ST(0), "version")) {
+                SV *tmp = SvRV(ST(0));
+               lobj = tmp;
+        }
+        else
+                Perl_croak(aTHX_ "lobj is not of type version");
+
+{
+    PUSHs(vstringify(lobj));
+}
+
+       PUTBACK;
+       return;
+    }
+}
+
+XS(XS_version_numify)
+{
+    dXSARGS;
+    if (items < 1)
+       Perl_croak(aTHX_ "Usage: version::numify(lobj, ...)");
+    SP -= items;
+    {
+       SV *    lobj;
+
+        if (sv_derived_from(ST(0), "version")) {
+                SV *tmp = SvRV(ST(0));
+               lobj = tmp;
+        }
+        else
+                Perl_croak(aTHX_ "lobj is not of type version");
+
+{
+    PUSHs(vnumify(lobj));
+}
+
+       PUTBACK;
+       return;
+    }
+}
+
+XS(XS_version_vcmp)
+{
+    dXSARGS;
+    if (items < 1)
+       Perl_croak(aTHX_ "Usage: version::vcmp(lobj, ...)");
+    SP -= items;
+    {
+       SV *    lobj;
+
+        if (sv_derived_from(ST(0), "version")) {
+                SV *tmp = SvRV(ST(0));
+               lobj = tmp;
+        }
+        else
+                Perl_croak(aTHX_ "lobj is not of type version");
+
+{
+    SV *rs;
+    SV *rvs;
+    SV * robj = ST(1);
+    IV  swap = (IV)SvIV(ST(2));
+
+    if ( ! sv_derived_from(robj, "version") )
+    {
+       robj = new_version(robj);
+    }
+    rvs = SvRV(robj);
+
+    if ( swap )
+    {
+        rs = newSViv(vcmp(rvs,lobj));
+    }
+    else
+    {
+        rs = newSViv(vcmp(lobj,rvs));
+    }
+
+    PUSHs(rs);
+}
+
+       PUTBACK;
+       return;
+    }
+}
+
+XS(XS_version_boolean)
+{
+    dXSARGS;
+    if (items < 1)
+       Perl_croak(aTHX_ "Usage: version::boolean(lobj, ...)");
+    SP -= items;
+    {
+       SV *    lobj;
+
+        if (sv_derived_from(ST(0), "version")) {
+                SV *tmp = SvRV(ST(0));
+               lobj = tmp;
+        }
+        else
+                Perl_croak(aTHX_ "lobj is not of type version");
+
+{
+    SV *rs;
+    rs = newSViv( vcmp(lobj,new_version(newSVpvn("0",1))) );
+    PUSHs(rs);
+}
+
+       PUTBACK;
+       return;
+    }
+}
+
+XS(XS_version_noop)
+{
+    dXSARGS;
+    if (items < 1)
+       Perl_croak(aTHX_ "Usage: version::noop(lobj, ...)");
+    {
+       SV *    lobj;
+
+        if (sv_derived_from(ST(0), "version")) {
+                SV *tmp = SvRV(ST(0));
+               lobj = tmp;
+        }
+        else
+                Perl_croak(aTHX_ "lobj is not of type version");
+
+{
+    Perl_croak(aTHX_ "operation not supported with version object");
+}
+
+    }
+    XSRETURN_EMPTY;
+}
+
 XS(XS_utf8_valid)
 {
     dXSARGS;