e448c1
From 9f38b6c605086a67f0d92591f8e8dc99bc1d9164 Mon Sep 17 00:00:00 2001
e448c1
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
e448c1
Date: Thu, 11 May 2017 09:25:35 +0200
e448c1
Subject: [PATCH] Upgrade to 2.167
e448c1
MIME-Version: 1.0
e448c1
Content-Type: text/plain; charset=UTF-8
e448c1
Content-Transfer-Encoding: 8bit
e448c1
e448c1
Unbundled from perl-5.25.12.
e448c1
e448c1
Signed-off-by: Petr Písař <ppisar@redhat.com>
e448c1
---
e448c1
 Changes     |  14 +++++
e448c1
 Dumper.pm   |  47 ++++++++---------
e448c1
 Dumper.xs   | 167 +++++++++++++++++++++++++++++++++++++++++++++---------------
e448c1
 t/bugs.t    |  37 +++++++++++++-
e448c1
 t/deparse.t |  22 ++++----
e448c1
 5 files changed, 207 insertions(+), 80 deletions(-)
e448c1
e448c1
diff --git a/Changes b/Changes
e448c1
index f9ea53f..a5430d5 100644
e448c1
--- a/Changes
e448c1
+++ b/Changes
e448c1
@@ -6,6 +6,20 @@ Changes - public release history for Data::Dumper
e448c1
 
e448c1
 =over 8
e448c1
 
e448c1
+=item 2,166 (Nov 29 2016)
e448c1
+
e448c1
+Reduce memory usage by not importing from Carp
e448c1
+Reduce memory usage by removing unused overload require.
e448c1
+
e448c1
+=item 2.165 (Nov 20 2016)
e448c1
+
e448c1
+Remove impediment to compiling under C++11.
e448c1
+
e448c1
+=item 2.164 (Nov 12 2016)
e448c1
+
e448c1
+The XS implementation now handles the C<Deparse> option, so using it no
e448c1
+longer forces use of the pure-Perl version.
e448c1
+
e448c1
 =item 2.161 (Jul 11 2016)
e448c1
 
e448c1
 Perl 5.12 fix/workaround until fixed PPPort release.
e448c1
diff --git a/Dumper.pm b/Dumper.pm
e448c1
index c71ad35..00f6326 100644
e448c1
--- a/Dumper.pm
e448c1
+++ b/Dumper.pm
e448c1
@@ -10,16 +10,15 @@
e448c1
 package Data::Dumper;
e448c1
 
e448c1
 BEGIN {
e448c1
-    $VERSION = '2.161'; # Don't forget to set version and release
e448c1
+    $VERSION = '2.167'; # Don't forget to set version and release
e448c1
 }               # date in POD below!
e448c1
 
e448c1
 #$| = 1;
e448c1
 
e448c1
 use 5.006_001;
e448c1
 require Exporter;
e448c1
-require overload;
e448c1
 
e448c1
-use Carp;
e448c1
+use Carp ();
e448c1
 
e448c1
 BEGIN {
e448c1
     @ISA = qw(Exporter);
e448c1
@@ -70,7 +69,7 @@ $Maxrecurse = 1000      unless defined $Maxrecurse;
e448c1
 sub new {
e448c1
   my($c, $v, $n) = @_;
e448c1
 
e448c1
-  croak "Usage:  PACKAGE->new(ARRAYREF, [ARRAYREF])"
e448c1
+  Carp::croak("Usage:  PACKAGE->new(ARRAYREF, [ARRAYREF])")
e448c1
     unless (defined($v) && (ref($v) eq 'ARRAY'));
e448c1
   $n = [] unless (defined($n) && (ref($n) eq 'ARRAY'));
e448c1
 
e448c1
@@ -170,11 +169,11 @@ sub Seen {
e448c1
           $s->{seen}{$id} = [$k, $v];
e448c1
         }
e448c1
         else {
e448c1
-          carp "Only refs supported, ignoring non-ref item \$$k";
e448c1
+          Carp::carp("Only refs supported, ignoring non-ref item \$$k");
e448c1
         }
e448c1
       }
e448c1
       else {
e448c1
-        carp "Value of ref must be defined; ignoring undefined item \$$k";
e448c1
+        Carp::carp("Value of ref must be defined; ignoring undefined item \$$k");
e448c1
       }
e448c1
     }
