This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: Cygwin PerlIO.t failing
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index d5dffef..ef61d1b 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -1,6 +1,6 @@
 /*    sv.c
  *
 /*    sv.c
  *
- *    Copyright (c) 1991-2001, Larry Wall
+ *    Copyright (c) 1991-2002, Larry Wall
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -199,7 +199,7 @@ S_del_sv(pTHX_ SV *p)
        }
        if (!ok) {
            if (ckWARN_d(WARN_INTERNAL))        
        }
        if (!ok) {
            if (ckWARN_d(WARN_INTERNAL))        
-               Perl_warner(aTHX_ WARN_INTERNAL,
+               Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
                            "Attempt to free non-arena SV: 0x%"UVxf,
                            PTR2UV(p));
            return;
                            "Attempt to free non-arena SV: 0x%"UVxf,
                            PTR2UV(p));
            return;
@@ -546,10 +546,10 @@ void
 Perl_report_uninit(pTHX)
 {
     if (PL_op)
 Perl_report_uninit(pTHX)
 {
     if (PL_op)
-       Perl_warner(aTHX_ WARN_UNINITIALIZED, PL_warn_uninit,
+       Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit,
                    " in ", OP_DESC(PL_op));
     else
                    " in ", OP_DESC(PL_op));
     else
-       Perl_warner(aTHX_ WARN_UNINITIALIZED, PL_warn_uninit, "", "");
+       Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit, "", "");
 }
 
 /* grab a new IV body from the free list, allocating more if necessary */
 }
 
 /* grab a new IV body from the free list, allocating more if necessary */
@@ -1226,13 +1226,13 @@ You generally want to use the C<SvUPGRADE> macro wrapper. See also C<svtype>.
 bool
 Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
 {
 bool
 Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
 {
-    char*      pv;
-    U32                cur;
-    U32                len;
-    IV         iv;
-    NV         nv;
-    MAGIC*     magic;
-    HV*                stash;
+    char*      pv = NULL;
+    U32                cur = 0;
+    U32                len = 0;
+    IV         iv = 0;
+    NV         nv = 0.0;
+    MAGIC*     magic = NULL;
+    HV*                stash = Nullhv;
 
     if (mt != SVt_PV && SvREADONLY(sv) && SvFAKE(sv)) {
        sv_force_normal(sv);
 
     if (mt != SVt_PV && SvREADONLY(sv) && SvFAKE(sv)) {
        sv_force_normal(sv);
@@ -1540,6 +1540,8 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
 {
     register char *s;
 
 {
     register char *s;
 
+
+
 #ifdef HAS_64K_LIMIT
     if (newlen >= 0x10000) {
        PerlIO_printf(Perl_debug_log,
 #ifdef HAS_64K_LIMIT
     if (newlen >= 0x10000) {
        PerlIO_printf(Perl_debug_log,
@@ -1565,6 +1567,7 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
     }
     else
        s = SvPVX(sv);
     }
     else
        s = SvPVX(sv);
+
     if (newlen > SvLEN(sv)) {          /* need more room? */
        if (SvLEN(sv) && s) {
 #if defined(MYMALLOC) && !defined(LEAKTEST)
     if (newlen > SvLEN(sv)) {          /* need more room? */
        if (SvLEN(sv) && s) {
 #if defined(MYMALLOC) && !defined(LEAKTEST)
@@ -1584,6 +1587,9 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
                SvREADONLY_off(sv);
            }
            New(703, s, newlen, char);
                SvREADONLY_off(sv);
            }
            New(703, s, newlen, char);
+           if (SvPVX(sv) && SvCUR(sv)) {
+               Move(SvPVX(sv), s, (newlen < SvCUR(sv)) ? newlen : SvCUR(sv), char);
+           }
        }
        SvPV_set(sv, s);
         SvLEN_set(sv, newlen);
        }
        SvPV_set(sv, s);
         SvLEN_set(sv, newlen);
@@ -1821,11 +1827,11 @@ S_not_a_number(pTHX_ SV *sv)
     }
 
     if (PL_op)
     }
 
     if (PL_op)
-       Perl_warner(aTHX_ WARN_NUMERIC,
+       Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
                    "Argument \"%s\" isn't numeric in %s", pv,
                    OP_DESC(PL_op));
     else
                    "Argument \"%s\" isn't numeric in %s", pv,
                    OP_DESC(PL_op));
     else
-       Perl_warner(aTHX_ WARN_NUMERIC,
+       Perl_warner(aTHX_ packWARN(WARN_NUMERIC),
                    "Argument \"%s\" isn't numeric", pv);
 }
 
                    "Argument \"%s\" isn't numeric", pv);
 }
 
@@ -2869,8 +2875,8 @@ uiv_2buf(char *buf, IV iv, UV uv, int is_uv, char **peob)
     return ptr;
 }
 
     return ptr;
 }
 
-/* For backwards-compatibility only. sv_2pv() is normally #def'ed to
- * C<sv_2pv_macro()>. See also C<sv_2pv_flags()>.
+/* sv_2pv() is now a macro using Perl_sv_2pv_flags();
+ * this function provided for binary compatibility only
  */
 
 char *
  */
 
 char *
@@ -3145,6 +3151,45 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
 }
 
 /*
 }
 
 /*
+=for apidoc sv_copypv
+
+Copies a stringified representation of the source SV into the
+destination SV.  Automatically performs any necessary mg_get and
+coercion of numeric values into strings.  Guaranteed to preserve
+UTF-8 flag even from overloaded objects.  Similar in nature to
+sv_2pv[_flags] but operates directly on an SV instead of just the
+string.  Mostly uses sv_2pv_flags to do its work, except when that
+would lose the UTF-8'ness of the PV.
+
+=cut
+*/
+
+void
+Perl_sv_copypv(pTHX_ SV *dsv, register SV *ssv)
+{
+    SV *tmpsv = sv_newmortal();
+
+    if ( SvTHINKFIRST(ssv) && SvROK(ssv) && SvAMAGIC(ssv) ) {
+       tmpsv = AMG_CALLun(ssv,string);
+       if (SvTYPE(tmpsv) != SVt_RV || (SvRV(tmpsv) != SvRV(ssv))) {
+           SvSetSV(dsv,tmpsv);
+           return;
+       }
+    }
+    {
+       STRLEN len;
+       char *s;
+       s = SvPV(ssv,len);
+       sv_setpvn(tmpsv,s,len);
+       if (SvUTF8(ssv))
+           SvUTF8_on(tmpsv);
+       else
+           SvUTF8_off(tmpsv);
+       SvSetSV(dsv,tmpsv);
+    }
+}
+
+/*
 =for apidoc sv_2pvbyte_nolen
 
 Return a pointer to the byte-encoded representation of the SV.
 =for apidoc sv_2pvbyte_nolen
 
 Return a pointer to the byte-encoded representation of the SV.
@@ -3271,9 +3316,17 @@ Forces the SV to string form if it is not already.
 Always sets the SvUTF8 flag to avoid future validity checks even
 if all the bytes have hibit clear.
 
 Always sets the SvUTF8 flag to avoid future validity checks even
 if all the bytes have hibit clear.
 
+This is not as a general purpose byte encoding to Unicode interface:
+use the Encode extension for that.
+
 =cut
 */
 
 =cut
 */
 
+/* sv_utf8_upgrade() is now a macro using sv_utf8_upgrade_flags();
+ * this function provided for binary compatibility only
+ */
+
+
 STRLEN
 Perl_sv_utf8_upgrade(pTHX_ register SV *sv)
 {
 STRLEN
 Perl_sv_utf8_upgrade(pTHX_ register SV *sv)
 {
@@ -3290,6 +3343,9 @@ if all the bytes have hibit clear. If C<flags> has C<SV_GMAGIC> bit set,
 will C<mg_get> on C<sv> if appropriate, else not. C<sv_utf8_upgrade> and
 C<sv_utf8_upgrade_nomg> are implemented in terms of this function.
 
 will C<mg_get> on C<sv> if appropriate, else not. C<sv_utf8_upgrade> and
 C<sv_utf8_upgrade_nomg> are implemented in terms of this function.
 
+This is not as a general purpose byte encoding to Unicode interface:
+use the Encode extension for that.
+
 =cut
 */
 
 =cut
 */
 
@@ -3317,7 +3373,7 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *sv, I32 flags)
     }
 
     if (PL_encoding)
     }
 
     if (PL_encoding)
