add -DPERL_Y2KWARN build option that will generate additional
[p5sagit/p5-mst-13.2.git] / sv.c
diff --git a/sv.c b/sv.c
index 9ba9f6c..b21c9ed 100644 (file)
--- a/sv.c
+++ b/sv.c
 #define PERL_IN_SV_C
 #include "perl.h"
 
-#ifdef PERL_OBJECT
-#define VTBL this->*vtbl
-#else /* !PERL_OBJECT */
-#define VTBL *vtbl
-#endif /* PERL_OBJECT */
-
 #define FCALL *f
 #define SV_CHECK_THINKFIRST(sv) if (SvTHINKFIRST(sv)) sv_force_normal(sv)
 
@@ -618,8 +612,8 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        pv      = (char*)SvRV(sv);
        cur     = 0;
        len     = 0;
-       iv      = (IV)pv;
-       nv      = (NV)(unsigned long)pv;
+       iv      = (IV)PTR_CAST pv;
+       nv      = (NV)(PTRV)pv;
        del_XRV(SvANY(sv));
        magic   = 0;
        stash   = 0;
@@ -1083,7 +1077,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
          SV* tmpstr;
          if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv, numer)))
              return SvIV(tmpstr);
-         return (IV)SvRV(sv);
+         return (IV)PTR_CAST SvRV(sv);
        }
        if (SvREADONLY(sv) && !SvOK(sv)) {
            dTHR;
@@ -1119,7 +1113,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
 #ifdef IV_IS_QUAD
            DEBUG_c(PerlIO_printf(Perl_debug_log, 
                                  "0x%" PERL_PRIx64 " 2iv(%" PERL_PRIu64 " => %" PERL_PRId64 ") (as unsigned)\n",
-                                 (UV)sv,
+                                 (UV)PTR_CAST sv,
                                  (UV)SvUVX(sv), (IV)SvUVX(sv)));
 #else
            DEBUG_c(PerlIO_printf(Perl_debug_log, 
@@ -1228,7 +1222,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
          SV* tmpstr;
          if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv, numer)))
              return SvUV(tmpstr);
-         return (UV)SvRV(sv);
+         return (UV)PTR_CAST SvRV(sv);
        }
        if (SvREADONLY(sv) && !SvOK(sv)) {
            dTHR;
@@ -1399,7 +1393,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
          SV* tmpstr;
          if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,numer)))
              return SvNV(tmpstr);
-         return (NV)(unsigned long)SvRV(sv);
+         return (NV)(PTRV)SvRV(sv);
        }
        if (SvREADONLY(sv) && !SvOK(sv)) {
            dTHR;
@@ -1783,7 +1777,7 @@ Perl_sv_2pv(pTHX_ register SV *sv, STRLEN *lp)
                else
                    sv_setpv(tsv, s);
 #ifdef IV_IS_QUAD
-               Perl_sv_catpvf(aTHX_ tsv, "(0x%" PERL_PRIx64")", (UV)sv);
+               Perl_sv_catpvf(aTHX_ tsv, "(0x%" PERL_PRIx64")", (UV)PTR_CAST sv);
 #else
                Perl_sv_catpvf(aTHX_ tsv, "(0x%lx)", (unsigned long)sv);
 #endif
@@ -1802,6 +1796,9 @@ Perl_sv_2pv(pTHX_ register SV *sv, STRLEN *lp)
     }
     if (SvNOKp(sv)) {                  /* See note in sv_2uv() */
        /* XXXX 64-bit?  IV may have better precision... */
+       /* I tried changing this for to be 64-bit-aware and
+        * the t/op/numconvert.t became very, very, angry.
+        * --jhi Sep 1999 */
        if (SvTYPE(sv) < SVt_PVNV)
            sv_upgrade(sv, SVt_PVNV);
        SvGROW(sv, 28);
@@ -2721,7 +2718,7 @@ Perl_sv_unmagic(pTHX_ SV *sv, int type)
            MGVTBL* vtbl = mg->mg_virtual;
            *mgp = mg->mg_moremagic;
            if (vtbl && (vtbl->svt_free != NULL))
-               (VTBL->svt_free)(aTHX_ sv, mg);
+               CALL_FPTR(vtbl->svt_free)(aTHX_ sv, mg);
            if (mg->mg_ptr && mg->mg_type != 'g')
                if (mg->mg_len >= 0)
                    Safefree(mg->mg_ptr);
@@ -3694,7 +3691,7 @@ Perl_sv_inc(pTHX_ register SV *sv)
            IV i;
            if (SvAMAGIC(sv) && AMG_CALLun(sv,inc))
                return;
-           i = (IV)SvRV(sv);
+           i = (IV)PTR_CAST SvRV(sv);
            sv_unref(sv);
            sv_setiv(sv, i);
        }
