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 + -
显示快捷键?