-        Perl_sv_recode_to_utf8(aTHX_ sv, PL_encoding);
+        sv_recode_to_utf8(sv, PL_encoding);
     else { /* Assume Latin-1/EBCDIC */
         /* This function could be much more efficient if we
          * had a FLAG in SVs to signal if there are any hibit
     else { /* Assume Latin-1/EBCDIC */
         /* This function could be much more efficient if we
          * had a FLAG in SVs to signal if there are any hibit
@@ -3355,6 +3411,9 @@ This may not be possible if the PV contains non-byte encoding characters;
 if this is the case, either returns false or, if C<fail_ok> is not
 true, croaks.
 
 if this is the case, either returns false or, if C<fail_ok> is not
 true, croaks.
 
+This is not as a general purpose Unicode to byte encoding interface:
+use the Encode extension for that.
+
 =cut
 */
 
 =cut
 */
 
@@ -3372,28 +3431,6 @@ Perl_sv_utf8_downgrade(pTHX_ register SV* sv, bool fail_ok)
            if (!utf8_to_bytes(s, &len)) {
                if (fail_ok)
                    return FALSE;
            if (!utf8_to_bytes(s, &len)) {
                if (fail_ok)
                    return FALSE;
-#ifdef USE_BYTES_DOWNGRADES
-               else if (IN_BYTES) {
-                   U8 *d = s;
-                   U8 *e = (U8 *) SvEND(sv);
-                   int first = 1;
-                   while (s < e) {
-                       UV ch = utf8n_to_uvchr(s,(e-s),&len,0);
-                       if (first && ch > 255) {
-                           if (PL_op)
-                               Perl_warner(aTHX_ WARN_UTF8, "Wide character in byte %s",
-                                          OP_DESC(PL_op);
-                           else
-                               Perl_warner(aTHX_ WARN_UTF8, "Wide character in byte");
-                           first = 0;
-                       }
-                       *d++ = ch;
-                       s += len;
-                   }
-                   *d = '\0';
-                   len = (d - (U8 *) SvPVX(sv));
-               }
-#endif
                else {
                    if (PL_op)
                        Perl_croak(aTHX_ "Wide character in %s",
                else {
                    if (PL_op)
                        Perl_croak(aTHX_ "Wide character in %s",
@@ -3484,9 +3521,10 @@ C<SvSetMagicSV_nosteal>.
 =cut
 */
 
 =cut
 */
 
-/* sv_setsv() is aliased to Perl_sv_setsv_macro; this function provided
-   for binary compatibility only
-*/
+/* sv_setsv() is now a macro using Perl_sv_setsv_flags();
+ * this function provided for binary compatibility only
+ */
+
 void
 Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
 {
 void
 Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
 {
@@ -3764,15 +3802,16 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                                            || sv_cmp(cv_const_sv(cv),
                                                      cv_const_sv((CV*)sref)))))
                                {
                                            || sv_cmp(cv_const_sv(cv),
                                                      cv_const_sv((CV*)sref)))))
                                {
-                                   Perl_warner(aTHX_ WARN_REDEFINE,
+                                   Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
                                        CvCONST(cv)
                                        ? "Constant subroutine %s redefined"
                                        : "Subroutine %s redefined",
                                        GvENAME((GV*)dstr));
                                }
                            }
                                        CvCONST(cv)
                                        ? "Constant subroutine %s redefined"
                                        : "Subroutine %s redefined",
                                        GvENAME((GV*)dstr));
                                }
                            }
-                           cv_ckproto(cv, (GV*)dstr,
-                                      SvPOK(sref) ? SvPVX(sref) : Nullch);
+                           if (!intro)
+                               cv_ckproto(cv, (GV*)dstr,
+                                       SvPOK(sref) ? SvPVX(sref) : Nullch);
                        }
                        GvCV(dstr) = (CV*)sref;
                        GvCVGEN(dstr) = 0; /* Switch off cacheness. */
                        }
                        GvCV(dstr) = (CV*)sref;
                        GvCVGEN(dstr) = 0; /* Switch off cacheness. */
