Resync with mainline prior to post-5.6.0 updates
[p5sagit/p5-mst-13.2.git] / ext / Data / Dumper / Dumper.xs
1 #define PERL_NO_GET_CONTEXT
2 #include "EXTERN.h"
3 #include "perl.h"
4 #include "XSUB.h"
5
6 #ifndef PERL_VERSION
7 #include "patchlevel.h"
8 #define PERL_VERSION PATCHLEVEL
9 #endif
10
11 #if PERL_VERSION < 5
12 #  ifndef PL_sv_undef
13 #    define PL_sv_undef sv_undef
14 #  endif
15 #  ifndef ERRSV
16 #    define ERRSV       GvSV(errgv)
17 #  endif
18 #  ifndef newSVpvn
19 #    define newSVpvn    newSVpv
20 #  endif
21 #endif
22
23 static I32 num_q (char *s, STRLEN slen);
24 static I32 esc_q (char *dest, char *src, STRLEN slen);
25 static SV *sv_x (pTHX_ SV *sv, char *str, STRLEN len, I32 n);
26 static I32 DD_dump (pTHX_ SV *val, char *name, STRLEN namelen, SV *retval,
27                     HV *seenhv, AV *postav, I32 *levelp, I32 indent,
28                     SV *pad, SV *xpad, SV *apad, SV *sep,
29                     SV *freezer, SV *toaster,
30                     I32 purity, I32 deepcopy, I32 quotekeys, SV *bless,
31                     I32 maxdepth);
32
33 /* does a string need to be protected? */
34 static I32
35 needs_quote(register char *s)
36 {
37 TOP:
38     if (s[0] == ':') {
39         if (*++s) {
40             if (*s++ != ':')
41                 return 1;
42         }
43         else
44             return 1;
45     }
46     if (isIDFIRST(*s)) {
47         while (*++s)
48             if (!isALNUM(*s)) {
49                 if (*s == ':')
50                     goto TOP;
51                 else
52                     return 1;
53             }
54     }
55     else 
56         return 1;
57     return 0;
58 }
59
60 /* count the number of "'"s and "\"s in string */
61 static I32
62 num_q(register char *s, register STRLEN slen)
63 {
64     register I32 ret = 0;
65
66     while (slen > 0) {
67         if (*s == '\'' || *s == '\\')
68             ++ret;
69         ++s;
70         --slen;
71     }
72     return ret;
73 }
74
75
76 /* returns number of chars added to escape "'"s and "\"s in s */
77 /* slen number of characters in s will be escaped */
78 /* destination must be long enough for additional chars */
79 static I32
80 esc_q(register char *d, register char *s, register STRLEN slen)
81 {
82     register I32 ret = 0;
83     
84     while (slen > 0) {
85         switch (*s) {
86         case '\'':
87         case '\\':
88             *d = '\\';
89             ++d; ++ret;
90         default:
91             *d = *s;
92             ++d; ++s; --slen;
93             break;
94         }
95     }
96     return ret;
97 }
98
99 /* append a repeated string to an SV */
100 static SV *
101 sv_x(pTHX_ SV *sv, register char *str, STRLEN len, I32 n)
102 {
103     if (sv == Nullsv)
104         sv = newSVpvn("", 0);
105     else
106         assert(SvTYPE(sv) >= SVt_PV);
107
108     if (n > 0) {
109         SvGROW(sv, len*n + SvCUR(sv) + 1);
110         if (len == 1) {
111             char *start = SvPVX(sv) + SvCUR(sv);
112             SvCUR(sv) += n;
113             start[n] = '\0';
114             while (n > 0)
115                 start[--n] = str[0];
116         }
117         else
118             while (n > 0) {
119                 sv_catpvn(sv, str, len);
120                 --n;
121             }
122     }
123     return sv;
124 }
125
126 /*
127  * This ought to be split into smaller functions. (it is one long function since
128  * it exactly parallels the perl version, which was one long thing for
129  * efficiency raisins.)  Ugggh!
130  */
131 static I32
132 DD_dump(pTHX_ SV *val, char *name, STRLEN namelen, SV *retval, HV *seenhv,
133         AV *postav, I32 *levelp, I32 indent, SV *pad, SV *xpad,
134         SV *apad, SV *sep, SV *freezer, SV *toaster, I32 purity,
135         I32 deepcopy, I32 quotekeys, SV *bless, I32 maxdepth)
136 {
137     char tmpbuf[128];
138     U32 i;
139     char *c, *r, *realpack, id[128];
140     SV **svp;
141     SV *sv, *ipad, *ival;
142     SV *blesspad = Nullsv;
143     AV *seenentry = Nullav;
144     char *iname;
145     STRLEN inamelen, idlen = 0;
146     U32 flags;
147     U32 realtype;
148
149     if (!val)
150         return 0;
151
152     flags = SvFLAGS(val);
153     realtype = SvTYPE(val);
154     
155     if (SvGMAGICAL(val))
156         mg_get(val);
157     if (SvROK(val)) {
158
159         if (SvOBJECT(SvRV(val)) && freezer &&
160             SvPOK(freezer) && SvCUR(freezer))
161         {
162             dSP; ENTER; SAVETMPS; PUSHMARK(sp);
163             XPUSHs(val); PUTBACK;
164             i = perl_call_method(SvPVX(freezer), G_EVAL|G_SCALAR);
165             SPAGAIN;
166             if (SvTRUE(ERRSV))
167                 warn("WARNING(Freezer method call failed): %s",
168                      SvPVX(ERRSV));
169             else if (i)
170                 val = newSVsv(POPs);
171             PUTBACK; FREETMPS; LEAVE;
172             if (i)
173                 (void)sv_2mortal(val);
174         }
175         
176         ival = SvRV(val);
177         flags = SvFLAGS(ival);
178         realtype = SvTYPE(ival);
179         (void) sprintf(id, "0x%lx", (unsigned long)ival);
180         idlen = strlen(id);
181         if (SvOBJECT(ival))
182             realpack = HvNAME(SvSTASH(ival));
183         else
184             realpack = Nullch;
185
186         /* if it has a name, we need to either look it up, or keep a tab
187          * on it so we know when we hit it later
188          */
189         if (namelen) {
190             if ((svp = hv_fetch(seenhv, id, idlen, FALSE))
191                 && (sv = *svp) && SvROK(sv) && (seenentry = (AV*)SvRV(sv)))
192             {
193                 SV *othername;
194                 if ((svp = av_fetch(seenentry, 0, FALSE))
195                     && (othername = *svp))
196                 {
197                     if (purity && *levelp > 0) {
198                         SV *postentry;
199                         
200                         if (realtype == SVt_PVHV)
201                             sv_catpvn(retval, "{}", 2);
202                         else if (realtype == SVt_PVAV)
203                             sv_catpvn(retval, "[]", 2);
204                         else
205                             sv_catpvn(retval, "do{my $o}", 9);
206                         postentry = newSVpvn(name, namelen);
207                         sv_catpvn(postentry, " = ", 3);
208                         sv_catsv(postentry, othername);
209                         av_push(postav, postentry);
210                     }
211                     else {
212                         if (name[0] == '@' || name[0] == '%') {
213                             if ((SvPVX(othername))[0] == '\\' &&
214                                 (SvPVX(othername))[1] == name[0]) {
215                                 sv_catpvn(retval, SvPVX(othername)+1,
216                                           SvCUR(othername)-1);
217                             }
218                             else {
219                                 sv_catpvn(retval, name, 1);
220                                 sv_catpvn(retval, "{", 1);
221                                 sv_catsv(retval, othername);
222                                 sv_catpvn(retval, "}", 1);
223                             }
224                         }
225                         else
226                             sv_catsv(retval, othername);
227                     }
228                     return 1;
229                 }
230                 else {
231                     warn("ref name not found for %s", id);
232                     return 0;
233                 }
234             }
235             else {   /* store our name and continue */
236                 SV *namesv;
237                 if (name[0] == '@' || name[0] == '%') {
238                     namesv = newSVpvn("\\", 1);
239                     sv_catpvn(namesv, name, namelen);
240                 }
241                 else if (realtype == SVt_PVCV && name[0] == '*') {
242                     namesv = newSVpvn("\\", 2);
243                     sv_catpvn(namesv, name, namelen);
244                     (SvPVX(namesv))[1] = '&';
245                 }
246                 else
247                     namesv = newSVpvn(name, namelen);
248                 seenentry = newAV();
249                 av_push(seenentry, namesv);
250                 (void)SvREFCNT_inc(val);
251                 av_push(seenentry, val);
252                 (void)hv_store(seenhv, id, strlen(id),
253                                newRV((SV*)seenentry), 0);
254                 SvREFCNT_dec(seenentry);
255             }
256         }
257
258         if (realpack && *realpack == 'R' && strEQ(realpack, "Regexp")) {
259             STRLEN rlen;
260             char *rval = SvPV(val, rlen);
261             char *slash = strchr(rval, '/');
262             sv_catpvn(retval, "qr/", 3);
263             while (slash) {
264                 sv_catpvn(retval, rval, slash-rval);
265                 sv_catpvn(retval, "\\/", 2);
266                 rlen -= slash-rval+1;
267                 rval = slash+1;
268                 slash = strchr(rval, '/');
269             }
270             sv_catpvn(retval, rval, rlen);
271             sv_catpvn(retval, "/", 1);
272             return 1;
273         }
274
275         /* If purity is not set and maxdepth is set, then check depth:
276          * if we have reached maximum depth, return the string
277          * representation of the thing we are currently examining
278          * at this depth (i.e., 'Foo=ARRAY(0xdeadbeef)'). 
279          */
280         if (!purity && maxdepth > 0 && *levelp >= maxdepth) {
281             STRLEN vallen;
282             char *valstr = SvPV(val,vallen);
283             sv_catpvn(retval, "'", 1);
284             sv_catpvn(retval, valstr, vallen);
285             sv_catpvn(retval, "'", 1);
286             return 1;
287         }
288
289         if (realpack) {                         /* we have a blessed ref */
290             STRLEN blesslen;
291             char *blessstr = SvPV(bless, blesslen);
292             sv_catpvn(retval, blessstr, blesslen);
293             sv_catpvn(retval, "( ", 2);
294             if (indent >= 2) {
295                 blesspad = apad;
296                 apad = newSVsv(apad);
297                 sv_x(aTHX_ apad, " ", 1, blesslen+2);
298             }
299         }
300
301         (*levelp)++;
302         ipad = sv_x(aTHX_ Nullsv, SvPVX(xpad), SvCUR(xpad), *levelp);
303
304         if (realtype <= SVt_PVBM) {                          /* scalar ref */
305             SV *namesv = newSVpvn("${", 2);
306             sv_catpvn(namesv, name, namelen);
307             sv_catpvn(namesv, "}", 1);
308             if (realpack) {                                  /* blessed */ 
309                 sv_catpvn(retval, "do{\\(my $o = ", 13);
310                 DD_dump(aTHX_ ival, SvPVX(namesv), SvCUR(namesv), retval, seenhv,
311                         postav, levelp, indent, pad, xpad, apad, sep,
312                         freezer, toaster, purity, deepcopy, quotekeys, bless,
313                         maxdepth);
314                 sv_catpvn(retval, ")}", 2);
315             }                                                /* plain */
316             else {
317                 sv_catpvn(retval, "\\", 1);
318                 DD_dump(aTHX_ ival, SvPVX(namesv), SvCUR(namesv), retval, seenhv,
319                         postav, levelp, indent, pad, xpad, apad, sep,
320                         freezer, toaster, purity, deepcopy, quotekeys, bless,
321                         maxdepth);
322             }
323             SvREFCNT_dec(namesv);
324         }
325         else if (realtype == SVt_PVGV) {                     /* glob ref */
326             SV *namesv = newSVpvn("*{", 2);
327             sv_catpvn(namesv, name, namelen);
328             sv_catpvn(namesv, "}", 1);
329             sv_catpvn(retval, "\\", 1);
330             DD_dump(aTHX_ ival, SvPVX(namesv), SvCUR(namesv), retval, seenhv,
331                     postav, levelp,     indent, pad, xpad, apad, sep,
332                     freezer, toaster, purity, deepcopy, quotekeys, bless,
333                     maxdepth);
334             SvREFCNT_dec(namesv);
335         }
336         else if (realtype == SVt_PVAV) {
337             SV *totpad;
338             I32 ix = 0;
339             I32 ixmax = av_len((AV *)ival);
340             
341             SV *ixsv = newSViv(0);
342             /* allowing for a 24 char wide array index */
343             New(0, iname, namelen+28, char);
344             (void)strcpy(iname, name);
345             inamelen = namelen;
346             if (name[0] == '@') {
347                 sv_catpvn(retval, "(", 1);
348                 iname[0] = '$';
349             }
350             else {
351                 sv_catpvn(retval, "[", 1);
352                 /* omit "->" in $foo{bar}->[0], but not in ${$foo}->[0] */
353                 /*if (namelen > 0
354                     && name[namelen-1] != ']' && name[namelen-1] != '}'
355                     && (namelen < 4 || (name[1] != '{' && name[2] != '{')))*/
356                 if ((namelen > 0
357                      && name[namelen-1] != ']' && name[namelen-1] != '}')
358                     || (namelen > 4
359                         && (name[1] == '{'
360                             || (name[0] == '\\' && name[2] == '{'))))
361                 {
362                     iname[inamelen++] = '-'; iname[inamelen++] = '>';
363                     iname[inamelen] = '\0';
364                 }
365             }
366             if (iname[0] == '*' && iname[inamelen-1] == '}' && inamelen >= 8 &&
367                 (instr(iname+inamelen-8, "{SCALAR}") ||
368                  instr(iname+inamelen-7, "{ARRAY}") ||
369                  instr(iname+inamelen-6, "{HASH}"))) {
370                 iname[inamelen++] = '-'; iname[inamelen++] = '>';
371             }
372             iname[inamelen++] = '['; iname[inamelen] = '\0';
373             totpad = newSVsv(sep);
374             sv_catsv(totpad, pad);
375             sv_catsv(totpad, apad);
376
377             for (ix = 0; ix <= ixmax; ++ix) {
378                 STRLEN ilen;
379                 SV *elem;
380                 svp = av_fetch((AV*)ival, ix, FALSE);
381                 if (svp)
382                     elem = *svp;
383                 else
384                     elem = &PL_sv_undef;
385                 
386                 ilen = inamelen;
387                 sv_setiv(ixsv, ix);
388                 (void) sprintf(iname+ilen, "%"IVdf, (IV)ix);
389                 ilen = strlen(iname);
390                 iname[ilen++] = ']'; iname[ilen] = '\0';
391                 if (indent >= 3) {
392                     sv_catsv(retval, totpad);
393                     sv_catsv(retval, ipad);
394                     sv_catpvn(retval, "#", 1);
395                     sv_catsv(retval, ixsv);
396                 }
397                 sv_catsv(retval, totpad);
398                 sv_catsv(retval, ipad);
399                 DD_dump(aTHX_ elem, iname, ilen, retval, seenhv, postav,
400                         levelp, indent, pad, xpad, apad, sep,
401                         freezer, toaster, purity, deepcopy, quotekeys, bless,
402                         maxdepth);
403                 if (ix < ixmax)
404                     sv_catpvn(retval, ",", 1);
405             }
406             if (ixmax >= 0) {
407                 SV *opad = sv_x(aTHX_ Nullsv, SvPVX(xpad), SvCUR(xpad), (*levelp)-1);
408                 sv_catsv(retval, totpad);
409                 sv_catsv(retval, opad);
410                 SvREFCNT_dec(opad);
411             }
412             if (name[0] == '@')
413                 sv_catpvn(retval, ")", 1);
414             else
415                 sv_catpvn(retval, "]", 1);
416             SvREFCNT_dec(ixsv);
417             SvREFCNT_dec(totpad);
418             Safefree(iname);
419         }
420         else if (realtype == SVt_PVHV) {
421             SV *totpad, *newapad;
422             SV *iname, *sname;
423             HE *entry;
424             char *key;
425             I32 klen;
426             SV *hval;
427             
428             iname = newSVpvn(name, namelen);
429             if (name[0] == '%') {
430                 sv_catpvn(retval, "(", 1);
431                 (SvPVX(iname))[0] = '$';
432             }
433             else {
434                 sv_catpvn(retval, "{", 1);
435                 /* omit "->" in $foo[0]->{bar}, but not in ${$foo}->{bar} */
436                 if ((namelen > 0
437                      && name[namelen-1] != ']' && name[namelen-1] != '}')
438                     || (namelen > 4
439                         && (name[1] == '{'
440                             || (name[0] == '\\' && name[2] == '{'))))
441                 {
442                     sv_catpvn(iname, "->", 2);
443                 }
444             }
445             if (name[0] == '*' && name[namelen-1] == '}' && namelen >= 8 &&
446                 (instr(name+namelen-8, "{SCALAR}") ||
447                  instr(name+namelen-7, "{ARRAY}") ||
448                  instr(name+namelen-6, "{HASH}"))) {
449                 sv_catpvn(iname, "->", 2);
450             }
451             sv_catpvn(iname, "{", 1);
452             totpad = newSVsv(sep);
453             sv_catsv(totpad, pad);
454             sv_catsv(totpad, apad);
455             
456             (void)hv_iterinit((HV*)ival);
457             i = 0;
458             while ((entry = hv_iternext((HV*)ival)))  {
459                 char *nkey;
460                 I32 nticks = 0;
461                 
462                 if (i)
463                     sv_catpvn(retval, ",", 1);
464                 i++;
465                 key = hv_iterkey(entry, &klen);
466                 hval = hv_iterval((HV*)ival, entry);
467
468                 if (quotekeys || needs_quote(key)) {
469                     nticks = num_q(key, klen);
470                     New(0, nkey, klen+nticks+3, char);
471                     nkey[0] = '\'';
472                     if (nticks)
473                         klen += esc_q(nkey+1, key, klen);
474                     else
475                         (void)Copy(key, nkey+1, klen, char);
476                     nkey[++klen] = '\'';
477                     nkey[++klen] = '\0';
478                 }
479                 else {
480                     New(0, nkey, klen, char);
481                     (void)Copy(key, nkey, klen, char);
482                 }
483                 
484                 sname = newSVsv(iname);
485                 sv_catpvn(sname, nkey, klen);
486                 sv_catpvn(sname, "}", 1);
487
488                 sv_catsv(retval, totpad);
489                 sv_catsv(retval, ipad);
490                 sv_catpvn(retval, nkey, klen);
491                 sv_catpvn(retval, " => ", 4);
492                 if (indent >= 2) {
493                     char *extra;
494                     I32 elen = 0;
495                     newapad = newSVsv(apad);
496                     New(0, extra, klen+4+1, char);
497                     while (elen < (klen+4))
498                         extra[elen++] = ' ';
499                     extra[elen] = '\0';
500                     sv_catpvn(newapad, extra, elen);
501                     Safefree(extra);
502                 }
503                 else
504                     newapad = apad;
505
506                 DD_dump(aTHX_ hval, SvPVX(sname), SvCUR(sname), retval, seenhv,
507                         postav, levelp, indent, pad, xpad, newapad, sep,
508                         freezer, toaster, purity, deepcopy, quotekeys, bless,
509                         maxdepth);
510                 SvREFCNT_dec(sname);
511                 Safefree(nkey);
512                 if (indent >= 2)
513                     SvREFCNT_dec(newapad);
514             }
515             if (i) {
516                 SV *opad = sv_x(aTHX_ Nullsv, SvPVX(xpad), SvCUR(xpad), *levelp-1);
517                 sv_catsv(retval, totpad);
518                 sv_catsv(retval, opad);
519                 SvREFCNT_dec(opad);
520             }
521             if (name[0] == '%')
522                 sv_catpvn(retval, ")", 1);
523             else
524                 sv_catpvn(retval, "}", 1);
525             SvREFCNT_dec(iname);
526             SvREFCNT_dec(totpad);
527         }
528         else if (realtype == SVt_PVCV) {
529             sv_catpvn(retval, "sub { \"DUMMY\" }", 15);
530             if (purity)
531                 warn("Encountered CODE ref, using dummy placeholder");
532         }
533         else {
534             warn("cannot handle ref type %ld", realtype);
535         }
536
537         if (realpack) {  /* free blessed allocs */
538             if (indent >= 2) {
539                 SvREFCNT_dec(apad);
540                 apad = blesspad;
541             }
542             sv_catpvn(retval, ", '", 3);
543             sv_catpvn(retval, realpack, strlen(realpack));
544             sv_catpvn(retval, "' )", 3);
545             if (toaster && SvPOK(toaster) && SvCUR(toaster)) {
546                 sv_catpvn(retval, "->", 2);
547                 sv_catsv(retval, toaster);
548                 sv_catpvn(retval, "()", 2);
549             }
550         }
551         SvREFCNT_dec(ipad);
552         (*levelp)--;
553     }
554     else {
555         STRLEN i;
556         
557         if (namelen) {
558             (void) sprintf(id, "0x%lx", (unsigned long)val);
559             if ((svp = hv_fetch(seenhv, id, (idlen = strlen(id)), FALSE)) &&
560                 (sv = *svp) && SvROK(sv) &&
561                 (seenentry = (AV*)SvRV(sv)))
562             {
563                 SV *othername;
564                 if ((svp = av_fetch(seenentry, 0, FALSE)) && (othername = *svp)
565                     && (svp = av_fetch(seenentry, 2, FALSE)) && *svp && SvIV(*svp) > 0)
566                 {
567                     sv_catpvn(retval, "${", 2);
568                     sv_catsv(retval, othername);
569                     sv_catpvn(retval, "}", 1);
570                     return 1;
571                 }
572             }
573             else {
574                 SV *namesv;
575                 namesv = newSVpvn("\\", 1);
576                 sv_catpvn(namesv, name, namelen);
577                 seenentry = newAV();
578                 av_push(seenentry, namesv);
579                 av_push(seenentry, newRV(val));
580                 (void)hv_store(seenhv, id, strlen(id), newRV((SV*)seenentry), 0);
581                 SvREFCNT_dec(seenentry);
582             }
583         }
584
585         if (SvIOK(val)) {
586             STRLEN len;
587             (void) sprintf(tmpbuf, "%"IVdf, SvIV(val));
588             len = strlen(tmpbuf);
589             sv_catpvn(retval, tmpbuf, len);
590         }
591         else if (realtype == SVt_PVGV) {/* GLOBs can end up with scribbly names */
592             c = SvPV(val, i);
593             ++c; --i;                   /* just get the name */
594             if (i >= 6 && strncmp(c, "main::", 6) == 0) {
595                 c += 4;
596                 i -= 4;
597             }
598             if (needs_quote(c)) {
599                 sv_grow(retval, SvCUR(retval)+6+2*i);
600                 r = SvPVX(retval)+SvCUR(retval);
601                 r[0] = '*'; r[1] = '{'; r[2] = '\'';
602                 i += esc_q(r+3, c, i);
603                 i += 3;
604                 r[i++] = '\''; r[i++] = '}';
605                 r[i] = '\0';
606             }
607             else {
608                 sv_grow(retval, SvCUR(retval)+i+2);
609                 r = SvPVX(retval)+SvCUR(retval);
610                 r[0] = '*'; strcpy(r+1, c);
611                 i++;
612             }
613             SvCUR_set(retval, SvCUR(retval)+i);
614
615             if (purity) {
616                 static char *entries[] = { "{SCALAR}", "{ARRAY}", "{HASH}" };
617                 static STRLEN sizes[] = { 8, 7, 6 };
618                 SV *e;
619                 SV *nname = newSVpvn("", 0);
620                 SV *newapad = newSVpvn("", 0);
621                 GV *gv = (GV*)val;
622                 I32 j;
623                 
624                 for (j=0; j<3; j++) {
625                     e = ((j == 0) ? GvSV(gv) : (j == 1) ? (SV*)GvAV(gv) : (SV*)GvHV(gv));
626                     if (!e)
627                         continue;
628                     if (j == 0 && !SvOK(e))
629                         continue;
630
631                     {
632                         I32 nlevel = 0;
633                         SV *postentry = newSVpvn(r,i);
634                         
635                         sv_setsv(nname, postentry);
636                         sv_catpvn(nname, entries[j], sizes[j]);
637                         sv_catpvn(postentry, " = ", 3);
638                         av_push(postav, postentry);
639                         e = newRV(e);
640                         
641                         SvCUR(newapad) = 0;
642                         if (indent >= 2)
643                             (void)sv_x(aTHX_ newapad, " ", 1, SvCUR(postentry));
644                         
645                         DD_dump(aTHX_ e, SvPVX(nname), SvCUR(nname), postentry,
646                                 seenhv, postav, &nlevel, indent, pad, xpad,
647                                 newapad, sep, freezer, toaster, purity,
648                                 deepcopy, quotekeys, bless, maxdepth);
649                         SvREFCNT_dec(e);
650                     }
651                 }
652                 
653                 SvREFCNT_dec(newapad);
654                 SvREFCNT_dec(nname);
655             }
656         }
657         else if (val == &PL_sv_undef || !SvOK(val)) {
658             sv_catpvn(retval, "undef", 5);
659         }
660         else {
661             c = SvPV(val, i);
662             sv_grow(retval, SvCUR(retval)+3+2*i);
663             r = SvPVX(retval)+SvCUR(retval);
664             r[0] = '\'';
665             i += esc_q(r+1, c, i);
666             ++i;
667             r[i++] = '\'';
668             r[i] = '\0';
669             SvCUR_set(retval, SvCUR(retval)+i);
670         }
671     }
672
673     if (idlen) {
674         if (deepcopy)
675             (void)hv_delete(seenhv, id, idlen, G_DISCARD);
676         else if (namelen && seenentry) {
677             SV *mark = *av_fetch(seenentry, 2, TRUE);
678             sv_setiv(mark,1);
679         }
680     }
681     return 1;
682 }
683
684
685 MODULE = Data::Dumper           PACKAGE = Data::Dumper         PREFIX = Data_Dumper_
686
687 #
688 # This is the exact equivalent of Dump.  Well, almost. The things that are
689 # different as of now (due to Laziness):
690 #   * doesnt do double-quotes yet.
691 #
692
693 void
694 Data_Dumper_Dumpxs(href, ...)
695         SV      *href;
696         PROTOTYPE: $;$$
697         PPCODE:
698         {
699             HV *hv;
700             SV *retval, *valstr;
701             HV *seenhv = Nullhv;
702             AV *postav, *todumpav, *namesav;
703             I32 level = 0;
704             I32 indent, terse, useqq, i, imax, postlen;
705             SV **svp;
706             SV *val, *name, *pad, *xpad, *apad, *sep, *tmp, *varname;
707             SV *freezer, *toaster, *bless;
708             I32 purity, deepcopy, quotekeys, maxdepth = 0;
709             char tmpbuf[1024];
710             I32 gimme = GIMME;
711
712             if (!SvROK(href)) {         /* call new to get an object first */
713                 if (items < 2)
714                     croak("Usage: Data::Dumper::Dumpxs(PACKAGE, VAL_ARY_REF, [NAME_ARY_REF])");
715                 
716                 ENTER;
717                 SAVETMPS;
718                 
719                 PUSHMARK(sp);
720                 XPUSHs(href);
721                 XPUSHs(sv_2mortal(newSVsv(ST(1))));
722                 if (items >= 3)
723                     XPUSHs(sv_2mortal(newSVsv(ST(2))));
724                 PUTBACK;
725                 i = perl_call_method("new", G_SCALAR);
726                 SPAGAIN;
727                 if (i)
728                     href = newSVsv(POPs);
729
730                 PUTBACK;
731                 FREETMPS;
732                 LEAVE;
733                 if (i)
734                     (void)sv_2mortal(href);
735             }
736
737             todumpav = namesav = Nullav;
738             seenhv = Nullhv;
739             val = pad = xpad = apad = sep = tmp = varname
740                 = freezer = toaster = bless = &PL_sv_undef;
741             name = sv_newmortal();
742             indent = 2;
743             terse = useqq = purity = deepcopy = 0;
744             quotekeys = 1;
745             
746             retval = newSVpvn("", 0);
747             if (SvROK(href)
748                 && (hv = (HV*)SvRV((SV*)href))
749                 && SvTYPE(hv) == SVt_PVHV)              {
750
751                 if ((svp = hv_fetch(hv, "seen", 4, FALSE)) && SvROK(*svp))
752                     seenhv = (HV*)SvRV(*svp);
753                 if ((svp = hv_fetch(hv, "todump", 6, FALSE)) && SvROK(*svp))
754                     todumpav = (AV*)SvRV(*svp);
755                 if ((svp = hv_fetch(hv, "names", 5, FALSE)) && SvROK(*svp))
756                     namesav = (AV*)SvRV(*svp);
757                 if ((svp = hv_fetch(hv, "indent", 6, FALSE)))
758                     indent = SvIV(*svp);
759                 if ((svp = hv_fetch(hv, "purity", 6, FALSE)))
760                     purity = SvIV(*svp);
761                 if ((svp = hv_fetch(hv, "terse", 5, FALSE)))
762                     terse = SvTRUE(*svp);
763                 if ((svp = hv_fetch(hv, "useqq", 5, FALSE)))
764                     useqq = SvTRUE(*svp);
765                 if ((svp = hv_fetch(hv, "pad", 3, FALSE)))
766                     pad = *svp;
767                 if ((svp = hv_fetch(hv, "xpad", 4, FALSE)))
768                     xpad = *svp;
769                 if ((svp = hv_fetch(hv, "apad", 4, FALSE)))
770                     apad = *svp;
771                 if ((svp = hv_fetch(hv, "sep", 3, FALSE)))
772                     sep = *svp;
773                 if ((svp = hv_fetch(hv, "varname", 7, FALSE)))
774                     varname = *svp;
775                 if ((svp = hv_fetch(hv, "freezer", 7, FALSE)))
776                     freezer = *svp;
777                 if ((svp = hv_fetch(hv, "toaster", 7, FALSE)))
778                     toaster = *svp;
779                 if ((svp = hv_fetch(hv, "deepcopy", 8, FALSE)))
780                     deepcopy = SvTRUE(*svp);
781                 if ((svp = hv_fetch(hv, "quotekeys", 9, FALSE)))
782                     quotekeys = SvTRUE(*svp);
783                 if ((svp = hv_fetch(hv, "bless", 5, FALSE)))
784                     bless = *svp;
785                 if ((svp = hv_fetch(hv, "maxdepth", 8, FALSE)))
786                     maxdepth = SvIV(*svp);
787                 postav = newAV();
788
789                 if (todumpav)
790                     imax = av_len(todumpav);
791                 else
792                     imax = -1;
793                 valstr = newSVpvn("",0);
794                 for (i = 0; i <= imax; ++i) {
795                     SV *newapad;
796                     
797                     av_clear(postav);
798                     if ((svp = av_fetch(todumpav, i, FALSE)))
799                         val = *svp;
800                     else
801                         val = &PL_sv_undef;
802                     if ((svp = av_fetch(namesav, i, TRUE)))
803                         sv_setsv(name, *svp);
804                     else
805                         SvOK_off(name);
806                     
807                     if (SvOK(name)) {
808                         if ((SvPVX(name))[0] == '*') {
809                             if (SvROK(val)) {
810                                 switch (SvTYPE(SvRV(val))) {
811                                 case SVt_PVAV:
812                                     (SvPVX(name))[0] = '@';
813                                     break;
814                                 case SVt_PVHV:
815                                     (SvPVX(name))[0] = '%';
816                                     break;
817                                 case SVt_PVCV:
818                                     (SvPVX(name))[0] = '*';
819                                     break;
820                                 default:
821                                     (SvPVX(name))[0] = '$';
822                                     break;
823                                 }
824                             }
825                             else
826                                 (SvPVX(name))[0] = '$';
827                         }
828                         else if ((SvPVX(name))[0] != '$')
829                             sv_insert(name, 0, 0, "$", 1);
830                     }
831                     else {
832                         STRLEN nchars = 0;
833                         sv_setpvn(name, "$", 1);
834                         sv_catsv(name, varname);
835                         (void) sprintf(tmpbuf, "%"IVdf, (IV)(i+1));
836                         nchars = strlen(tmpbuf);
837                         sv_catpvn(name, tmpbuf, nchars);
838                     }
839                     
840                     if (indent >= 2) {
841                         SV *tmpsv = sv_x(aTHX_ Nullsv, " ", 1, SvCUR(name)+3);
842                         newapad = newSVsv(apad);
843                         sv_catsv(newapad, tmpsv);
844                         SvREFCNT_dec(tmpsv);
845                     }
846                     else
847                         newapad = apad;
848                     
849                     DD_dump(aTHX_ val, SvPVX(name), SvCUR(name), valstr, seenhv,
850                             postav, &level, indent, pad, xpad, newapad, sep,
851                             freezer, toaster, purity, deepcopy, quotekeys,
852                             bless, maxdepth);
853                     
854                     if (indent >= 2)
855                         SvREFCNT_dec(newapad);
856
857                     postlen = av_len(postav);
858                     if (postlen >= 0 || !terse) {
859                         sv_insert(valstr, 0, 0, " = ", 3);
860                         sv_insert(valstr, 0, 0, SvPVX(name), SvCUR(name));
861                         sv_catpvn(valstr, ";", 1);
862                     }
863                     sv_catsv(retval, pad);
864                     sv_catsv(retval, valstr);
865                     sv_catsv(retval, sep);
866                     if (postlen >= 0) {
867                         I32 i;
868                         sv_catsv(retval, pad);
869                         for (i = 0; i <= postlen; ++i) {
870                             SV *elem;
871                             svp = av_fetch(postav, i, FALSE);
872                             if (svp && (elem = *svp)) {
873                                 sv_catsv(retval, elem);
874                                 if (i < postlen) {
875                                     sv_catpvn(retval, ";", 1);
876                                     sv_catsv(retval, sep);
877                                     sv_catsv(retval, pad);
878                                 }
879                             }
880                         }
881                         sv_catpvn(retval, ";", 1);
882                             sv_catsv(retval, sep);
883                     }
884                     sv_setpvn(valstr, "", 0);
885                     if (gimme == G_ARRAY) {
886                         XPUSHs(sv_2mortal(retval));
887                         if (i < imax)   /* not the last time thro ? */
888                             retval = newSVpvn("",0);
889                     }
890                 }
891                 SvREFCNT_dec(postav);
892                 SvREFCNT_dec(valstr);
893             }
894             else
895                 croak("Call to new() method failed to return HASH ref");
896             if (gimme == G_SCALAR)
897                 XPUSHs(sv_2mortal(retval));
898         }