diff src/print.c @ 278:90d73dddcdc4 r21-0b37

Import from CVS: tag r21-0b37
author cvs
date Mon, 13 Aug 2007 10:31:29 +0200
parents 6330739388db
children 7df0dd720c89
line wrap: on
line diff
--- a/src/print.c	Mon Aug 13 10:30:38 2007 +0200
+++ b/src/print.c	Mon Aug 13 10:31:29 2007 +0200
@@ -28,7 +28,6 @@
 #include <config.h>
 #include "lisp.h"
 
-#ifndef standalone
 #include "backtrace.h"
 #include "buffer.h"
 #include "bytecode.h"
@@ -40,8 +39,6 @@
 #include "lstream.h"
 #include "sysfile.h"
 
-#endif /* not standalone */
-
 #include <float.h>
 /* Define if not in float.h */
 #ifndef DBL_DIG
@@ -152,7 +149,7 @@
 	       Lisp_Object reloc, Bytecount offset, Bytecount len)
 {
   /* This function can GC */
-  Charcount ccoff, cclen;
+  Charcount cclen;
   /* We change the value of nonreloc (fetching it from reloc as
      necessary), but we don't want to pass this changed value on to
      other functions that take both a nonreloc and a reloc, or things
@@ -172,7 +169,6 @@
   if (STRINGP (reloc))
     newnonreloc = XSTRING_DATA (reloc);
 
-  ccoff = bytecount_to_charcount (newnonreloc, offset);
   cclen = bytecount_to_charcount (newnonreloc + offset, len);
 
   if (LSTREAMP (function))
@@ -182,8 +178,7 @@
 	  /* Protect against Lstream_write() causing a GC and
 	     relocating the string.  For small strings, we do it by
 	     alloc'ing the string and using a copy; for large strings,
-	     we inhibit GC.  Now that print_streams are dead, this
-	     case should happen very rarely anyway.  */
+	     we inhibit GC.  */
 	  if (len < 65536)
 	    {
 	      Bufbyte *copied = alloca_array (Bufbyte, len);
@@ -206,8 +201,6 @@
       if (print_unbuffered)
 	Lstream_flush (XLSTREAM (function));
     }
-
-#ifndef standalone
   else if (BUFFERP (function))
     {
       CHECK_LIVE_BUFFER (function);
@@ -215,10 +208,10 @@
     }
   else if (MARKERP (function))
     {
-      /* marker_position will err if marker doesn't point anywhere */
+      /* marker_position() will err if marker doesn't point anywhere.  */
       Bufpos spoint = marker_position (function);
 
-      buffer_insert_string_1 (XBUFFER (Fmarker_buffer (function)),
+      buffer_insert_string_1 (XMARKER (function)->buffer,
 			      spoint, nonreloc, reloc, offset, len,
 			      0);
       Fset_marker (function, make_int (spoint + cclen),
@@ -226,12 +219,15 @@
     }
   else if (FRAMEP (function))
     {
+      /* This gets used by functions not invoking print_prepare(),
+         such as Fwrite_char.  */
       struct frame *f = XFRAME (function);
+      CHECK_LIVE_FRAME (function);
+
       if (!EQ (Vprint_message_label, echo_area_status (f)))
 	clear_echo_area_from_print (f, Qnil, 1);
       echo_area_append (f, nonreloc, reloc, offset, len, Vprint_message_label);
     }
-#endif /* not standalone */
   else if (EQ (function, Qt) || EQ (function, Qnil))
     {
       write_string_to_stdio_stream (stdout, 0, newnonreloc, offset, len,
@@ -239,6 +235,7 @@
     }
   else
     {
+      Charcount ccoff = bytecount_to_charcount (newnonreloc, offset);
       Charcount iii;
 
       for (iii = ccoff; iii < cclen + ccoff; iii++)
@@ -252,6 +249,11 @@
 
   UNGCPRO;
 }
+
+#define RESET_PRINT_GENSYM do {			\
+  if (!CONSP (Vprint_gensym))			\
+    Vprint_gensym_alist = Qnil;			\
+} while (0)
 
 static Lisp_Object
 canonicalize_printcharfun (Lisp_Object printcharfun)
@@ -260,54 +262,92 @@
     printcharfun = Vstandard_output;
 
   if (EQ (printcharfun, Qt) || NILP (printcharfun))
-    {
-#ifndef standalone
-      printcharfun = Fselected_frame (Qnil); /* print to minibuffer */
-#endif
-    }
+    printcharfun = Fselected_frame (Qnil); /* print to minibuffer */
+
   return printcharfun;
 }
 
-/* Now that print_streams are dead, I wonder if the following two
-   functions are needed as separate entities.  */
-
 static Lisp_Object
-print_prepare (Lisp_Object printcharfun)
+print_prepare (Lisp_Object printcharfun, Lisp_Object *frame_kludge)
 {
   /* Emacs won't print whilst GCing, but an external debugger might */
   if (gc_in_progress)
     return Qnil;
 
+  RESET_PRINT_GENSYM;
+
   printcharfun = canonicalize_printcharfun (printcharfun);
-  if (!CONSP (Vprint_gensym))
-    Vprint_gensym_alist = Qnil;
+
+  /* Here we could safely return the canonicalized PRINTCHARFUN.
+     However, if PRINTCHARFUN is a frame, printing of complex
+     structures becomes very expensive, because `append-message'
+     (called by echo_area_append) gets called as many times as
+     output_string() is called (and that's a *lot*).  append-message
+     tries to keep top of the message-stack in sync with the contents
+     of " *Echo Area" buffer, consing a new string for each component
+     of the printed structure.  For instance, if you print (a a),
+     append-message will cons up the following strings:
+
+         "("
+	 "(a"
+	 "(a "
+	 "(a a"
+	 "(a a)"
+
+     and will use only the last one.  With larger objects, this turns
+     into an O(n^2) consing frenzy that locks up XEmacs in incessant
+     garbage collection.
+
+     We prevent this by creating a resizing_buffer stream and letting
+     the printer write into it.  print_finish() will notice this
+     stream, and invoke echo_area_append() with the stream's buffer,
+     only once.  */
+  if (FRAMEP (printcharfun))
+    {
+      CHECK_LIVE_FRAME (printcharfun);
+      *frame_kludge = printcharfun;
+      printcharfun = make_resizing_buffer_output_stream ();
+    }
 
   return printcharfun;
 }
 
 static void
-print_finish (Lisp_Object stream)
+print_finish (Lisp_Object stream, Lisp_Object frame_kludge)
 {
   /* Emacs won't print whilst GCing, but an external debugger might */
   if (gc_in_progress)
     return;
 
-  if (!CONSP (Vprint_gensym))
-    Vprint_gensym_alist = Qnil;
+  RESET_PRINT_GENSYM;
+
+  /* See the comment in print_prepare().  */
+  if (FRAMEP (frame_kludge))
+    {
+      struct frame *f = XFRAME (frame_kludge);
+      Lstream *str = XLSTREAM (stream);
+      CHECK_LIVE_FRAME (frame_kludge);
+
+      Lstream_flush (str);
+      if (!EQ (Vprint_message_label, echo_area_status (f)))
+	clear_echo_area_from_print (f, Qnil, 1);
+      echo_area_append (f, resizing_buffer_stream_ptr (str),
+			Qnil, 0, Lstream_byte_count (str),
+			Vprint_message_label);	
+      Lstream_delete (str);
+    }
 }
 
-#if 1 /* Prefer space over "speed" */
-#define write_char_internal(string_of_length_1, stream) \
-  write_string_1 ((CONST Bufbyte *) (string_of_length_1), 1, (stream))
-#else
-#define write_char_internal(string_of_length_1, stream) \
-  output_string ((stream), (CONST Bufbyte *) (string_of_length_1), Qnil, 0, 1)
-#endif
+/* Used for printing a character.  STRING_OF_LENGTH_1 must contain a
+   single-byte character, not just any emchar.  */
+#define write_char_internal(string_of_length_1, stream)			\
+  output_string ((stream), (CONST Bufbyte *) (string_of_length_1),	\
+		 Qnil, 0, 1)
 
 /* NOTE:  Do not call this with the data of a Lisp_String,
  *  as printcharfun might cause a GC, which might cause
  *  the string's data to be relocated.
- *  Use print_object_internal (string, printcharfun, 0)
+ *  Use print_internal (string, printcharfun, 0)
  *  to princ a Lisp_String
  * Note: "stream" should be the result of "canonicalize_printcharfun"
  *  (ie Qnil means stdout, not Vstandard_output, etc)
@@ -316,7 +356,9 @@
 write_string_1 (CONST Bufbyte *str, Bytecount size, Lisp_Object stream)
 {
   /* This function can GC */
+#ifdef ERROR_CHECK_BUFPOS
   assert (size >= 0);
+#endif
   output_string (stream, str, Qnil, 0, size);
 }
 
@@ -339,13 +381,13 @@
   Bytecount len;
 
   CHECK_CHAR_COERCE_INT (ch);
+  RESET_PRINT_GENSYM;
   len = set_charptr_emchar (str, XCHAR (ch));
   output_string (canonicalize_printcharfun (stream), str, Qnil, 0, len);
+  RESET_PRINT_GENSYM;
   return ch;
 }
 