@@ -3887,7 +3926,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
        }
        else {                          /* have to copy actual string */
            STRLEN len = SvCUR(sstr);
        }
        else {                          /* have to copy actual string */
            STRLEN len = SvCUR(sstr);
-
            SvGROW(dstr, len + 1);      /* inlined from sv_setpvn */
            Move(SvPVX(sstr),SvPVX(dstr),len,char);
            SvCUR_set(dstr, len);
            SvGROW(dstr, len + 1);      /* inlined from sv_setpvn */
            Move(SvPVX(sstr),SvPVX(dstr),len,char);
            SvCUR_set(dstr, len);
@@ -3943,7 +3981,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
     else {
        if (dtype == SVt_PVGV) {
            if (ckWARN(WARN_MISC))
     else {
        if (dtype == SVt_PVGV) {
            if (ckWARN(WARN_MISC))
-               Perl_warner(aTHX_ WARN_MISC, "Undefined value assigned to typeglob");
+               Perl_warner(aTHX_ packWARN(WARN_MISC), "Undefined value assigned to typeglob");
        }
        else
            (void)SvOK_off(dstr);
        }
        else
            (void)SvOK_off(dstr);
@@ -4215,9 +4253,10 @@ Handles 'get' magic, but not 'set' magic.  See C<sv_catpvn_mg>.
 =cut
 */
 
 =cut
 */
 
-/* sv_catpvn() is aliased to Perl_sv_catpvn_macro; this function provided
-   for binary compatibility only
-*/
+/* sv_catpvn() is now a macro using Perl_sv_catpvn_flags();
+ * this function provided for binary compatibility only
+ */
+
 void
 Perl_sv_catpvn(pTHX_ SV *dsv, const char* sstr, STRLEN slen)
 {
 void
 Perl_sv_catpvn(pTHX_ SV *dsv, const char* sstr, STRLEN slen)
 {
@@ -4278,9 +4317,10 @@ not 'set' magic.  See C<sv_catsv_mg>.
 
 =cut */
 
 
 =cut */
 
-/* sv_catsv() is aliased to Perl_sv_catsv_macro; this function provided
-   for binary compatibility only
-*/
+/* sv_catsv() is now a macro using Perl_sv_catsv_flags();
+ * this function provided for binary compatibility only
+ */
+
 void
 Perl_sv_catsv(pTHX_ SV *dstr, register SV *sstr)
 {
 void
 Perl_sv_catsv(pTHX_ SV *dstr, register SV *sstr)
 {
@@ -4415,43 +4455,33 @@ Perl_newSV(pTHX_ STRLEN len)
     }
     return sv;
 }
     }
     return sv;
 }
-
 /*
 /*
-=for apidoc sv_magic
+=for apidoc sv_magicext
 
 
-Adds magic to an SV. First upgrades C<sv> to type C<SVt_PVMG> if necessary,
-then adds a new magic item of type C<how> to the head of the magic list.
+Adds magic to an SV, upgrading it if necessary. Applies the
+supplied vtable and returns pointer to the magic added.
+
+Note that sv_magicext will allow things that sv_magic will not.
+In particular you can add magic to SvREADONLY SVs and and more than
+one instance of the same 'how'
 
 
-C<name> is assumed to contain an C<SV*> if C<(name && namelen == HEf_SVKEY)>
+I C<namelen> is greater then zero then a savepvn() I<copy> of C<name> is stored,
+if C<namelen> is zero then C<name> is stored as-is and - as another special
+case - if C<(name && namelen == HEf_SVKEY)> then C<name> is assumed to contain
+an C<SV*> and has its REFCNT incremented
+
+(This is now used as a subroutine by sv_magic.)
 
 =cut
 */
 
 =cut
 */
-
-void
-Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 namlen)
+MAGIC *        
+Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, MGVTBL *vtable,
+                const char* name, I32 namlen)
 {
     MAGIC* mg;
 
 {
     MAGIC* mg;
 
-    if (SvREADONLY(sv)) {
-       if (PL_curcop != &PL_compiling
-           && how != PERL_MAGIC_regex_global
-           && how != PERL_MAGIC_bm
-           && how != PERL_MAGIC_fm
-           && how != PERL_MAGIC_sv
-          )
-       {
-           Perl_croak(aTHX_ PL_no_modify);
-       }
-    }
-    if (SvMAGICAL(sv) || (how == PERL_MAGIC_taint && SvTYPE(sv) >= SVt_PVMG)) {
-       if (SvMAGIC(sv) && (mg = mg_find(sv, how))) {
-           if (how == PERL_MAGIC_taint)
-               mg->mg_len |= 1;
-           return;
-       }
-    }
-    else {
-        (void)SvUPGRADE(sv, SVt_PVMG);
+    if (SvTYPE(sv) < SVt_PVMG) {
+       (void)SvUPGRADE(sv, SVt_PVMG);
     }
     Newz(702,mg, 1, MAGIC);
     mg->mg_moremagic = SvMAGIC(sv);
     }
     Newz(702,mg, 1, MAGIC);
     mg->mg_moremagic = SvMAGIC(sv);
@@ -4478,129 +4508,182 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
     mg->mg_type = how;
     mg->mg_len = namlen;
     if (name) {
     mg->mg_type = how;
     mg->mg_len = namlen;
     if (name) {
-       if (namlen >= 0)
+       if (namlen > 0)
            mg->mg_ptr = savepvn(name, namlen);
        else if (namlen == HEf_SVKEY)
            mg->mg_ptr = (char*)SvREFCNT_inc((SV*)name);
            mg->mg_ptr = savepvn(name, namlen);
        else if (namlen == HEf_SVKEY)
            mg->mg_ptr = (char*)SvREFCNT_inc((SV*)name);
+       else
+           mg->mg_ptr = (char *) name;
+    }
+    mg->mg_virtual = vtable;
+
+    mg_magical(sv);
+    if (SvGMAGICAL(sv))
+       SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK|SVf_POK);
+    return mg;
+}
+
+/*
+=for apidoc sv_magic
+
+Adds magic to an SV. First upgrades C<sv> to type C<SVt_PVMG> if necessary,
+then adds a new magic item of type C<how> to the head of the magic list.
+
+=cut
+*/
+
+void
+Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 namlen)
+{
+    MAGIC* mg;
+    MGVTBL *vtable = 0;
+
+    if (SvREADONLY(sv)) {
+       if (PL_curcop != &PL_compiling
+           && how != PERL_MAGIC_regex_global
+           && how != PERL_MAGIC_bm
+           && how != PERL_MAGIC_fm
+           && how != PERL_MAGIC_sv
+          )
+       {
+           Perl_croak(aTHX_ PL_no_modify);
+       }
+    }
+    if (SvMAGICAL(sv) || (how == PERL_MAGIC_taint && SvTYPE(sv) >= SVt_PVMG)) {
+       if (SvMAGIC(sv) && (mg = mg_find(sv, how))) {
+           /* sv_magic() refuses to add a magic of the same 'how' as an
+              existing one
+            */
+           if (how == PERL_MAGIC_taint)
+               mg->mg_len |= 1;
+           return;
+       }
     }
 
     switch (how) {
     case PERL_MAGIC_sv:
     }
 
     switch (how) {
     case PERL_MAGIC_sv:
-       mg->mg_virtual = &PL_vtbl_sv;
+       vtable = &PL_vtbl_sv;
        break;
     case PERL_MAGIC_overload:
        break;
     case PERL_MAGIC_overload:
-        mg->mg_virtual = &PL_vtbl_amagic;
+        vtable = &PL_vtbl_amagic;
         break;
     case PERL_MAGIC_overload_elem:
         break;
     case PERL_MAGIC_overload_elem:
-        mg->mg_virtual = &PL_vtbl_amagicelem;
+        vtable = &PL_vtbl_amagicelem;
         break;
     case PERL_MAGIC_overload_table:
         break;
     case PERL_MAGIC_overload_table:
-        mg->mg_virtual = &PL_vtbl_ovrld;
+        vtable = &PL_vtbl_ovrld;
         break;
     case PERL_MAGIC_bm:
         break;
     case PERL_MAGIC_bm:
-       mg->mg_virtual = &PL_vtbl_bm;
+       vtable = &PL_vtbl_bm;
        break;
     case PERL_MAGIC_regdata:
        break;
     case PERL_MAGIC_regdata:
-       mg->mg_virtual = &PL_vtbl_regdata;
+       vtable = &PL_vtbl_regdata;
        break;
     case PERL_MAGIC_regdatum:
        break;
     case PERL_MAGIC_regdatum:
-       mg->mg_virtual = &PL_vtbl_regdatum;
+       vtable = &PL_vtbl_regdatum;
        break;
     case PERL_MAGIC_env:
        break;
     case PERL_MAGIC_env:
-       mg->mg_virtual = &PL_vtbl_env;
+       vtable = &PL_vtbl_env;
        break;
     case PERL_MAGIC_fm:
        break;
     case PERL_MAGIC_fm:
-       mg->mg_virtual = &PL_vtbl_fm;
+       vtable = &PL_vtbl_fm;
        break;
     case PERL_MAGIC_envelem:
        break;
     case PERL_MAGIC_envelem:
-       mg->mg_virtual = &PL_vtbl_envelem;
+       vtable = &PL_vtbl_envelem;
        break;
     case PERL_MAGIC_regex_global:
        break;
     case PERL_MAGIC_regex_global:
-       mg->mg_virtual = &PL_vtbl_mglob;
+       vtable = &PL_vtbl_mglob;
        break;
     case PERL_MAGIC_isa:
        break;
     case PERL_MAGIC_isa:
-       mg->mg_virtual = &PL_vtbl_isa;
+       vtable = &PL_vtbl_isa;
        break;
     case PERL_MAGIC_isaelem:
        break;
     case PERL_MAGIC_isaelem:
-       mg->mg_virtual = &PL_vtbl_isaelem;
+       vtable = &PL_vtbl_isaelem;
        break;
     case PERL_MAGIC_nkeys:
        break;
     case PERL_MAGIC_nkeys:
-       mg->mg_virtual = &PL_vtbl_nkeys;
+       vtable = &PL_vtbl_nkeys;
        break;
     case PERL_MAGIC_dbfile:
        break;
     case PERL_MAGIC_dbfile:
-       SvRMAGICAL_on(sv);
-       mg->mg_virtual = 0;
+       vtable = 0;
        break;
     case PERL_MAGIC_dbline:
        break;
     case PERL_MAGIC_dbline:
-       mg->mg_virtual = &PL_vtbl_dbline;
+       vtable = &PL_vtbl_dbline;
        break;
 #ifdef USE_5005THREADS
     case PERL_MAGIC_mutex:
        break;
 #ifdef USE_5005THREADS
     case PERL_MAGIC_mutex:
-       mg->mg_virtual = &PL_vtbl_mutex;
+       vtable = &PL_vtbl_mutex;
        break;
 #endif /* USE_5005THREADS */
 #ifdef USE_LOCALE_COLLATE
     case PERL_MAGIC_collxfrm:
        break;
 #endif /* USE_5005THREADS */
 #ifdef USE_LOCALE_COLLATE
     case PERL_MAGIC_collxfrm:
-        mg->mg_virtual = &PL_vtbl_collxfrm;
+        vtable = &PL_vtbl_collxfrm;
         break;
 #endif /* USE_LOCALE_COLLATE */
     case PERL_MAGIC_tied:
         break;
 #endif /* USE_LOCALE_COLLATE */
     case PERL_MAGIC_tied:
-       mg->mg_virtual = &PL_vtbl_pack;
+       vtable = &PL_vtbl_pack;
        break;
     case PERL_MAGIC_tiedelem:
     case PERL_MAGIC_tiedscalar:
        break;
     case PERL_MAGIC_tiedelem:
     case PERL_MAGIC_tiedscalar:
-       mg->mg_virtual = &PL_vtbl_packelem;
+       vtable = &PL_vtbl_packelem;
        break;
     case PERL_MAGIC_qr:
        break;
     case PERL_MAGIC_qr:
-       mg->mg_virtual = &PL_vtbl_regexp;
+       vtable = &PL_vtbl_regexp;
        break;
     case PERL_MAGIC_sig:
        break;
     case PERL_MAGIC_sig:
-       mg->mg_virtual = &PL_vtbl_sig;
+       vtable = &PL_vtbl_sig;
        break;
     case PERL_MAGIC_sigelem:
        break;
     case PERL_MAGIC_sigelem:
-       mg->mg_virtual = &PL_vtbl_sigelem;
+       vtable = &PL_vtbl_sigelem;
        break;
     case PERL_MAGIC_taint:
        break;
     case PERL_MAGIC_taint:
-       mg->mg_virtual = &PL_vtbl_taint;
-       mg->mg_len = 1;
+       vtable = &PL_vtbl_taint;
        break;
     case PERL_MAGIC_uvar:
        break;
     case PERL_MAGIC_uvar:
-       mg->mg_virtual = &PL_vtbl_uvar;
+       vtable = &PL_vtbl_uvar;
        break;
     case PERL_MAGIC_vec:
        break;
     case PERL_MAGIC_vec:
-       mg->mg_virtual = &PL_vtbl_vec;
+       vtable = &PL_vtbl_vec;
        break;
     case PERL_MAGIC_substr:
        break;
     case PERL_MAGIC_substr:
-       mg->mg_virtual = &PL_vtbl_substr;
+       vtable = &PL_vtbl_substr;
        break;
     case PERL_MAGIC_defelem:
        break;
     case PERL_MAGIC_defelem:
-       mg->mg_virtual = &PL_vtbl_defelem;
+       vtable = &PL_vtbl_defelem;
        break;
     case PERL_MAGIC_glob:
        break;
     case PERL_MAGIC_glob:
-       mg->mg_virtual = &PL_vtbl_glob;
+       vtable = &PL_vtbl_glob;
        break;
     case PERL_MAGIC_arylen:
        break;
     case PERL_MAGIC_arylen:
-       mg->mg_virtual = &PL_vtbl_arylen;
+       vtable = &PL_vtbl_arylen;
        break;
     case PERL_MAGIC_pos:
        break;
     case PERL_MAGIC_pos:
-       mg->mg_virtual = &PL_vtbl_pos;
+       vtable = &PL_vtbl_pos;
        break;
     case PERL_MAGIC_backref:
        break;
     case PERL_MAGIC_backref:
-       mg->mg_virtual = &PL_vtbl_backref;
+       vtable = &PL_vtbl_backref;
        break;
     case PERL_MAGIC_ext:
        /* Reserved for use by extensions not perl internals.           */
        /* Useful for attaching extension internal data to perl vars.   */
        /* Note that multiple extensions may clash if magical scalars   */
        /* etc holding private data from one are passed to another.     */
        break;
     case PERL_MAGIC_ext:
        /* Reserved for use by extensions not perl internals.           */
        /* Useful for attaching extension internal data to perl vars.   */
        /* Note that multiple extensions may clash if magical scalars   */
        /* etc holding private data from one are passed to another.     */
-       SvRMAGICAL_on(sv);
        break;
     default:
        Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
     }
        break;
     default:
        Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
     }
-    mg_magical(sv);
-    if (SvGMAGICAL(sv))
-       SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK|SVf_POK);
+
+    /* Rest of work is done else where */
+    mg = sv_magicext(sv,obj,how,vtable,name,namlen);
+
+    switch (how) {
+    case PERL_MAGIC_taint:
+       mg->mg_len = 1;
+       break;
+    case PERL_MAGIC_ext:
+    case PERL_MAGIC_dbfile:
+       SvRMAGICAL_on(sv);
+       break;
+    }
 }
 
 /*
 }
 
 /*
@@ -4626,7 +4709,7 @@ Perl_sv_unmagic(pTHX_ SV *sv, int type)
            if (vtbl && vtbl->svt_free)
                CALL_FPTR(vtbl->svt_free)(aTHX_ sv, mg);
            if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
            if (vtbl && vtbl->svt_free)
                CALL_FPTR(vtbl->svt_free)(aTHX_ sv, mg);
            if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
-               if (mg->mg_len >= 0)
+               if (mg->mg_len > 0)
                    Safefree(mg->mg_ptr);
                else if (mg->mg_len == HEf_SVKEY)
                    SvREFCNT_dec((SV*)mg->mg_ptr);
                    Safefree(mg->mg_ptr);
                else if (mg->mg_len == HEf_SVKEY)
                    SvREFCNT_dec((SV*)mg->mg_ptr);
@@ -4667,7 +4750,7 @@ Perl_sv_rvweaken(pTHX_ SV *sv)
        Perl_croak(aTHX_ "Can't weaken a nonreference");
     else if (SvWEAKREF(sv)) {
        if (ckWARN(WARN_MISC))
        Perl_croak(aTHX_ "Can't weaken a nonreference");
     else if (SvWEAKREF(sv)) {
        if (ckWARN(WARN_MISC))
-           Perl_warner(aTHX_ WARN_MISC, "Reference is already weak");
+           Perl_warner(aTHX_ packWARN(WARN_MISC), "Reference is already weak");
        return sv;
     }
     tsv = SvRV(sv);
        return sv;
     }
     tsv = SvRV(sv);
@@ -4707,7 +4790,7 @@ S_sv_del_backref(pTHX_ SV *sv)
     SV **svp;
     I32 i;
     SV *tsv = SvRV(sv);
     SV **svp;
     I32 i;
     SV *tsv = SvRV(sv);
-    MAGIC *mg;
+    MAGIC *mg = NULL;
     if (!SvMAGICAL(tsv) || !(mg = mg_find(tsv, PERL_MAGIC_backref)))
        Perl_croak(aTHX_ "panic: del_backref");
     av = (AV *)mg->mg_obj;
     if (!SvMAGICAL(tsv) || !(mg = mg_find(tsv, PERL_MAGIC_backref)))
        Perl_croak(aTHX_ "panic: del_backref");
     av = (AV *)mg->mg_obj;
@@ -4834,7 +4917,7 @@ Perl_sv_replace(pTHX_ register SV *sv, register SV *nsv)
     U32 refcnt = SvREFCNT(sv);
     SV_CHECK_THINKFIRST(sv);
     if (SvREFCNT(nsv) != 1 && ckWARN_d(WARN_INTERNAL))
     U32 refcnt = SvREFCNT(sv);
     SV_CHECK_THINKFIRST(sv);
     if (SvREFCNT(nsv) != 1 && ckWARN_d(WARN_INTERNAL))
-       Perl_warner(aTHX_ WARN_INTERNAL, "Reference miscount in sv_replace()");
+       Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "Reference miscount in sv_replace()");
     if (SvMAGICAL(sv)) {
        if (SvMAGICAL(nsv))
            mg_free(nsv);
     if (SvMAGICAL(sv)) {
        if (SvMAGICAL(nsv))
            mg_free(nsv);
@@ -5109,7 +5192,7 @@ Perl_sv_free(pTHX_ SV *sv)
            return;
        }
        if (ckWARN_d(WARN_INTERNAL))
            return;
        }
        if (ckWARN_d(WARN_INTERNAL))
-           Perl_warner(aTHX_ WARN_INTERNAL, "Attempt to free unreferenced scalar");
+           Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "Attempt to free unreferenced scalar");
        return;
     }
     ATOMIC_DEC_AND_TEST(refcount_is_zero, SvREFCNT(sv));
        return;
     }
     ATOMIC_DEC_AND_TEST(refcount_is_zero, SvREFCNT(sv));
@@ -5118,7 +5201,7 @@ Perl_sv_free(pTHX_ SV *sv)
 #ifdef DEBUGGING
     if (SvTEMP(sv)) {
        if (ckWARN_d(WARN_DEBUGGING))
 #ifdef DEBUGGING
     if (SvTEMP(sv)) {
        if (ckWARN_d(WARN_DEBUGGING))
-           Perl_warner(aTHX_ WARN_DEBUGGING,
+           Perl_warner(aTHX_ packWARN(WARN_DEBUGGING),
                        "Attempt to free temp prematurely: SV 0x%"UVxf,
                        PTR2UV(sv));
        return;
                        "Attempt to free temp prematurely: SV 0x%"UVxf,
                        PTR2UV(sv));
        return;
@@ -5286,6 +5369,7 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
     STRLEN cur2;
     I32  eq     = 0;
     char *tpv   = Nullch;
     STRLEN cur2;
     I32  eq     = 0;
     char *tpv   = Nullch;
+    SV* svrecode = Nullsv;
 
     if (!sv1) {
        pv1 = "";
 
     if (!sv1) {
        pv1 = "";
@@ -5301,33 +5385,57 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
     else
        pv2 = SvPV(sv2, cur2);
 
     else
        pv2 = SvPV(sv2, cur2);
 
-    /* do not utf8ize the comparands as a side-effect */
     if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
     if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
