+static void
+std_handle_out_external (FILE *stream, Lisp_Object lstream,
+ const Extbyte *extptr, Extcount extlen,
+ /* is this really stdout/stderr?
+ (controls termscript writing) */
+ int output_is_std_handle,
+ int must_flush)
+{
+ if (stream)
+ {
+#ifdef WIN32_NATIVE
+ HANDLE errhand = GetStdHandle (STD_INPUT_HANDLE);
+ int no_useful_stderr = errhand == 0 || errhand == INVALID_HANDLE_VALUE;
+
+ if (!no_useful_stderr)
+ no_useful_stderr = !PeekNamedPipe (errhand, 0, 0, 0, 0, 0);
+ /* we typically have no useful stdout/stderr under windows if we're
+ being invoked graphically. */
+ if (no_useful_stderr)
+ mswindows_output_console_string (extptr, extlen);
+ else
+#endif
+ {
+ 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
+ article, I thought it was a bug. Thanks MS, I feel much
+ better now. - kkm */
+ must_flush = 1;
+#endif
+ if (must_flush)
+ fflush (stream);
+ }
+ }
+ else
+ Lstream_write (XLSTREAM (lstream), extptr, extlen);
+
+ if (output_is_std_handle)
+ {
+ if (termscript)
+ {
+ fwrite (extptr, 1, extlen, termscript);
+ fflush (termscript);
+ }
+ stdout_needs_newline = (extptr[extlen - 1] != '\n');
+ }
+}
+
+/* #### The following function should be replaced a call to the
+ emacs_doprnt_*() functions. This is the only way to ensure that
+ I18N3 works properly (many implementations of the *printf()
+ functions, including the ones included in glibc, do not implement
+ the %###$ argument-positioning syntax).
+
+ Note, however, that to do this, we'd have to
+
+ 1) pre-allocate all the lstreams and do whatever else was necessary
+ to make sure that no allocation occurs, since these functions may be
+ called from fatal_error_signal().
+
+ 2) (to be really correct) make a new lstream that outputs using
+ mswindows_output_console_string(). */
+
+static int
+std_handle_out_va (FILE *stream, const char *fmt, va_list args)
+{
+ Bufbyte kludge[8192];
+ Extbyte *extptr;
+ Extcount extlen;
+ int retval;
+
+ retval = vsprintf ((char *) kludge, fmt, args);
+ if (initialized && !inhibit_non_essential_printing_operations)
+ TO_EXTERNAL_FORMAT (DATA, (kludge, strlen ((char *) kludge)),
+ ALLOCA, (extptr, extlen),
+ Qnative);
+ else
+ {
+ extptr = (Extbyte *) kludge;
+ extlen = (Extcount) strlen ((char *) kludge);
+ }
+
+ std_handle_out_external (stream, Qnil, extptr, extlen, 1, 1);
+ return retval;
+}
+
+/* Output portably to stderr or its equivalent; call GETTEXT on the
+ format string. Automatically flush when done. */
+
+int
+stderr_out (const char *fmt, ...)
+{
+ int retval;
+ va_list args;
+ va_start (args, fmt);
+ retval =
+ std_handle_out_va
+ (stderr, initialized && !fatal_error_in_progress ? GETTEXT (fmt) : fmt,
+ args);
+ va_end (args);
+ return retval;
+}
+
+/* Output portably to stdout or its equivalent; call GETTEXT on the
+ format string. Automatically flush when done. */
+
+int
+stdout_out (const char *fmt, ...)
+{
+ int retval;
+ va_list args;
+ va_start (args, fmt);
+ retval =
+ std_handle_out_va
+ (stdout, initialized && !fatal_error_in_progress ? GETTEXT (fmt) : fmt,
+ args);
+ va_end (args);
+ return retval;
+}
+
+DOESNT_RETURN
+fatal (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+
+ stderr_out ("\nXEmacs: ");
+ std_handle_out_va (stderr, GETTEXT (fmt), args);
+ stderr_out ("\n");
+
+ va_end (args);
+ exit (1);
+}
+