]> code.delx.au - gnu-emacs/blobdiff - src/print.c
(syms_of_coding): Doc fix for inhibit-eol-conversion.
[gnu-emacs] / src / print.c
index c6c6c2b52946ced6a4c8c6bf7b3fbdc56a44343e..a24826f24c484bf90f9ee97268e719ec6f450132 100644 (file)
@@ -1,5 +1,6 @@
 /* Lisp object printing and output streams.
-   Copyright (C) 1985, 86, 88, 93, 94, 95, 97 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 88, 93, 94, 95, 97, 1998
+       Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -40,6 +41,8 @@ Boston, MA 02111-1307, USA.  */
 
 Lisp_Object Vstandard_output, Qstandard_output;
 
+Lisp_Object Qtemp_buffer_setup_hook;
+
 /* These are used to print like we read.  */
 extern Lisp_Object Qbackquote, Qcomma, Qcomma_at, Qcomma_dot, Qfunction;
 
@@ -108,8 +111,10 @@ char *print_buffer;
 
 /* Size allocated in print_buffer.  */
 int print_buffer_size;
-/* Size used in print_buffer.  */
+/* Chars stored in print_buffer.  */
 int print_buffer_pos;
+/* Bytes stored in print_buffer.  */
+int print_buffer_pos_byte;
 
 /* Maximum length of list to print in full; noninteger means
    effectively infinity */
@@ -125,7 +130,17 @@ Lisp_Object Vprint_level;
 
 int print_escape_newlines;
 
+/* Nonzero means to print single-byte non-ascii characters in strings as
+   octal escapes.  */
+
+int print_escape_nonascii;
+
+/* Nonzero means to print multibyte characters in strings as hex escapes.  */
+
+int print_escape_multibyte;
+
 Lisp_Object Qprint_escape_newlines;
+Lisp_Object Qprint_escape_multibyte, Qprint_escape_nonascii;
 
 /* Nonzero means print (quote foo) forms as 'foo, etc.  */
 
@@ -252,10 +267,20 @@ glyph_to_str_cpy (glyphs, str)
      }                                                         \
    if (NILP (printcharfun))                                    \
      {                                                         \
+       Lisp_Object string;                                     \
+       if (NILP (current_buffer->enable_multibyte_characters)  \
+          && ! print_escape_multibyte)                         \
+         specbind (Qprint_escape_multibyte, Qt);               \
+       if (! NILP (current_buffer->enable_multibyte_characters)        \
+          && ! print_escape_nonascii)                          \
+         specbind (Qprint_escape_nonascii, Qt);                        \
        if (print_buffer != 0)                                  \
-        record_unwind_protect (print_unwind,                   \
-                               make_string (print_buffer,      \
-                                            print_buffer_pos)); \
+        {                                                      \
+          string = make_string_from_bytes (print_buffer,       \
+                                           print_buffer_pos,   \
+                                           print_buffer_pos_byte); \
+          record_unwind_protect (print_unwind, string);        \
+        }                                                      \
        else                                                    \
         {                                                      \
            print_buffer_size = 1000;                           \
@@ -263,29 +288,44 @@ glyph_to_str_cpy (glyphs, str)
           free_print_buffer = 1;                               \
         }                                                      \
        print_buffer_pos = 0;                                   \
+       print_buffer_pos_byte = 0;                              \
      }                                                         \
    if (!CONSP (Vprint_gensym))                                 \
      Vprint_gensym_alist = Qnil
 
-#define PRINTFINISH                                    \
-   if (NILP (printcharfun))                            \
-     insert (print_buffer, print_buffer_pos);          \
-   if (free_print_buffer)                              \
-     {                                                 \
-       xfree (print_buffer);                           \
-       print_buffer = 0;                               \
-     }                                                 \
-   unbind_to (specpdl_count, Qnil);                    \
-   if (MARKERP (original))                             \
-     set_marker_both (original, Qnil, PT, PT_BYTE);    \
-   if (old_point >= 0)                                 \
-     SET_PT_BOTH (old_point + (old_point >= start_point        \
-                              ? PT - start_point : 0), \
+#define PRINTFINISH                                                    \
+   if (NILP (printcharfun))                                            \
+     {                                                                 \
+       if (print_buffer_pos != print_buffer_pos_byte                   \
+          && NILP (current_buffer->enable_multibyte_characters))       \
+        {                                                              \
+          unsigned char *temp                                          \
+            = (unsigned char *) alloca (print_buffer_pos + 1);         \
+          copy_text (print_buffer, temp, print_buffer_pos_byte,        \
+                     1, 0);                                            \
+          insert_1_both (temp, print_buffer_pos,                       \
+                         print_buffer_pos, 0, 1, 0);                   \
+        }                                                              \
+       else                                                            \
+        insert_1_both (print_buffer, print_buffer_pos,                 \
+                       print_buffer_pos_byte, 0, 1, 0);                \
+     }                                                                 \
+   if (free_print_buffer)                                              \
+     {                                                                 \
+       xfree (print_buffer);                                           \
+       print_buffer = 0;                                               \
+     }                                                                 \
+   unbind_to (specpdl_count, Qnil);                                    \
+   if (MARKERP (original))                                             \
+     set_marker_both (original, Qnil, PT, PT_BYTE);                    \
+   if (old_point >= 0)                                                 \
+     SET_PT_BOTH (old_point + (old_point >= start_point                        \
+                              ? PT - start_point : 0),                 \
                  old_point_byte + (old_point_byte >= start_point_byte  \
                               ? PT_BYTE - start_point_byte : 0));      \
-   if (old != current_buffer)                          \
-     set_buffer_internal (old);                                \
-   if (!CONSP (Vprint_gensym))                         \
+   if (old != current_buffer)                                          \
+     set_buffer_internal (old);                                                \
+   if (!CONSP (Vprint_gensym))                                         \
      Vprint_gensym_alist = Qnil
 
 #define PRINTCHAR(ch) printchar (ch, printcharfun)
@@ -328,11 +368,12 @@ printchar (ch, fun)
 
       QUIT;
       len = CHAR_STRING (ch, work, str);
-      if (print_buffer_pos + len >= print_buffer_size)
+      if (print_buffer_pos_byte + len >= print_buffer_size)
        print_buffer = (char *) xrealloc (print_buffer,
                                          print_buffer_size *= 2);
-      bcopy (str, print_buffer + print_buffer_pos, len);
-      print_buffer_pos += len;
+      bcopy (str, print_buffer + print_buffer_pos_byte, len);
+      print_buffer_pos += 1;
+      print_buffer_pos_byte += len;
       return;
     }
 