-       bool is_utf8 = TRUE;
-        /* UTF-8ness differs */
-
-       if (SvUTF8(sv1)) {
-           /* sv1 is the UTF-8 one , If is equal it must be downgrade-able */
-           char *pv = (char*)bytes_from_utf8((U8*)pv1, &cur1, &is_utf8);
-           if (pv != pv1)
-               pv1 = tpv = pv;
-       }
-       else {
-           /* sv2 is the UTF-8 one , If is equal it must be downgrade-able */
-           char *pv = (char *)bytes_from_utf8((U8*)pv2, &cur2, &is_utf8);
-           if (pv != pv2)
-               pv2 = tpv = pv;
-       }
-       if (is_utf8) {
-           /* Downgrade not possible - cannot be eq */
-           return FALSE;
-       }
+        /* Differing utf8ness.
+        * Do not UTF8size the comparands as a side-effect. */
+        if (PL_encoding) {
+             if (SvUTF8(sv1)) {
+                  svrecode = newSVpvn(pv2, cur2);
+                  sv_recode_to_utf8(svrecode, PL_encoding);
+                  pv2 = SvPV(svrecode, cur2);
+             }
+             else {
+                  svrecode = newSVpvn(pv1, cur1);
+                  sv_recode_to_utf8(svrecode, PL_encoding);
+                  pv1 = SvPV(svrecode, cur1);
+             }
+             /* Now both are in UTF-8. */
+             if (cur1 != cur2)
+                  return FALSE;
+        }
+        else {
+             bool is_utf8 = TRUE;
+
+             if (SvUTF8(sv1)) {
+                  /* sv1 is the UTF-8 one,
+                   * if is equal it must be downgrade-able */
+                  char *pv = (char*)bytes_from_utf8((U8*)pv1,
+                                                    &cur1, &is_utf8);
+                  if (pv != pv1)
+                       pv1 = tpv = pv;
+             }
+             else {
+                  /* sv2 is the UTF-8 one,
+                   * if is equal it must be downgrade-able */
+                  char *pv = (char *)bytes_from_utf8((U8*)pv2,
+                                                     &cur2, &is_utf8);
+                  if (pv != pv2)
+                       pv2 = tpv = pv;
+             }
+             if (is_utf8) {
+                  /* Downgrade not possible - cannot be eq */
+                  return FALSE;
+             }
+        }
     }
 
     if (cur1 == cur2)
        eq = memEQ(pv1, pv2, cur1);
        
     }
 
     if (cur1 == cur2)
        eq = memEQ(pv1, pv2, cur1);
        
