APPROVE COMMIT
NOTE: This patch has been committed
# HG changeset patch
# User Aidan Kehoe <kehoea(a)parhasard.net>
# Date 1514041062 0
#      Sat Dec 23 14:57:42 2017 +0000
# Node ID 714a6e9c1669a4ed929d87438abe9886a1c77f81
# Parent  296ee062f9f9ce4957f6aa450a2b4ad7fb57935c
Return a Bytecount from write_fmt_string() and friends.
src/ChangeLog addition:
2017-12-23  Aidan Kehoe  <kehoea(a)parhasard.net>
	* console-msw.c (mswindows_output_console_string):
	Return a Bytecount reflecting the number of Ibytes written from
	this function.
	* doprnt.c (write_string_1_lstream):
	* doprnt.c (write_lisp_string_lstream):
	Return a Bytecount, not void, in these two functions.
	* doprnt.c (doprnt_1):
	Use this.
	* doprnt.c (write_fmt_string_va):
	* doprnt.c (write_fmt_string):
	* doprnt.c (write_fmt_string_lisp_va):
	* doprnt.c (write_fmt_string_lisp):
	* doprnt.c (stderr_out):
	* doprnt.c (stdout_out):
	* doprnt.c (stderr_out_lisp):
	Return a Bytecount in all these functions, not void, pass through
	the result from the underlying call.
	* lisp.h:
	Adjust the declarations for these functions to reflect that they
	return a Bytecount.
	* print.c (write_string_to_stdio_stream_1):
	* print.c (write_string_to_stdio_stream):
	* print.c (write_string_to_external_output):
	Return the shortest of the results of the writes to the various
	destinations here.
	* print.c (write_string_to_external_output_va):
	* print.c (external_out):
	* print.c (output_string):
	* print.c (write_lisp_string):
	* print.c (write_string_1):
	* print.c (write_eistring):
	* print.c (debug_out):
	* print.c (debug_print):
	* print.c (debug_out_lisp):
	Return Bytecount values, not void, in all these functions.
diff -r 296ee062f9f9 -r 714a6e9c1669 src/ChangeLog
--- a/src/ChangeLog	Mon Dec 25 11:34:22 2017 +0000
+++ b/src/ChangeLog	Sat Dec 23 14:57:42 2017 +0000
@@ -1,3 +1,41 @@
+2017-12-23  Aidan Kehoe  <kehoea(a)parhasard.net>
+
+	* console-msw.c (mswindows_output_console_string):
+	Return a Bytecount reflecting the number of Ibytes written from
+	this function.
+	* doprnt.c (write_string_1_lstream):
+	* doprnt.c (write_lisp_string_lstream):
+	Return a Bytecount, not void, in these two functions.
+	* doprnt.c (doprnt_1):
+	Use this.
+	* doprnt.c (write_fmt_string_va):
+	* doprnt.c (write_fmt_string):
+	* doprnt.c (write_fmt_string_lisp_va):
+	* doprnt.c (write_fmt_string_lisp):
+	* doprnt.c (stderr_out):
+	* doprnt.c (stdout_out):
+	* doprnt.c (stderr_out_lisp):
+	Return a Bytecount in all these functions, not void, pass through
+	the result from the underlying call.
+	* lisp.h:
+	Adjust the declarations for these functions to reflect that they
+	return a Bytecount.
+	* print.c (write_string_to_stdio_stream_1):
+	* print.c (write_string_to_stdio_stream):
+	* print.c (write_string_to_external_output):
+	Return the shortest of the results of the writes to the various
+	destinations here.
+	* print.c (write_string_to_external_output_va):
+	* print.c (external_out):
+	* print.c (output_string):
+	* print.c (write_lisp_string):
+	* print.c (write_string_1):
+	* print.c (write_eistring):
+	* print.c (debug_out):
+	* print.c (debug_print):
+	* print.c (debug_out_lisp):
+	Return Bytecount values, not void, in all these functions.
+
 2017-12-22  Aidan Kehoe  <kehoea(a)parhasard.net>
 
 	* redisplay-x.c (separate_textual_runs_mule):
diff -r 296ee062f9f9 -r 714a6e9c1669 src/console-msw.c
--- a/src/console-msw.c	Mon Dec 25 11:34:22 2017 +0000
+++ b/src/console-msw.c	Sat Dec 23 14:57:42 2017 +0000
@@ -287,7 +287,7 @@
 
 int mswindows_message_outputted;
 