e448c1
     return $s;
e448c1
@@ -195,7 +194,7 @@ sub Values {
e448c1
       return $s;
e448c1
     }
e448c1
     else {
e448c1
-      croak "Argument to Values, if provided, must be array ref";
e448c1
+      Carp::croak("Argument to Values, if provided, must be array ref");
e448c1
     }
e448c1
   }
e448c1
   else {
e448c1
@@ -214,7 +213,7 @@ sub Names {
e448c1
       return $s;
e448c1
     }
e448c1
     else {
e448c1
-      croak "Argument to Names, if provided, must be array ref";
e448c1
+      Carp::croak("Argument to Names, if provided, must be array ref");
e448c1
     }
e448c1
   }
e448c1
   else {
e448c1
@@ -227,7 +226,6 @@ sub DESTROY {}
e448c1
 sub Dump {
e448c1
     return &Dumpxs
e448c1
     unless $Data::Dumper::Useperl || (ref($_[0]) && $_[0]->{useperl})
e448c1
-        || $Data::Dumper::Deparse || (ref($_[0]) && $_[0]->{deparse})
e448c1
 
e448c1
             # Use pure perl version on earlier releases on EBCDIC platforms
e448c1
         || (! $IS_ASCII && $] lt 5.021_010);
e448c1
@@ -439,7 +437,7 @@ sub _dump {
e448c1
         if (ref($s->{sortkeys}) eq 'CODE') {
e448c1
           $keys = $s->{sortkeys}($val);
e448c1
           unless (ref($keys) eq 'ARRAY') {
e448c1
-            carp "Sortkeys subroutine did not return ARRAYREF";
e448c1
+            Carp::carp("Sortkeys subroutine did not return ARRAYREF");
e448c1
             $keys = [];
e448c1
           }
e448c1
         }
e448c1
@@ -487,16 +485,16 @@ sub _dump {
e448c1
         require B::Deparse;
e448c1
         my $sub =  'sub ' . (B::Deparse->new)->coderef2text($val);
e448c1
         $pad    =  $s->{sep} . $s->{pad} . $s->{apad} . $s->{xpad} x ($s->{level} - 1);
e448c1
-        $sub    =~ s/\n/$pad/gse;
e448c1
+        $sub    =~ s/\n/$pad/gs;
e448c1
         $out   .=  $sub;
e448c1
       }
e448c1
       else {
e448c1
         $out .= 'sub { "DUMMY" }';
e448c1
-        carp "Encountered CODE ref, using dummy placeholder" if $s->{purity};
e448c1
+        Carp::carp("Encountered CODE ref, using dummy placeholder") if $s->{purity};
e448c1
       }
e448c1
     }
e448c1
     else {
e448c1
-      croak "Can't handle '$realtype' type";
e448c1
+      Carp::croak("Can't handle '$realtype' type");
e448c1
     }
e448c1
 
e448c1
     if ($realpack and !$no_bless) { # we have a blessed ref
e448c1
@@ -1212,9 +1210,10 @@ $Data::Dumper::Deparse  I<or>  $I<OBJ>->Deparse(I<[NEWVAL]>)
e448c1
 
e448c1
 Can be set to a boolean value to control whether code references are
e448c1
 turned into perl source code. If set to a true value, C<B::Deparse>
e448c1
-will be used to get the source of the code reference. Using this option
e448c1
-will force using the Perl implementation of the dumper, since the fast
e448c1
-XSUB implementation doesn't support it.
e448c1
+will be used to get the source of the code reference. In older versions,
e448c1
+using this option imposed a significant performance penalty when dumping
e448c1
+parts of a data structure other than code references, but that is no
e448c1
+longer the case.
e448c1
 
e448c1
 Caution : use this option only if you know that your coderefs will be
e448c1
 properly reconstructed by C<B::Deparse>.
e448c1
@@ -1435,15 +1434,9 @@ the C<Deparse> flag), an anonymous subroutine that
e448c1
 contains the string '"DUMMY"' will be inserted in its place, and a warning
e448c1
 will be printed if C<Purity> is set.  You can C<eval> the result, but bear
e448c1
 in mind that the anonymous sub that gets created is just a placeholder.
e448c1
-Someday, perl will have a switch to cache-on-demand the string
e448c1
-representation of a compiled piece of code, I hope.  If you have prior
e448c1
-knowledge of all the code refs that your data structures are likely
e448c1
-to have, you can use the C<Seen> method to pre-seed the internal reference
e448c1
-table and make the dumped output point to them, instead.  See L</EXAMPLES>
e448c1
-above.
e448c1
-
e448c1
-The C<Deparse> flag makes Dump() run slower, since the XSUB
e448c1
-implementation does not support it.
e448c1
+Even using the C<Deparse> flag will in some cases produce results that
e448c1
+behave differently after being passed to C<eval>; see the documentation
e448c1
+for L<B::Deparse>.
e448c1
 
e448c1
 SCALAR objects have the weirdest looking C<bless> workaround.
e448c1
 
e448c1
@@ -1466,13 +1459,13 @@ be to use the C<Sortkeys> filter of Data::Dumper.
e448c1
 
e448c1
 Gurusamy Sarathy        gsar@activestate.com
e448c1
 
e448c1
-Copyright (c) 1996-2016 Gurusamy Sarathy. All rights reserved.
e448c1
+Copyright (c) 1996-2017 Gurusamy Sarathy. All rights reserved.
e448c1
 This program is free software; you can redistribute it and/or
e448c1
 modify it under the same terms as Perl itself.
e448c1
 
e448c1
 =head1 VERSION
e448c1
 
e448c1
-Version 2.161  (July 11 2016)
e448c1
+Version 2.167  (January 4 2017)
e448c1
 
e448c1
 =head1 SEE ALSO
e448c1
 
e448c1
diff --git a/Dumper.xs b/Dumper.xs
e448c1
index b22088f..0e7142e 100644
e448c1
--- a/Dumper.xs
e448c1
+++ b/Dumper.xs
e448c1
@@ -63,6 +63,7 @@ typedef struct {
e448c1
     I32 useqq;
e448c1
     int use_sparse_seen_hash;
e448c1
     int trailingcomma;
e448c1
+    int deparse;
e448c1
 } Style;
e448c1
 
e448c1
 static STRLEN num_q (const char *s, STRLEN slen);
e448c1
@@ -369,7 +370,7 @@ esc_q_utf8(pTHX_ SV* sv, const char *src, STRLEN slen, I32 do_utf8, I32 useqq)
e448c1
             UV k;
e448c1
 
e448c1
             if (do_utf8
e448c1
-                && ! isASCII(*(U8*)s)
e448c1
+                && ! isASCII(*s)
e448c1
                     /* Exclude non-ASCII low ordinal controls.  This should be
e448c1
                      * optimized out by the compiler on ASCII platforms; if not
e448c1
                      * could wrap it in a #ifdef EBCDIC, but better to avoid
e448c1
@@ -387,11 +388,11 @@ esc_q_utf8(pTHX_ SV* sv, const char *src, STRLEN slen, I32 do_utf8, I32 useqq)
e448c1
                 increment = (k == 0 && *s != '\0') ? 1 : UTF8SKIP(s);
e448c1
 
e448c1
 #if PERL_VERSION < 10
e448c1
-                sprintf(r, "\\x{%"UVxf"}", k);
e448c1
+                sprintf(r, "\\x{%" UVxf "}", k);
e448c1
                 r += strlen(r);
e448c1
                 /* my_sprintf is not supported by ppport.h */
e448c1
 #else
e448c1
-                r = r + my_sprintf(r, "\\x{%"UVxf"}", k);
e448c1
+                r = r + my_sprintf(r, "\\x{%" UVxf "}", k);
e448c1
 #endif
e448c1
                 continue;
e448c1
             }
e448c1
@@ -505,6 +506,53 @@ sv_x(pTHX_ SV *sv, const char *str, STRLEN len, I32 n)
e448c1
     return sv;
e448c1
 }