-#ifndef standalone
-
 void
 temp_output_buffer_setup (CONST char *bufname)
 {
@@ -428,7 +470,6 @@
 
   return unbind_to (speccount, val);
 }
-#endif /* not standalone */
 
 DEFUN ("terpri", Fterpri, 0, 1, 0, /*
 Output a newline to STREAM.
@@ -452,21 +493,18 @@
        (object, stream))
 {
   /* This function can GC */
-  Lisp_Object the_stream = Qnil;
+  Lisp_Object the_stream = Qnil, frame = Qnil;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
   GCPRO3 (object, stream, the_stream);
   print_depth = 0;
-  the_stream = print_prepare (stream);
+  the_stream = print_prepare (stream, &frame);
   print_internal (object, the_stream, 1);
-  print_finish (the_stream);
+  print_finish (the_stream, frame);
   UNGCPRO;
   return object;
 }
 
-/* Stream to which prin1-to-string prints. */
-static Lisp_Object Vprin1_to_string_stream;
-
 DEFUN ("prin1-to-string", Fprin1_to_string, 1, 2, 0, /*
 Return a string containing the printed representation of OBJECT,
 any Lisp object.  Quoting characters are used when needed to make output
@@ -476,29 +514,23 @@
        (object, noescape))
 {
   /* This function can GC */
-  Lstream *stream;
-  struct gcpro gcpro1;
+  Lisp_Object stream;
+  Lstream *str;
+  struct gcpro gcpro1, gcpro2;
 
-  /* We avoid creating a new stream for every invocation of
-     prin1_to_string, for better memory usage.  #### Is it necessary?  */
-
-  if (NILP (Vprin1_to_string_stream))
-    Vprin1_to_string_stream = make_resizing_buffer_output_stream ();
-  stream = XLSTREAM (Vprin1_to_string_stream);
-  Lstream_rewind (stream);
+  stream = make_resizing_buffer_output_stream ();
+  str = XLSTREAM (stream);
 
-  /* In case a caller forgot to protect. */
-  GCPRO1 (object);
+  /* Protect OBJECT, in case a caller forgot to protect. */
+  GCPRO2 (object, stream);
   print_depth = 0;
-  if (!CONSP (Vprint_gensym))
-    Vprint_gensym_alist = Qnil;
-  print_internal (object, Vprin1_to_string_stream, NILP (noescape));
-  if (!CONSP (Vprint_gensym))
-    Vprint_gensym_alist = Qnil;
-  Lstream_flush (stream);
+  RESET_PRINT_GENSYM;
+  print_internal (object, stream, NILP (noescape));
+  RESET_PRINT_GENSYM;
+  Lstream_flush (str);
   UNGCPRO;
-  return make_string (resizing_buffer_stream_ptr (stream),
-		      Lstream_byte_count (stream));
+  return make_string (resizing_buffer_stream_ptr (str),
+		      Lstream_byte_count (str));
 }
 
 DEFUN ("princ", Fprinc, 1, 2, 0, /*
@@ -510,14 +542,14 @@
        (obj, stream))
 {
   /* This function can GC */
-  Lisp_Object the_stream = Qnil;
+  Lisp_Object the_stream = Qnil, frame = Qnil;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
   GCPRO3 (obj, stream, the_stream);
-  the_stream = print_prepare (stream);
+  the_stream = print_prepare (stream, &frame);
   print_depth = 0;
   print_internal (obj, the_stream, 0);
-  print_finish (the_stream);
+  print_finish (the_stream, frame);
   UNGCPRO;
   return obj;
 }