-    if (tpv != Nullch)
+    if (svrecode)
+        SvREFCNT_dec(svrecode);
+
+    if (tpv)
        Safefree(tpv);
 
     return eq;
        Safefree(tpv);
 
     return eq;
@@ -5348,10 +5456,9 @@ I32
 Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
 {
     STRLEN cur1, cur2;
 Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
 {
     STRLEN cur1, cur2;
-    char *pv1, *pv2;
+    char *pv1, *pv2, *tpv = Nullch;
     I32  cmp;
     I32  cmp;
-    bool pv1tmp = FALSE;
-    bool pv2tmp = FALSE;
+    SV *svrecode = Nullsv;
 
     if (!sv1) {
        pv1 = "";
 
     if (!sv1) {
        pv1 = "";
@@ -5360,22 +5467,35 @@ Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
     else
        pv1 = SvPV(sv1, cur1);
 
     else
        pv1 = SvPV(sv1, cur1);
 
-    if (!sv2){
+    if (!sv2) {
        pv2 = "";
        cur2 = 0;
     }
     else
        pv2 = SvPV(sv2, cur2);
 
        pv2 = "";
        cur2 = 0;
     }
     else
        pv2 = SvPV(sv2, cur2);
 
-    /* do not utf8ize the comparands as a side-effect */
     if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
     if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
+        /* Differing utf8ness.
+        * Do not UTF8size the comparands as a side-effect. */
        if (SvUTF8(sv1)) {
        if (SvUTF8(sv1)) {
-           pv2 = (char*)bytes_to_utf8((U8*)pv2, &cur2);
-           pv2tmp = TRUE;
+           if (PL_encoding) {
+                svrecode = newSVpvn(pv2, cur2);
+                sv_recode_to_utf8(svrecode, PL_encoding);
+                pv2 = SvPV(svrecode, cur2);
+           }
+           else {
+                pv2 = tpv = (char*)bytes_to_utf8((U8*)pv2, &cur2);
+           }
        }
        else {
        }
        else {
-           pv1 = (char*)bytes_to_utf8((U8*)pv1, &cur1);
-           pv1tmp = TRUE;
+           if (PL_encoding) {
+                svrecode = newSVpvn(pv1, cur1);
+                sv_recode_to_utf8(svrecode, PL_encoding);
+                pv1 = SvPV(svrecode, cur1);
+           }
+           else {
+                pv1 = tpv = (char*)bytes_to_utf8((U8*)pv1, &cur1);
+           }
        }
     }
 
        }
     }
 
@@ -5395,10 +5515,11 @@ Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
        }
     }
 
        }
     }
 
-    if (pv1tmp)
-       Safefree(pv1);
-    if (pv2tmp)
-       Safefree(pv2);
+    if (svrecode)
+        SvREFCNT_dec(svrecode);
+
+    if (tpv)
+       Safefree(tpv);
 
     return cmp;
 }
 
     return cmp;
 }
@@ -6418,7 +6539,7 @@ Perl_newSVsv(pTHX_ register SV *old)
        return Nullsv;
     if (SvTYPE(old) == SVTYPEMASK) {
         if (ckWARN_d(WARN_INTERNAL))
        return Nullsv;
     if (SvTYPE(old) == SVTYPEMASK) {
         if (ckWARN_d(WARN_INTERNAL))
-           Perl_warner(aTHX_ WARN_INTERNAL, "semi-panic: attempt to dup freed string");
+           Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "semi-panic: attempt to dup freed string");
        return Nullsv;
     }
     new_SV(sv);
        return Nullsv;
     }
     new_SV(sv);
