This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
pv_uni_display: Use common fcn; \b mnemonic
authorKarl Williamson <khw@cpan.org>
Thu, 16 Jan 2020 23:14:40 +0000 (16:14 -0700)
committerKarl Williamson <khw@cpan.org>
Thu, 23 Jan 2020 22:46:56 +0000 (15:46 -0700)
This removes the (almost) duplicate code in this function to display
mnemonics for control characters that have them.  The reason the two
pieces of code aren't precisely the same is that the other function also
uses \b as a mnemonic for backspace.  Using all possible mnemonics is
desirable, so a flag is added for pv_uni_display to now use \b.  This is
now by default enabled in double-quoted strings, but not regex patterns
(as \b there means something quite different except in character classes).
B.pm is changed to expect \b.

ext/B/B.pm
ext/B/B.xs
ext/B/t/b.t
utf8.c
utf8.h

index 8eb749c..f199a05 100644 (file)
@@ -20,7 +20,7 @@ sub import {
 # walkoptree comes from B.xs
 
 BEGIN {
-    $B::VERSION = '1.78';
+    $B::VERSION = '1.79';
     @B::EXPORT_OK = ();
 
     # Our BOOT code needs $VERSION set, and will append to @EXPORT_OK.
index 7bd8353..b3d04b8 100644 (file)
@@ -258,7 +258,7 @@ cstring(pTHX_ SV *sv, bool perlstyle)
                sv_catpvs(sstr, "\\@");
            else if (*s == '\\')
            {
-               if (memCHRs("nrftax\\",*(s+1)))
+               if (memCHRs("nrftabx\\",*(s+1)))
                    sv_catpvn(sstr, s++, 2);
                else
                    sv_catpvs(sstr, "\\\\");
index d1dba06..aa67fd3 100644 (file)
@@ -290,7 +290,6 @@ is(B::opnumber("pp_null"), 0, "Testing opnumber with opname (pp_null)");
     while (my ($test, $expect) = splice @tests, 0, 2) {
        is(B::perlstring($test), $expect, "B::perlstring($expect)");
        utf8::upgrade $test;
-       $expect =~ s/\\b/sprintf("\\x{%x}", utf8::unicode_to_native(8))/eg;
        $expect =~ s/\\([0-7]{3})/sprintf "\\x\{%x\}", oct $1/eg;
        is(B::perlstring($test), $expect, "B::perlstring($expect) (Unicode)");
     }
diff --git a/utf8.c b/utf8.c
index 7b82985..a67c987 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -4053,9 +4053,9 @@ Perl_check_utf8_print(pTHX_ const U8* s, const STRLEN len)
 /*
 =for apidoc pv_uni_display
 
-Build to the scalar C<dsv> a displayable version of the string C<spv>,
-length C<len>, the displayable version being at most C<pvlim> bytes long
-(if longer, the rest is truncated and C<"..."> will be appended).
+Build to the scalar C<dsv> a displayable version of the UTF-8 encoded string
+C<spv>, length C<len>, the displayable version being at most C<pvlim> bytes
+long (if longer, the rest is truncated and C<"..."> will be appended).
 
 The C<flags> argument can have C<UNI_DISPLAY_ISPRINT> set to display
 C<isPRINT()>able characters as themselves, C<UNI_DISPLAY_BACKSLASH>
@@ -4064,6 +4064,9 @@ to display the C<\\[nrfta\\]> as the backslashed versions (like C<"\n">)
 C<UNI_DISPLAY_QQ> (and its alias C<UNI_DISPLAY_REGEX>) have both
 C<UNI_DISPLAY_BACKSLASH> and C<UNI_DISPLAY_ISPRINT> turned on.
 
+Additionally, there is now C<UNI_DISPLAY_BACKSPACE> which allows C<\b> for a
+backspace, but only when C<UNI_DISPLAY_BACKSLASH> also is set.
+
 The pointer to the PV of the C<dsv> is returned.
 
 See also L</sv_uni_display>.
@@ -4082,10 +4085,7 @@ Perl_pv_uni_display(pTHX_ SV *dsv, const U8 *spv, STRLEN len, STRLEN pvlim,
     SvUTF8_off(dsv);
     for (s = (const char *)spv, e = s + len; s < e; s += UTF8SKIP(s)) {
         UV u;
-         /* This serves double duty as a flag and a character to print after
-            a \ when flags & UNI_DISPLAY_BACKSLASH is true.
-         */
-        char ok = 0;
+        bool ok = 0;
 
         if (pvlim && SvCUR(dsv) >= pvlim) {
              truncated++;
@@ -4095,27 +4095,19 @@ Perl_pv_uni_display(pTHX_ SV *dsv, const U8 *spv, STRLEN len, STRLEN pvlim,
         if (u < 256) {
             const unsigned char c = (unsigned char)u & 0xFF;
             if (flags & UNI_DISPLAY_BACKSLASH) {
-                switch (c) {
-                case '\n':
-                    ok = 'n'; break;
-                case '\r':
-                    ok = 'r'; break;
-                case '\t':
-                    ok = 't'; break;
-                case '\f':
-                    ok = 'f'; break;
-                case '\a':
-                    ok = 'a'; break;
-                case '\\':
-                    ok = '\\'; break;
-                default: break;
-                }
-                if (ok) {
-                    const char string = ok;
-                    sv_catpvs(dsv, "\\");
-                    sv_catpvn(dsv, &string, 1);
-                }
-            }
+                 if (    isMNEMONIC_CNTRL(c)
+                     && (   c != '\b'
+                         || (flags & UNI_DISPLAY_BACKSPACE)))
+                 {
+                    const char * mnemonic = cntrl_to_mnemonic(c);
+                    sv_catpvn(dsv, mnemonic, strlen(mnemonic));
+                    ok = 1;
+                 }
+                 else if (c == '\\') {
+                    sv_catpvs(dsv, "\\\\");
+                    ok = 1;
+                 }
+             }
             /* isPRINT() is the locale-blind version. */
             if (!ok && (flags & UNI_DISPLAY_ISPRINT) && isPRINT(c)) {
                 const char string = c;
diff --git a/utf8.h b/utf8.h
index fa036f0..fb83507 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -1009,7 +1009,13 @@ Evaluates to 0xFFFD, the code point of the Unicode REPLACEMENT CHARACTER
 
 #define UNI_DISPLAY_ISPRINT    0x0001
 #define UNI_DISPLAY_BACKSLASH  0x0002
-#define UNI_DISPLAY_QQ         (UNI_DISPLAY_ISPRINT|UNI_DISPLAY_BACKSLASH)
+#define UNI_DISPLAY_BACKSPACE  0x0004  /* Allow \b when also
+                                           UNI_DISPLAY_BACKSLASH */
+#define UNI_DISPLAY_QQ         (UNI_DISPLAY_ISPRINT                \
+                                |UNI_DISPLAY_BACKSLASH              \
+                                |UNI_DISPLAY_BACKSPACE)
+
+/* Character classes could also allow \b, but not patterns in general */
 #define UNI_DISPLAY_REGEX      (UNI_DISPLAY_ISPRINT|UNI_DISPLAY_BACKSLASH)
 
 #define ANYOF_FOLD_SHARP_S(node, input, end)   \