e448c1
 
e448c1
+static SV *
e448c1
+deparsed_output(pTHX_ SV *val)
e448c1
+{
e448c1
+    SV *text;
e448c1
+    int n;
e448c1
+    dSP;
e448c1
+
e448c1
+    /* This is passed to load_module(), which decrements its ref count and
e448c1
+     * modifies it (so we also can't reuse it below) */
e448c1
+    SV *pkg = newSVpvs("B::Deparse");
e448c1
+
e448c1
+    load_module(PERL_LOADMOD_NOIMPORT, pkg, 0);
e448c1
+
e448c1
+    SAVETMPS;
e448c1
+
e448c1
+    PUSHMARK(SP);
e448c1
+    mXPUSHs(newSVpvs("B::Deparse"));
e448c1
+    PUTBACK;
e448c1
+
e448c1
+    n = call_method("new", G_SCALAR);
e448c1
+    SPAGAIN;
e448c1
+
e448c1
+    if (n != 1) {
e448c1
+        croak("B::Deparse->new returned %d items, but expected exactly 1", n);
e448c1
+    }
e448c1
+
e448c1
+    PUSHMARK(SP - n);
e448c1
+    XPUSHs(val);
e448c1
+    PUTBACK;
e448c1
+
e448c1
+    n = call_method("coderef2text", G_SCALAR);
e448c1
+    SPAGAIN;
e448c1
+
e448c1
+    if (n != 1) {
e448c1
+        croak("$b_deparse->coderef2text returned %d items, but expected exactly 1", n);
e448c1
+    }
e448c1
+
e448c1
+    text = POPs;
e448c1
+    SvREFCNT_inc(text);         /* the caller will mortalise this */
e448c1
+
e448c1
+    FREETMPS;
e448c1
+
e448c1
+    PUTBACK;
e448c1
+
e448c1
+    return text;
e448c1
+}
e448c1
+
e448c1
 /*
e448c1
  * This ought to be split into smaller functions. (it is one long function since
e448c1
  * it exactly parallels the perl version, which was one long thing for
e448c1
@@ -565,14 +613,14 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
e448c1
             i = perl_call_method(SvPVX_const(style->freezer), G_EVAL|G_VOID|G_DISCARD);
e448c1
 	    SPAGAIN;
e448c1
 	    if (SvTRUE(ERRSV))
e448c1
-		warn("WARNING(Freezer method call failed): %"SVf"", ERRSV);
e448c1
+		warn("WARNING(Freezer method call failed): %" SVf, ERRSV);
e448c1
 	    PUTBACK; FREETMPS; LEAVE;
e448c1
 	}
e448c1
 	
e448c1
 	ival = SvRV(val);
e448c1
 	realtype = SvTYPE(ival);
e448c1
 #ifdef DD_USE_OLD_ID_FORMAT
e448c1
-        idlen = my_snprintf(id, sizeof(id), "0x%"UVxf, PTR2UV(ival));
e448c1
+        idlen = my_snprintf(id, sizeof(id), "0x%" UVxf, PTR2UV(ival));
e448c1
 #else
e448c1
 	id_buffer = PTR2UV(ival);
e448c1
 	idlen = sizeof(id_buffer);
e448c1
@@ -630,7 +678,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
e448c1
 #ifdef DD_USE_OLD_ID_FORMAT
e448c1
 		    warn("ref name not found for %s", id);
e448c1
 #else
e448c1
-		    warn("ref name not found for 0x%"UVxf, PTR2UV(ival));
e448c1
+		    warn("ref name not found for 0x%" UVxf, PTR2UV(ival));
e448c1
 #endif
e448c1
 		    return 0;
e448c1
 		}
e448c1
@@ -848,10 +896,10 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
e448c1
 		ilen = inamelen;
e448c1
 		sv_setiv(ixsv, ix);
e448c1
 #if PERL_VERSION < 10
e448c1
-                (void) sprintf(iname+ilen, "%"IVdf, (IV)ix);
e448c1
+                (void) sprintf(iname+ilen, "%" IVdf, (IV)ix);
e448c1
 		ilen = strlen(iname);
e448c1
 #else
e448c1
-                ilen = ilen + my_sprintf(iname+ilen, "%"IVdf, (IV)ix);
e448c1
+                ilen = ilen + my_sprintf(iname+ilen, "%" IVdf, (IV)ix);
e448c1
 #endif
e448c1
 		iname[ilen++] = ']'; iname[ilen] = '\0';
e448c1
                 if (style->indent >= 3) {
e448c1
@@ -886,7 +934,6 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
e448c1
 	    SV *sname;
e448c1
 	    HE *entry = NULL;
e448c1
 	    char *key;
e448c1
-	    STRLEN klen;
e448c1
 	    SV *hval;
e448c1
 	    AV *keys = NULL;
e448c1
 	
e448c1
@@ -976,6 +1023,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
e448c1
                 char *nkey_buffer = NULL;
e448c1
                 STRLEN nticks = 0;
e448c1
 		SV* keysv;
e448c1
+                STRLEN klen;
e448c1
 		STRLEN keylen;
e448c1
                 STRLEN nlen;
e448c1
 		bool do_utf8 = FALSE;
e448c1
@@ -1029,7 +1077,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
e448c1
                 if (style->quotekeys || key_needs_quote(key,keylen)) {
e448c1
                     if (do_utf8 || style->useqq) {
e448c1
                         STRLEN ocur = SvCUR(retval);
e448c1
-                        nlen = esc_q_utf8(aTHX_ retval, key, klen, do_utf8, style->useqq);
e448c1
+                        klen = nlen = esc_q_utf8(aTHX_ retval, key, klen, do_utf8, style->useqq);
e448c1
                         nkey = SvPVX(retval) + ocur;
e448c1
                     }
e448c1
                     else {
e448c1
@@ -1095,9 +1143,41 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
e448c1
 	    SvREFCNT_dec(totpad);
e448c1
 	}
e448c1
 	else if (realtype == SVt_PVCV) {
e448c1
-	    sv_catpvs(retval, "sub { \"DUMMY\" }");
e448c1
-            if (style->purity)
e448c1
-		warn("Encountered CODE ref, using dummy placeholder");
e448c1
+            if (style->deparse) {
e448c1
+                SV *deparsed = sv_2mortal(deparsed_output(aTHX_ val));
e448c1
+                SV *fullpad = sv_2mortal(newSVsv(style->sep));
e448c1
+                const char *p;
e448c1
+                STRLEN plen;
e448c1
+                I32 i;
e448c1
+
e448c1
+                sv_catsv(fullpad, style->pad);
e448c1
+                sv_catsv(fullpad, apad);
e448c1
+                for (i = 0; i < level; i++) {
e448c1
+                    sv_catsv(fullpad, style->xpad);
e448c1
+                }
e448c1
+
e448c1
+                sv_catpvs(retval, "sub ");
e448c1
+                p = SvPV(deparsed, plen);
e448c1
+                while (plen > 0) {
e448c1
+                    const char *nl = (const char *) memchr(p, '\n', plen);
e448c1
+                    if (!nl) {
e448c1
+                        sv_catpvn(retval, p, plen);
e448c1
+                        break;
e448c1
+                    }
e448c1
+                    else {
e448c1
+                        size_t n = nl - p;
e448c1
+                        sv_catpvn(retval, p, n);
e448c1
+                        sv_catsv(retval, fullpad);
e448c1
+                        p += n + 1;
e448c1
+                        plen -= n + 1;
e448c1
+                    }
e448c1
+                }
e448c1
+            }
e448c1
+            else {
e448c1
+                sv_catpvs(retval, "sub { \"DUMMY\" }");
e448c1
+                if (style->purity)
e448c1
+                    warn("Encountered CODE ref, using dummy placeholder");
e448c1
+            }
e448c1
 	}
e448c1
 	else {
e448c1
 	    warn("cannot handle ref type %d", (int)realtype);
e448c1
@@ -1144,7 +1224,7 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
e448c1
 	
e448c1
 	if (namelen) {
e448c1
 #ifdef DD_USE_OLD_ID_FORMAT
e448c1
-	    idlen = my_snprintf(id, sizeof(id), "0x%"UVxf, PTR2UV(val));
e448c1
+	    idlen = my_snprintf(id, sizeof(id), "0x%" UVxf, PTR2UV(val));
e448c1
 #else
e448c1
 	    id_buffer = PTR2UV(val);
e448c1
 	    idlen = sizeof(id_buffer);
e448c1
@@ -1184,9 +1264,9 @@ DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
e448c1
         if (DD_is_integer(val)) {
e448c1
             STRLEN len;
e448c1
 	    if (SvIsUV(val))
e448c1
-	      len = my_snprintf(tmpbuf, sizeof(tmpbuf), "%"UVuf, SvUV(val));
e448c1
+	      len = my_snprintf(tmpbuf, sizeof(tmpbuf), "%" UVuf, SvUV(val));
e448c1
 	    else
e448c1
-	      len = my_snprintf(tmpbuf, sizeof(tmpbuf), "%"IVdf, SvIV(val));
e448c1
+	      len = my_snprintf(tmpbuf, sizeof(tmpbuf), "%" IVdf, SvIV(val));
e448c1
             if (SvPOK(val)) {
e448c1
               /* Need to check to see if this is a string such as " 0".
e448c1
                  I'm assuming from sprintf isn't going to clash with utf8. */