-int
+Bytecount
 mswindows_output_console_string (const Ibyte *ptr, Bytecount len)
 {
   DWORD num_written;
@@ -303,15 +303,25 @@
       TO_EXTERNAL_FORMAT (DATA, (ptr, len),
 			  ALLOCA, (extptr, extlen),
 			  Qmswindows_tstr);
-      return qxeWriteConsole (mswindows_console_buffer, extptr,
-			      extlen / XETCHAR_SIZE, &num_written, NULL);
+      qxeWriteConsole (mswindows_console_buffer, extptr,
+		       extlen / XETCHAR_SIZE, &num_written, NULL);
+
+      if (num_written != (extlen / XETCHAR_SIZE))
+	{
+	  TO_INTERNAL_FORMAT (DATA, (extptr, num_written * XETCHAR_SIZE),
+			      ALLOCA, (ptr, len), Qmswindows_tstr);
+	}
+
+      return len;
     }
-  else
+
 #ifdef NON_ASCII_INTERNAL_FORMAT
 #error Do something here
 #endif
-    return WriteConsoleA (mswindows_console_buffer, (Chbyte *) ptr, len,
-			  &num_written, NULL);
+  WriteConsoleA (mswindows_console_buffer, (Chbyte *) ptr, len, &num_written,
+		 NULL);
+
+  return (Bytecount) num_written;
 }
 
 DEFUN ("mswindows-debugging-output", Fmswindows_debugging_output, 1, 1, 0, /*
diff -r 296ee062f9f9 -r 714a6e9c1669 src/doprnt.c
--- a/src/doprnt.c	Mon Dec 25 11:34:22 2017 +0000
+++ b/src/doprnt.c	Sat Dec 23 14:57:42 2017 +0000
@@ -780,19 +780,19 @@
       break;                                                            \
     } while (0)
 
-static void
+static Bytecount
 write_string_1_lstream (Lisp_Object stream, const Ibyte *str, Bytecount size)
 {
   /* This becomes just a jmp _Lstream_write in the assembler. */
-  Lstream_write (XLSTREAM (stream), (const void *) str, size);
+  return Lstream_write (XLSTREAM (stream), (const void *) str, size);
 }
 
-static void
+static Bytecount
 write_lisp_string_lstream (Lisp_Object stream, Lisp_Object string,
                            Bytecount offset, Bytecount len)
 {
   /* And this becomes just a jmp _Lstream_write_with_extents. */
-  Lstream_write_with_extents (XLSTREAM (stream), string, offset, len);
+  return Lstream_write_with_extents (XLSTREAM (stream), string, offset, len);
 }
 
 /* Append the string of length LEN starting at OFFSET to STREAM. Preserve any
@@ -844,8 +844,9 @@
 {
   Bytecount result_len = 0, begin;
   const Ibyte *newnonreloc = NILP (reloc) ? nonreloc : XSTRING_DATA (reloc);
-  void (*write_string_2) (Lisp_Object, const Ibyte *, Bytecount);
-  void (*write_lisp_string_2) (Lisp_Object, Lisp_Object, Bytecount, Bytecount);
+  Bytecount (*write_string_2) (Lisp_Object, const Ibyte *, Bytecount);
+  Bytecount (*write_lisp_string_2) (Lisp_Object, Lisp_Object, Bytecount,
+				    Bytecount);
 
   text_checking_assert (!(EQ (reloc, format_object)) || NILP (reloc));
 
@@ -964,14 +965,13 @@
       text_checking_assert (realfill <= filllen);
       if (realfill)
         {
-          write_string_2 (stream, filling, realfill);
-          result_len += realfill;
+          result_len += write_string_2 (stream, filling, realfill);
           fill_cursor = filling;
         }
 
       if (NILP (reloc))
         {
-          write_string_2 (stream, newnonreloc + offset, len);
+          result_len += write_string_2 (stream, newnonreloc + offset, len);
         }
       else
         {
@@ -979,11 +979,9 @@
              adjusts it such that its bytecount changes.
              2. Copy RELOC's extent information directly to this point in the
              output, do not stretch it. */
-          write_lisp_string_2 (stream, reloc, offset, len);
+          result_len += write_lisp_string_2 (stream, reloc, offset, len);
         }
 
