1 #define PERL_NO_GET_CONTEXT
10 # define DD_USE_OLD_ID_FORMAT
13 static I32 num_q (const char *s, STRLEN slen);
14 static I32 esc_q (char *dest, const char *src, STRLEN slen);
15 static I32 esc_q_utf8 (pTHX_ SV *sv, const char *src, STRLEN slen);
16 static I32 needs_quote(register const char *s);
17 static SV *sv_x (pTHX_ SV *sv, const char *str, STRLEN len, I32 n);
18 static I32 DD_dump (pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval,
19 HV *seenhv, AV *postav, I32 *levelp, I32 indent,
20 SV *pad, SV *xpad, SV *apad, SV *sep, SV *pair,
21 SV *freezer, SV *toaster,
22 I32 purity, I32 deepcopy, I32 quotekeys, SV *bless,
23 I32 maxdepth, SV *sortkeys);
26 #define HvNAME_get HvNAME
29 #if PERL_VERSION <= 6 /* Perl 5.6 and earlier */
32 # define UNI_TO_NATIVE(ch) (((ch) > 255) ? (ch) : ASCII_TO_NATIVE(ch))
34 # define UNI_TO_NATIVE(ch) (ch)
38 Perl_utf8_to_uvchr(pTHX_ U8 *s, STRLEN *retlen)
40 const UV uv = utf8_to_uv(s, UTF8_MAXLEN, retlen,
41 ckWARN(WARN_UTF8) ? 0 : UTF8_ALLOW_ANY);
42 return UNI_TO_NATIVE(uv);
45 # if !defined(PERL_IMPLICIT_CONTEXT)
46 # define utf8_to_uvchr Perl_utf8_to_uvchr
48 # define utf8_to_uvchr(a,b) Perl_utf8_to_uvchr(aTHX_ a,b)
51 #endif /* PERL_VERSION <= 6 */
53 /* Changes in 5.7 series mean that now IOK is only set if scalar is
54 precisely integer but in 5.6 and earlier we need to do a more
57 #define DD_is_integer(sv) (SvIOK(sv) && (SvIsUV(val) ? SvUV(sv) == SvNV(sv) : SvIV(sv) == SvNV(sv)))
59 #define DD_is_integer(sv) SvIOK(sv)
62 /* does a string need to be protected? */
64 needs_quote(register const char *s)
89 /* count the number of "'"s and "\"s in string */
91 num_q(register const char *s, register STRLEN slen)
96 if (*s == '\'' || *s == '\\')
105 /* returns number of chars added to escape "'"s and "\"s in s */
106 /* slen number of characters in s will be escaped */
107 /* destination must be long enough for additional chars */
109 esc_q(register char *d, register const char *s, register STRLEN slen)
111 register I32 ret = 0;
129 esc_q_utf8(pTHX_ SV* sv, register const char *src, register STRLEN slen)
133 const char * const send = src + slen;
134 STRLEN j, cur = SvCUR(sv);
135 /* Could count 128-255 and 256+ in two variables, if we want to
136 be like &qquote and make a distinction. */
137 STRLEN grow = 0; /* bytes needed to represent chars 128+ */
138 /* STRLEN topbit_grow = 0; bytes needed to represent chars 128-255 */
139 STRLEN backslashes = 0;
140 STRLEN single_quotes = 0;
141 STRLEN qq_escapables = 0; /* " $ @ will need a \ in "" strings. */
144 /* this will need EBCDICification */
145 for (s = src; s < send; s += UTF8SKIP(s)) {
146 const UV k = utf8_to_uvchr((U8*)s, NULL);
149 if (!isprint(k) || k > 256) {
153 /* 4: \x{} then count the number of hex digits. */
154 grow += 4 + (k <= 0xFF ? 2 : k <= 0xFFF ? 3 : k <= 0xFFFF ? 4 :
156 8 /* We may allocate a bit more than the minimum here. */
158 k <= 0xFFFFFFFF ? 8 : UVSIZE * 4
161 } else if (k == '\\') {
163 } else if (k == '\'') {
165 } else if (k == '"' || k == '$' || k == '@') {
172 /* We have something needing hex. 3 is ""\0 */
173 sv_grow(sv, cur + 3 + grow + 2*backslashes + single_quotes
174 + 2*qq_escapables + normal);
175 rstart = r = SvPVX(sv) + cur;
179 for (s = src; s < send; s += UTF8SKIP(s)) {
180 const UV k = utf8_to_uvchr((U8*)s, NULL);
182 if (k == '"' || k == '\\' || k == '$' || k == '@') {
188 if (isprint(k) && k < 256)
194 r = r + my_sprintf(r, "\\x{%"UVxf"}", k);
200 sv_grow(sv, cur + 3 + 2*backslashes + 2*single_quotes
201 + qq_escapables + normal);
202 rstart = r = SvPVX(sv) + cur;
204 for (s = src; s < send; s ++) {
206 if (k == '\'' || k == '\\')
214 SvCUR_set(sv, cur + j);
219 /* append a repeated string to an SV */
221 sv_x(pTHX_ SV *sv, const char *str, STRLEN len, I32 n)
224 sv = newSVpvn("", 0);
227 assert(SvTYPE(sv) >= SVt_PV);
231 SvGROW(sv, len*n + SvCUR(sv) + 1);
233 char * const start = SvPVX(sv) + SvCUR(sv);
234 SvCUR_set(sv, SvCUR(sv) + n);
241 sv_catpvn(sv, str, len);
249 * This ought to be split into smaller functions. (it is one long function since
250 * it exactly parallels the perl version, which was one long thing for
251 * efficiency raisins.) Ugggh!
254 DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,
255 AV *postav, I32 *levelp, I32 indent, SV *pad, SV *xpad,
256 SV *apad, SV *sep, SV *pair, SV *freezer, SV *toaster, I32 purity,
257 I32 deepcopy, I32 quotekeys, SV *bless, I32 maxdepth, SV *sortkeys)
261 char *c, *r, *realpack;
262 #ifdef DD_USE_OLD_ID_FORMAT
266 char *const id = (char *)&id_buffer;
269 SV *sv, *ipad, *ival;
270 SV *blesspad = Nullsv;
271 AV *seenentry = NULL;
273 STRLEN inamelen, idlen = 0;
279 /* If the ouput buffer has less than some arbitary amount of space
280 remaining, then enlarge it. For the test case (25M of output),
281 *1.1 was slower, *2.0 was the same, so the first guess of 1.5 is
282 deemed to be good enough. */
283 if (SvTYPE(retval) >= SVt_PV && (SvLEN(retval) - SvCUR(retval)) < 42) {
284 sv_grow(retval, SvCUR(retval) * 3 / 2);
287 realtype = SvTYPE(val);
293 /* If a freeze method is provided and the object has it, call
294 it. Warn on errors. */
295 if (SvOBJECT(SvRV(val)) && freezer &&
296 SvPOK(freezer) && SvCUR(freezer) &&
297 gv_fetchmeth(SvSTASH(SvRV(val)), SvPVX_const(freezer),
298 SvCUR(freezer), -1) != NULL)
300 dSP; ENTER; SAVETMPS; PUSHMARK(sp);
301 XPUSHs(val); PUTBACK;
302 i = perl_call_method(SvPVX_const(freezer), G_EVAL|G_VOID);
305 warn("WARNING(Freezer method call failed): %"SVf"", ERRSV);
306 PUTBACK; FREETMPS; LEAVE;
310 realtype = SvTYPE(ival);
311 #ifdef DD_USE_OLD_ID_FORMAT
312 idlen = my_snprintf(id, sizeof(id), "0x%"UVxf, PTR2UV(ival));
314 id_buffer = PTR2UV(ival);
315 idlen = sizeof(id_buffer);
318 realpack = HvNAME_get(SvSTASH(ival));
322 /* if it has a name, we need to either look it up, or keep a tab
323 * on it so we know when we hit it later
326 if ((svp = hv_fetch(seenhv, id, idlen, FALSE))
327 && (sv = *svp) && SvROK(sv) && (seenentry = (AV*)SvRV(sv)))
330 if ((svp = av_fetch(seenentry, 0, FALSE))
331 && (othername = *svp))
333 if (purity && *levelp > 0) {
336 if (realtype == SVt_PVHV)
337 sv_catpvn(retval, "{}", 2);
338 else if (realtype == SVt_PVAV)
339 sv_catpvn(retval, "[]", 2);
341 sv_catpvn(retval, "do{my $o}", 9);
342 postentry = newSVpvn(name, namelen);
343 sv_catpvn(postentry, " = ", 3);
344 sv_catsv(postentry, othername);
345 av_push(postav, postentry);
348 if (name[0] == '@' || name[0] == '%') {
349 if ((SvPVX_const(othername))[0] == '\\' &&
350 (SvPVX_const(othername))[1] == name[0]) {
351 sv_catpvn(retval, SvPVX_const(othername)+1,
355 sv_catpvn(retval, name, 1);
356 sv_catpvn(retval, "{", 1);
357 sv_catsv(retval, othername);
358 sv_catpvn(retval, "}", 1);
362 sv_catsv(retval, othername);
367 #ifdef DD_USE_OLD_ID_FORMAT
368 warn("ref name not found for %s", id);
370 warn("ref name not found for 0x%"UVxf, PTR2UV(ival));
375 else { /* store our name and continue */
377 if (name[0] == '@' || name[0] == '%') {
378 namesv = newSVpvn("\\", 1);
379 sv_catpvn(namesv, name, namelen);
381 else if (realtype == SVt_PVCV && name[0] == '*') {
382 namesv = newSVpvn("\\", 2);
383 sv_catpvn(namesv, name, namelen);
384 (SvPVX(namesv))[1] = '&';
387 namesv = newSVpvn(name, namelen);
389 av_push(seenentry, namesv);
390 (void)SvREFCNT_inc(val);
391 av_push(seenentry, val);
392 (void)hv_store(seenhv, id, idlen,
393 newRV_inc((SV*)seenentry), 0);
394 SvREFCNT_dec(seenentry);
398 if (realpack && *realpack == 'R' && strEQ(realpack, "Regexp")) {
400 const char *rval = SvPV(val, rlen);
401 const char *slash = strchr(rval, '/');
402 sv_catpvn(retval, "qr/", 3);
404 sv_catpvn(retval, rval, slash-rval);
405 sv_catpvn(retval, "\\/", 2);
406 rlen -= slash-rval+1;
408 slash = strchr(rval, '/');
410 sv_catpvn(retval, rval, rlen);
411 sv_catpvn(retval, "/", 1);
415 /* If purity is not set and maxdepth is set, then check depth:
416 * if we have reached maximum depth, return the string
417 * representation of the thing we are currently examining
418 * at this depth (i.e., 'Foo=ARRAY(0xdeadbeef)').
420 if (!purity && maxdepth > 0 && *levelp >= maxdepth) {
422 const char * const valstr = SvPV(val,vallen);
423 sv_catpvn(retval, "'", 1);
424 sv_catpvn(retval, valstr, vallen);
425 sv_catpvn(retval, "'", 1);
429 if (realpack) { /* we have a blessed ref */
431 const char * const blessstr = SvPV(bless, blesslen);
432 sv_catpvn(retval, blessstr, blesslen);
433 sv_catpvn(retval, "( ", 2);
436 apad = newSVsv(apad);
437 sv_x(aTHX_ apad, " ", 1, blesslen+2);
442 ipad = sv_x(aTHX_ Nullsv, SvPVX_const(xpad), SvCUR(xpad), *levelp);
451 SV * const namesv = newSVpvn("${", 2);
452 sv_catpvn(namesv, name, namelen);
453 sv_catpvn(namesv, "}", 1);
454 if (realpack) { /* blessed */
455 sv_catpvn(retval, "do{\\(my $o = ", 13);
456 DD_dump(aTHX_ ival, SvPVX_const(namesv), SvCUR(namesv), retval, seenhv,
457 postav, levelp, indent, pad, xpad, apad, sep, pair,
458 freezer, toaster, purity, deepcopy, quotekeys, bless,
460 sv_catpvn(retval, ")}", 2);
463 sv_catpvn(retval, "\\", 1);
464 DD_dump(aTHX_ ival, SvPVX_const(namesv), SvCUR(namesv), retval, seenhv,
465 postav, levelp, indent, pad, xpad, apad, sep, pair,
466 freezer, toaster, purity, deepcopy, quotekeys, bless,
469 SvREFCNT_dec(namesv);
471 else if (realtype == SVt_PVGV) { /* glob ref */
472 SV * const namesv = newSVpvn("*{", 2);
473 sv_catpvn(namesv, name, namelen);
474 sv_catpvn(namesv, "}", 1);
475 sv_catpvn(retval, "\\", 1);
476 DD_dump(aTHX_ ival, SvPVX_const(namesv), SvCUR(namesv), retval, seenhv,
477 postav, levelp, indent, pad, xpad, apad, sep, pair,
478 freezer, toaster, purity, deepcopy, quotekeys, bless,
480 SvREFCNT_dec(namesv);
482 else if (realtype == SVt_PVAV) {
485 const I32 ixmax = av_len((AV *)ival);
487 SV * const ixsv = newSViv(0);
488 /* allowing for a 24 char wide array index */
489 New(0, iname, namelen+28, char);
490 (void)strcpy(iname, name);
492 if (name[0] == '@') {
493 sv_catpvn(retval, "(", 1);
497 sv_catpvn(retval, "[", 1);
498 /* omit "->" in $foo{bar}->[0], but not in ${$foo}->[0] */
500 && name[namelen-1] != ']' && name[namelen-1] != '}'
501 && (namelen < 4 || (name[1] != '{' && name[2] != '{')))*/
503 && name[namelen-1] != ']' && name[namelen-1] != '}')
506 || (name[0] == '\\' && name[2] == '{'))))
508 iname[inamelen++] = '-'; iname[inamelen++] = '>';
509 iname[inamelen] = '\0';
512 if (iname[0] == '*' && iname[inamelen-1] == '}' && inamelen >= 8 &&
513 (instr(iname+inamelen-8, "{SCALAR}") ||
514 instr(iname+inamelen-7, "{ARRAY}") ||
515 instr(iname+inamelen-6, "{HASH}"))) {
516 iname[inamelen++] = '-'; iname[inamelen++] = '>';
518 iname[inamelen++] = '['; iname[inamelen] = '\0';
519 totpad = newSVsv(sep);
520 sv_catsv(totpad, pad);
521 sv_catsv(totpad, apad);
523 for (ix = 0; ix <= ixmax; ++ix) {
526 svp = av_fetch((AV*)ival, ix, FALSE);
534 ilen = ilen + my_sprintf(iname+ilen, "%"IVdf, (IV)ix);
535 iname[ilen++] = ']'; iname[ilen] = '\0';
537 sv_catsv(retval, totpad);
538 sv_catsv(retval, ipad);
539 sv_catpvn(retval, "#", 1);
540 sv_catsv(retval, ixsv);
542 sv_catsv(retval, totpad);
543 sv_catsv(retval, ipad);
544 DD_dump(aTHX_ elem, iname, ilen, retval, seenhv, postav,
545 levelp, indent, pad, xpad, apad, sep, pair,
546 freezer, toaster, purity, deepcopy, quotekeys, bless,
549 sv_catpvn(retval, ",", 1);
552 SV * const opad = sv_x(aTHX_ Nullsv, SvPVX_const(xpad), SvCUR(xpad), (*levelp)-1);
553 sv_catsv(retval, totpad);
554 sv_catsv(retval, opad);
558 sv_catpvn(retval, ")", 1);
560 sv_catpvn(retval, "]", 1);
562 SvREFCNT_dec(totpad);
565 else if (realtype == SVt_PVHV) {
566 SV *totpad, *newapad;
574 SV * const iname = newSVpvn(name, namelen);
575 if (name[0] == '%') {
576 sv_catpvn(retval, "(", 1);
577 (SvPVX(iname))[0] = '$';
580 sv_catpvn(retval, "{", 1);
581 /* omit "->" in $foo[0]->{bar}, but not in ${$foo}->{bar} */
583 && name[namelen-1] != ']' && name[namelen-1] != '}')
586 || (name[0] == '\\' && name[2] == '{'))))
588 sv_catpvn(iname, "->", 2);
591 if (name[0] == '*' && name[namelen-1] == '}' && namelen >= 8 &&
592 (instr(name+namelen-8, "{SCALAR}") ||
593 instr(name+namelen-7, "{ARRAY}") ||
594 instr(name+namelen-6, "{HASH}"))) {
595 sv_catpvn(iname, "->", 2);
597 sv_catpvn(iname, "{", 1);
598 totpad = newSVsv(sep);
599 sv_catsv(totpad, pad);
600 sv_catsv(totpad, apad);
602 /* If requested, get a sorted/filtered array of hash keys */
604 if (sortkeys == &PL_sv_yes) {
606 sortkeys = sv_2mortal(newSVpvn("Data::Dumper::_sortkeys", 23));
609 (void)hv_iterinit((HV*)ival);
610 while ((entry = hv_iternext((HV*)ival))) {
611 sv = hv_iterkeysv(entry);
615 # ifdef USE_LOCALE_NUMERIC
616 sortsv(AvARRAY(keys),
618 IN_LOCALE ? Perl_sv_cmp_locale : Perl_sv_cmp);
620 sortsv(AvARRAY(keys),
626 if (sortkeys != &PL_sv_yes) {
627 dSP; ENTER; SAVETMPS; PUSHMARK(sp);
628 XPUSHs(sv_2mortal(newRV_inc(ival))); PUTBACK;
629 i = perl_call_sv(sortkeys, G_SCALAR | G_EVAL);
633 if (SvROK(sv) && (SvTYPE(SvRV(sv)) == SVt_PVAV))
634 keys = (AV*)SvREFCNT_inc(SvRV(sv));
637 warn("Sortkeys subroutine did not return ARRAYREF\n");
638 PUTBACK; FREETMPS; LEAVE;
641 sv_2mortal((SV*)keys);
644 (void)hv_iterinit((HV*)ival);
646 /* foreach (keys %hash) */
647 for (i = 0; 1; i++) {
649 char *nkey_buffer = NULL;
654 bool do_utf8 = FALSE;
657 if (!(keys && (I32)i <= av_len(keys))) break;
659 if (!(entry = hv_iternext((HV *)ival))) break;
663 sv_catpvn(retval, ",", 1);
667 svp = av_fetch(keys, i, FALSE);
668 keysv = svp ? *svp : sv_mortalcopy(&PL_sv_undef);
669 key = SvPV(keysv, keylen);
670 svp = hv_fetch((HV*)ival, key,
671 SvUTF8(keysv) ? -(I32)keylen : keylen, 0);
672 hval = svp ? *svp : sv_mortalcopy(&PL_sv_undef);
675 keysv = hv_iterkeysv(entry);
676 hval = hv_iterval((HV*)ival, entry);
679 key = SvPV(keysv, keylen);
680 do_utf8 = DO_UTF8(keysv);
683 sv_catsv(retval, totpad);
684 sv_catsv(retval, ipad);
685 /* old logic was first to check utf8 flag, and if utf8 always
686 call esc_q_utf8. This caused test to break under -Mutf8,
687 because there even strings like 'c' have utf8 flag on.
688 Hence with quotekeys == 0 the XS code would still '' quote
689 them based on flags, whereas the perl code would not,
691 The perl code is correct.
692 needs_quote() decides that anything that isn't a valid
693 perl identifier needs to be quoted, hence only correctly
694 formed strings with no characters outside [A-Za-z0-9_:]
695 won't need quoting. None of those characters are used in
696 the byte encoding of utf8, so anything with utf8
697 encoded characters in will need quoting. Hence strings
698 with utf8 encoded characters in will end up inside do_utf8
699 just like before, but now strings with utf8 flag set but
700 only ascii characters will end up in the unquoted section.
702 There should also be less tests for the (probably currently)
703 more common doesn't need quoting case.
704 The code is also smaller (22044 vs 22260) because I've been
705 able to pull the common logic out to both sides. */
706 if (quotekeys || needs_quote(key)) {
708 STRLEN ocur = SvCUR(retval);
709 nlen = esc_q_utf8(aTHX_ retval, key, klen);
710 nkey = SvPVX(retval) + ocur;
713 nticks = num_q(key, klen);
714 New(0, nkey_buffer, klen+nticks+3, char);
718 klen += esc_q(nkey+1, key, klen);
720 (void)Copy(key, nkey+1, klen, char);
724 sv_catpvn(retval, nkey, klen);
730 sv_catpvn(retval, nkey, klen);
732 sname = newSVsv(iname);
733 sv_catpvn(sname, nkey, nlen);
734 sv_catpvn(sname, "}", 1);
736 sv_catsv(retval, pair);
740 newapad = newSVsv(apad);
741 New(0, extra, klen+4+1, char);
742 while (elen < (klen+4))
745 sv_catpvn(newapad, extra, elen);
751 DD_dump(aTHX_ hval, SvPVX_const(sname), SvCUR(sname), retval, seenhv,
752 postav, levelp, indent, pad, xpad, newapad, sep, pair,
753 freezer, toaster, purity, deepcopy, quotekeys, bless,
756 Safefree(nkey_buffer);
758 SvREFCNT_dec(newapad);
761 SV *opad = sv_x(aTHX_ Nullsv, SvPVX_const(xpad), SvCUR(xpad), *levelp-1);
762 sv_catsv(retval, totpad);
763 sv_catsv(retval, opad);
767 sv_catpvn(retval, ")", 1);
769 sv_catpvn(retval, "}", 1);
771 SvREFCNT_dec(totpad);
773 else if (realtype == SVt_PVCV) {
774 sv_catpvn(retval, "sub { \"DUMMY\" }", 15);
776 warn("Encountered CODE ref, using dummy placeholder");
779 warn("cannot handle ref type %ld", realtype);
782 if (realpack) { /* free blessed allocs */
787 sv_catpvn(retval, ", '", 3);
788 sv_catpvn(retval, realpack, strlen(realpack));
789 sv_catpvn(retval, "' )", 3);
790 if (toaster && SvPOK(toaster) && SvCUR(toaster)) {
791 sv_catpvn(retval, "->", 2);
792 sv_catsv(retval, toaster);
793 sv_catpvn(retval, "()", 2);
803 #ifdef DD_USE_OLD_ID_FORMAT
804 idlen = my_snprintf(id, sizeof(id), "0x%"UVxf, PTR2UV(val));
806 id_buffer = PTR2UV(val);
807 idlen = sizeof(id_buffer);
809 if ((svp = hv_fetch(seenhv, id, idlen, FALSE)) &&
810 (sv = *svp) && SvROK(sv) &&
811 (seenentry = (AV*)SvRV(sv)))
814 if ((svp = av_fetch(seenentry, 0, FALSE)) && (othername = *svp)
815 && (svp = av_fetch(seenentry, 2, FALSE)) && *svp && SvIV(*svp) > 0)
817 sv_catpvn(retval, "${", 2);
818 sv_catsv(retval, othername);
819 sv_catpvn(retval, "}", 1);
823 else if (val != &PL_sv_undef) {
824 SV * const namesv = newSVpvn("\\", 1);
825 sv_catpvn(namesv, name, namelen);
827 av_push(seenentry, namesv);
828 av_push(seenentry, newRV_inc(val));
829 (void)hv_store(seenhv, id, idlen, newRV_inc((SV*)seenentry), 0);
830 SvREFCNT_dec(seenentry);
834 if (DD_is_integer(val)) {
837 len = my_snprintf(tmpbuf, sizeof(tmpbuf), "%"UVuf, SvUV(val));
839 len = my_snprintf(tmpbuf, sizeof(tmpbuf), "%"IVdf, SvIV(val));
841 /* Need to check to see if this is a string such as " 0".
842 I'm assuming from sprintf isn't going to clash with utf8.
843 Is this valid on EBCDIC? */
845 const char * const pv = SvPV(val, pvlen);
846 if (pvlen != len || memNE(pv, tmpbuf, len))
847 goto integer_came_from_string;
850 /* Looks like we're on a 64 bit system. Make it a string so that
851 if a 32 bit system reads the number it will cope better. */
852 sv_catpvf(retval, "'%s'", tmpbuf);
854 sv_catpvn(retval, tmpbuf, len);
856 else if (realtype == SVt_PVGV) {/* GLOBs can end up with scribbly names */
858 ++c; --i; /* just get the name */
859 if (i >= 6 && strncmp(c, "main::", 6) == 0) {
863 if (needs_quote(c)) {
864 sv_grow(retval, SvCUR(retval)+6+2*i);
865 r = SvPVX(retval)+SvCUR(retval);
866 r[0] = '*'; r[1] = '{'; r[2] = '\'';
867 i += esc_q(r+3, c, i);
869 r[i++] = '\''; r[i++] = '}';
873 sv_grow(retval, SvCUR(retval)+i+2);
874 r = SvPVX(retval)+SvCUR(retval);
875 r[0] = '*'; strcpy(r+1, c);
878 SvCUR_set(retval, SvCUR(retval)+i);
881 static const char* const entries[] = { "{SCALAR}", "{ARRAY}", "{HASH}" };
882 static const STRLEN sizes[] = { 8, 7, 6 };
884 SV * const nname = newSVpvn("", 0);
885 SV * const newapad = newSVpvn("", 0);
886 GV * const gv = (GV*)val;
889 for (j=0; j<3; j++) {
890 e = ((j == 0) ? GvSV(gv) : (j == 1) ? (SV*)GvAV(gv) : (SV*)GvHV(gv));
893 if (j == 0 && !SvOK(e))
898 SV *postentry = newSVpvn(r,i);
900 sv_setsv(nname, postentry);
901 sv_catpvn(nname, entries[j], sizes[j]);
902 sv_catpvn(postentry, " = ", 3);
903 av_push(postav, postentry);
906 SvCUR_set(newapad, 0);
908 (void)sv_x(aTHX_ newapad, " ", 1, SvCUR(postentry));
910 DD_dump(aTHX_ e, SvPVX_const(nname), SvCUR(nname), postentry,
911 seenhv, postav, &nlevel, indent, pad, xpad,
912 newapad, sep, pair, freezer, toaster, purity,
913 deepcopy, quotekeys, bless, maxdepth,
919 SvREFCNT_dec(newapad);
923 else if (val == &PL_sv_undef || !SvOK(val)) {
924 sv_catpvn(retval, "undef", 5);
927 integer_came_from_string:
930 i += esc_q_utf8(aTHX_ retval, c, i);
932 sv_grow(retval, SvCUR(retval)+3+2*i); /* 3: ""\0 */
933 r = SvPVX(retval) + SvCUR(retval);
935 i += esc_q(r+1, c, i);
939 SvCUR_set(retval, SvCUR(retval)+i);
946 (void)hv_delete(seenhv, id, idlen, G_DISCARD);
947 else if (namelen && seenentry) {
948 SV *mark = *av_fetch(seenentry, 2, TRUE);
956 MODULE = Data::Dumper PACKAGE = Data::Dumper PREFIX = Data_Dumper_
959 # This is the exact equivalent of Dump. Well, almost. The things that are
960 # different as of now (due to Laziness):
961 # * doesnt do double-quotes yet.
965 Data_Dumper_Dumpxs(href, ...)
973 AV *postav, *todumpav, *namesav;
975 I32 indent, terse, i, imax, postlen;
977 SV *val, *name, *pad, *xpad, *apad, *sep, *pair, *varname;
978 SV *freezer, *toaster, *bless, *sortkeys;
979 I32 purity, deepcopy, quotekeys, maxdepth = 0;
983 if (!SvROK(href)) { /* call new to get an object first */
985 croak("Usage: Data::Dumper::Dumpxs(PACKAGE, VAL_ARY_REF, [NAME_ARY_REF])");
992 XPUSHs(sv_2mortal(newSVsv(ST(1))));
994 XPUSHs(sv_2mortal(newSVsv(ST(2))));
996 i = perl_call_method("new", G_SCALAR);
999 href = newSVsv(POPs);
1005 (void)sv_2mortal(href);
1008 todumpav = namesav = NULL;
1010 val = pad = xpad = apad = sep = pair = varname
1011 = freezer = toaster = bless = sortkeys = &PL_sv_undef;
1012 name = sv_newmortal();
1014 terse = purity = deepcopy = 0;
1017 retval = newSVpvn("", 0);
1019 && (hv = (HV*)SvRV((SV*)href))
1020 && SvTYPE(hv) == SVt_PVHV) {
1022 if ((svp = hv_fetch(hv, "seen", 4, FALSE)) && SvROK(*svp))
1023 seenhv = (HV*)SvRV(*svp);
1024 if ((svp = hv_fetch(hv, "todump", 6, FALSE)) && SvROK(*svp))
1025 todumpav = (AV*)SvRV(*svp);
1026 if ((svp = hv_fetch(hv, "names", 5, FALSE)) && SvROK(*svp))
1027 namesav = (AV*)SvRV(*svp);
1028 if ((svp = hv_fetch(hv, "indent", 6, FALSE)))
1029 indent = SvIV(*svp);
1030 if ((svp = hv_fetch(hv, "purity", 6, FALSE)))
1031 purity = SvIV(*svp);
1032 if ((svp = hv_fetch(hv, "terse", 5, FALSE)))
1033 terse = SvTRUE(*svp);
1034 #if 0 /* useqq currently unused */
1035 if ((svp = hv_fetch(hv, "useqq", 5, FALSE)))
1036 useqq = SvTRUE(*svp);
1038 if ((svp = hv_fetch(hv, "pad", 3, FALSE)))
1040 if ((svp = hv_fetch(hv, "xpad", 4, FALSE)))
1042 if ((svp = hv_fetch(hv, "apad", 4, FALSE)))
1044 if ((svp = hv_fetch(hv, "sep", 3, FALSE)))
1046 if ((svp = hv_fetch(hv, "pair", 4, FALSE)))
1048 if ((svp = hv_fetch(hv, "varname", 7, FALSE)))
1050 if ((svp = hv_fetch(hv, "freezer", 7, FALSE)))
1052 if ((svp = hv_fetch(hv, "toaster", 7, FALSE)))
1054 if ((svp = hv_fetch(hv, "deepcopy", 8, FALSE)))
1055 deepcopy = SvTRUE(*svp);
1056 if ((svp = hv_fetch(hv, "quotekeys", 9, FALSE)))
1057 quotekeys = SvTRUE(*svp);
1058 if ((svp = hv_fetch(hv, "bless", 5, FALSE)))
1060 if ((svp = hv_fetch(hv, "maxdepth", 8, FALSE)))
1061 maxdepth = SvIV(*svp);
1062 if ((svp = hv_fetch(hv, "sortkeys", 8, FALSE))) {
1064 if (! SvTRUE(sortkeys))
1066 else if (! (SvROK(sortkeys) &&
1067 SvTYPE(SvRV(sortkeys)) == SVt_PVCV) )
1069 /* flag to use qsortsv() for sorting hash keys */
1070 sortkeys = &PL_sv_yes;
1076 imax = av_len(todumpav);
1079 valstr = newSVpvn("",0);
1080 for (i = 0; i <= imax; ++i) {
1084 if ((svp = av_fetch(todumpav, i, FALSE)))
1088 if ((svp = av_fetch(namesav, i, TRUE))) {
1089 sv_setsv(name, *svp);
1090 if (SvOK(*svp) && !SvPOK(*svp))
1091 (void)SvPV_nolen_const(name);
1094 (void)SvOK_off(name);
1097 if ((SvPVX_const(name))[0] == '*') {
1099 switch (SvTYPE(SvRV(val))) {
1101 (SvPVX(name))[0] = '@';
1104 (SvPVX(name))[0] = '%';
1107 (SvPVX(name))[0] = '*';
1110 (SvPVX(name))[0] = '$';
1115 (SvPVX(name))[0] = '$';
1117 else if ((SvPVX_const(name))[0] != '$')
1118 sv_insert(name, 0, 0, "$", 1);
1122 sv_setpvn(name, "$", 1);
1123 sv_catsv(name, varname);
1124 nchars = my_snprintf(tmpbuf, sizeof(tmpbuf), "%"IVdf, (IV)(i+1));
1125 sv_catpvn(name, tmpbuf, nchars);
1129 SV * const tmpsv = sv_x(aTHX_ NULL, " ", 1, SvCUR(name)+3);
1130 newapad = newSVsv(apad);
1131 sv_catsv(newapad, tmpsv);
1132 SvREFCNT_dec(tmpsv);
1137 DD_dump(aTHX_ val, SvPVX_const(name), SvCUR(name), valstr, seenhv,
1138 postav, &level, indent, pad, xpad, newapad, sep, pair,
1139 freezer, toaster, purity, deepcopy, quotekeys,
1140 bless, maxdepth, sortkeys);
1143 SvREFCNT_dec(newapad);
1145 postlen = av_len(postav);
1146 if (postlen >= 0 || !terse) {
1147 sv_insert(valstr, 0, 0, " = ", 3);
1148 sv_insert(valstr, 0, 0, SvPVX_const(name), SvCUR(name));
1149 sv_catpvn(valstr, ";", 1);
1151 sv_catsv(retval, pad);
1152 sv_catsv(retval, valstr);
1153 sv_catsv(retval, sep);
1156 sv_catsv(retval, pad);
1157 for (i = 0; i <= postlen; ++i) {
1159 svp = av_fetch(postav, i, FALSE);
1160 if (svp && (elem = *svp)) {
1161 sv_catsv(retval, elem);
1163 sv_catpvn(retval, ";", 1);
1164 sv_catsv(retval, sep);
1165 sv_catsv(retval, pad);
1169 sv_catpvn(retval, ";", 1);
1170 sv_catsv(retval, sep);
1172 sv_setpvn(valstr, "", 0);
1173 if (gimme == G_ARRAY) {
1174 XPUSHs(sv_2mortal(retval));
1175 if (i < imax) /* not the last time thro ? */
1176 retval = newSVpvn("",0);
1179 SvREFCNT_dec(postav);
1180 SvREFCNT_dec(valstr);
1183 croak("Call to new() method failed to return HASH ref");
1184 if (gimme == G_SCALAR)
1185 XPUSHs(sv_2mortal(retval));