dumper.xs
来自「source of perl for linux application,」· XS 代码 · 共 1,207 行 · 第 1/3 页
XS
1,207 行
#define PERL_NO_GET_CONTEXT#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#ifdef USE_PPPORT_H# include "ppport.h"#endif#if PERL_VERSION < 6# define DD_USE_OLD_ID_FORMAT#endifstatic I32 num_q (const char *s, STRLEN slen);static I32 esc_q (char *dest, const char *src, STRLEN slen);static I32 esc_q_utf8 (pTHX_ SV *sv, const char *src, STRLEN slen);static I32 needs_quote(register const char *s);static SV *sv_x (pTHX_ SV *sv, const char *str, STRLEN len, I32 n);static I32 DD_dump (pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv, AV *postav, I32 *levelp, I32 indent, SV *pad, SV *xpad, SV *apad, SV *sep, SV *pair, SV *freezer, SV *toaster, I32 purity, I32 deepcopy, I32 quotekeys, SV *bless, I32 maxdepth, SV *sortkeys);#ifndef HvNAME_get#define HvNAME_get HvNAME#endif#if PERL_VERSION <= 6 /* Perl 5.6 and earlier */# ifdef EBCDIC# define UNI_TO_NATIVE(ch) (((ch) > 255) ? (ch) : ASCII_TO_NATIVE(ch))# else# define UNI_TO_NATIVE(ch) (ch)# endifUVPerl_utf8_to_uvchr(pTHX_ U8 *s, STRLEN *retlen){ const UV uv = utf8_to_uv(s, UTF8_MAXLEN, retlen, ckWARN(WARN_UTF8) ? 0 : UTF8_ALLOW_ANY); return UNI_TO_NATIVE(uv);}# if !defined(PERL_IMPLICIT_CONTEXT)# define utf8_to_uvchr Perl_utf8_to_uvchr# else# define utf8_to_uvchr(a,b) Perl_utf8_to_uvchr(aTHX_ a,b)# endif#endif /* PERL_VERSION <= 6 *//* Changes in 5.7 series mean that now IOK is only set if scalar is precisely integer but in 5.6 and earlier we need to do a more complex test */#if PERL_VERSION <= 6#define DD_is_integer(sv) (SvIOK(sv) && (SvIsUV(val) ? SvUV(sv) == SvNV(sv) : SvIV(sv) == SvNV(sv)))#else#define DD_is_integer(sv) SvIOK(sv)#endif/* does a string need to be protected? */static I32needs_quote(register const char *s){TOP: if (s[0] == ':') { if (*++s) { if (*s++ != ':') return 1; } else return 1; } if (isIDFIRST(*s)) { while (*++s) if (!isALNUM(*s)) { if (*s == ':') goto TOP; else return 1; } } else return 1; return 0;}/* count the number of "'"s and "\"s in string */static I32num_q(register const char *s, register STRLEN slen){ register I32 ret = 0; while (slen > 0) { if (*s == '\'' || *s == '\\') ++ret; ++s; --slen; } return ret;}/* returns number of chars added to escape "'"s and "\"s in s *//* slen number of characters in s will be escaped *//* destination must be long enough for additional chars */static I32esc_q(register char *d, register const char *s, register STRLEN slen){ register I32 ret = 0; while (slen > 0) { switch (*s) { case '\'': case '\\': *d = '\\'; ++d; ++ret; default: *d = *s; ++d; ++s; --slen; break; } } return ret;}static I32esc_q_utf8(pTHX_ SV* sv, register const char *src, register STRLEN slen){ char *r, *rstart; const char *s = src; const char * const send = src + slen; STRLEN j, cur = SvCUR(sv); /* Could count 128-255 and 256+ in two variables, if we want to be like &qquote and make a distinction. */ STRLEN grow = 0; /* bytes needed to represent chars 128+ */ /* STRLEN topbit_grow = 0; bytes needed to represent chars 128-255 */ STRLEN backslashes = 0; STRLEN single_quotes = 0; STRLEN qq_escapables = 0; /* " $ @ will need a \ in "" strings. */ STRLEN normal = 0; /* this will need EBCDICification */ for (s = src; s < send; s += UTF8SKIP(s)) { const UV k = utf8_to_uvchr((U8*)s, NULL);#ifdef EBCDIC if (!isprint(k) || k > 256) {#else if (k > 127) {#endif /* 4: \x{} then count the number of hex digits. */ grow += 4 + (k <= 0xFF ? 2 : k <= 0xFFF ? 3 : k <= 0xFFFF ? 4 :#if UVSIZE == 4 8 /* We may allocate a bit more than the minimum here. */#else k <= 0xFFFFFFFF ? 8 : UVSIZE * 4#endif ); } else if (k == '\\') { backslashes++; } else if (k == '\'') { single_quotes++; } else if (k == '"' || k == '$' || k == '@') { qq_escapables++; } else { normal++; } } if (grow) { /* We have something needing hex. 3 is ""\0 */ sv_grow(sv, cur + 3 + grow + 2*backslashes + single_quotes + 2*qq_escapables + normal); rstart = r = SvPVX(sv) + cur; *r++ = '"'; for (s = src; s < send; s += UTF8SKIP(s)) { const UV k = utf8_to_uvchr((U8*)s, NULL); if (k == '"' || k == '\\' || k == '$' || k == '@') { *r++ = '\\'; *r++ = (char)k; } else#ifdef EBCDIC if (isprint(k) && k < 256)#else if (k < 0x80)#endif *r++ = (char)k; else { r = r + my_sprintf(r, "\\x{%"UVxf"}", k); } } *r++ = '"'; } else { /* Single quotes. */ sv_grow(sv, cur + 3 + 2*backslashes + 2*single_quotes + qq_escapables + normal); rstart = r = SvPVX(sv) + cur; *r++ = '\''; for (s = src; s < send; s ++) { const char k = *s; if (k == '\'' || k == '\\') *r++ = '\\'; *r++ = k; } *r++ = '\''; } *r = '\0'; j = r - rstart; SvCUR_set(sv, cur + j); return j;}/* append a repeated string to an SV */static SV *sv_x(pTHX_ SV *sv, const char *str, STRLEN len, I32 n){ if (!sv) sv = newSVpvn("", 0);#ifdef DEBUGGING else assert(SvTYPE(sv) >= SVt_PV);#endif if (n > 0) { SvGROW(sv, len*n + SvCUR(sv) + 1); if (len == 1) { char * const start = SvPVX(sv) + SvCUR(sv); SvCUR_set(sv, SvCUR(sv) + n); start[n] = '\0'; while (n > 0) start[--n] = str[0]; } else while (n > 0) { sv_catpvn(sv, str, len); --n; } } return sv;}/* * This ought to be split into smaller functions. (it is one long function since * it exactly parallels the perl version, which was one long thing for * efficiency raisins.) Ugggh! */static I32DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv, AV *postav, I32 *levelp, I32 indent, SV *pad, SV *xpad, SV *apad, SV *sep, SV *pair, SV *freezer, SV *toaster, I32 purity, I32 deepcopy, I32 quotekeys, SV *bless, I32 maxdepth, SV *sortkeys){ char tmpbuf[128]; U32 i; char *c, *r, *realpack;#ifdef DD_USE_OLD_ID_FORMAT char id[128];#else UV id_buffer; char *const id = (char *)&id_buffer;#endif SV **svp; SV *sv, *ipad, *ival; SV *blesspad = Nullsv; AV *seenentry = NULL; char *iname; STRLEN inamelen, idlen = 0; U32 realtype; if (!val) return 0; /* If the ouput buffer has less than some arbitary amount of space remaining, then enlarge it. For the test case (25M of output), *1.1 was slower, *2.0 was the same, so the first guess of 1.5 is deemed to be good enough. */ if (SvTYPE(retval) >= SVt_PV && (SvLEN(retval) - SvCUR(retval)) < 42) { sv_grow(retval, SvCUR(retval) * 3 / 2); } realtype = SvTYPE(val); if (SvGMAGICAL(val)) mg_get(val); if (SvROK(val)) { /* If a freeze method is provided and the object has it, call it. Warn on errors. */ if (SvOBJECT(SvRV(val)) && freezer && SvPOK(freezer) && SvCUR(freezer) && gv_fetchmeth(SvSTASH(SvRV(val)), SvPVX_const(freezer), SvCUR(freezer), -1) != NULL) { dSP; ENTER; SAVETMPS; PUSHMARK(sp); XPUSHs(val); PUTBACK; i = perl_call_method(SvPVX_const(freezer), G_EVAL|G_VOID); SPAGAIN; if (SvTRUE(ERRSV)) warn("WARNING(Freezer method call failed): %"SVf"", ERRSV); PUTBACK; FREETMPS; LEAVE; } ival = SvRV(val); realtype = SvTYPE(ival);#ifdef DD_USE_OLD_ID_FORMAT idlen = my_snprintf(id, sizeof(id), "0x%"UVxf, PTR2UV(ival));#else id_buffer = PTR2UV(ival); idlen = sizeof(id_buffer);#endif if (SvOBJECT(ival)) realpack = HvNAME_get(SvSTASH(ival)); else realpack = Nullch; /* if it has a name, we need to either look it up, or keep a tab * on it so we know when we hit it later */ if (namelen) { if ((svp = hv_fetch(seenhv, id, idlen, FALSE)) && (sv = *svp) && SvROK(sv) && (seenentry = (AV*)SvRV(sv))) { SV *othername; if ((svp = av_fetch(seenentry, 0, FALSE)) && (othername = *svp)) { if (purity && *levelp > 0) { SV *postentry; if (realtype == SVt_PVHV) sv_catpvn(retval, "{}", 2); else if (realtype == SVt_PVAV) sv_catpvn(retval, "[]", 2); else sv_catpvn(retval, "do{my $o}", 9); postentry = newSVpvn(name, namelen); sv_catpvn(postentry, " = ", 3); sv_catsv(postentry, othername); av_push(postav, postentry); } else { if (name[0] == '@' || name[0] == '%') { if ((SvPVX_const(othername))[0] == '\\' && (SvPVX_const(othername))[1] == name[0]) { sv_catpvn(retval, SvPVX_const(othername)+1, SvCUR(othername)-1); } else { sv_catpvn(retval, name, 1); sv_catpvn(retval, "{", 1); sv_catsv(retval, othername); sv_catpvn(retval, "}", 1); } } else sv_catsv(retval, othername); } return 1; } else {#ifdef DD_USE_OLD_ID_FORMAT warn("ref name not found for %s", id);#else warn("ref name not found for 0x%"UVxf, PTR2UV(ival));#endif return 0; } } else { /* store our name and continue */ SV *namesv; if (name[0] == '@' || name[0] == '%') { namesv = newSVpvn("\\", 1); sv_catpvn(namesv, name, namelen); } else if (realtype == SVt_PVCV && name[0] == '*') { namesv = newSVpvn("\\", 2); sv_catpvn(namesv, name, namelen); (SvPVX(namesv))[1] = '&'; } else namesv = newSVpvn(name, namelen); seenentry = newAV(); av_push(seenentry, namesv); (void)SvREFCNT_inc(val); av_push(seenentry, val); (void)hv_store(seenhv, id, idlen, newRV_inc((SV*)seenentry), 0); SvREFCNT_dec(seenentry); } } if (realpack && *realpack == 'R' && strEQ(realpack, "Regexp")) { STRLEN rlen; const char *rval = SvPV(val, rlen); const char *slash = strchr(rval, '/'); sv_catpvn(retval, "qr/", 3); while (slash) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?