@@ -531,16 +563,16 @@
        (obj, stream))
 {
   /* This function can GC */
-  Lisp_Object the_stream = Qnil;
+  Lisp_Object the_stream = Qnil, frame = Qnil;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
   GCPRO3 (obj, stream, the_stream);
-  the_stream = print_prepare (stream);
+  the_stream = print_prepare (stream, &frame);
   print_depth = 0;
   write_char_internal ("\n", the_stream);
   print_internal (obj, the_stream, 1);
   write_char_internal ("\n", the_stream);
-  print_finish (the_stream);
+  print_finish (the_stream, frame);
   UNGCPRO;
   return obj;
 }
@@ -761,6 +793,40 @@
     }
 }
 #endif /* LISP_FLOAT_TYPE */
+
+/* Print NUMBER to BUFFER.  The digits are first written in reverse
+   order (the least significant digit first), and are then reversed.
+   This is equivalent to sprintf(buffer, "%ld", number), only much
+   faster.  */
+void
+long_to_string (char *buffer, long number)
+{
+  char *p;
+  int i, l;
+
+  if (number < 0)
+    {
+      *buffer++ = '-';
+      number = -number;
+    }
+  p = buffer;
+  /* Print the digits to the string.  */
+  do
+    {
+      *p++ = number % 10 + '0';
+      number /= 10;
+    }
+  while (number);
+  /* And reverse them.  */
+  l = p - buffer - 1;
+  for (i = l/2; i >= 0; i--)
+    {
+      char c = buffer[i];
+      buffer[i] = buffer[l - i];
+      buffer[l - i] = c;
+    }
+  buffer[l + 1] = '\0';
+}
 
 static void
 print_vector_internal (CONST char *start, CONST char *end,
@@ -911,8 +977,7 @@
 		  write_char_internal ("\\", printcharfun);
 		  /* This is correct for Mule because the
 		     character is either \ or " */
-		  write_char_internal ((char *) (string_data (s) + i),
-				       printcharfun);
+		  write_char_internal (string_data (s) + i, printcharfun);
 		}
 	      last = i + 1;
 	    }
