14 static I32 num_q _((char *s));
15 static I32 esc_q _((char *dest, char *src, STRLEN slen));
16 static SV *sv_x _((SV *sv, char *str, STRLEN len, I32 n));
17 static I32 DD_dump _((SV *val, char *name, STRLEN namelen, SV *retval,
18 HV *seenhv, AV *postav, I32 *levelp, I32 indent,
19 SV *pad, SV *xpad, SV *apad, SV *sep,
20 SV *freezer, SV *toaster,
21 I32 purity, I32 deepcopy, I32 quotekeys, SV *bless));
23 /* does a string need to be protected? */
25 needs_quote(register char *s)
49 /* count the number of "'"s and "\"s in string */
51 num_q(register char *s)
56 if (*s == '\'' || *s == '\\')
64 /* returns number of chars added to escape "'"s and "\"s in s */
65 /* slen number of characters in s will be escaped */
66 /* destination must be long enough for additional chars */
68 esc_q(register char *d, register char *s, register STRLEN slen)
87 /* append a repeated string to an SV */
89 sv_x(SV *sv, register char *str, STRLEN len, I32 n)
94 assert(SvTYPE(sv) >= SVt_PV);
97 SvGROW(sv, len*n + SvCUR(sv) + 1);
99 char *start = SvPVX(sv) + SvCUR(sv);
107 sv_catpvn(sv, str, len);
115 * This ought to be split into smaller functions. (it is one long function since
116 * it exactly parallels the perl version, which was one long thing for
117 * efficiency raisins.) Ugggh!
120 DD_dump(SV *val, char *name, STRLEN namelen, SV *retval, HV *seenhv,
121 AV *postav, I32 *levelp, I32 indent, SV *pad, SV *xpad,
122 SV *apad, SV *sep, SV *freezer, SV *toaster, I32 purity,
123 I32 deepcopy, I32 quotekeys, SV *bless)
127 char *c, *r, *realpack, id[128];
130 SV *blesspad = Nullsv;
135 STRLEN inamelen, idlen = 0;
142 flags = SvFLAGS(val);
143 realtype = SvTYPE(val);
147 if (val == &sv_undef || !SvOK(val)) {
148 sv_catpvn(retval, "undef", 5);
153 if (SvOBJECT(SvRV(val)) && freezer &&
154 SvPOK(freezer) && SvCUR(freezer))
156 dSP; ENTER; SAVETMPS; PUSHMARK(sp);
157 XPUSHs(val); PUTBACK;
158 i = perl_call_method(SvPVX(freezer), G_EVAL|G_SCALAR);
160 if (SvTRUE(GvSV(errgv)))
161 warn("WARNING(Freezer method call failed): %s",
165 PUTBACK; FREETMPS; LEAVE;
167 (void)sv_2mortal(val);
171 flags = SvFLAGS(ival);
172 realtype = SvTYPE(ival);
173 (void) sprintf(id, "0x%lx", (unsigned long)ival);
176 realpack = HvNAME(SvSTASH(ival));
179 if ((svp = hv_fetch(seenhv, id, idlen, FALSE)) &&
180 (sv = *svp) && SvROK(sv) &&
181 (seenentry = (AV*)SvRV(sv))) {
183 if ((svp = av_fetch(seenentry, 0, FALSE)) && (othername = *svp)) {
184 if (purity && *levelp > 0) {
187 if (realtype == SVt_PVHV)
188 sv_catpvn(retval, "{}", 2);
189 else if (realtype == SVt_PVAV)
190 sv_catpvn(retval, "[]", 2);
192 sv_catpvn(retval, "''", 2);
193 postentry = newSVpv(name, namelen);
194 sv_catpvn(postentry, " = ", 3);
195 sv_catsv(postentry, othername);
196 av_push(postav, postentry);
199 if (name[0] == '@' || name[0] == '%') {
200 if ((SvPVX(othername))[0] == '\\' &&
201 (SvPVX(othername))[1] == name[0]) {
202 sv_catpvn(retval, SvPVX(othername)+1, SvCUR(othername)-1);
205 sv_catpvn(retval, name, 1);
206 sv_catpvn(retval, "{", 1);
207 sv_catsv(retval, othername);
208 sv_catpvn(retval, "}", 1);
212 sv_catsv(retval, othername);
217 warn("ref name not found for %s", id);
221 else { /* store our name and continue */
223 if (name[0] == '@' || name[0] == '%') {
224 namesv = newSVpv("\\", 1);
225 sv_catpvn(namesv, name, namelen);
227 else if (realtype == SVt_PVCV && name[0] == '*') {
228 namesv = newSVpv("\\", 2);
229 sv_catpvn(namesv, name, namelen);
230 (SvPVX(namesv))[1] = '&';
233 namesv = newSVpv(name, namelen);
235 av_push(seenentry, namesv);
236 (void)SvREFCNT_inc(val);
237 av_push(seenentry, val);
238 (void)hv_store(seenhv, id, strlen(id), newRV((SV*)seenentry), 0);
239 SvREFCNT_dec(seenentry);
243 ipad = sv_x(Nullsv, SvPVX(xpad), SvCUR(xpad), *levelp);
245 if (realpack) { /* we have a blessed ref */
247 char *blessstr = SvPV(bless, blesslen);
248 sv_catpvn(retval, blessstr, blesslen);
249 sv_catpvn(retval, "( ", 2);
252 apad = newSVsv(apad);
253 sv_x(apad, " ", 1, blesslen+2);
257 if (realtype <= SVt_PVBM || realtype == SVt_PVGV) { /* scalars */
258 if (realpack && realtype != SVt_PVGV) { /* blessed */
259 sv_catpvn(retval, "do{\\(my $o = ", 13);
260 DD_dump(ival, "", 0, retval, seenhv, postav,
261 levelp, indent, pad, xpad, apad, sep,
262 freezer, toaster, purity, deepcopy, quotekeys, bless);
263 sv_catpvn(retval, ")}", 2);
266 sv_catpvn(retval, "\\", 1);
267 DD_dump(ival, "", 0, retval, seenhv, postav,
268 levelp, indent, pad, xpad, apad, sep,
269 freezer, toaster, purity, deepcopy, quotekeys, bless);
272 else if (realtype == SVt_PVAV) {
275 I32 ixmax = av_len((AV *)ival);
277 SV *ixsv = newSViv(0);
278 /* allowing for a 24 char wide array index */
279 New(0, iname, namelen+28, char);
280 (void)strcpy(iname, name);
282 if (name[0] == '@') {
283 sv_catpvn(retval, "(", 1);
287 sv_catpvn(retval, "[", 1);
288 if (namelen > 0 && name[namelen-1] != ']' && name[namelen-1] != '}') {
289 iname[inamelen++] = '-'; iname[inamelen++] = '>';
290 iname[inamelen] = '\0';
293 if (iname[0] == '*' && iname[inamelen-1] == '}' && inamelen >= 8 &&
294 (instr(iname+inamelen-8, "{SCALAR}") ||
295 instr(iname+inamelen-7, "{ARRAY}") ||
296 instr(iname+inamelen-6, "{HASH}"))) {
297 iname[inamelen++] = '-'; iname[inamelen++] = '>';
299 iname[inamelen++] = '['; iname[inamelen] = '\0';
300 totpad = newSVsv(sep);
301 sv_catsv(totpad, pad);
302 sv_catsv(totpad, apad);
304 for (ix = 0; ix <= ixmax; ++ix) {
307 svp = av_fetch((AV*)ival, ix, FALSE);
315 (void) sprintf(iname+ilen, "%ld", ix);
316 ilen = strlen(iname);
317 iname[ilen++] = ']'; iname[ilen] = '\0';
319 sv_catsv(retval, totpad);
320 sv_catsv(retval, ipad);
321 sv_catpvn(retval, "#", 1);
322 sv_catsv(retval, ixsv);
324 sv_catsv(retval, totpad);
325 sv_catsv(retval, ipad);
326 DD_dump(elem, iname, ilen, retval, seenhv, postav,
327 levelp, indent, pad, xpad, apad, sep,
328 freezer, toaster, purity, deepcopy, quotekeys, bless);
330 sv_catpvn(retval, ",", 1);
333 SV *opad = sv_x(Nullsv, SvPVX(xpad), SvCUR(xpad), (*levelp)-1);
334 sv_catsv(retval, totpad);
335 sv_catsv(retval, opad);
339 sv_catpvn(retval, ")", 1);
341 sv_catpvn(retval, "]", 1);
343 SvREFCNT_dec(totpad);
346 else if (realtype == SVt_PVHV) {
347 SV *totpad, *newapad;
354 iname = newSVpv(name, namelen);
355 if (name[0] == '%') {
356 sv_catpvn(retval, "(", 1);
357 (SvPVX(iname))[0] = '$';
360 sv_catpvn(retval, "{", 1);
361 if (namelen > 0 && name[namelen-1] != ']' && name[namelen-1] != '}') {
362 sv_catpvn(iname, "->", 2);
365 if (name[0] == '*' && name[namelen-1] == '}' && namelen >= 8 &&
366 (instr(name+namelen-8, "{SCALAR}") ||
367 instr(name+namelen-7, "{ARRAY}") ||
368 instr(name+namelen-6, "{HASH}"))) {
369 sv_catpvn(iname, "->", 2);
371 sv_catpvn(iname, "{", 1);
372 totpad = newSVsv(sep);
373 sv_catsv(totpad, pad);
374 sv_catsv(totpad, apad);
376 (void)hv_iterinit((HV*)ival);
378 while ((entry = hv_iternext((HV*)ival))) {
383 sv_catpvn(retval, ",", 1);
385 key = hv_iterkey(entry, &klen);
386 hval = hv_iterval((HV*)ival, entry);
388 if (quotekeys || needs_quote(key)) {
390 New(0, nkey, klen+nticks+3, char);
393 klen += esc_q(nkey+1, key, klen);
395 (void)Copy(key, nkey+1, klen, char);
400 New(0, nkey, klen, char);
401 (void)Copy(key, nkey, klen, char);
404 sname = newSVsv(iname);
405 sv_catpvn(sname, nkey, klen);
406 sv_catpvn(sname, "}", 1);
408 sv_catsv(retval, totpad);
409 sv_catsv(retval, ipad);
410 sv_catpvn(retval, nkey, klen);
411 sv_catpvn(retval, " => ", 4);
415 newapad = newSVsv(apad);
416 New(0, extra, klen+4+1, char);
417 while (elen < (klen+4))
420 sv_catpvn(newapad, extra, elen);
426 DD_dump(hval, SvPVX(sname), SvCUR(sname), retval, seenhv,
427 postav, levelp, indent, pad, xpad, newapad, sep,
428 freezer, toaster, purity, deepcopy, quotekeys, bless);
432 SvREFCNT_dec(newapad);
435 SV *opad = sv_x(Nullsv, SvPVX(xpad), SvCUR(xpad), *levelp-1);
436 sv_catsv(retval, totpad);
437 sv_catsv(retval, opad);
441 sv_catpvn(retval, ")", 1);
443 sv_catpvn(retval, "}", 1);
445 SvREFCNT_dec(totpad);
447 else if (realtype == SVt_PVCV) {
448 sv_catpvn(retval, "sub { \"DUMMY\" }", 15);
450 warn("Encountered CODE ref, using dummy placeholder");
453 warn("cannot handle ref type %ld", realtype);
456 if (realpack) { /* free blessed allocs */
461 sv_catpvn(retval, ", '", 3);
462 sv_catpvn(retval, realpack, strlen(realpack));
463 sv_catpvn(retval, "' )", 3);
464 if (toaster && SvPOK(toaster) && SvCUR(toaster)) {
465 sv_catpvn(retval, "->", 2);
466 sv_catsv(retval, toaster);
467 sv_catpvn(retval, "()", 2);
477 (void) sprintf(id, "0x%lx", (unsigned long)val);
478 if ((svp = hv_fetch(seenhv, id, (idlen = strlen(id)), FALSE)) &&
479 (sv = *svp) && SvROK(sv) &&
480 (seenentry = (AV*)SvRV(sv))) {
482 if ((svp = av_fetch(seenentry, 0, FALSE)) && (othername = *svp)) {
483 sv_catsv(retval, othername);
489 namesv = newSVpv("\\", 1);
490 sv_catpvn(namesv, name, namelen);
492 av_push(seenentry, namesv);
493 (void)SvREFCNT_inc(val);
494 av_push(seenentry, val);
495 (void)hv_store(seenhv, id, strlen(id), newRV((SV*)seenentry), 0);
496 SvREFCNT_dec(seenentry);
503 (void) sprintf(tmpbuf, "%d", i);
504 len = strlen(tmpbuf);
505 sv_catpvn(retval, tmpbuf, len);
508 else if (realtype == SVt_PVGV) {/* GLOBs can end up with scribbly names */
510 ++c; --i; /* just get the name */
511 if (i >= 6 && strncmp(c, "main::", 6) == 0) {
515 if (needs_quote(c)) {
516 sv_grow(retval, SvCUR(retval)+6+2*i);
517 r = SvPVX(retval)+SvCUR(retval);
518 r[0] = '*'; r[1] = '{'; r[2] = '\'';
519 i += esc_q(r+3, c, i);
521 r[i++] = '\''; r[i++] = '}';
525 sv_grow(retval, SvCUR(retval)+i+2);
526 r = SvPVX(retval)+SvCUR(retval);
527 r[0] = '*'; strcpy(r+1, c);
532 static char *entries[] = { "{SCALAR}", "{ARRAY}", "{HASH}" };
533 static STRLEN sizes[] = { 8, 7, 6 };
535 SV *nname = newSVpv("", 0);
536 SV *newapad = newSVpv("", 0);
540 for (j=0; j<3; j++) {
541 e = ((j == 0) ? GvSV(gv) : (j == 1) ? (SV*)GvAV(gv) : (SV*)GvHV(gv));
544 SV *postentry = newSVpv(r,i);
546 sv_setsv(nname, postentry);
547 sv_catpvn(nname, entries[j], sizes[j]);
548 sv_catpvn(postentry, " = ", 3);
549 av_push(postav, postentry);
554 (void)sv_x(newapad, " ", 1, SvCUR(postentry));
556 DD_dump(e, SvPVX(nname), SvCUR(nname), postentry,
557 seenhv, postav, &nlevel, indent, pad, xpad,
558 newapad, sep, freezer, toaster, purity,
559 deepcopy, quotekeys, bless);
564 SvREFCNT_dec(newapad);
570 sv_grow(retval, SvCUR(retval)+3+2*i);
571 r = SvPVX(retval)+SvCUR(retval);
573 i += esc_q(r+1, c, i);
578 SvCUR_set(retval, SvCUR(retval)+i);
581 if (deepcopy && idlen)
582 (void)hv_delete(seenhv, id, idlen, G_DISCARD);
588 MODULE = Data::Dumper PACKAGE = Data::Dumper PREFIX = Data_Dumper_
591 # This is the exact equivalent of Dump. Well, almost. The things that are
592 # different as of now (due to Laziness):
593 # * doesnt do double-quotes yet.
597 Data_Dumper_Dumpxs(href, ...)
605 AV *postav, *todumpav, *namesav;
607 I32 indent, terse, useqq, i, imax, postlen;
609 SV *val, *name, *pad, *xpad, *apad, *sep, *tmp, *varname;
610 SV *freezer, *toaster, *bless;
611 I32 purity, deepcopy, quotekeys;
615 if (!SvROK(href)) { /* call new to get an object first */
624 croak("Usage: Data::Dumper::Dumpxs(PACKAGE, VAL_ARY_REF, NAME_ARY_REF)");
631 XPUSHs(sv_2mortal(newSVsv(valarray)));
632 XPUSHs(sv_2mortal(newSVsv(namearray)));
634 i = perl_call_method("new", G_SCALAR);
637 href = newSVsv(POPs);
643 (void)sv_2mortal(href);
646 todumpav = namesav = Nullav;
648 val = pad = xpad = apad = sep = tmp = varname
649 = freezer = toaster = bless = &sv_undef;
650 name = sv_newmortal();
652 terse = useqq = purity = deepcopy = 0;
655 retval = newSVpv("", 0);
657 && (hv = (HV*)SvRV((SV*)href))
658 && SvTYPE(hv) == SVt_PVHV) {
660 if ((svp = hv_fetch(hv, "seen", 4, FALSE)) && SvROK(*svp))
661 seenhv = (HV*)SvRV(*svp);
662 if ((svp = hv_fetch(hv, "todump", 6, FALSE)) && SvROK(*svp))
663 todumpav = (AV*)SvRV(*svp);
664 if ((svp = hv_fetch(hv, "names", 5, FALSE)) && SvROK(*svp))
665 namesav = (AV*)SvRV(*svp);
666 if ((svp = hv_fetch(hv, "indent", 6, FALSE)))
668 if ((svp = hv_fetch(hv, "purity", 6, FALSE)))
670 if ((svp = hv_fetch(hv, "terse", 5, FALSE)))
671 terse = SvTRUE(*svp);
672 if ((svp = hv_fetch(hv, "useqq", 5, FALSE)))
673 useqq = SvTRUE(*svp);
674 if ((svp = hv_fetch(hv, "pad", 3, FALSE)))
676 if ((svp = hv_fetch(hv, "xpad", 4, FALSE)))
678 if ((svp = hv_fetch(hv, "apad", 4, FALSE)))
680 if ((svp = hv_fetch(hv, "sep", 3, FALSE)))
682 if ((svp = hv_fetch(hv, "varname", 7, FALSE)))
684 if ((svp = hv_fetch(hv, "freezer", 7, FALSE)))
686 if ((svp = hv_fetch(hv, "toaster", 7, FALSE)))
688 if ((svp = hv_fetch(hv, "deepcopy", 8, FALSE)))
689 deepcopy = SvTRUE(*svp);
690 if ((svp = hv_fetch(hv, "quotekeys", 9, FALSE)))
691 quotekeys = SvTRUE(*svp);
692 if ((svp = hv_fetch(hv, "bless", 5, FALSE)))
697 imax = av_len(todumpav);
700 valstr = newSVpv("",0);
701 for (i = 0; i <= imax; ++i) {
705 if ((svp = av_fetch(todumpav, i, FALSE)))
709 if ((svp = av_fetch(namesav, i, TRUE)))
710 sv_setsv(name, *svp);
715 if ((SvPVX(name))[0] == '*') {
717 switch (SvTYPE(SvRV(val))) {
719 (SvPVX(name))[0] = '@';
722 (SvPVX(name))[0] = '%';
725 (SvPVX(name))[0] = '*';
728 (SvPVX(name))[0] = '$';
733 (SvPVX(name))[0] = '$';
735 else if ((SvPVX(name))[0] != '$')
736 sv_insert(name, 0, 0, "$", 1);
740 sv_setpvn(name, "$", 1);
741 sv_catsv(name, varname);
742 (void) sprintf(tmpbuf, "%ld", i+1);
743 nchars = strlen(tmpbuf);
744 sv_catpvn(name, tmpbuf, nchars);
748 SV *tmpsv = sv_x(Nullsv, " ", 1, SvCUR(name)+3);
749 newapad = newSVsv(apad);
750 sv_catsv(newapad, tmpsv);
756 DD_dump(val, SvPVX(name), SvCUR(name), valstr, seenhv,
757 postav, &level, indent, pad, xpad, newapad, sep,
758 freezer, toaster, purity, deepcopy, quotekeys,
762 SvREFCNT_dec(newapad);
764 postlen = av_len(postav);
765 if (postlen >= 0 || !terse) {
766 sv_insert(valstr, 0, 0, " = ", 3);
767 sv_insert(valstr, 0, 0, SvPVX(name), SvCUR(name));
768 sv_catpvn(valstr, ";", 1);
770 sv_catsv(retval, pad);
771 sv_catsv(retval, valstr);
772 sv_catsv(retval, sep);
775 sv_catsv(retval, pad);
776 for (i = 0; i <= postlen; ++i) {
778 svp = av_fetch(postav, i, FALSE);
779 if (svp && (elem = *svp)) {
780 sv_catsv(retval, elem);
782 sv_catpvn(retval, ";", 1);
783 sv_catsv(retval, sep);
784 sv_catsv(retval, pad);
788 sv_catpvn(retval, ";", 1);
789 sv_catsv(retval, sep);
791 sv_setpvn(valstr, "", 0);
792 if (gimme == G_ARRAY) {
793 XPUSHs(sv_2mortal(retval));
794 if (i < imax) /* not the last time thro ? */
795 retval = newSVpv("",0);
798 SvREFCNT_dec(postav);
799 SvREFCNT_dec(valstr);
802 croak("Call to new() method failed to return HASH ref");
803 if (gimme == G_SCALAR)
804 XPUSHs(sv_2mortal(retval));