e448c1
@@ -1412,53 +1492,55 @@ Data_Dumper_Dumpxs(href, ...)
e448c1
 		&& (hv = (HV*)SvRV((SV*)href))
e448c1
 		&& SvTYPE(hv) == SVt_PVHV)		{
e448c1
 
e448c1
-		if ((svp = hv_fetch(hv, "seen", 4, FALSE)) && SvROK(*svp))
e448c1
+		if ((svp = hv_fetchs(hv, "seen", FALSE)) && SvROK(*svp))
e448c1
 		    seenhv = (HV*)SvRV(*svp);
e448c1
                 else
e448c1
                     style.use_sparse_seen_hash = 1;
e448c1
-		if ((svp = hv_fetch(hv, "noseen", 6, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "noseen", FALSE)))
e448c1
                     style.use_sparse_seen_hash = (SvOK(*svp) && SvIV(*svp) != 0);
e448c1
-		if ((svp = hv_fetch(hv, "todump", 6, FALSE)) && SvROK(*svp))
e448c1
+		if ((svp = hv_fetchs(hv, "todump", FALSE)) && SvROK(*svp))
e448c1
 		    todumpav = (AV*)SvRV(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "names", 5, FALSE)) && SvROK(*svp))
e448c1
+		if ((svp = hv_fetchs(hv, "names", FALSE)) && SvROK(*svp))
e448c1
 		    namesav = (AV*)SvRV(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "indent", 6, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "indent", FALSE)))