@@ -6569,8 +6690,8 @@ possible to set C<*st> and C<*gvp> to the stash and GV associated with it.
 CV *
 Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, I32 lref)
 {
 CV *
 Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, I32 lref)
 {
-    GV *gv;
-    CV *cv;
+    GV *gv = Nullgv;
+    CV *cv = Nullcv;
     STRLEN n_a;
 
     if (!sv)
     STRLEN n_a;
 
     if (!sv)
@@ -6734,12 +6855,16 @@ Perl_sv_nv(pTHX_ register SV *sv)
 /*
 =for apidoc sv_pv
 
 /*
 =for apidoc sv_pv
 
-A private implementation of the C<SvPV_nolen> macro for compilers which can't
-cope with complex macro expressions. Always use the macro instead.
+Use the C<SvPV_nolen> macro instead
 
 =cut
 */
 
 
 =cut
 */
 
+/* sv_pv() is now a macro using SvPV_nolen();
+ * this function provided for binary compatibility only
+ */
+
+
 char *
 Perl_sv_pv(pTHX_ SV *sv)
 {
 char *
 Perl_sv_pv(pTHX_ SV *sv)
 {
@@ -6770,8 +6895,6 @@ Perl_sv_pvn(pTHX_ SV *sv, STRLEN *lp)
     return sv_2pv(sv, lp);
 }
 
     return sv_2pv(sv, lp);
 }
 
-/* For -DCRIPPLED_CC only. See also C<sv_2pv_flags()>.
- */
 
 char *
 Perl_sv_pvn_nomg(pTHX_ register SV *sv, STRLEN *lp)
 
 char *
 Perl_sv_pvn_nomg(pTHX_ register SV *sv, STRLEN *lp)
@@ -6793,6 +6916,10 @@ can't cope with complex macro expressions. Always use the macro instead.
 =cut
 */
 
 =cut
 */
 
+/* sv_pvn_force() is now a macro using Perl_sv_pvn_force_flags();
+ * this function provided for binary compatibility only
+ */
+
 char *
 Perl_sv_pvn_force(pTHX_ SV *sv, STRLEN *lp)
 {
 char *
 Perl_sv_pvn_force(pTHX_ SV *sv, STRLEN *lp)
 {
@@ -6815,7 +6942,7 @@ C<SvPV_force> and C<SvPV_force_nomg>
 char *
 Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
 {
 char *
 Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
 {
-    char *s;
+    char *s = NULL;
 
     if (SvTHINKFIRST(sv) && !SvROK(sv))
        sv_force_normal(sv);
 
     if (SvTHINKFIRST(sv) && !SvROK(sv))
        sv_force_normal(sv);
@@ -6854,13 +6981,16 @@ Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
 /*
 =for apidoc sv_pvbyte
 
 /*
 =for apidoc sv_pvbyte
 
-A private implementation of the C<SvPVbyte_nolen> macro for compilers
-which can't cope with complex macro expressions. Always use the macro
-instead.
+Use C<SvPVbyte_nolen> instead.
 
 =cut
 */
 
 
 =cut
 */
 
+/* sv_pvbyte () is now a macro using Perl_sv_2pv_flags();
+ * this function provided for binary compatibility only
+ */
+
+
 char *
 Perl_sv_pvbyte(pTHX_ SV *sv)
 {
 char *
 Perl_sv_pvbyte(pTHX_ SV *sv)
 {
@@ -6905,12 +7035,14 @@ Perl_sv_pvbyten_force(pTHX_ SV *sv, STRLEN *lp)
 /*
 =for apidoc sv_pvutf8
 
 /*
 =for apidoc sv_pvutf8
 
-A private implementation of the C<SvPVutf8_nolen> macro for compilers
-which can't cope with complex macro expressions. Always use the macro
-instead.
+Use the C<SvPVutf8_nolen> macro instead
 
 =cut
 */
 
 =cut
 */
+/* sv_pvutf8 () is now a macro using Perl_sv_2pv_flags();
+ * this function provided for binary compatibility only
+ */
+
 
 char *
 Perl_sv_pvutf8(pTHX_ SV *sv)
 
 char *
 Perl_sv_pvutf8(pTHX_ SV *sv)
@@ -7724,7 +7856,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        SV *vecsv;
        U8 *vecstr = Null(U8*);
        STRLEN veclen = 0;
        SV *vecsv;
        U8 *vecstr = Null(U8*);
        STRLEN veclen = 0;
-       char c;
+       char c = 0;
        int i;
        unsigned base = 0;
        IV iv = 0;
        int i;
        unsigned base = 0;
        IV iv = 0;
@@ -8181,7 +8313,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                    if (n >= 2 && s[n-2] == '1' && s[n-1] == '9'
                        && (n == 2 || !isDIGIT(s[n-3])))
                    {
                    if (n >= 2 && s[n-2] == '1' && s[n-1] == '9'
                        && (n == 2 || !isDIGIT(s[n-3])))
                    {
-                       Perl_warner(aTHX_ WARN_Y2K,
+                       Perl_warner(aTHX_ packWARN(WARN_Y2K),
                                    "Possible Y2K bug: %%%c %s",
                                    c, "format string following '19'");
                    }
                                    "Possible Y2K bug: %%%c %s",
                                    c, "format string following '19'");
                    }
@@ -8318,7 +8450,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                                       (UV)c & 0xFF);
                } else
                    sv_catpv(msg, "end of string");
                                       (UV)c & 0xFF);
                } else
                    sv_catpv(msg, "end of string");
-               Perl_warner(aTHX_ WARN_PRINTF, "%"SVf, msg); /* yes, this is reentrant */
+               Perl_warner(aTHX_ packWARN(WARN_PRINTF), "%"SVf, msg); /* yes, this is reentrant */
            }
 
            /* output mangled stuff ... */
            }
 
            /* output mangled stuff ... */
@@ -8337,6 +8469,22 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            continue;   /* not "break" */
        }
 
            continue;   /* not "break" */
        }
 
+       if (is_utf8 != has_utf8) {
+            if (is_utf8) {
+                 if (SvCUR(sv))
+                      sv_utf8_upgrade(sv);
+            }
+            else {
+                 SV *nsv = sv_2mortal(newSVpvn(eptr, elen));
+                 sv_utf8_upgrade(nsv);
+                 eptr = SvPVX(nsv);
+                 elen = SvCUR(nsv);
+            }
+            SvGROW(sv, SvCUR(sv) + elen + 1);
+            p = SvEND(sv);
+            *p = '\0';
+       }
+       
        have = esignlen + zeros + elen;
        need = (have > width ? have : width);
        gap = need - have;
        have = esignlen + zeros + elen;
        need = (have > width ? have : width);
        gap = need - have;
@@ -8360,20 +8508,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                *p++ = '0';
        }
        if (elen) {
                *p++ = '0';
        }
        if (elen) {
-           if (is_utf8 != has_utf8) {
-               if (is_utf8) {
-                   if (SvCUR(sv)) {
-                       sv_utf8_upgrade(sv);
-                       p = SvEND(sv);
-                   }
-               }
-               else {
-                   SV *nsv = sv_2mortal(newSVpvn(eptr, elen));
-                   sv_utf8_upgrade(nsv);
-                   eptr = SvPVX(nsv);
-                   elen = SvCUR(nsv);
-               }
-           }
            Copy(eptr, p, elen, char);
            p += elen;
        }
            Copy(eptr, p, elen, char);
            p += elen;
        }
@@ -8477,6 +8611,7 @@ Perl_re_dup(pTHX_ REGEXP *r, CLONE_PARAMS *param)
        s->min_offset = r->substrs->data[i].min_offset;
        s->max_offset = r->substrs->data[i].max_offset;
        s->substr     = sv_dup_inc(r->substrs->data[i].substr, param);
        s->min_offset = r->substrs->data[i].min_offset;
        s->max_offset = r->substrs->data[i].max_offset;
        s->substr     = sv_dup_inc(r->substrs->data[i].substr, param);
+       s->utf8_substr = sv_dup_inc(r->substrs->data[i].utf8_substr, param);
     }
 
     ret->regstclass = NULL;
     }
 
     ret->regstclass = NULL;
@@ -8656,7 +8791,7 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
        nmg->mg_len     = mg->mg_len;
        nmg->mg_ptr     = mg->mg_ptr;   /* XXX random ptr? */
        if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
        nmg->mg_len     = mg->mg_len;
        nmg->mg_ptr     = mg->mg_ptr;   /* XXX random ptr? */
        if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