@@ -3794,7 +3791,7 @@ Perl_sv_dec(pTHX_ register SV *sv)
            IV i;
            if (SvAMAGIC(sv) && AMG_CALLun(sv,dec))
                return;
-           i = (IV)SvRV(sv);
+           i = (IV)PTR_CAST SvRV(sv);
            sv_unref(sv);
            sv_setiv(sv, i);
        }
@@ -4398,7 +4395,7 @@ Perl_sv_setref_pv(pTHX_ SV *rv, const char *classname, void *pv)
        SvSETMAGIC(rv);
     }
     else
-       sv_setiv(newSVrv(rv,classname), (IV)pv);
+       sv_setiv(newSVrv(rv,classname), (IV)PTR_CAST pv);
     return rv;
 }
 
@@ -4648,14 +4645,14 @@ Perl_sv_vcatpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
 }
 
 void
-Perl_sv_vsetpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *used_locale)
+Perl_sv_vsetpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *maybe_tainted)
 {
     sv_setpvn(sv, "", 0);
-    sv_vcatpvfn(sv, pat, patlen, args, svargs, svmax, used_locale);
+    sv_vcatpvfn(sv, pat, patlen, args, svargs, svmax, maybe_tainted);
 }
 
 void
-Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *used_locale)
+Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *maybe_tainted)
 {
     dTHR;
     char *p;
@@ -4901,15 +4898,15 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
        case 'p':
            if (args)
-               uv = (UV)va_arg(*args, void*);
+               uv = (UV)PTR_CAST va_arg(*args, void*);
            else
-               uv = (svix < svmax) ? (UV)svargs[svix++] : 0;
+               uv = (svix < svmax) ? (UV)PTR_CAST svargs[svix++] : 0;
            base = 16;
            goto integer;
 
        case 'D':
 #ifdef IV_IS_QUAD
-           /* nothing */
+           intsize = 'q';
 #else
            intsize = 'l';
 #endif
@@ -4919,11 +4916,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            if (args) {
                switch (intsize) {
                case 'h':       iv = (short)va_arg(*args, int); break;
-#ifdef IV_IS_QUAD
-               default:        iv = va_arg(*args, IV); break;
-#else
                default:        iv = va_arg(*args, int); break;
-#endif
                case 'l':       iv = va_arg(*args, long); break;
                case 'V':       iv = va_arg(*args, IV); break;
 #ifdef HAS_QUAD
@@ -4935,11 +4928,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                iv = (svix < svmax) ? SvIVx(svargs[svix++]) : 0;
                switch (intsize) {
                case 'h':       iv = (short)iv; break;
-#ifdef IV_IS_QUAD
-               default:        break;
-#else
                default:        iv = (int)iv; break;
-#endif
                case 'l':       iv = (long)iv; break;
                case 'V':       break;
 #ifdef HAS_QUAD
@@ -4961,7 +4950,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
        case 'U':
 #ifdef IV_IS_QUAD
-           /* nothing */
+           intsize = 'q';
 #else
            intsize = 'l';
 #endif
@@ -4976,7 +4965,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
        case 'O':
 #ifdef IV_IS_QUAD
-           /* nothing */
+           intsize = 'q';
 #else
            intsize = 'l';
 #endif
@@ -4993,11 +4982,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            if (args) {
                switch (intsize) {
                case 'h':  uv = (unsigned short)va_arg(*args, unsigned); break;
-#ifdef UV_IS_QUAD
-               default:   uv = va_arg(*args, UV); break;
-#else
                default:   uv = va_arg(*args, unsigned); break;
-#endif
                case 'l':  uv = va_arg(*args, unsigned long); break;
                case 'V':  uv = va_arg(*args, UV); break;
 #ifdef HAS_QUAD
@@ -5009,11 +4994,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                uv = (svix < svmax) ? SvUVx(svargs[svix++]) : 0;
                switch (intsize) {
                case 'h':       uv = (unsigned short)uv; break;
-#ifdef UV_IS_QUAD
-               default:        break;
-#else
                default:        uv = (unsigned)uv; break;
-#endif
                case 'l':       uv = (unsigned long)uv; break;
                case 'V':       break;
 #ifdef HAS_QUAD
@@ -5056,6 +5037,19 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                    *--eptr = '0';
                break;
            default:            /* it had better be ten or less */
+#if defined(PERL_Y2KWARN)
+               if (ckWARN(WARN_MISC)) {
+                   STRLEN n;
+                   char *s = SvPV(sv,n);
+                   if (n >= 2 && s[n-2] == '1' && s[n-1] == '9'
+                       && (n == 2 || !isDIGIT(s[n-3])))
+                   {
+                       Perl_warner(aTHX_ WARN_MISC,
+                                   "Possible Y2K bug: %%%c %s",
+                                   c, "format string following '19'");
+                   }
+               }
+#endif
                do {
                    dig = uv % base;
                    *--eptr = '0' + dig;
@@ -5105,6 +5099,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                Safefree(PL_efloatbuf);
                PL_efloatsize = need + 20; /* more fudge */
                New(906, PL_efloatbuf, PL_efloatsize, char);
+               PL_efloatbuf[0] = '\0';
            }
 
            eptr = ebuf + sizeof ebuf;
@@ -5144,15 +5139,36 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            eptr = PL_efloatbuf;
            elen = strlen(PL_efloatbuf);
 
-#ifdef LC_NUMERIC
+#ifdef USE_LOCALE_NUMERIC
            /*
             * User-defined locales may include arbitrary characters.
-            * And, unfortunately, some system may alloc the "C" locale
-            * to be overridden by a malicious user.
+            * And, unfortunately, some (broken) systems may allow the
+            * "C" locale to be overridden by a malicious user.
+            * XXX This is an extreme way to cope with broken systems.
             */
-           if (used_locale)
-               *used_locale = TRUE;
-#endif /* LC_NUMERIC */
+           if (maybe_tainted && PL_tainting) {
+               /* safe if it matches /[-+]?\d*(\.\d*)?([eE][-+]?\d*)?/ */
+               if (*eptr == '-' || *eptr == '+')
+                   ++eptr;
+               while (isDIGIT(*eptr))
+                   ++eptr;
+               if (*eptr == '.') {
+                   ++eptr;
+                   while (isDIGIT(*eptr))
+                       ++eptr;
+               }
+               if (*eptr == 'e' || *eptr == 'E') {
+                   ++eptr;
+                   if (*eptr == '-' || *eptr == '+')
+                       ++eptr;
+                   while (isDIGIT(*eptr))
+                       ++eptr;
+               }
+               if (*eptr)
+                   *maybe_tainted = TRUE;      /* results are suspect */
+               eptr = PL_efloatbuf;
+           }
+#endif /* USE_LOCALE_NUMERIC */
 
            break;
 
@@ -5163,11 +5179,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            if (args) {
                switch (intsize) {
                case 'h':       *(va_arg(*args, short*)) = i; break;
-#ifdef IV_IS_QUAD
-               default:        *(va_arg(*args, IV*)) = i; break;
-#else
                default:        *(va_arg(*args, int*)) = i; break;
-#endif
                case 'l':       *(va_arg(*args, long*)) = i; break;
                case 'V':       *(va_arg(*args, IV*)) = i; break;
 #ifdef HAS_QUAD