e448c1
                     style.indent = SvIV(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "purity", 6, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "purity", FALSE)))
e448c1
                     style.purity = SvIV(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "terse", 5, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "terse", FALSE)))
e448c1
 		    terse = SvTRUE(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "useqq", 5, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "useqq", FALSE)))
e448c1
                     style.useqq = SvTRUE(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "pad", 3, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "pad", FALSE)))
e448c1
                     style.pad = *svp;
e448c1
-		if ((svp = hv_fetch(hv, "xpad", 4, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "xpad", FALSE)))
e448c1
                     style.xpad = *svp;
e448c1
-		if ((svp = hv_fetch(hv, "apad", 4, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "apad", FALSE)))
e448c1
 		    apad = *svp;
e448c1
-		if ((svp = hv_fetch(hv, "sep", 3, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "sep", FALSE)))
e448c1
                     style.sep = *svp;
e448c1
-		if ((svp = hv_fetch(hv, "pair", 4, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "pair", FALSE)))
e448c1
                     style.pair = *svp;
e448c1
-		if ((svp = hv_fetch(hv, "varname", 7, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "varname", FALSE)))
e448c1
 		    varname = *svp;
e448c1
-		if ((svp = hv_fetch(hv, "freezer", 7, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "freezer", FALSE)))
e448c1
                     style.freezer = *svp;