-           if (mg->mg_len >= 0) {
+           if (mg->mg_len > 0) {
                nmg->mg_ptr     = SAVEPVN(mg->mg_ptr, mg->mg_len);
                if (mg->mg_type == PERL_MAGIC_overload_table &&
                        AMT_AMAGIC((AMT*)mg->mg_ptr))
                nmg->mg_ptr     = SAVEPVN(mg->mg_ptr, mg->mg_len);
                if (mg->mg_type == PERL_MAGIC_overload_table &&
                        AMT_AMAGIC((AMT*)mg->mg_ptr))
@@ -8672,6 +8807,9 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
            else if (mg->mg_len == HEf_SVKEY)
                nmg->mg_ptr     = (char*)sv_dup_inc((SV*)mg->mg_ptr, param);
        }
            else if (mg->mg_len == HEf_SVKEY)
                nmg->mg_ptr     = (char*)sv_dup_inc((SV*)mg->mg_ptr, param);
        }
+       if ((mg->mg_flags & MGf_DUP) && mg->mg_virtual && mg->mg_virtual->svt_dup) {
+           CALL_FPTR(nmg->mg_virtual->svt_dup)(aTHX_ nmg, param);
+       }
        mgprev = nmg;
     }
     return mgret;
        mgprev = nmg;
     }
     return mgret;
@@ -8881,6 +9019,40 @@ S_gv_share(pTHX_ SV *sstr)
 
 /* duplicate an SV of any type (including AV, HV etc) */
 
 
 /* duplicate an SV of any type (including AV, HV etc) */
 
+void
+Perl_rvpv_dup(pTHX_ SV *dstr, SV *sstr, CLONE_PARAMS* param)
+{
+    if (SvROK(sstr)) {
+        SvRV(dstr) = SvWEAKREF(sstr)
+                    ? sv_dup(SvRV(sstr), param)
+                    : sv_dup_inc(SvRV(sstr), param);
+    }
+    else if (SvPVX(sstr)) {
+       /* Has something there */
+       if (SvLEN(sstr)) {
+           /* Normal PV - clone whole allocated space */
+           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
+       }
+       else {
+           /* Special case - not normally malloced for some reason */
+           if (SvREADONLY(sstr) && SvFAKE(sstr)) {
+               /* A "shared" PV - clone it as unshared string */
+               SvFAKE_off(dstr);
+               SvREADONLY_off(dstr);
+               SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvCUR(sstr));
+           }
+           else {
+               /* Some other special case - random pointer */
+               SvPVX(dstr) = SvPVX(sstr);              
+            }
+       }
+    }
+    else {
+       /* Copy the Null */
+       SvPVX(dstr) = SvPVX(sstr);
+    }
+}
+
 SV *
 Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
 {
 SV *
 Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
 {
@@ -8922,36 +9094,20 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        break;
     case SVt_RV:
        SvANY(dstr)     = new_XRV();
        break;
     case SVt_RV:
        SvANY(dstr)     = new_XRV();
-    SvRV(dstr)    = SvRV(sstr) && SvWEAKREF(sstr)
-                       ? sv_dup(SvRV(sstr), param)
-                       : sv_dup_inc(SvRV(sstr), param);
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PV:
        SvANY(dstr)     = new_XPV();
        SvCUR(dstr)     = SvCUR(sstr);
        SvLEN(dstr)     = SvLEN(sstr);
        break;
     case SVt_PV:
        SvANY(dstr)     = new_XPV();
        SvCUR(dstr)     = SvCUR(sstr);
        SvLEN(dstr)     = SvLEN(sstr);
-       if (SvROK(sstr))
-        SvRV(dstr)    = SvWEAKREF(sstr)
-                       ? sv_dup(SvRV(sstr), param)
-                       : sv_dup_inc(SvRV(sstr), param);
-       else if (SvPVX(sstr) && SvLEN(sstr))
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
-       else
-           SvPVX(dstr) = SvPVX(sstr);          /* XXX shared string/random ptr? */
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PVIV:
        SvANY(dstr)     = new_XPVIV();
        SvCUR(dstr)     = SvCUR(sstr);
        SvLEN(dstr)     = SvLEN(sstr);
        SvIVX(dstr)     = SvIVX(sstr);
        break;
     case SVt_PVIV:
        SvANY(dstr)     = new_XPVIV();
        SvCUR(dstr)     = SvCUR(sstr);
        SvLEN(dstr)     = SvLEN(sstr);
        SvIVX(dstr)     = SvIVX(sstr);
-       if (SvROK(sstr))
-        SvRV(dstr)    = SvWEAKREF(sstr)
-                       ? sv_dup(SvRV(sstr), param)
-                       : sv_dup_inc(SvRV(sstr), param);
-       else if (SvPVX(sstr) && SvLEN(sstr))
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
-       else
-           SvPVX(dstr) = SvPVX(sstr);          /* XXX shared string/random ptr? */
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PVNV:
        SvANY(dstr)     = new_XPVNV();
        break;
     case SVt_PVNV:
        SvANY(dstr)     = new_XPVNV();
@@ -8959,14 +9115,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvLEN(dstr)     = SvLEN(sstr);
        SvIVX(dstr)     = SvIVX(sstr);
        SvNVX(dstr)     = SvNVX(sstr);
        SvLEN(dstr)     = SvLEN(sstr);
        SvIVX(dstr)     = SvIVX(sstr);
        SvNVX(dstr)     = SvNVX(sstr);
-       if (SvROK(sstr))
-        SvRV(dstr)    = SvWEAKREF(sstr)
-                       ? sv_dup(SvRV(sstr), param)
-                       : sv_dup_inc(SvRV(sstr), param);
-       else if (SvPVX(sstr) && SvLEN(sstr))
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
-       else
-           SvPVX(dstr) = SvPVX(sstr);          /* XXX shared string/random ptr? */
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PVMG:
        SvANY(dstr)     = new_XPVMG();
        break;
     case SVt_PVMG:
        SvANY(dstr)     = new_XPVMG();
@@ -8976,14 +9125,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
-       if (SvROK(sstr))
-        SvRV(dstr)    = SvWEAKREF(sstr)
-                       ? sv_dup(SvRV(sstr), param)
-                       : sv_dup_inc(SvRV(sstr), param);
-       else if (SvPVX(sstr) && SvLEN(sstr))
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
-       else
-           SvPVX(dstr) = SvPVX(sstr);          /* XXX shared string/random ptr? */
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PVBM:
        SvANY(dstr)     = new_XPVBM();
        break;
     case SVt_PVBM:
        SvANY(dstr)     = new_XPVBM();
@@ -8993,14 +9135,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
-       if (SvROK(sstr))
-        SvRV(dstr)    = SvWEAKREF(sstr)
-                       ? sv_dup(SvRV(sstr), param)
-                       : sv_dup_inc(SvRV(sstr), param);
-       else if (SvPVX(sstr) && SvLEN(sstr))
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
-       else
-           SvPVX(dstr) = SvPVX(sstr);          /* XXX shared string/random ptr? */
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        BmRARE(dstr)    = BmRARE(sstr);
        BmUSEFUL(dstr)  = BmUSEFUL(sstr);
        BmPREVIOUS(dstr)= BmPREVIOUS(sstr);
        BmRARE(dstr)    = BmRARE(sstr);
        BmUSEFUL(dstr)  = BmUSEFUL(sstr);
        BmPREVIOUS(dstr)= BmPREVIOUS(sstr);
@@ -9013,14 +9148,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
-       if (SvROK(sstr))
-        SvRV(dstr)    = SvWEAKREF(sstr)
-                       ? sv_dup(SvRV(sstr), param)
-                       : sv_dup_inc(SvRV(sstr), param);
-       else if (SvPVX(sstr) && SvLEN(sstr))
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
-       else
-           SvPVX(dstr) = SvPVX(sstr);          /* XXX shared string/random ptr? */
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        LvTARGOFF(dstr) = LvTARGOFF(sstr);      /* XXX sometimes holds PMOP* when DEBUGGING */
        LvTARGLEN(dstr) = LvTARGLEN(sstr);
        LvTARG(dstr)    = sv_dup_inc(LvTARG(sstr), param);
        LvTARGOFF(dstr) = LvTARGOFF(sstr);      /* XXX sometimes holds PMOP* when DEBUGGING */
        LvTARGLEN(dstr) = LvTARGLEN(sstr);
        LvTARG(dstr)    = sv_dup_inc(LvTARG(sstr), param);
@@ -9046,14 +9174,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
-       if (SvROK(sstr))
-        SvRV(dstr)    = SvWEAKREF(sstr)
-                       ? sv_dup(SvRV(sstr), param)
-                       : sv_dup_inc(SvRV(sstr), param);
-       else if (SvPVX(sstr) && SvLEN(sstr))
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
-       else
-           SvPVX(dstr) = SvPVX(sstr);          /* XXX shared string/random ptr? */
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        GvNAMELEN(dstr) = GvNAMELEN(sstr);
        GvNAME(dstr)    = SAVEPVN(GvNAME(sstr), GvNAMELEN(sstr));
        GvSTASH(dstr)   = hv_dup_inc(GvSTASH(sstr), param);
        GvNAMELEN(dstr) = GvNAMELEN(sstr);
        GvNAME(dstr)    = SAVEPVN(GvNAME(sstr), GvNAMELEN(sstr));
        GvSTASH(dstr)   = hv_dup_inc(GvSTASH(sstr), param);
@@ -9069,14 +9190,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
-       if (SvROK(sstr))
-        SvRV(dstr)    = SvWEAKREF(sstr)
-                       ? sv_dup(SvRV(sstr), param)
-                       : sv_dup_inc(SvRV(sstr), param);
-       else if (SvPVX(sstr) && SvLEN(sstr))
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
-       else
-           SvPVX(dstr) = SvPVX(sstr);          /* XXX shared string/random ptr? */
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        IoIFP(dstr)     = fp_dup(IoIFP(sstr), IoTYPE(sstr), param);
        if (IoOFP(sstr) == IoIFP(sstr))
            IoOFP(dstr) = IoIFP(dstr);
        IoIFP(dstr)     = fp_dup(IoIFP(sstr), IoTYPE(sstr), param);
        if (IoOFP(sstr) == IoIFP(sstr))
            IoOFP(dstr) = IoIFP(dstr);
@@ -9184,10 +9298,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
        SvNVX(dstr)     = SvNVX(sstr);
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
-       if (SvPVX(sstr) && SvLEN(sstr))
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
-       else
-           SvPVX(dstr) = SvPVX(sstr);          /* XXX shared string/random ptr? */
+       Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        CvSTASH(dstr)   = hv_dup(CvSTASH(sstr), param); /* NOTE: not refcounted */
        CvSTART(dstr)   = CvSTART(sstr);
        CvROOT(dstr)    = OpREFCNT_inc(CvROOT(sstr));
        CvSTASH(dstr)   = hv_dup(CvSTASH(sstr), param); /* NOTE: not refcounted */
        CvSTART(dstr)   = CvSTART(sstr);
        CvROOT(dstr)    = OpREFCNT_inc(CvROOT(sstr));
@@ -9388,8 +9499,9 @@ Perl_any_dup(pTHX_ void *v, PerlInterpreter *proto_perl)
     /* see if it is part of the interpreter structure */
     if (v >= (void*)proto_perl && v < (void*)(proto_perl+1))
        ret = (void*)(((char*)aTHX) + (((char*)v) - (char*)proto_perl));
     /* see if it is part of the interpreter structure */
     if (v >= (void*)proto_perl && v < (void*)(proto_perl+1))
        ret = (void*)(((char*)aTHX) + (((char*)v) - (char*)proto_perl));
-    else
+    else {
        ret = v;
        ret = v;
+    }
 
     return ret;
 }
 
     return ret;
 }
