15759b3d2Safresh1################################################################################
25759b3d2Safresh1##
35759b3d2Safresh1##  Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
45759b3d2Safresh1##  Version 2.x, Copyright (C) 2001, Paul Marquess.
55759b3d2Safresh1##  Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
65759b3d2Safresh1##
75759b3d2Safresh1##  This program is free software; you can redistribute it and/or
85759b3d2Safresh1##  modify it under the same terms as Perl itself.
95759b3d2Safresh1##
105759b3d2Safresh1################################################################################
115759b3d2Safresh1
125759b3d2Safresh1=provides
135759b3d2Safresh1
145759b3d2Safresh1__UNDEFINED__
155759b3d2Safresh1pv_escape
165759b3d2Safresh1pv_pretty
175759b3d2Safresh1pv_display
185759b3d2Safresh1
195759b3d2Safresh1=implementation
205759b3d2Safresh1
215759b3d2Safresh1__UNDEFINED__ PERL_PV_ESCAPE_QUOTE              0x0001
225759b3d2Safresh1__UNDEFINED__ PERL_PV_PRETTY_QUOTE              PERL_PV_ESCAPE_QUOTE
235759b3d2Safresh1__UNDEFINED__ PERL_PV_PRETTY_ELLIPSES           0x0002
245759b3d2Safresh1__UNDEFINED__ PERL_PV_PRETTY_LTGT               0x0004
255759b3d2Safresh1__UNDEFINED__ PERL_PV_ESCAPE_FIRSTCHAR          0x0008
265759b3d2Safresh1__UNDEFINED__ PERL_PV_ESCAPE_UNI                0x0100
275759b3d2Safresh1__UNDEFINED__ PERL_PV_ESCAPE_UNI_DETECT         0x0200
285759b3d2Safresh1__UNDEFINED__ PERL_PV_ESCAPE_ALL                0x1000
295759b3d2Safresh1__UNDEFINED__ PERL_PV_ESCAPE_NOBACKSLASH        0x2000
305759b3d2Safresh1__UNDEFINED__ PERL_PV_ESCAPE_NOCLEAR            0x4000
315759b3d2Safresh1__UNDEFINED__ PERL_PV_ESCAPE_RE                 0x8000
325759b3d2Safresh1__UNDEFINED__ PERL_PV_PRETTY_NOCLEAR            PERL_PV_ESCAPE_NOCLEAR
335759b3d2Safresh1
345759b3d2Safresh1__UNDEFINED__ PERL_PV_PRETTY_DUMP               PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_QUOTE
355759b3d2Safresh1__UNDEFINED__ PERL_PV_PRETTY_REGPROP            PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_LTGT|PERL_PV_ESCAPE_RE
365759b3d2Safresh1
375759b3d2Safresh1/* Hint: pv_escape
385759b3d2Safresh1 * Note that unicode functionality is only backported to
395759b3d2Safresh1 * those perl versions that support it. For older perl
405759b3d2Safresh1 * versions, the implementation will fall back to bytes.
415759b3d2Safresh1 */
425759b3d2Safresh1
435759b3d2Safresh1#ifndef pv_escape
445759b3d2Safresh1#if { NEED pv_escape }
455759b3d2Safresh1
465759b3d2Safresh1char *
475759b3d2Safresh1pv_escape(pTHX_ SV *dsv, char const * const str,
485759b3d2Safresh1  const STRLEN count, const STRLEN max,
495759b3d2Safresh1  STRLEN * const escaped, const U32 flags)
505759b3d2Safresh1{
515759b3d2Safresh1    const char esc = flags & PERL_PV_ESCAPE_RE ? '%' : '\\';
525759b3d2Safresh1    const char dq = flags & PERL_PV_ESCAPE_QUOTE ? '"' : esc;
535759b3d2Safresh1    char octbuf[32] = "%123456789ABCDF";
545759b3d2Safresh1    STRLEN wrote = 0;
555759b3d2Safresh1    STRLEN chsize = 0;
565759b3d2Safresh1    STRLEN readsize = 1;
57f3efcd01Safresh1#if defined(is_utf8_string) && defined(utf8_to_uvchr_buf)
585759b3d2Safresh1    bool isuni = flags & PERL_PV_ESCAPE_UNI ? 1 : 0;
595759b3d2Safresh1#endif
605759b3d2Safresh1    const char *pv  = str;
615759b3d2Safresh1    const char * const end = pv + count;
625759b3d2Safresh1    octbuf[0] = esc;
635759b3d2Safresh1
645759b3d2Safresh1    if (!(flags & PERL_PV_ESCAPE_NOCLEAR))
655759b3d2Safresh1        sv_setpvs(dsv, "");
665759b3d2Safresh1
67f3efcd01Safresh1#if defined(is_utf8_string) && defined(utf8_to_uvchr_buf)
685759b3d2Safresh1    if ((flags & PERL_PV_ESCAPE_UNI_DETECT) && is_utf8_string((U8*)pv, count))
695759b3d2Safresh1        isuni = 1;
705759b3d2Safresh1#endif
715759b3d2Safresh1
725759b3d2Safresh1    for (; pv < end && (!max || wrote < max) ; pv += readsize) {
735759b3d2Safresh1        const UV u =
74f3efcd01Safresh1#if defined(is_utf8_string) && defined(utf8_to_uvchr_buf)
75f3efcd01Safresh1                     isuni ? utf8_to_uvchr_buf((U8*)pv, end, &readsize) :
765759b3d2Safresh1#endif
775759b3d2Safresh1                             (U8)*pv;
785759b3d2Safresh1        const U8 c = (U8)u & 0xFF;
795759b3d2Safresh1
805759b3d2Safresh1        if (u > 255 || (flags & PERL_PV_ESCAPE_ALL)) {
815759b3d2Safresh1            if (flags & PERL_PV_ESCAPE_FIRSTCHAR)
825759b3d2Safresh1                chsize = my_snprintf(octbuf, sizeof octbuf,
835759b3d2Safresh1                                      "%" UVxf, u);
845759b3d2Safresh1            else
855759b3d2Safresh1                chsize = my_snprintf(octbuf, sizeof octbuf,
865759b3d2Safresh1                                      "%cx{%" UVxf "}", esc, u);
875759b3d2Safresh1        } else if (flags & PERL_PV_ESCAPE_NOBACKSLASH) {
885759b3d2Safresh1            chsize = 1;
895759b3d2Safresh1        } else {
905759b3d2Safresh1            if (c == dq || c == esc || !isPRINT(c)) {
915759b3d2Safresh1                chsize = 2;
925759b3d2Safresh1                switch (c) {
935759b3d2Safresh1                case '\\' : /* fallthrough */
945759b3d2Safresh1                case '%'  : if (c == esc)
955759b3d2Safresh1                                octbuf[1] = esc;
965759b3d2Safresh1                            else
975759b3d2Safresh1                                chsize = 1;
985759b3d2Safresh1                            break;
995759b3d2Safresh1                case '\v' : octbuf[1] = 'v'; break;
1005759b3d2Safresh1                case '\t' : octbuf[1] = 't'; break;
1015759b3d2Safresh1                case '\r' : octbuf[1] = 'r'; break;
1025759b3d2Safresh1                case '\n' : octbuf[1] = 'n'; break;
1035759b3d2Safresh1                case '\f' : octbuf[1] = 'f'; break;
1045759b3d2Safresh1                case '"'  : if (dq == '"')
1055759b3d2Safresh1                                octbuf[1] = '"';
1065759b3d2Safresh1                            else
1075759b3d2Safresh1                                chsize = 1;
1085759b3d2Safresh1                            break;
1095759b3d2Safresh1                default:    chsize = my_snprintf(octbuf, sizeof octbuf,
1105759b3d2Safresh1                                pv < end && isDIGIT((U8)*(pv+readsize))
1115759b3d2Safresh1                                ? "%c%03o" : "%c%o", esc, c);
1125759b3d2Safresh1                }
1135759b3d2Safresh1            } else {
1145759b3d2Safresh1                chsize = 1;
1155759b3d2Safresh1            }
1165759b3d2Safresh1        }
1175759b3d2Safresh1        if (max && wrote + chsize > max) {
1185759b3d2Safresh1            break;
1195759b3d2Safresh1        } else if (chsize > 1) {
1205759b3d2Safresh1            sv_catpvn(dsv, octbuf, chsize);
1215759b3d2Safresh1            wrote += chsize;
1225759b3d2Safresh1        } else {
1235759b3d2Safresh1            char tmp[2];
1245759b3d2Safresh1            my_snprintf(tmp, sizeof tmp, "%c", c);
1255759b3d2Safresh1            sv_catpvn(dsv, tmp, 1);
1265759b3d2Safresh1            wrote++;
1275759b3d2Safresh1        }
1285759b3d2Safresh1        if (flags & PERL_PV_ESCAPE_FIRSTCHAR)
1295759b3d2Safresh1            break;
1305759b3d2Safresh1    }
1315759b3d2Safresh1    if (escaped != NULL)
1325759b3d2Safresh1        *escaped= pv - str;
1335759b3d2Safresh1    return SvPVX(dsv);
1345759b3d2Safresh1}
1355759b3d2Safresh1
1365759b3d2Safresh1#endif
1375759b3d2Safresh1#endif
1385759b3d2Safresh1
1395759b3d2Safresh1#ifndef pv_pretty
1405759b3d2Safresh1#if { NEED pv_pretty }
1415759b3d2Safresh1
1425759b3d2Safresh1char *
1435759b3d2Safresh1pv_pretty(pTHX_ SV *dsv, char const * const str, const STRLEN count,
1445759b3d2Safresh1  const STRLEN max, char const * const start_color, char const * const end_color,
1455759b3d2Safresh1  const U32 flags)
1465759b3d2Safresh1{
1475759b3d2Safresh1    const U8 dq = (flags & PERL_PV_PRETTY_QUOTE) ? '"' : '%';
1485759b3d2Safresh1    STRLEN escaped;
1495759b3d2Safresh1
1505759b3d2Safresh1    if (!(flags & PERL_PV_PRETTY_NOCLEAR))
1515759b3d2Safresh1        sv_setpvs(dsv, "");
1525759b3d2Safresh1
1535759b3d2Safresh1    if (dq == '"')
1545759b3d2Safresh1        sv_catpvs(dsv, "\"");
1555759b3d2Safresh1    else if (flags & PERL_PV_PRETTY_LTGT)
1565759b3d2Safresh1        sv_catpvs(dsv, "<");
1575759b3d2Safresh1
1585759b3d2Safresh1    if (start_color != NULL)
1595759b3d2Safresh1        sv_catpv(dsv, D_PPP_CONSTPV_ARG(start_color));
1605759b3d2Safresh1
1615759b3d2Safresh1    pv_escape(dsv, str, count, max, &escaped, flags | PERL_PV_ESCAPE_NOCLEAR);
1625759b3d2Safresh1
1635759b3d2Safresh1    if (end_color != NULL)
1645759b3d2Safresh1        sv_catpv(dsv, D_PPP_CONSTPV_ARG(end_color));
1655759b3d2Safresh1
1665759b3d2Safresh1    if (dq == '"')
1675759b3d2Safresh1        sv_catpvs(dsv, "\"");
1685759b3d2Safresh1    else if (flags & PERL_PV_PRETTY_LTGT)
1695759b3d2Safresh1        sv_catpvs(dsv, ">");
1705759b3d2Safresh1
1715759b3d2Safresh1    if ((flags & PERL_PV_PRETTY_ELLIPSES) && escaped < count)
1725759b3d2Safresh1        sv_catpvs(dsv, "...");
1735759b3d2Safresh1
1745759b3d2Safresh1    return SvPVX(dsv);
1755759b3d2Safresh1}
1765759b3d2Safresh1
1775759b3d2Safresh1#endif
1785759b3d2Safresh1#endif
1795759b3d2Safresh1
1805759b3d2Safresh1#ifndef pv_display
1815759b3d2Safresh1#if { NEED pv_display }
1825759b3d2Safresh1
1835759b3d2Safresh1char *
1845759b3d2Safresh1pv_display(pTHX_ SV *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim)
1855759b3d2Safresh1{
1865759b3d2Safresh1    pv_pretty(dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP);
1875759b3d2Safresh1    if (len > cur && pv[cur] == '\0')
1885759b3d2Safresh1        sv_catpvs(dsv, "\\0");
1895759b3d2Safresh1    return SvPVX(dsv);
1905759b3d2Safresh1}
1915759b3d2Safresh1
1925759b3d2Safresh1#endif
1935759b3d2Safresh1#endif
1945759b3d2Safresh1
1955759b3d2Safresh1=xsinit
1965759b3d2Safresh1
1975759b3d2Safresh1#define NEED_pv_escape
1985759b3d2Safresh1#define NEED_pv_pretty
1995759b3d2Safresh1#define NEED_pv_display
2005759b3d2Safresh1
2015759b3d2Safresh1=xsubs
2025759b3d2Safresh1
2035759b3d2Safresh1void
2045759b3d2Safresh1pv_escape_can_unicode()
2055759b3d2Safresh1        PPCODE:
206f3efcd01Safresh1#if defined(is_utf8_string) && defined(utf8_to_uvchr_buf)
2075759b3d2Safresh1                XSRETURN_YES;
2085759b3d2Safresh1#else
2095759b3d2Safresh1                XSRETURN_NO;
2105759b3d2Safresh1#endif
2115759b3d2Safresh1
2125759b3d2Safresh1void
2135759b3d2Safresh1pv_pretty()
2145759b3d2Safresh1        PREINIT:
2155759b3d2Safresh1                char *rv;
2165759b3d2Safresh1        PPCODE:
2175759b3d2Safresh1                EXTEND(SP, 8);
2185759b3d2Safresh1                ST(0) = sv_newmortal();
2195759b3d2Safresh1                rv = pv_pretty(ST(0), "foobarbaz",
2205759b3d2Safresh1                                9, 40, NULL, NULL, 0);
2215759b3d2Safresh1                ST(1) = sv_2mortal(newSVpv(rv, 0));
2225759b3d2Safresh1                ST(2) = sv_newmortal();
2235759b3d2Safresh1                rv = pv_pretty(ST(2), "pv_p\retty\n",
2245759b3d2Safresh1                                10, 40, "left", "right", PERL_PV_PRETTY_LTGT);
2255759b3d2Safresh1                ST(3) = sv_2mortal(newSVpv(rv, 0));
2265759b3d2Safresh1                ST(4) = sv_newmortal();
2275759b3d2Safresh1                rv = pv_pretty(ST(4), "N\303\275 Batter\303\255",
2285759b3d2Safresh1                                12, 20, NULL, NULL, PERL_PV_ESCAPE_UNI_DETECT);
2295759b3d2Safresh1                ST(5) = sv_2mortal(newSVpv(rv, 0));
2305759b3d2Safresh1                ST(6) = sv_newmortal();
2315759b3d2Safresh1                rv = pv_pretty(ST(6), "\303\201g\303\246tis Byrjun",
2325759b3d2Safresh1                                15, 18, NULL, NULL, PERL_PV_ESCAPE_UNI_DETECT|PERL_PV_PRETTY_ELLIPSES);
2335759b3d2Safresh1                ST(7) = sv_2mortal(newSVpv(rv, 0));
2345759b3d2Safresh1                XSRETURN(8);
2355759b3d2Safresh1
2365759b3d2Safresh1void
2375759b3d2Safresh1pv_display()
2385759b3d2Safresh1        PREINIT:
2395759b3d2Safresh1                char *rv;
2405759b3d2Safresh1        PPCODE:
2415759b3d2Safresh1                EXTEND(SP, 4);
2425759b3d2Safresh1                ST(0) = sv_newmortal();
2435759b3d2Safresh1                rv = pv_display(ST(0), "foob\0rbaz", 9, 10, 20);
2445759b3d2Safresh1                ST(1) = sv_2mortal(newSVpv(rv, 0));
2455759b3d2Safresh1                ST(2) = sv_newmortal();
2465759b3d2Safresh1                rv = pv_display(ST(2), "pv_display", 10, 11, 5);
2475759b3d2Safresh1                ST(3) = sv_2mortal(newSVpv(rv, 0));
2485759b3d2Safresh1                XSRETURN(4);
2495759b3d2Safresh1
2505759b3d2Safresh1=tests plan => 13
2515759b3d2Safresh1
2525759b3d2Safresh1my $uni = &Devel::PPPort::pv_escape_can_unicode();
2535759b3d2Safresh1
2545759b3d2Safresh1# sanity check
255*9a4edab6Sbluhmok($uni ? ivers($]) >= ivers("5.006") : ivers($]) < ivers("5.008"));
2565759b3d2Safresh1
2575759b3d2Safresh1my @r;
2585759b3d2Safresh1
2595759b3d2Safresh1@r = &Devel::PPPort::pv_pretty();
260de8cc8edSafresh1is($r[0], $r[1]);
261de8cc8edSafresh1is($r[0], "foobarbaz");
262de8cc8edSafresh1is($r[2], $r[3]);
263de8cc8edSafresh1is($r[2], '<leftpv_p\retty\nright>');
264de8cc8edSafresh1is($r[4], $r[5]);
265de8cc8edSafresh1if(ord("A") == 65) {
266de8cc8edSafresh1    is($r[4], $uni ? 'N\375 Batter\355' : 'N\303\275 Batter\303');
267de8cc8edSafresh1}
268de8cc8edSafresh1else {
269de8cc8edSafresh1    skip("Skip for non-ASCII platform");
270de8cc8edSafresh1}
271de8cc8edSafresh1is($r[6], $r[7]);
272de8cc8edSafresh1if(ord("A") == 65) {
273de8cc8edSafresh1    is($r[6], $uni ? '\301g\346tis Byrju...' : '\303\201g\303\246t...');
274de8cc8edSafresh1}
275de8cc8edSafresh1else {
276de8cc8edSafresh1    skip("Skip for non-ASCII platform");
277de8cc8edSafresh1}
2785759b3d2Safresh1
2795759b3d2Safresh1@r = &Devel::PPPort::pv_display();
280de8cc8edSafresh1is($r[0], $r[1]);
281de8cc8edSafresh1is($r[0], '"foob\0rbaz"\0');
282de8cc8edSafresh1is($r[2], $r[3]);
2835759b3d2Safresh1ok($r[2] eq '"pv_di"...\0' ||
2845759b3d2Safresh1   $r[2] eq '"pv_d"...\0');  # some perl implementations are broken... :(
285