]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve octal-escape output in bool vectors and strings
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 2 Mar 2018 01:58:26 +0000 (17:58 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 2 Mar 2018 02:16:43 +0000 (18:16 -0800)
* src/print.c (octalout): New function.
(print_vectorlike): When printing bool vectors, use
octal escapes for control characters when
print-escape-control-characters is non-nil, so that
the printed representation avoids encoding issues.
Rename locals to avoid byte-vs-char confusion.
(print_object): Don't output unnecessary zeros when
printing octal escapes.  Simplify by using octalout.

src/print.c

index b3c0f6f38fcef2e775aa4ac85df5f6bb3cfae3f6..a8bbb9d37a1b9871940f0f8b467d0548a71321e0 100644 (file)
@@ -313,6 +313,25 @@ printchar (unsigned int ch, Lisp_Object fun)
     }
 }
 
+/* Output an octal escape for C.  If C is less than '\100' consult the
+   following character (if any) to see whether to use three octal
+   digits to avoid misinterpretation of the next character.  The next
+   character after C will be taken from DATA, starting at byte
+   location I, if I is less than SIZE.  Use PRINTCHARFUN to output
+   each character.  */
+
+static void
+octalout (unsigned char c, unsigned char *data, ptrdiff_t i, ptrdiff_t size,
+         Lisp_Object printcharfun)
+{
+  int digits = (c > '\77' || (i < size && '0' <= data[i] && data[i] <= '7')
+               ? 3
+               : c > '\7' ? 2 : 1);
+  printchar ('\\', printcharfun);
+  do
+    printchar ('0' + ((c >> (3 * --digits)) & 7), printcharfun);
+  while (digits != 0);
+}
 
 /* Output SIZE characters, SIZE_BYTE bytes from string PTR using
    method PRINTCHARFUN.  PRINTCHARFUN nil means output to
@@ -1367,32 +1386,33 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
     case PVEC_BOOL_VECTOR:
       {
        EMACS_INT size = bool_vector_size (obj);
-       ptrdiff_t size_in_chars = bool_vector_bytes (size);
-       ptrdiff_t real_size_in_chars = size_in_chars;
+       ptrdiff_t size_in_bytes = bool_vector_bytes (size);
+       ptrdiff_t real_size_in_bytes = size_in_bytes;
+       unsigned char *data = bool_vector_uchar_data (obj);
 
        int len = sprintf (buf, "#&%"pI"d\"", size);
        strout (buf, len, len, printcharfun);
 
-       /* Don't print more characters than the specified maximum.
+       /* Don't print more bytes than the specified maximum.
           Negative values of print-length are invalid.  Treat them
           like a print-length of nil.  */
        if (NATNUMP (Vprint_length)
-           && XFASTINT (Vprint_length) < size_in_chars)
-         size_in_chars = XFASTINT (Vprint_length);
+           && XFASTINT (Vprint_length) < size_in_bytes)
+         size_in_bytes = XFASTINT (Vprint_length);
 
-       for (ptrdiff_t i = 0; i < size_in_chars; i++)
+       for (ptrdiff_t i = 0; i < size_in_bytes; i++)
          {
            maybe_quit ();
-           unsigned char c = bool_vector_uchar_data (obj)[i];
+           unsigned char c = data[i];
            if (c == '\n' && print_escape_newlines)
              print_c_string ("\\n", printcharfun);
            else if (c == '\f' && print_escape_newlines)
              print_c_string ("\\f", printcharfun);
-           else if (c > '\177')
+           else if (c > '\177'
+                    || (print_escape_control_characters && c_iscntrl (c)))
              {
                /* Use octal escapes to avoid encoding issues.  */
-               int len = sprintf (buf, "\\%o", c);
-               strout (buf, len, len, printcharfun);
+               octalout (c, data, i + 1, size_in_bytes, printcharfun);
              }
            else
              {
@@ -1402,7 +1422,7 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
              }
          }
 
-       if (size_in_chars < real_size_in_chars)
+       if (size_in_bytes < real_size_in_bytes)
          print_c_string (" ...", printcharfun);
        printchar ('\"', printcharfun);
       }
@@ -1854,9 +1874,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
                     (when requested) a non-ASCII character in a unibyte buffer,
                     print single-byte non-ASCII string chars
                     using octal escapes.  */
-                 char outbuf[5];
-                 int len = sprintf (outbuf, "\\%03o", c + 0u);
-                 strout (outbuf, len, len, printcharfun);
+                 octalout (c, SDATA (obj), i_byte, size_byte, printcharfun);
                  need_nonhex = false;
                }
              else if (multibyte
@@ -1870,7 +1888,6 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
                }
              else
                {
-                  bool still_need_nonhex = false;
                  /* If we just had a hex escape, and this character
                     could be taken as part of it,
                     output `\ ' to prevent that.  */
@@ -1884,22 +1901,16 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
                            ? (c = 'n', true)
                            : c == '\f' && print_escape_newlines
                            ? (c = 'f', true)
-                           : c == '\0' && print_escape_control_characters
-                           ? (c = '0', still_need_nonhex = true)
                            : c == '\"' || c == '\\')
                     {
                       printchar ('\\', printcharfun);
                       printchar (c, printcharfun);
                     }
                   else if (print_escape_control_characters && c_iscntrl (c))
-                    {
-                      char outbuf[1 + 3 + 1];
-                      int len = sprintf (outbuf, "\\%03o", c + 0u);
-                      strout (outbuf, len, len, printcharfun);
-                    }
+                   octalout (c, SDATA (obj), i_byte, size_byte, printcharfun);
                   else
                     printchar (c, printcharfun);
-                 need_nonhex = still_need_nonhex;
+                 need_nonhex = false;
                }
            }
          printchar ('\"', printcharfun);