@@ -927,41 +992,6 @@
       write_char_internal ("\"", printcharfun);
     }
   UNGCPRO;
-  return;
-}
-
-/* Print NUMBER to BUFFER.  The digits are first written in reverse
-   order (the least significant digit first), and are then reversed.
-   This is equivalent to sprintf(buffer, "%ld", number), only much
-   faster.  */
-void
-long_to_string (char *buffer, long number)
-{
-  char *p;
-  int i, l;
-
-  if (number < 0)
-    {
-      *buffer++ = '-';
-      number = -number;
-    }
-  p = buffer;
-  /* Print the digits to the string.  */
-  do
-    {
-      *p++ = number % 10 + '0';
-      number /= 10;
-    }
-  while (number);
-  /* And reverse them.  */
-  l = p - buffer - 1;
-  for (i = l/2; i >= 0; i--)
-    {
-      char c = buffer[i];
-      buffer[i] = buffer[l - i];
-      buffer[l - i] = c;
-    }
-  buffer[l + 1] = '\0';
 }
 
 static void
@@ -988,9 +1018,9 @@
 			 int escapeflag)
 {
   char buf[200];
-  sprintf (buf, "#<INTERNAL OBJECT (XEmacs bug?) (%s) 0x%p>",
+  sprintf (buf, "#<INTERNAL OBJECT (XEmacs bug?) (%s) 0x%lx>",
 	   XRECORD_LHEADER_IMPLEMENTATION (obj)->name,
-	   (void *) XPNTR (obj));
+	   (unsigned long) XPNTR (obj));
   write_c_string (buf, printcharfun);
 }
 