e448c1
-		if ((svp = hv_fetch(hv, "toaster", 7, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "toaster", FALSE)))
e448c1
                     style.toaster = *svp;
e448c1
-		if ((svp = hv_fetch(hv, "deepcopy", 8, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "deepcopy", FALSE)))
e448c1
                     style.deepcopy = SvTRUE(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "quotekeys", 9, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "quotekeys", FALSE)))
e448c1
                     style.quotekeys = SvTRUE(*svp);
e448c1
-                if ((svp = hv_fetch(hv, "trailingcomma", 13, FALSE)))
e448c1
+                if ((svp = hv_fetchs(hv, "trailingcomma", FALSE)))
e448c1
                     style.trailingcomma = SvTRUE(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "bless", 5, FALSE)))
e448c1
+                if ((svp = hv_fetchs(hv, "deparse", FALSE)))
e448c1
+                    style.deparse = SvTRUE(*svp);
e448c1
+		if ((svp = hv_fetchs(hv, "bless", FALSE)))
e448c1
                     style.bless = *svp;
e448c1
-		if ((svp = hv_fetch(hv, "maxdepth", 8, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "maxdepth", FALSE)))
e448c1
                     style.maxdepth = SvIV(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "maxrecurse", 10, FALSE)))
e448c1
+		if ((svp = hv_fetchs(hv, "maxrecurse", FALSE)))
e448c1
                     style.maxrecurse = SvIV(*svp);