-      result_len += len;
-
       /* Padding at end to left-justify ... */
       if (left_justify)
         {
@@ -1007,8 +1005,7 @@
           text_checking_assert (realfill < filllen);
           if (realfill)
             {
-              write_string_2 (stream, filling, realfill);
-              result_len += realfill;
+              result_len += write_string_2 (stream, filling, realfill);
             }
         }
 
@@ -1026,7 +1023,7 @@
     {
       if (NILP (reloc))
         {
-          write_string_2 (stream, newnonreloc + offset, len);
+          result_len += write_string_2 (stream, newnonreloc + offset, len);
         }
       else
         {
@@ -1034,9 +1031,8 @@
              adjusts it such that its bytecount changes.
              2. Copy RELOC's extent information directly to this point in the
              output, do not stretch it. */
-          write_lisp_string_2 (stream, reloc, offset, len);
+          result_len += write_lisp_string_2 (stream, reloc, offset, len);
         }
-      result_len += len;
     }
 
   return result_len;
@@ -2868,7 +2864,7 @@
    We also do not handle the $ repositioning specs; they make it harder to
    determine an upper bound on the number of specs. This can be revised if
    necessary, but it is unlikely to be that necessary on the C level.  */
-void
+Bytecount
 write_fmt_string_va (Lisp_Object stream, const CIbyte *fmt, va_list va)
 {
   const CIbyte *cursor = fmt;
@@ -2890,7 +2886,7 @@
 
   if (speccount == 1)
     {
-      write_string_1 (stream, (const Ibyte *) fmt, len);
+      return write_string_1 (stream, (const Ibyte *) fmt, len);
     }
   else
     {
@@ -2907,26 +2903,28 @@
       args = alloca_array (printf_arg, nargs);
 
       get_doprnt_c_args (args, nargs, &specs, va);
-      emacs_doprnt (stream, (const Ibyte *) fmt, len, Qnil, &specs, NULL,
-                    args);
+      return emacs_doprnt (stream, (const Ibyte *) fmt, len, Qnil, &specs,
+			   NULL, args);
     }
 }
 
 /* Write a printf-style string to STREAM; see output_string(). Arguments are C
    doubles, longs, uints, char *s, etc, rather than uniformly Lisp_Objects. */
-void
+Bytecount
 write_fmt_string (Lisp_Object stream, const CIbyte *fmt, ...)
 {
   va_list va;
+  Bytecount result;
   va_start (va, fmt);
-  write_fmt_string_va (stream, fmt, va);
+  result = write_fmt_string_va (stream, fmt, va);
   va_end (va);
+  return result;
 }
 
 /* Write a printf-style string to STREAM, an object accepted by
    output_string(), using FMT as the format string, and taking Lisp_Object
    arguments from the va_list VA. */
-void
+Bytecount
 write_fmt_string_lisp_va (Lisp_Object stream, const CIbyte *fmt, va_list va)
 {
   Bytecount len = strlen (fmt);
@@ -2936,15 +2934,19 @@
   int count = record_unwind_protect_freeing_dynarr (specs);
   Lisp_Object *largs = alloca_array (Lisp_Object, nargs);
   struct gcpro gcpro1, gcpro2;
+  Bytecount result;
 
   for (ii = 0; ii < nargs; ii++)
     largs[ii] = va_arg (va, Lisp_Object);
 
   GCPRO2 (largs[0], stream);
   gcpro1.nvars = nargs;
-  emacs_doprnt (stream, (const Ibyte *) fmt, len, Qnil, specs, largs, NULL);
+  result = emacs_doprnt (stream, (const Ibyte *) fmt, len, Qnil, specs,
+			 largs, NULL);
   UNGCPRO;
   unbind_to (count);
+
+  return result;
 }
 
 /* Write a printf-style string to STREAM, where the arguments are Lisp objects
@@ -2954,7 +2956,7 @@
    but write_fmt_string_lisp () itself is called far more often, and since
    write_fmt_string_lisp_va is externally visible, the compiler is unlikely to
    inline it. */
-void
+Bytecount
 write_fmt_string_lisp (Lisp_Object stream, const CIbyte *fmt, ...)
 {
   Bytecount len = strlen (fmt);
@@ -2965,6 +2967,7 @@
   Lisp_Object *largs = alloca_array (Lisp_Object, nargs);
   struct gcpro gcpro1, gcpro2;
   va_list va;
+  Bytecount result;
 
   va_start (va, fmt);
   for (ii = 0; ii < nargs; ii++)
@@ -2973,9 +2976,12 @@
 
   GCPRO2 (largs[0], stream);
   gcpro1.nvars = nargs;
-  emacs_doprnt (stream, (const Ibyte *) fmt, len, Qnil, specs, largs, NULL);
+  result = emacs_doprnt (stream, (const Ibyte *) fmt, len, Qnil, specs, largs,
+			 NULL);
   UNGCPRO;
   unbind_to (count);
+
+  return result;
 }
 
 /* Output portably to stderr or its equivalent (i.e. may be a console
@@ -2993,48 +2999,55 @@
 
    This function is safe to use even when not initialized or when dying --
    we don't do conversion in such cases. */