@@ -1056,26 +1086,27 @@
       {
 	/* God intended that this be #\..., you know. */
 	Emchar ch = XCHAR (obj);
-	write_c_string ("?", printcharfun);
+	char *p = buf;
+	*p++ = '?';
 	if (ch == '\n')
-	  strcpy (buf, "\\n");
+	  *p++ = '\\', *p++ = 'n';
 	else if (ch == '\r')
-	  strcpy (buf, "\\r");
+	  *p++ = '\\', *p++ = 'r';
 	else if (ch == '\t')
-	  strcpy (buf, "\\t");
-	else if (ch < 32) {
-	  sprintf (buf, "\\^%c", ch + 64);
-	  if ((ch + 64) == '\\') {
-	    strcat(buf, "\\");
+	  *p++ = '\\', *p++ = 't';
+	else if (ch < 32)
+	  {
+	    *p++ = '\\', *p++ = '^';
+	    *p++ = ch + 64;
+	    if ((ch + 64) == '\\')
+	      *p++ = '\\';
 	  }
-	} else if (ch == 127)
-	  strcpy (buf, "\\^?");
+	else if (ch == 127)
+	  *p++ = '\\', *p++ = '^', *p++ = '?';
 	else if (ch >= 128 && ch < 160)
 	  {
-	    Bytecount i;
-	    strcpy (buf, "\\^");
-	    i = set_charptr_emchar ((unsigned char *) (buf + 2), ch + 64);
-	    buf[2+i] = '\0';
+	    *p++ = '\\', *p++ = '^';
+	    p += set_charptr_emchar ((Bufbyte *)p, ch + 64);
 	  }
 	else if (ch < 127
 		 && !isdigit (ch)
@@ -1083,21 +1114,17 @@
 		 && ch != '^') /* must not backslash this or it will
 				  be interpreted as the start of a
 				  control char */
-	  sprintf (buf, "\\%c", ch);
+	  *p++ = '\\', *p++ = ch;
 	else
-	  {
-	    Bytecount i;
-	    i = set_charptr_emchar ((unsigned char *) buf, ch);
-	    buf[i] = '\0';
-	  }
-	write_c_string (buf, printcharfun);
+	  p += set_charptr_emchar ((Bufbyte *)p, ch);
+	output_string (printcharfun, (Bufbyte *)buf, Qnil, 0, p - buf);
 	break;
       }
 
 #ifndef LRECORD_STRING
     case Lisp_Type_String:
       {
-	print_string(obj, printcharfun, escapeflag);
+	print_string (obj, printcharfun, escapeflag);
 	break;
       }
 #endif /* ! LRECORD_STRING */
@@ -1125,12 +1152,11 @@
 #ifndef LRECORD_VECTOR
     case Lisp_Type_Vector:
       {
-	struct gcpro gcpro1, gcpro2;
-
 	/* If deeper than spec'd depth, print placeholder.  */
 	if (INTP (Vprint_level)
 	    && print_depth > XINT (Vprint_level))
 	  {
+	    struct gcpro gcpro1, gcpro2;
 	    GCPRO2 (obj, printcharfun);
 	    write_c_string ("...", printcharfun);
 	    UNGCPRO;
@@ -1293,7 +1319,7 @@
   /* This function can GC */
   /* #### Bug!! (intern "") isn't printed in some distinguished way */
   /* ####  (the reader also loses on it) */
-  struct Lisp_String *name = XSYMBOL (obj)->name;
+  struct Lisp_String *name = symbol_name (XSYMBOL (obj));
   Bytecount size = string_length (name);
   struct gcpro gcpro1, gcpro2;
 
@@ -1372,6 +1398,9 @@
 
 #ifdef LISP_FLOAT_TYPE
     if (!confusing)
+      /* #### Ugh, this is needlessly complex and slow for what we
+         need here.  It might be a good idea to copy equivalent code
+         from FSF.  --hniksic */
       confusing = isfloat_string ((char *) data);
 #endif
     if (confusing)
@@ -1406,6 +1435,9 @@
   UNGCPRO;
 }
 
+/* #ifdef DEBUG_XEMACS */
+/* I don't like seeing `Note: Strange doc (not fboundp) for function */
+/* alternate-debugging-output @ 429542' -slb */
 int alternate_do_pointer;
 char alternate_do_string[5000];
 
@@ -1414,7 +1446,6 @@
 This can be used in place of `external-debugging-output' as a function
 to be passed to `print'.  Before calling `print', set `alternate_do_pointer'
 to 0.
-
 */
        (character))
 {
@@ -1431,6 +1462,7 @@
   alternate_do_string[alternate_do_pointer] = 0;
   return character;
 }
+/* #endif /* DEBUG_XEMACS */
 
 DEFUN ("external-debugging-output", Fexternal_debugging_output, 1, 3, 0, /*
 Write CHAR-OR-STRING to stderr or stdout.
@@ -1502,7 +1534,7 @@
       file = Fexpand_file_name (file, Qnil);
       termscript = fopen ((char *) XSTRING_DATA (file), "w");
       if (termscript == NULL)
-	report_file_error ("Opening termscript", Fcons (file, Qnil));
+	report_file_error ("Opening termscript", list1 (file));
     }
   return Qnil;
 }
@@ -1672,9 +1704,7 @@
   DEFSUBR (Fexternal_debugging_output);
   DEFSUBR (Fopen_termscript);
   defsymbol (&Qexternal_debugging_output, "external-debugging-output");
-#ifndef standalone
   DEFSUBR (Fwith_output_to_temp_buffer);
-#endif /* not standalone */
 }
 
 void
@@ -1784,7 +1814,4 @@
 generally be bound with `let' rather than set.  (See `display-message'.)
 */ );
   Vprint_message_label = Qprint;
-
-  Vprin1_to_string_stream = Qnil;
-  staticpro (&Vprin1_to_string_stream);
 }