@@ -374,10 +415,53 @@ printchar (ch, fun)
            }
        }
 
-      message_dolog (str, len, 0);
+      if (len == 1
+         && ! NILP (current_buffer->enable_multibyte_characters)
+         && ! CHAR_HEAD_P (*str))
+       {
+         /* Convert the unibyte character to multibyte.  */
+         unsigned char c = *str;
+
+         len = count_size_as_multibyte (&c, 1);
+         copy_text (&c, work, 1, 0, 1);
+         str = work;
+       }
+
+      message_dolog (str, len, 0, len > 1);
+
+      if (! NILP (current_buffer->enable_multibyte_characters)
+         && ! message_enable_multibyte)
+       {
+         /* Record that the message buffer is multibyte.  */
+         message_enable_multibyte = 1;
+
+         /* If we have already had some message text in the messsage
+             buffer, we convert it to multibyte.  */
+         if (printbufidx > 0)
+           {
+             int size
+               = count_size_as_multibyte (FRAME_MESSAGE_BUF (mini_frame),
+                                          printbufidx);
+             unsigned char *tembuf = (unsigned char *) alloca (size + 1);
+             copy_text (FRAME_MESSAGE_BUF (mini_frame), tembuf, printbufidx,
+                        0, 1);
+             printbufidx = size;
+             if (printbufidx > FRAME_MESSAGE_BUF_SIZE (mini_frame))
+               {
+                 printbufidx = FRAME_MESSAGE_BUF_SIZE (mini_frame);
+                 /* Rewind incomplete multi-byte form.  */
+                 while (printbufidx > 0 && tembuf[printbufidx] >= 0xA0)
+                   printbufidx--;
+               }
+             bcopy (tembuf, FRAME_MESSAGE_BUF (mini_frame), printbufidx);
+           }
+       }
+
       if (printbufidx < FRAME_MESSAGE_BUF_SIZE (mini_frame) - len)
-       bcopy (str, &FRAME_MESSAGE_BUF (mini_frame)[printbufidx], len),
-       printbufidx += len;
+       {
+         bcopy (str, &FRAME_MESSAGE_BUF (mini_frame)[printbufidx], len);
+         printbufidx += len;
+       }
       FRAME_MESSAGE_BUF (mini_frame)[printbufidx] = 0;
       echo_area_glyphs_length = printbufidx;
 
@@ -390,26 +474,28 @@ printchar (ch, fun)
 }
 
 static void
-strout (ptr, size, printcharfun)
+strout (ptr, size, size_byte, printcharfun, multibyte)
      char *ptr;
-     int size;
+     int size, size_byte;
      Lisp_Object printcharfun;
+     int multibyte;
 {
   int i = 0;
 
   if (size < 0)
-    size = strlen (ptr);
+    size_byte = size = strlen (ptr);
 
   if (EQ (printcharfun, Qnil))
     {
-      if (print_buffer_pos + size > print_buffer_size)
+      if (print_buffer_pos_byte + size_byte > print_buffer_size)
        {
-         print_buffer_size = print_buffer_size * 2 + size;
+         print_buffer_size = print_buffer_size * 2 + size_byte;
          print_buffer = (char *) xrealloc (print_buffer,
                                            print_buffer_size);
        }
-      bcopy (ptr, print_buffer + print_buffer_pos, size);
+      bcopy (ptr, print_buffer + print_buffer_pos_byte, size_byte);
       print_buffer_pos += size;
+      print_buffer_pos_byte += size_byte;
 
 #ifdef MAX_PRINT_CHARS
       if (max_print)
@@ -431,7 +517,7 @@ strout (ptr, size, printcharfun)
 
       if (noninteractive)
        {
-         fwrite (ptr, 1, size, stdout);
+         fwrite (ptr, 1, size_byte, stdout);
          noninteractive_need_newline = 1;
          return;
        }
@@ -457,55 +543,128 @@ strout (ptr, size, printcharfun)
            }
        }
 