-
-void
+Bytecount
 stderr_out (const CIbyte *fmt, ...)
 {
+  Bytecount result;
   va_list args;
   va_start (args, fmt);
 
   if (initialized && !inhibit_non_essential_conversion_operations)
     fmt = GETTEXT (fmt);
 
-  write_fmt_string_va (Qexternal_debugging_output, fmt, args);
+  result = write_fmt_string_va (Qexternal_debugging_output, fmt, args);
   va_end (args);
+
+  return result;
 }
 
 /* Output portably to stdout or its equivalent (i.e. may be a console
    window under MS Windows).  Works like stderr_out(). */
-void
+Bytecount
 stdout_out (const CIbyte *fmt, ...)
 {
+  Bytecount result;
   va_list args;
   va_start (args, fmt);
 
   if (initialized && !inhibit_non_essential_conversion_operations)
     fmt = GETTEXT (fmt);
 
-  write_fmt_string_va (Qt, fmt, args);
+  result = write_fmt_string_va (Qt, fmt, args);
   va_end (args);
+  return result;
 }
 
 /* Write a printf-style string to standard output, where the arguments are
    Lisp_Objects. */
-void
+Bytecount
 stderr_out_lisp (const CIbyte *fmt, ...)
 {
+  Bytecount result;
   va_list va;
 
   if (initialized && !inhibit_non_essential_conversion_operations)
     fmt = GETTEXT (fmt);
 
   va_start (va, fmt);
-  write_fmt_string_lisp_va (Qexternal_debugging_output, fmt, va);
+  result = write_fmt_string_lisp_va (Qexternal_debugging_output, fmt, va);
   va_end (va);
+
+  return result;
 }
 
 /* Return a Lisp string reflecting FORMAT_NONRELOC and VARGS, where VARGS
diff -r 296ee062f9f9 -r 714a6e9c1669 src/lisp.h
--- a/src/lisp.h	Mon Dec 25 11:34:22 2017 +0000
+++ b/src/lisp.h	Sat Dec 23 14:57:42 2017 +0000
@@ -4770,18 +4770,19 @@
 Lisp_Object format_into (Lisp_Object stream, Lisp_Object format_reloc,
                          int nargs, const Lisp_Object *largs);
 
-MODULE_API void write_fmt_string (Lisp_Object stream, const CIbyte *fmt, ...)
+MODULE_API Bytecount write_fmt_string (Lisp_Object stream, const CIbyte *fmt,
+				       ...)
   PRINTF_ARGS (2, 3);
-MODULE_API void write_fmt_string_va (Lisp_Object stream,
-                                     const CIbyte *fmt, va_list);
-MODULE_API void write_fmt_string_lisp (Lisp_Object stream, const CIbyte *fmt,
-				       ...);
-MODULE_API void write_fmt_string_lisp_va (Lisp_Object stream,
-                                          const CIbyte *fmt, va_list);
-
-void stderr_out (const CIbyte *, ...) PRINTF_ARGS (1, 2);
-void stderr_out_lisp (const CIbyte *, ...);
-void stdout_out (const CIbyte *, ...) PRINTF_ARGS (1, 2);
+MODULE_API Bytecount write_fmt_string_va (Lisp_Object stream,
+					  const CIbyte *fmt, va_list);
+MODULE_API Bytecount write_fmt_string_lisp (Lisp_Object stream,
+					    const CIbyte *fmt, ...);
+MODULE_API Bytecount write_fmt_string_lisp_va (Lisp_Object stream,
+					       const CIbyte *fmt, va_list);
+
+Bytecount stderr_out (const CIbyte *, ...) PRINTF_ARGS (1, 2);
+Bytecount stderr_out_lisp (const CIbyte *, ...);
+Bytecount stdout_out (const CIbyte *, ...) PRINTF_ARGS (1, 2);
 
 Lisp_Object emacs_vsprintf_string_lisp (const CIbyte *format_nonreloc,
                                         va_list vargs);
@@ -5864,8 +5865,8 @@
 void debug_p3 (Lisp_Object obj);
 void debug_short_backtrace (int);
 void debug_backtrace (void);
-MODULE_API void write_lisp_string (Lisp_Object stream, Lisp_Object string,
-                                   Bytecount offset, Bytecount len);
+MODULE_API Bytecount write_lisp_string (Lisp_Object stream, Lisp_Object string,
+					Bytecount offset, Bytecount len);
 
 /* NOTE: Do not call the following with the data of a Lisp_String.  Use
    write_lisp_string().
@@ -5873,41 +5874,41 @@
    If you would like a STREAM value of Qt, Qnil to indicate output to the
    selected frame, rather than C's standard output, call
    canonicalize_printcharfun () before calling this function. */