e448c1
-		if ((svp = hv_fetch(hv, "sortkeys", 8, FALSE))) {
e448c1
+		if ((svp = hv_fetchs(hv, "sortkeys", FALSE))) {
e448c1
                     SV *sv = *svp;
e448c1
                     if (! SvTRUE(sv))
e448c1
                         style.sortkeys = NULL;
e448c1
@@ -1525,9 +1607,10 @@ Data_Dumper_Dumpxs(href, ...)
e448c1
 		    }
e448c1
 		    else {
e448c1
 			STRLEN nchars;
e448c1
-			sv_setpvn(name, "$", 1);
e448c1
+			sv_setpvs(name, "$");
e448c1
 			sv_catsv(name, varname);
e448c1
-			nchars = my_snprintf(tmpbuf, sizeof(tmpbuf), "%"IVdf, (IV)(i+1));
e448c1
+			nchars = my_snprintf(tmpbuf, sizeof(tmpbuf), "%" IVdf,
e448c1
+                                                                     (IV)(i+1));
e448c1
 			sv_catpvn(name, tmpbuf, nchars);
e448c1
 		    }
e448c1
 		
e448c1
@@ -1575,7 +1658,7 @@ Data_Dumper_Dumpxs(href, ...)
e448c1
 			sv_catpvs(retval, ";");
e448c1
                         sv_catsv(retval, style.sep);
e448c1
 		    }