-      message_dolog (ptr, size, 0);
-      if (size > FRAME_MESSAGE_BUF_SIZE (mini_frame) - printbufidx - 1)
+      message_dolog (ptr, size_byte, 0, multibyte);
+
+      /* Convert message to multibyte if we are now adding multibyte text.  */
+      if (multibyte
+         && ! message_enable_multibyte
+         && printbufidx > 0)
+       {
+         int size = count_size_as_multibyte (FRAME_MESSAGE_BUF (mini_frame),
+                                             printbufidx);
+         unsigned char *tembuf = (unsigned char *) alloca (size + 1);
+         copy_text (FRAME_MESSAGE_BUF (mini_frame), tembuf, printbufidx,
+                    0, 1);
+         printbufidx = size;
+         if (printbufidx > FRAME_MESSAGE_BUF_SIZE (mini_frame))
+           {
+             printbufidx = FRAME_MESSAGE_BUF_SIZE (mini_frame);
+             /* Rewind incomplete multi-byte form.  */
+             while (printbufidx > 0 && tembuf[printbufidx] >= 0xA0)
+               printbufidx--;
+           }
+
+         bcopy (tembuf, FRAME_MESSAGE_BUF (mini_frame), printbufidx);
+       }
+
+      if (multibyte)
+       message_enable_multibyte = 1;
+
+      /* Compute how much of the new text will fit there.  */
+      if (size_byte > FRAME_MESSAGE_BUF_SIZE (mini_frame) - printbufidx - 1)
        {
-         size = FRAME_MESSAGE_BUF_SIZE (mini_frame) - printbufidx - 1;
+         size_byte = FRAME_MESSAGE_BUF_SIZE (mini_frame) - printbufidx - 1;
          /* Rewind incomplete multi-byte form.  */
-         while (size && (unsigned char) ptr[size] >= 0xA0) size--;
+         while (size_byte && (unsigned char) ptr[size_byte] >= 0xA0)
+           size_byte--;
        }
-      bcopy (ptr, &FRAME_MESSAGE_BUF (mini_frame) [printbufidx], size);
-      printbufidx += size;
-      echo_area_glyphs_length = printbufidx;
+
+      /* Put that part of the new text in.  */
+      bcopy (ptr, &FRAME_MESSAGE_BUF (mini_frame) [printbufidx], size_byte);
+      printbufidx += size_byte;
       FRAME_MESSAGE_BUF (mini_frame) [printbufidx] = 0;
+      echo_area_glyphs_length = printbufidx;
 
       return;
     }
 
   i = 0;
-  while (i < size)
-    {
-      /* Here, we must convert each multi-byte form to the
-         corresponding character code before handing it to PRINTCHAR.  */
-      int len;
-      int ch = STRING_CHAR_AND_LENGTH (ptr + i, size - i, len);
+  if (size == size_byte)
+    while (i < size_byte)
+      {
+       int ch = ptr[i++];
 
-      PRINTCHAR (ch);
-      i += len;
-    }
+       PRINTCHAR (ch);
+      }
+  else
+    while (i < size_byte)
+      {
+       /* Here, we must convert each multi-byte form to the
+          corresponding character code before handing it to PRINTCHAR.  */
+       int len;
+       int ch = STRING_CHAR_AND_LENGTH (ptr + i, size_byte - i, len);
+
+       PRINTCHAR (ch);
+       i += len;
+      }
 }
 
 /* Print the contents of a string STRING using PRINTCHARFUN.
    It isn't safe to use strout in many cases,
    because printing one char can relocate.  */
 
-void
+static void
 print_string (string, printcharfun)
      Lisp_Object string;
      Lisp_Object printcharfun;
 {
   if (EQ (printcharfun, Qt) || NILP (printcharfun))
-    /* strout is safe for output to a frame (echo area) or to print_buffer.  */
-    strout (XSTRING (string)->data, XSTRING (string)->size, printcharfun);
+    {
+      int chars;
+
+      if (STRING_MULTIBYTE (string))
+       chars = XSTRING (string)->size;
+      else if (EQ (printcharfun, Qt)
+              ? ! NILP (buffer_defaults.enable_multibyte_characters)
+              : ! NILP (current_buffer->enable_multibyte_characters))
+       chars = multibyte_chars_in_text (XSTRING (string)->data,
+                                        STRING_BYTES (XSTRING (string)));
+      else
+       chars = STRING_BYTES (XSTRING (string));
+
+      /* strout is safe for output to a frame (echo area) or to print_buffer.  */
+      strout (XSTRING (string)->data,
+             chars, STRING_BYTES (XSTRING (string)),
+             printcharfun, STRING_MULTIBYTE (string));
+    }
   else
     {
-      /* Otherwise, fetch the string address for each character.  */
+      /* Otherwise, string may be relocated by printing one char.
+        So re-fetch the string address for each character.  */
       int i;
       int size = XSTRING (string)->size;
+      int size_byte = STRING_BYTES (XSTRING (string));
       struct gcpro gcpro1;
       GCPRO1 (string);
-      for (i = 0; i < size; i++)
-       PRINTCHAR (XSTRING (string)->data[i]);
+      if (size == size_byte)
+       for (i = 0; i < size; i++)
+         PRINTCHAR (XSTRING (string)->data[i]);
+      else
+       for (i = 0; i < size_byte; i++)
+         {
+           /* Here, we must convert each multi-byte form to the
+              corresponding character code before handing it to PRINTCHAR.  */
+           int len;
+           int ch = STRING_CHAR_AND_CHAR_LENGTH (XSTRING (string)->data + i,
+                                                 size_byte - i, len);
+           if (!CHAR_VALID_P (ch, 0))
+             {
+               ch = XSTRING (string)->data[i];
+               len = 1;
+             }
+           PRINTCHAR (ch);
+           i += len;
+         }
       UNGCPRO;
     }
 }