-void write_string_1 (Lisp_Object stream, const Ibyte *str, Bytecount size);
+Bytecount write_string_1 (Lisp_Object stream, const Ibyte *str,
+			  Bytecount size);
 
 /* Same goes for this function. */
 DECLARE_INLINE_HEADER (
-void write_istring (Lisp_Object stream, const Ibyte *str)
-)
-{
-  /* This function can GC. We'd like to qxestrlen, but that's not yet
-     available in this file. */
-  write_string_1 (stream, str, strlen ((const char *) str));
-}
-/* Same goes for this function. */
-DECLARE_INLINE_HEADER (
-void write_cistring (Lisp_Object stream, const CIbyte *str)
+Bytecount write_istring (Lisp_Object stream, const Ibyte *str)
 )
 {
   /* This function can GC. We'd like to qxestrlen, but that's not yet
      available in this file. */
-  write_string_1 (stream, (const Ibyte *) str,
-                  strlen ((const char *) str));
+  return write_string_1 (stream, str, strlen ((const char *) str));
 }
 /* Same goes for this function. */
 DECLARE_INLINE_HEADER (
-void write_ascstring (Lisp_Object stream, const Ascbyte *str)
+Bytecount write_cistring (Lisp_Object stream, const CIbyte *str)
+)
+{
+  /* This function can GC. We'd like to qxestrlen, but that's not yet
+     available in this file. */
+  return write_string_1 (stream, (const Ibyte *) str,
+			 strlen ((const char *) str));
+}
+/* Same goes for this function. */
+DECLARE_INLINE_HEADER (
+Bytecount write_ascstring (Lisp_Object stream, const Ascbyte *str)
 )
 {
   /* This function can GC. */
-  write_string_1 (stream, (const Ibyte *) str,
-                  strlen ((char *) str));
+  return write_string_1 (stream, (const Ibyte *) str, strlen ((char *) str));
 }
-void write_eistring (Lisp_Object stream, const Eistring *ei);
-
-void external_out (int dest, const CIbyte *fmt, ...) PRINTF_ARGS (2, 3);
-void debug_out (const CIbyte *, ...) PRINTF_ARGS (1, 2);
-void debug_out_lisp (const CIbyte *, ...);
+Bytecount write_eistring (Lisp_Object stream, const Eistring *ei);
+
+Bytecount external_out (int dest, const CIbyte *fmt, ...) PRINTF_ARGS (2, 3);
+Bytecount debug_out (const CIbyte *, ...) PRINTF_ARGS (1, 2);
+Bytecount debug_out_lisp (const CIbyte *, ...);
 DECLARE_DOESNT_RETURN (fatal (const CIbyte *, ...)) PRINTF_ARGS(1, 2);
 
 /* Internal functions: */
diff -r 296ee062f9f9 -r 714a6e9c1669 src/print.c
--- a/src/print.c	Mon Dec 25 11:34:22 2017 +0000
+++ b/src/print.c	Sat Dec 23 14:57:42 2017 +0000
@@ -158,8 +158,8 @@
 
 FILE *termscript;	/* Stdio stream being used for copy of all output.  */
 
-static void write_string_to_alternate_debugging_output (const Ibyte *str,
-							Bytecount len);
+static Bytecount write_string_to_alternate_debugging_output (const Ibyte *str,
+							     Bytecount len);
 
 /* To avoid consing in debug_prin1, we package up variables we need to bind
    into an opaque object. */
@@ -186,17 +186,17 @@
 
 /* Basic function to actually write to a stdio stream or TTY console. */
 