@@ -9442,6 +9554,12 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
            break;
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
            break;
+       case SAVEt_SHARED_PVREF:                /* char* in shared space */
+           c = (char*)POPPTR(ss,ix);
+           TOPPTR(nss,ix) = savesharedpv(c);
+           ptr = POPPTR(ss,ix);
+           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+           break;
         case SAVEt_GENERIC_SVREF:              /* generic sv */
         case SAVEt_SVREF:                      /* scalar reference */
            sv = (SV*)POPPTR(ss,ix);
         case SAVEt_GENERIC_SVREF:              /* generic sv */
         case SAVEt_SVREF:                      /* scalar reference */
            sv = (SV*)POPPTR(ss,ix);
@@ -9780,8 +9898,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_debug           = proto_perl->Idebug;
 
 #ifdef USE_REENTRANT_API
     PL_debug           = proto_perl->Idebug;
 
 #ifdef USE_REENTRANT_API
-    New(31337, PL_reentrant_buffer,1, REBUF);
-    New(31337, PL_reentrant_buffer->tmbuff,1, struct tm);
+    Perl_reentrant_init(aTHX);
 #endif
 
     /* create SV map for pointer relocation */
 #endif
 
     /* create SV map for pointer relocation */
@@ -9811,15 +9928,21 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     SvNVX(&PL_sv_yes)          = 1;
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes);
 
     SvNVX(&PL_sv_yes)          = 1;
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes);
 
-    /* create shared string table */
+    /* create (a non-shared!) shared string table */
     PL_strtab          = newHV();
     HvSHAREKEYS_off(PL_strtab);
     hv_ksplit(PL_strtab, 512);
     ptr_table_store(PL_ptr_table, proto_perl->Istrtab, PL_strtab);
 
     PL_strtab          = newHV();
     HvSHAREKEYS_off(PL_strtab);
     hv_ksplit(PL_strtab, 512);
     ptr_table_store(PL_ptr_table, proto_perl->Istrtab, PL_strtab);
 
-    PL_compiling               = proto_perl->Icompiling;
-    PL_compiling.cop_stashpv   = SAVEPV(PL_compiling.cop_stashpv);
-    PL_compiling.cop_file      = SAVEPV(PL_compiling.cop_file);
+    PL_compiling = proto_perl->Icompiling;
+
+    /* These two PVs will be free'd special way so must set them same way op.c does */
+    PL_compiling.cop_stashpv = savesharedpv(PL_compiling.cop_stashpv);
+    ptr_table_store(PL_ptr_table, proto_perl->Icompiling.cop_stashpv, PL_compiling.cop_stashpv);
+
+    PL_compiling.cop_file    = savesharedpv(PL_compiling.cop_file);
+    ptr_table_store(PL_ptr_table, proto_perl->Icompiling.cop_file, PL_compiling.cop_file);
+
     ptr_table_store(PL_ptr_table, &proto_perl->Icompiling, &PL_compiling);
     if (!specialWARN(PL_compiling.cop_warnings))
        PL_compiling.cop_warnings = sv_dup_inc(PL_compiling.cop_warnings, param);
     ptr_table_store(PL_ptr_table, &proto_perl->Icompiling, &PL_compiling);
     if (!specialWARN(PL_compiling.cop_warnings))
        PL_compiling.cop_warnings = sv_dup_inc(PL_compiling.cop_warnings, param);
@@ -9885,6 +10008,10 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 #endif
     PL_encoding                = sv_dup(proto_perl->Iencoding, param);
 
 #endif
     PL_encoding                = sv_dup(proto_perl->Iencoding, param);
 
+    sv_setpvn(PERL_DEBUG_PAD(0), "", 0);       /* For regex debugging. */
+    sv_setpvn(PERL_DEBUG_PAD(1), "", 0);       /* ext/re needs these */
+    sv_setpvn(PERL_DEBUG_PAD(2), "", 0);       /* even without DEBUGGING. */
+
     /* Clone the regex array */
     PL_regex_padav = newAV();
     {
     /* Clone the regex array */
     PL_regex_padav = newAV();
     {
@@ -10462,3 +10589,4 @@ Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding)
      return SvPVX(sv);
 }
 
      return SvPVX(sv);
 }
 
+