@@ -527,8 +686,8 @@ PRINTCHARFUN defaults to the value of `standard-output' (which see).")
   return character;
 }
 
-/* Used from outside of print.c to print a block of SIZE chars at DATA
-   on the default output stream.
+/* Used from outside of print.c to print a block of SIZE
+   single-byte chars at DATA on the default output stream.
    Do not use this on the contents of a Lisp string.  */
 
 void
@@ -542,12 +701,12 @@ write_string (data, size)
   printcharfun = Vstandard_output;
 
   PRINTPREPARE;
-  strout (data, size, printcharfun);
+  strout (data, size, size, printcharfun, 0);
   PRINTFINISH;
 }
 
-/* Used from outside of print.c to print a block of SIZE chars at DATA
-   on a specified stream PRINTCHARFUN.
+/* Used from outside of print.c to print a block of SIZE
+   single-byte chars at DATA on a specified stream PRINTCHARFUN.
    Do not use this on the contents of a Lisp string.  */
 
 void
@@ -559,7 +718,7 @@ write_string_1 (data, size, printcharfun)
   PRINTDECLARE;
 
   PRINTPREPARE;
-  strout (data, size, printcharfun);
+  strout (data, size, size, printcharfun, 0);
   PRINTFINISH;
 }
 
@@ -570,25 +729,36 @@ void
 temp_output_buffer_setup (bufname)
     char *bufname;
 {
+  int count = specpdl_ptr - specpdl;
   register struct buffer *old = current_buffer;
   register Lisp_Object buf;
 
+  record_unwind_protect (set_buffer_if_live, Fcurrent_buffer ());
+
   Fset_buffer (Fget_buffer_create (build_string (bufname)));
 
   current_buffer->directory = old->directory;
   current_buffer->read_only = Qnil;
+  current_buffer->filename = Qnil;
+  current_buffer->undo_list = Qt;
+  current_buffer->overlays_before = Qnil;
+  current_buffer->overlays_after = Qnil;
+  current_buffer->enable_multibyte_characters
+    = buffer_defaults.enable_multibyte_characters;
   Ferase_buffer ();
-
   XSETBUFFER (buf, current_buffer);
-  specbind (Qstandard_output, buf);
 
-  set_buffer_internal (old);
+  call1 (Vrun_hooks, Qtemp_buffer_setup_hook);
+
+  unbind_to (count, Qnil);
+
+  specbind (Qstandard_output, buf);
 }
 
 Lisp_Object
 internal_with_output_to_temp_buffer (bufname, function, args)
      char *bufname;
-     Lisp_Object (*function) ();
+     Lisp_Object (*function) P_ ((Lisp_Object));
      Lisp_Object args;
 {
   int count = specpdl_ptr - specpdl;
@@ -617,9 +787,17 @@ The buffer is cleared out initially, and marked as unmodified when done.\n\
 All output done by BODY is inserted in that buffer by default.\n\
 The buffer is displayed in another window, but not selected.\n\
 The value of the last form in BODY is returned.\n\
-If BODY does not finish normally, the buffer BUFNAME is not displayed.\n\n\
+If BODY does not finish normally, the buffer BUFNAME is not displayed.\n\
+\n\
+The hook `temp-buffer-setup-hook' is run before BODY,\n\
+with the buffer BUFNAME temporarily current.\n\
+The hook `temp-buffer-show-hook' is run after the buffer is displayed,\n\
+with the buffer temporarily current, and the window that was used\n\
+to display it temporarily selected.\n\
+\n\
 If variable `temp-buffer-show-function' is non-nil, call it at the end\n\
-to get the buffer displayed.  It gets one argument, the buffer to display.")
+to get the buffer displayed instead of just displaying the non-selected\n\
+buffer and calling the hook.  It gets one argument, the buffer to display.")
   (args)
      Lisp_Object args;
 {
@@ -919,6 +1097,26 @@ float_to_string (buf, data)
   unsigned char *cp;
   int width;
       
+  /* Check for plus infinity in a way that won't lose
+     if there is no plus infinity.  */
+  if (data == data / 2 && data > 1.0)
+    {
+      strcpy (buf, "1.0e+INF");
+      return;
+    }
+  /* Likewise for minus infinity.  */
+  if (data == data / 2 && data < -1.0)
+    {
+      strcpy (buf, "-1.0e+INF");
+      return;
+    }
+  /* Check for NaN in a way that won't fail if there are no NaNs.  */
+  if (! (data * 0.0 >= 0.0))
+    {
+      strcpy (buf, "0.0e+NaN");
+      return;
+    }
+
   if (NILP (Vfloat_output_format)
       || !STRINGP (Vfloat_output_format))
   lose:
@@ -1023,7 +1221,7 @@ print (obj, printcharfun, escapeflag)
        if (EQ (obj, being_printed[i]))
          {
            sprintf (buf, "#%d", i);
-           strout (buf, -1, printcharfun);
+           strout (buf, -1, -1, printcharfun, 0);
            return;
          }
     }
@@ -1051,7 +1249,7 @@ print (obj, printcharfun, escapeflag)
        sprintf (buf, "%ld", XINT (obj));
       else
        abort ();
-      strout (buf, -1, printcharfun);
+      strout (buf, -1, -1, printcharfun, 0);
       break;
 
 #ifdef LISP_FLOAT_TYPE
@@ -1060,7 +1258,7 @@ print (obj, printcharfun, escapeflag)
        char pigbuf[350];       /* see comments in float_to_string */
 
        float_to_string (pigbuf, XFLOAT(obj)->data);
-       strout (pigbuf, -1, printcharfun);
+       strout (pigbuf, -1, -1, printcharfun, 0);
       }
       break;
 #endif
@@ -1070,10 +1268,14 @@ print (obj, printcharfun, escapeflag)
        print_string (obj, printcharfun);
       else
        {
-         register int i;
+         register int i, i_byte;
          register unsigned char c;
          struct gcpro gcpro1;
-         int size;
+         unsigned char *str;
+         int size_byte;
+         /* 1 means we must ensure that the next character we output
+            cannot be taken as part of a hex character escape.  */
+         int need_nonhex = 0;
 
          GCPRO1 (obj);
 
@@ -1086,15 +1288,28 @@ print (obj, printcharfun, escapeflag)
 #endif
 
          PRINTCHAR ('\"');
-         size = XSTRING (obj)->size;
-         for (i = 0; i < size;)
+         str = XSTRING (obj)->data;
+         size_byte = STRING_BYTES (XSTRING (obj));
+
+         for (i = 0, i_byte = 0; i_byte < size_byte;)
            {
              /* Here, we must convert each multi-byte form to the
                 corresponding character code before handing it to PRINTCHAR.  */
              int len;
-             int c = STRING_CHAR_AND_LENGTH (&XSTRING (obj)->data[i],
-                                             size - i, len);
-             i += len;
+             int c;
+
+             if (STRING_MULTIBYTE (obj))
+               {
+                 c = STRING_CHAR_AND_CHAR_LENGTH (str + i_byte,
+                                                  size_byte - i_byte, len);
+                 if (CHAR_VALID_P (c, 0))
+                   i_byte += len;
+                 else
+                   c = str[i_byte++];
+               }
+             else
+               c = str[i_byte++];
+
              QUIT;
 
              if (c == '\n' && print_escape_newlines)
@@ -1107,8 +1322,40 @@ print (obj, printcharfun, escapeflag)
                  PRINTCHAR ('\\');
                  PRINTCHAR ('f');
                }
+             else if (! SINGLE_BYTE_CHAR_P (c) && print_escape_multibyte)
+               {
+                 /* When multibyte is disabled,
+                    print multibyte string chars using hex escapes.  */
+                 unsigned char outbuf[50];
+                 sprintf (outbuf, "\\x%x", c);
+                 strout (outbuf, -1, -1, printcharfun, 0);
+                 need_nonhex = 1;
+               }
+             else if (SINGLE_BYTE_CHAR_P (c) && ! ASCII_BYTE_P (c)
+                      && print_escape_nonascii)
+               {
+                 /* When printing in a multibyte buffer
+                    or when explicitly requested,
+                    print single-byte non-ASCII string chars
+                    using octal escapes.  */
+                 unsigned char outbuf[5];
+                 sprintf (outbuf, "\\%03o", c);
+                 strout (outbuf, -1, -1, printcharfun, 0);
+               }
              else
                {
+                 /* If we just had a hex escape, and this character
+                    could be taken as part of it,
+                    output `\ ' to prevent that.  */
+                 if (need_nonhex)
+                   {
+                     need_nonhex = 0;
+                     if ((c >= 'a' && c <= 'f')
+                         || (c >= 'A' && c <= 'F')
+                         || (c >= '0' && c <= '9'))
+                       strout ("\\ ", -1, -1, printcharfun, 0);
+                   }
+
                  if (c == '\"' || c == '\\')
                    PRINTCHAR ('\\');
                  PRINTCHAR (c);