-static void
+static Bytecount
 write_string_to_stdio_stream_1 (FILE *stream, struct console *con,
 				const Ibyte *ptr, Bytecount len,
 				int must_flush)
 {
   Extbyte *extptr = 0;
-  Bytecount extlen = 0;
-  int output_is_std_handle =
+  Bytecount extlen = 0, result;
+  Boolint output_is_std_handle =
     stream ? stream == stdout || stream == stderr :
-      CONSOLE_TTY_DATA (con)->is_stdio;
-
+    CONSOLE_TTY_DATA (con)->is_stdio;
+  
   if (stream || output_is_std_handle)
     {
       if (initialized && !inhibit_non_essential_conversion_operations)
@@ -229,7 +229,7 @@
       else
 #endif
 	{
-	  retry_fwrite (extptr, 1, extlen, stream);
+	  result = retry_fwrite (extptr, 1, extlen, stream);
 #ifdef WIN32_NATIVE
 	  /* Q122442 says that pipes are "treated as files, not as
 	     devices", and that this is a feature. Before I found that
@@ -243,7 +243,8 @@
     }
   else
     /* The stream itself does conversion to external format */
-    Lstream_write (XLSTREAM (CONSOLE_TTY_DATA (con)->outstream), ptr, len);
+    result = Lstream_write (XLSTREAM (CONSOLE_TTY_DATA (con)->outstream),
+			    ptr, len);
 
   if (output_is_std_handle)
     {
@@ -254,12 +255,14 @@
 	}
       stdout_needs_newline = (ptr[len - 1] != '\n');
     }
+
+  return result;
 }
 
 /* Write to a stdio stream or TTY console, first clearing the left side
    if necessary. */
 
-static void
+static Bytecount
 write_string_to_stdio_stream (FILE *stream, struct console *con,
 			      const Ibyte *ptr, Bytecount len,
 			      int must_flush)
@@ -274,7 +277,7 @@
       stdout_clear_before_next_output = 0;
     }
 
-  write_string_to_stdio_stream_1 (stream, con, ptr, len, must_flush);
+  return write_string_to_stdio_stream_1 (stream, con, ptr, len, must_flush);
 }
 
 /*
@@ -299,20 +302,35 @@
     EXT_PRINT_ALL = 14
   };
 
-static void
+static Bytecount
 write_string_to_external_output (const Ibyte *ptr, Bytecount len,
 				 int dest)
 {
+  Bytecount result = 0, output;
   if (dest & EXT_PRINT_STDOUT)
-    write_string_to_stdio_stream (stdout, 0, ptr, len, 1);
+    {
+      output = write_string_to_stdio_stream (stdout, 0, ptr, len, 1);
+      result = min (result, output);
+    }
   if (dest & EXT_PRINT_STDERR)
-    write_string_to_stdio_stream (stderr, 0, ptr, len, 1);
+    {
+      output = write_string_to_stdio_stream (stderr, 0, ptr, len, 1);
+      result = min (result, output);      
+    }
   if (dest & EXT_PRINT_ALTERNATE)
-    write_string_to_alternate_debugging_output (ptr, len);
+    {
+      output = write_string_to_alternate_debugging_output (ptr, len);
+      result = min (result, output);
+    }
 #ifdef WIN32_NATIVE
   if (dest & EXT_PRINT_MSWINDOWS)
-    write_string_to_mswindows_debugging_output (ptr, len);
+    {
+      output = write_string_to_mswindows_debugging_output (ptr, len);
+      result = min (result, output);
+    }
 #endif
+
+  return result;
 }
 
 /* This function can be called from fatal_error_signal() and so should make as
@@ -332,7 +350,7 @@
 
    Both emacs_vsnprintf() and write_string_to_external_output_va() will fail
    if we run out of stack space. Oh well. */
-static void
+static Bytecount
 write_string_to_external_output_va (const CIbyte *fmt, va_list args,
 				    int dest)
 {
@@ -347,17 +365,22 @@
   write_string_to_external_output (kludge,
                                    min (klen, (Bytecount) sizeof (kludge)),
                                    dest);
+
+  return klen;
 }
 
 /* Output portably to print destination as specified by DEST. */
 
-void
+Bytecount
 external_out (int dest, const CIbyte *fmt, ...)
 {
+  Bytecount result;
   va_list args;
   va_start (args, fmt);
-  write_string_to_external_output_va (fmt, args, dest);
+  result = write_string_to_external_output_va (fmt, args, dest);
   va_end (args);
+
+  return result;
 }
 
 DOESNT_RETURN