e448c1
-		    sv_setpvn(valstr, "", 0);
e448c1
+		    SvPVCLEAR(valstr);
e448c1
 		    if (gimme == G_ARRAY) {
e448c1
 			XPUSHs(sv_2mortal(retval));
e448c1
 			if (i < imax)	/* not the last time thro ? */
e448c1
diff --git a/t/bugs.t b/t/bugs.t
e448c1
index a440b0a..5db82da 100644
e448c1
--- a/t/bugs.t
e448c1
+++ b/t/bugs.t
e448c1
@@ -12,7 +12,7 @@ BEGIN {
e448c1
 }
e448c1
 
e448c1
 use strict;
e448c1
-use Test::More tests => 15;
e448c1
+use Test::More tests => 24;
e448c1
 use Data::Dumper;
e448c1
 
e448c1
 {
e448c1
@@ -144,4 +144,39 @@ SKIP: {
e448c1
   &$tests;
e448c1
 }
e448c1
 
e448c1
+{ # https://rt.perl.org/Ticket/Display.html?id=128524
e448c1
+    my $want;
e448c1
+    my $runtime = "runtime";
e448c1
+    my $requires = "requires";
e448c1
+    utf8::upgrade(my $uruntime = $runtime);
e448c1
+    utf8::upgrade(my $urequires = $requires);
e448c1
+    for my $run ($runtime, $uruntime) {
e448c1
+        for my $req ($requires, $urequires) {
e448c1
+            my $data = { $run => { $req => { foo => "bar" } } };
e448c1
+            local $Data::Dumper::Useperl = 1;
e448c1
+            # we want them all the same
e448c1
+            defined $want or $want = Dumper($data);
e448c1
+            is(Dumper( $data ), $want, "utf-8 indents");
e448c1
+          SKIP:
e448c1
+            {
e448c1
+                defined &Data::Dumper::Dumpxs
e448c1
+                  or skip "No XS available", 1;
e448c1
+                local $Data::Dumper::Useperl = 0;
e448c1
+                is(Dumper( $data ), $want, "utf8-indents");
e448c1
+            }
e448c1
+        }
e448c1
+    }
e448c1
+}
e448c1
+
e448c1
+# RT#130487 - stack management bug in XS deparse
e448c1
+SKIP: {
e448c1
+    skip "No XS available", 1 if !defined &Data::Dumper::Dumpxs;
e448c1
+    sub rt130487_args { 0 + @_ }
e448c1
+    my $code = sub {};
e448c1
+    local $Data::Dumper::Useperl = 0;
e448c1
+    local $Data::Dumper::Deparse = 1;
e448c1
+    my $got = rt130487_args( Dumper($code) );
e448c1
+    is($got, 1, "stack management in XS deparse works, rt 130487");
e448c1
+}
e448c1
+
e448c1
 # EOF
e448c1
diff --git a/t/deparse.t b/t/deparse.t
e448c1
index c281fce..cddde8c 100644
e448c1
--- a/t/deparse.t
e448c1
+++ b/t/deparse.t
e448c1
@@ -15,7 +15,7 @@ BEGIN {
e448c1
 use strict;
e448c1
 
e448c1
 use Data::Dumper;
e448c1
-use Test::More tests =>  8;
e448c1
+use Test::More tests =>  16;
e448c1
 use lib qw( ./t/lib );
e448c1
 use Testing qw( _dumptostr );
e448c1
 
e448c1
@@ -24,7 +24,9 @@ use Testing qw( _dumptostr );
e448c1
 
e448c1
 note("\$Data::Dumper::Deparse and Deparse()");
e448c1
 
e448c1
-{
e448c1
+for my $useperl (0, 1) {
e448c1
+    local $Data::Dumper::Useperl = $useperl;
e448c1
+
e448c1
     my ($obj, %dumps, $deparse, $starting);
e448c1
     use strict;
e448c1
     my $struct = { foo => "bar\nbaz", quux => sub { "fleem" } };
e448c1
@@ -46,11 +48,11 @@ note("\$Data::Dumper::Deparse and Deparse()");
e448c1
     $dumps{'objzero'} = _dumptostr($obj);
e448c1
 
e448c1
     is($dumps{'noprev'}, $dumps{'dddzero'},
e448c1
-        "No previous setting and \$Data::Dumper::Deparse = 0 are equivalent");
e448c1
+        "No previous setting and \$Data::Dumper::Deparse = 0 are equivalent (useperl=$useperl)");
e448c1
     is($dumps{'noprev'}, $dumps{'objempty'},
e448c1
-        "No previous setting and Deparse() are equivalent");
e448c1
+        "No previous setting and Deparse() are equivalent (useperl=$useperl)");
e448c1
     is($dumps{'noprev'}, $dumps{'objzero'},
e448c1
-        "No previous setting and Deparse(0) are equivalent");
e448c1
+        "No previous setting and Deparse(0) are equivalent (useperl=$useperl)");
e448c1
 
e448c1
     local $Data::Dumper::Deparse = 1;
e448c1
     $obj = Data::Dumper->new( [ $struct ] );
e448c1
@@ -62,19 +64,19 @@ note("\$Data::Dumper::Deparse and Deparse()");
e448c1
     $dumps{'objone'} = _dumptostr($obj);
e448c1
 
e448c1
     is($dumps{'dddtrue'}, $dumps{'objone'},
e448c1
-        "\$Data::Dumper::Deparse = 1 and Deparse(1) are equivalent");
e448c1
+        "\$Data::Dumper::Deparse = 1 and Deparse(1) are equivalent (useperl=$useperl)");
e448c1
 
e448c1
     isnt($dumps{'dddzero'}, $dumps{'dddtrue'},
e448c1
-        "\$Data::Dumper::Deparse = 0 differs from \$Data::Dumper::Deparse = 1");
e448c1
+        "\$Data::Dumper::Deparse = 0 differs from \$Data::Dumper::Deparse = 1 (useperl=$useperl)");
e448c1
 
e448c1
     like($dumps{'dddzero'},
e448c1
         qr/quux.*?sub.*?DUMMY/s,
e448c1
-        "\$Data::Dumper::Deparse = 0 reports DUMMY instead of deparsing coderef");
e448c1
+        "\$Data::Dumper::Deparse = 0 reports DUMMY instead of deparsing coderef (useperl=$useperl)");
e448c1
     unlike($dumps{'dddtrue'},
e448c1
         qr/quux.*?sub.*?DUMMY/s,
e448c1
-        "\$Data::Dumper::Deparse = 1 does not report DUMMY");
e448c1
+        "\$Data::Dumper::Deparse = 1 does not report DUMMY (useperl=$useperl)");
e448c1
     like($dumps{'dddtrue'},
e448c1
         qr/quux.*?sub.*?use\sstrict.*?fleem/s,
e448c1
-        "\$Data::Dumper::Deparse = 1 deparses coderef");
e448c1
+        "\$Data::Dumper::Deparse = 1 deparses coderef (useperl=$useperl)");
e448c1
 }
e448c1
 
e448c1
-- 
e448c1
2.9.3
e448c1