@@ -1133,9 +1380,12 @@ print (obj, printcharfun, escapeflag)
       {
        register int confusing;
        register unsigned char *p = XSYMBOL (obj)->name->data;
-       register unsigned char *end = p + XSYMBOL (obj)->name->size;
-       register unsigned char c;
-       int i, size;
+       register unsigned char *end = p + STRING_BYTES (XSYMBOL (obj)->name);
+       register int c;
+       int i, i_byte, size_byte;
+       Lisp_Object name;
+
+       XSETSTRING (name, XSYMBOL (obj)->name);
 
        if (p != end && (*p == '-' || *p == '+')) p++;
        if (p == end)
@@ -1192,15 +1442,18 @@ print (obj, printcharfun, escapeflag)
            PRINTCHAR (':');
          }
 
-       size = XSYMBOL (obj)->name->size;
-       for (i = 0; i < size;)
+       size_byte = STRING_BYTES (XSTRING (name));
+
+       for (i = 0, i_byte = 0; i_byte < size_byte;)
          {
            /* Here, we must convert each multi-byte form to the
               corresponding character code before handing it to PRINTCHAR.  */
-           int len;
-           int c = STRING_CHAR_AND_LENGTH (&XSYMBOL (obj)->name->data[i],
-                                           size - i, len);
-           i += len;
+
+           if (STRING_MULTIBYTE (name))
+             FETCH_STRING_CHAR_ADVANCE (c, name, i, i_byte);
+           else
+             c = XSTRING (name)->data[i_byte++];
+
            QUIT;
 
            if (escapeflag)
@@ -1221,7 +1474,7 @@ print (obj, printcharfun, escapeflag)
       /* If deeper than spec'd depth, print placeholder.  */
       if (INTEGERP (Vprint_level)
          && print_depth > XINT (Vprint_level))
-       strout ("...", -1, printcharfun);
+       strout ("...", -1, -1, printcharfun, 0);
       else if (print_quoted && CONSP (XCDR (obj)) && NILP (XCDR (XCDR (obj)))
               && (EQ (XCAR (obj), Qquote)))
        {
@@ -1249,29 +1502,37 @@ print (obj, printcharfun, escapeflag)
          PRINTCHAR ('(');
          {
            register int i = 0;
-           register int max = 0;
+           register int print_length = 0;
+           Lisp_Object halftail = obj;
 
            if (INTEGERP (Vprint_length))
-             max = XINT (Vprint_length);
-           /* Could recognize circularities in cdrs here,
-              but that would make printing of long lists quadratic.
-              It's not worth doing.  */
+             print_length = XINT (Vprint_length);
            while (CONSP (obj))
              {
+               /* Detect circular list.  */
+               if (i != 0 && EQ (obj, halftail))
+                 {
+                   sprintf (buf, " . #%d", i / 2);
+                   strout (buf, -1, -1, printcharfun, 0);
+                   obj = Qnil;
+                   break;
+                 }
                if (i++)
                  PRINTCHAR (' ');
-               if (max && i > max)
+               if (print_length && i > print_length)
                  {
-                   strout ("...", 3, printcharfun);
+                   strout ("...", 3, 3, printcharfun, 0);
                    break;
                  }
                print (XCAR (obj), printcharfun, escapeflag);
                obj = XCDR (obj);
+               if (!(i & 1))
+                 halftail = XCDR (halftail);
              }
          }
          if (!NILP (obj))
            {
-             strout (" . ", 3, printcharfun);
+             strout (" . ", 3, 3, printcharfun, 0);
              print (obj, printcharfun, escapeflag);
            }
          PRINTCHAR (')');
@@ -1283,7 +1544,7 @@ print (obj, printcharfun, escapeflag)
        {
          if (escapeflag)
            {
-             strout ("#<process ", -1, printcharfun);
+             strout ("#<process ", -1, -1, printcharfun, 0);
              print_string (XPROCESS (obj)->name, printcharfun);
              PRINTCHAR ('>');
            }
@@ -1303,7 +1564,7 @@ print (obj, printcharfun, escapeflag)
          PRINTCHAR ('#');
          PRINTCHAR ('&');
          sprintf (buf, "%d", XBOOL_VECTOR (obj)->size);
-         strout (buf, -1, printcharfun);
+         strout (buf, -1, -1, printcharfun, 0);
          PRINTCHAR ('\"');
 
          /* Don't print more characters than the specified maximum.  */
@@ -1338,19 +1599,19 @@ print (obj, printcharfun, escapeflag)
        }
       else if (SUBRP (obj))
        {
-         strout ("#<subr ", -1, printcharfun);
-         strout (XSUBR (obj)->symbol_name, -1, printcharfun);
+         strout ("#<subr ", -1, -1, printcharfun, 0);
+         strout (XSUBR (obj)->symbol_name, -1, -1, printcharfun, 0);
          PRINTCHAR ('>');
        }
 #ifndef standalone
       else if (WINDOWP (obj))
        {
-         strout ("#<window ", -1, printcharfun);
+         strout ("#<window ", -1, -1, printcharfun, 0);
          sprintf (buf, "%d", XFASTINT (XWINDOW (obj)->sequence_number));
-         strout (buf, -1, printcharfun);
+         strout (buf, -1, -1, printcharfun, 0);
          if (!NILP (XWINDOW (obj)->buffer))
            {
-             strout (" on ", -1, printcharfun);
+             strout (" on ", -1, -1, printcharfun, 0);
              print_string (XBUFFER (XWINDOW (obj)->buffer)->name, printcharfun);
            }
          PRINTCHAR ('>');
@@ -1358,10 +1619,10 @@ print (obj, printcharfun, escapeflag)
       else if (BUFFERP (obj))
        {
          if (NILP (XBUFFER (obj)->name))
-           strout ("#<killed buffer>", -1, printcharfun);
+           strout ("#<killed buffer>", -1, -1, printcharfun, 0);
          else if (escapeflag)
            {
-             strout ("#<buffer ", -1, printcharfun);
+             strout ("#<buffer ", -1, -1, printcharfun, 0);
              print_string (XBUFFER (obj)->name, printcharfun);
              PRINTCHAR ('>');
            }
@@ -1370,16 +1631,16 @@ print (obj, printcharfun, escapeflag)
        }
       else if (WINDOW_CONFIGURATIONP (obj))
        {
-         strout ("#<window-configuration>", -1, printcharfun);
+         strout ("#<window-configuration>", -1, -1, printcharfun, 0);
        }
       else if (FRAMEP (obj))
        {
          strout ((FRAME_LIVE_P (XFRAME (obj))
                   ? "#<frame " : "#<dead frame "),
-                 -1, printcharfun);
+                 -1, -1, printcharfun, 0);
          print_string (XFRAME (obj)->name, printcharfun);
-         sprintf (buf, " 0x%lx", (unsigned long) (XFRAME (obj)));
-         strout (buf, -1, printcharfun);
+         sprintf (buf, " 0x%lx\\ ", (unsigned long) (XFRAME (obj)));
+         strout (buf, -1, -1, printcharfun, 0);
          PRINTCHAR ('>');
        }
 #endif /* not standalone */
@@ -1431,34 +1692,32 @@ print (obj, printcharfun, escapeflag)
       switch (XMISCTYPE (obj))
        {
        case Lisp_Misc_Marker:
-         strout ("#<marker ", -1, printcharfun);
-#if 0
+         strout ("#<marker ", -1, -1, printcharfun, 0);
          /* Do you think this is necessary?  */
          if (XMARKER (obj)->insertion_type != 0)
-           strout ("(before-insertion) ", -1, printcharfun);
-#endif /* 0 */
+           strout ("(before-insertion) ", -1, -1, printcharfun, 0);
          if (!(XMARKER (obj)->buffer))
-           strout ("in no buffer", -1, printcharfun);
+           strout ("in no buffer", -1, -1, printcharfun, 0);
          else
            {
              sprintf (buf, "at %d", marker_position (obj));
-             strout (buf, -1, printcharfun);
-             strout (" in ", -1, printcharfun);
+             strout (buf, -1, -1, printcharfun, 0);
+             strout (" in ", -1, -1, printcharfun, 0);
              print_string (XMARKER (obj)->buffer->name, printcharfun);
            }
          PRINTCHAR ('>');
          break;
 
        case Lisp_Misc_Overlay:
-         strout ("#<overlay ", -1, printcharfun);
+         strout ("#<overlay ", -1, -1, printcharfun, 0);
          if (!(XMARKER (OVERLAY_START (obj))->buffer))
-           strout ("in no buffer", -1, printcharfun);
+           strout ("in no buffer", -1, -1, printcharfun, 0);
          else
            {
              sprintf (buf, "from %d to %d in ",
                       marker_position (OVERLAY_START (obj)),
                       marker_position (OVERLAY_END   (obj)));
-             strout (buf, -1, printcharfun);
+             strout (buf, -1, -1, printcharfun, 0);
              print_string (XMARKER (OVERLAY_START (obj))->buffer->name,
                            printcharfun);
            }
@@ -1468,28 +1727,28 @@ print (obj, printcharfun, escapeflag)
       /* Remaining cases shouldn't happen in normal usage, but let's print
         them anyway for the benefit of the debugger.  */
        case Lisp_Misc_Free:
-         strout ("#<misc free cell>", -1, printcharfun);
+         strout ("#<misc free cell>", -1, -1, printcharfun, 0);
          break;
 
        case Lisp_Misc_Intfwd:
          sprintf (buf, "#<intfwd to %d>", *XINTFWD (obj)->intvar);
-         strout (buf, -1, printcharfun);
+         strout (buf, -1, -1, printcharfun, 0);
          break;
 
        case Lisp_Misc_Boolfwd:
          sprintf (buf, "#<boolfwd to %s>",
                   (*XBOOLFWD (obj)->boolvar ? "t" : "nil"));
-         strout (buf, -1, printcharfun);
+         strout (buf, -1, -1, printcharfun, 0);
          break;
 
        case Lisp_Misc_Objfwd:
-         strout ("#<objfwd to ", -1, printcharfun);
+         strout ("#<objfwd to ", -1, -1, printcharfun, 0);
          print (*XOBJFWD (obj)->objvar, printcharfun, escapeflag);
          PRINTCHAR ('>');
          break;
 
        case Lisp_Misc_Buffer_Objfwd:
-         strout ("#<buffer_objfwd to ", -1, printcharfun);
+         strout ("#<buffer_objfwd to ", -1, -1, printcharfun, 0);
          print (*(Lisp_Object *)((char *)current_buffer
                                  + XBUFFER_OBJFWD (obj)->offset),
                 printcharfun, escapeflag);
@@ -1497,7 +1756,7 @@ print (obj, printcharfun, escapeflag)
          break;
 
        case Lisp_Misc_Kboard_Objfwd:
-         strout ("#<kboard_objfwd to ", -1, printcharfun);
+         strout ("#<kboard_objfwd to ", -1, -1, printcharfun, 0);
          print (*(Lisp_Object *)((char *) current_kboard
                                  + XKBOARD_OBJFWD (obj)->offset),
                 printcharfun, escapeflag);
@@ -1505,21 +1764,33 @@ print (obj, printcharfun, escapeflag)
          break;
 
        case Lisp_Misc_Buffer_Local_Value:
-         strout ("#<buffer_local_value ", -1, printcharfun);
+         strout ("#<buffer_local_value ", -1, -1, printcharfun, 0);
          goto do_buffer_local;
        case Lisp_Misc_Some_Buffer_Local_Value:
-         strout ("#<some_buffer_local_value ", -1, printcharfun);
+         strout ("#<some_buffer_local_value ", -1, -1, printcharfun, 0);
        do_buffer_local:
-         strout ("[realvalue] ", -1, printcharfun);
-         print (XBUFFER_LOCAL_VALUE (obj)->car, printcharfun, escapeflag);
-         strout ("[buffer] ", -1, printcharfun);
-         print (XCONS (XBUFFER_LOCAL_VALUE (obj)->cdr)->car,
+         strout ("[realvalue] ", -1, -1, printcharfun, 0);
+         print (XBUFFER_LOCAL_VALUE (obj)->realvalue, printcharfun, escapeflag);
+         if (XBUFFER_LOCAL_VALUE (obj)->found_for_buffer)
+           strout ("[local in buffer] ", -1, -1, printcharfun, 0);
+         else
+           strout ("[buffer] ", -1, -1, printcharfun, 0);
+         print (XBUFFER_LOCAL_VALUE (obj)->buffer,
                 printcharfun, escapeflag);
-         strout ("[alist-elt] ", -1, printcharfun);
-         print (XCONS (XCONS (XBUFFER_LOCAL_VALUE (obj)->cdr)->cdr)->car,
+         if (XBUFFER_LOCAL_VALUE (obj)->check_frame)
+           {
+             if (XBUFFER_LOCAL_VALUE (obj)->found_for_frame)
+               strout ("[local in frame] ", -1, -1, printcharfun, 0);
+             else
+               strout ("[frame] ", -1, -1, printcharfun, 0);
+             print (XBUFFER_LOCAL_VALUE (obj)->frame,
+                    printcharfun, escapeflag);
+           }
+         strout ("[alist-elt] ", -1, -1, printcharfun, 0);
+         print (XCONS (XBUFFER_LOCAL_VALUE (obj)->cdr)->car,
                 printcharfun, escapeflag);
-         strout ("[default-value] ", -1, printcharfun);
-         print (XCONS (XCONS (XBUFFER_LOCAL_VALUE (obj)->cdr)->cdr)->cdr,
+         strout ("[default-value] ", -1, -1, printcharfun, 0);
+         print (XCONS (XBUFFER_LOCAL_VALUE (obj)->cdr)->cdr,
                 printcharfun, escapeflag);
          PRINTCHAR ('>');
          break;
@@ -1535,16 +1806,16 @@ print (obj, printcharfun, escapeflag)
       {
        /* We're in trouble if this happens!
           Probably should just abort () */
-       strout ("#<EMACS BUG: INVALID DATATYPE ", -1, printcharfun);
+       strout ("#<EMACS BUG: INVALID DATATYPE ", -1, -1, printcharfun, 0);
        if (MISCP (obj))
          sprintf (buf, "(MISC 0x%04x)", (int) XMISCTYPE (obj));
        else if (VECTORLIKEP (obj))
          sprintf (buf, "(PVEC 0x%08x)", (int) XVECTOR (obj)->size);
        else
          sprintf (buf, "(0x%02x)", (int) XTYPE (obj));
-       strout (buf, -1, printcharfun);
+       strout (buf, -1, -1, printcharfun, 0);
        strout (" Save your buffers immediately and please report this bug>",
-               -1, printcharfun);
+               -1, -1, printcharfun, 0);
       }
     }
 
@@ -1575,6 +1846,9 @@ print_interval (interval, printcharfun)
 void
 syms_of_print ()
 {
+  Qtemp_buffer_setup_hook = intern ("temp-buffer-setup-hook");
+  staticpro (&Qtemp_buffer_setup_hook);
+
   DEFVAR_LISP ("standard-output", &Vstandard_output,
     "Output stream `print' uses by default for outputting a character.\n\
 This may be any function of one argument.\n\
@@ -1621,6 +1895,18 @@ A value of nil means no limit.");
 Also print formfeeds as backslash-f.");
   print_escape_newlines = 0;
 
+  DEFVAR_BOOL ("print-escape-nonascii", &print_escape_nonascii,
+    "Non-nil means print unibyte non-ASCII chars in strings as \\OOO.\n\
+\(OOO is the octal representation of the character code.)\n\
+Only single-byte characters are affected, and only in `prin1'.");
+  print_escape_nonascii = 0;
+
+  DEFVAR_BOOL ("print-escape-multibyte", &print_escape_multibyte,
+    "Non-nil means print multibyte characters in strings as \\xXXXX.\n\
+\(XXX is the hex representation of the character code.)\n\
+This affects only `prin1'.");
+  print_escape_multibyte = 0;
+
   DEFVAR_BOOL ("print-quoted", &print_quoted,
     "Non-nil means print quoted forms with reader syntax.\n\
 I.e., (quote foo) prints as 'foo, (function foo) as #'foo, and, backquoted\n\
@@ -1665,6 +1951,12 @@ with #N= for the specified value of N.");
   Qprint_escape_newlines = intern ("print-escape-newlines");
   staticpro (&Qprint_escape_newlines);
 
+  Qprint_escape_multibyte = intern ("print-escape-multibyte");
+  staticpro (&Qprint_escape_multibyte);
+
+  Qprint_escape_nonascii = intern ("print-escape-nonascii");
+  staticpro (&Qprint_escape_nonascii);
+
 #ifndef standalone
   defsubr (&Swith_output_to_temp_buffer);
 #endif /* not standalone */