@@ -391,7 +414,7 @@
    Use Qexternal_debugging_output to get output to stderr.
 */
 
-static void
+static Bytecount
 output_string (Lisp_Object function, const Ibyte *nonreloc,
 	       Lisp_Object reloc, Bytecount offset, Bytecount len)
 {
@@ -402,22 +425,22 @@
      may get confused and an assertion failure in
      fixup_internal_substring() may get triggered. */
   const Ibyte *newnonreloc;
-  struct gcpro gcpro1, gcpro2;
+  Bytecount result;
 
   /* Emacs won't print while GCing, but an external debugger might */
 #ifdef NO_PRINT_DURING_GC
-  if (gc_in_progress) return;
+  if (gc_in_progress) return 0;
 #endif
 
-  /* Perhaps not necessary but probably safer. */
-  GCPRO2 (function, reloc);
-
   fixup_internal_substring (nonreloc, reloc, offset, &len);
 
   newnonreloc = STRINGP (reloc) ? XSTRING_DATA (reloc) : nonreloc;
 
   if (LSTREAMP (function))
     {
+      struct gcpro gcpro1, gcpro2;
+      GCPRO2 (reloc, function);
+
       if (STRINGP (reloc))
 	{
           /* We used to inhibit GC here. There's no need, the only Lstreams
@@ -429,24 +452,37 @@
              have write_with_extents (), which knows it has been handed a Lisp
              string, and can take appropriate action to re-fetch string
              data. */
-          Lstream_write_with_extents (XLSTREAM (function), reloc, offset,
-                                      len);
+	  result = Lstream_write_with_extents (XLSTREAM (function), reloc,
+					       offset, len);
 	}
       else
         {
-          Lstream_write (XLSTREAM (function), newnonreloc + offset, len);
+          result = Lstream_write (XLSTREAM (function), newnonreloc + offset,
+				  len);
         }
 
       if (print_unbuffered)
 	Lstream_flush (XLSTREAM (function));
+
+      RETURN_UNGCPRO (result);
     }
   else if (BUFFERP (function))
     {
+      struct gcpro gcpro1;
+
       CHECK_LIVE_BUFFER (function);
+
+      GCPRO1 (reloc);
+      
       buffer_insert_string (XBUFFER (function), nonreloc, reloc, offset, len);
+
+      RETURN_UNGCPRO (len);
     }
   else if (MARKERP (function))
     {
+      struct gcpro gcpro1;
+      GCPRO1 (reloc);
+
       buffer_insert_string_1 (XMARKER (function)->buffer,
 			      /* marker_position() will err if marker
 				 doesn't point anywhere.  */
@@ -454,22 +490,29 @@
 			      offset, len, -1, 0);
       set_byte_marker_position (function,
 				byte_marker_position (function) + len);
+      RETURN_UNGCPRO (len); /* We will have errored on failure. */
     }
   else if (FRAMEP (function))
     {
       /* This gets used by functions not invoking print_prepare(),
          such as Fwrite_char, Fterpri, etc..  */
       struct frame *f = XFRAME (function);
+      struct gcpro gcpro1;
+
       CHECK_LIVE_FRAME (function);
 
+      GCPRO1 (reloc);
+
       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);
+
+      RETURN_UNGCPRO (len);
     }
   else if (EQ (function, Qt) || EQ (function, Qnil))
     {
-      write_string_to_stdio_stream (stdout, 0, newnonreloc + offset, len,
-				    print_unbuffered);
+      return write_string_to_stdio_stream (stdout, 0, newnonreloc + offset,
+					   len, print_unbuffered);
     }
   else if (EQ (function, Qexternal_debugging_output))
     {
@@ -477,15 +520,19 @@
 	 having each character passed separately to
 	 `external-debugging-output'.  The API says to pass each character
 	 separately because that is the Lisp Way. */
-      write_string_to_stdio_stream (stderr, 0, newnonreloc + offset, len,
-				    print_unbuffered);
+      return write_string_to_stdio_stream (stderr, 0, newnonreloc + offset,
+					   len, print_unbuffered);
     }
   else
     {
       Bytecount end = offset + len;
+      struct gcpro gcpro1;
+
+      GCPRO1 (reloc);
 
       while (offset < end)
 	{
+	  /* call1() GCPROs FUNCTION. */
 	  call1 (function, make_char (itext_ichar (newnonreloc + offset)));
 
           if (STRINGP (reloc))
@@ -509,9 +556,9 @@
 
           offset += itext_ichar_len (newnonreloc + offset);
 	}
+
+      RETURN_UNGCPRO (len);
     }
-
-  UNGCPRO;
 }
 
 static int
@@ -645,12 +692,12 @@
 
 /* Write a Lisp string to STREAM, preserving extent data if STREAM can handle
    it, and protecting its string data from relocation when appropriate. */
-void
+Bytecount
 write_lisp_string (Lisp_Object stream, Lisp_Object string, Bytecount offset,
                    Bytecount len)
 {
   /* This function can GC */
-  output_string (stream, NULL, string, offset, len);
+  return output_string (stream, NULL, string, offset, len);
 }  
 
 /* Write internal-format data to STREAM.  See output_string() for
@@ -668,18 +715,18 @@
 
    Also note that STREAM should be the result of canonicalize_printcharfun()
    (i.e. Qnil means stdout, not Vstandard_output, etc.)  */
-void
+Bytecount
 write_string_1 (Lisp_Object stream, const Ibyte *str, Bytecount size)
 {
   /* This function can GC */
   text_checking_assert (size >= 0);
-  output_string (stream, str, Qnil, 0, size);
+  return output_string (stream, str, Qnil, 0, size);
 }
 
-void
+Bytecount
 write_eistring (Lisp_Object stream, const Eistring *ei)
 {
-  write_string_1 (stream, eidata (ei), eilen (ei));
+  return write_string_1 (stream, eidata (ei), eilen (ei));
 }
 
 DEFUN ("write-char", Fwrite_char, 1, 2, 0, /*
@@ -2467,7 +2514,7 @@
   return character;
 }
 
-static void
+static Bytecount
 write_string_to_alternate_debugging_output (const Ibyte *str, Bytecount len)
 {
   int extlen;
@@ -2486,7 +2533,7 @@
 
   /* If not yet initialized, just skip it. */
   if (alternate_do_string == NULL)
-    return;
+    return 0;
 
   if (alternate_do_pointer + extlen >= alternate_do_size)
     {
@@ -2497,6 +2544,7 @@
   memcpy (alternate_do_string + alternate_do_pointer, extptr, extlen);
   alternate_do_pointer += extlen;
   alternate_do_string[alternate_do_pointer] = 0;
+  return extlen;
 }
 
 
@@ -2839,15 +2887,17 @@
 
 /* Printf-style debugging output. */
 
-void
+Bytecount
 debug_out (const CIbyte *fmt, ...)
 {
   int depth =  begin_inhibit_non_essential_conversion_operations ();
+  Bytecount result;
   va_list args;
   va_start (args, fmt);
-  write_string_to_external_output_va (fmt, args, EXT_PRINT_ALL);
+  result = write_string_to_external_output_va (fmt, args, EXT_PRINT_ALL);
   va_end (args);
   unbind_to (depth);
+  return result;
 }
 
 /* Basic entry point: Print out a Lisp object to the debugging output. */
@@ -2855,7 +2905,7 @@
 void
 debug_print (Lisp_Object debug_print_obj)
 {
-  external_debug_print (debug_print_obj, EXT_PRINT_ALL);
+  return external_debug_print (debug_print_obj, EXT_PRINT_ALL);
 }
 
 /* Printf-style output when the objects being printed are Lisp objects.
@@ -2864,13 +2914,13 @@
    debug_out_lisp ("Called foo(%s %s)\n", arg0, arg1)
 */
 
-void
+Bytecount
 debug_out_lisp (const CIbyte *format, ...)
 {
   /* This function cannot GC, since GC is forbidden */
   struct debug_bindings bindings;
   int specdepth = debug_print_enter (&bindings);
-  Bytecount len;
+  Bytecount len, result;
   va_list va;
   Ibyte *msgout;
 
@@ -2878,9 +2928,11 @@
   len = emacs_vasprintf_lisp (&msgout, format, va);
   va_end (va);
 
-  write_string_to_external_output (msgout, len, EXT_PRINT_ALL);
+  result = write_string_to_external_output (msgout, len, EXT_PRINT_ALL);
   xfree (msgout);
   unbind_to (specdepth);
+
+  return result;
 }
 
 /* Getting tired of typing debug_print() ... */
-- 
‘As I sat looking up at the Guinness ad, I could never figure out /
How your man stayed up on the surfboard after forty pints of stout’
(C. Moore)