From 91fa47f0d041b866230d2ed421f97ee89f176b00 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 8 Jul 2019 19:16:28 -0700 Subject: [PATCH] Send informative messages to stdout, not stderr This helps avoid interleaving info lines with lines from other processes, since stdout is normally at least line buffered. * doc/emacs/cmdargs.texi (Initial Options), etc/NEWS: Document this. * src/dispnew.c (init_display_interactive): * src/emacs.c (main, Fdump_emacs): * src/gtkutil.c (my_log_handler, xg_set_geometry) (xg_create_widget): * src/image.c (convert_mono_to_color_image): * src/lread.c (dir_warning): * src/nsmenu.m (ns_update_menubar): * src/nsterm.m (ns_mouse_position, ns_default) (sendEvent:, performDragOperation:, mouseDown:): * src/pdumper.c (dump_fingerprint, print_paths_to_root_1) (Fdump_emacs_portable): * src/xdisp.c (message_to_stdout, vmessage): * src/xselect.c (x_clipboard_manager_error_2): * src/xsmfns.c (x_session_initialize): * src/xterm.c (my_log_handler, x_initialize): Send info messages to stdout, not stderr. * src/xdisp.c (message_to_stdout): Rename from message_to_stderr. All uses changed. Avoid need to allocate a buffer on the heap. --- doc/emacs/cmdargs.texi | 4 ++-- etc/NEWS | 5 +++++ src/dispnew.c | 3 +-- src/emacs.c | 23 +++++++++++------------ src/gtkutil.c | 9 +++------ src/image.c | 2 +- src/lread.c | 4 ++-- src/nsmenu.m | 2 +- src/nsterm.m | 13 ++++++------- src/pdumper.c | 31 +++++++++++++++---------------- src/xdisp.c | 42 ++++++++++++++++-------------------------- src/xselect.c | 2 +- src/xsmfns.c | 4 ++-- src/xterm.c | 4 ++-- 14 files changed, 68 insertions(+), 80 deletions(-) diff --git a/doc/emacs/cmdargs.texi b/doc/emacs/cmdargs.texi index 34a5ff5f2c..24319ea2d4 100644 --- a/doc/emacs/cmdargs.texi +++ b/doc/emacs/cmdargs.texi @@ -254,8 +254,8 @@ Initial Options message in the echo area will print to either the standard output stream (@code{stdout}) or the standard error stream (@code{stderr}) instead. (To be precise, functions like @code{prin1}, @code{princ} -and @code{print} print to @code{stdout}, while @code{message} and -@code{error} print to @code{stderr}.) Functions that normally read +@code{print} and @code{message} print to @code{stdout}, while +@code{error} prints to @code{stderr}.) Functions that normally read keyboard input from the minibuffer take their input from the terminal's standard input stream (@code{stdin}) instead. diff --git a/etc/NEWS b/etc/NEWS index 532babd0fa..8d6bac87a8 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1732,6 +1732,11 @@ old-style backquotes as new-style, bind the new variable 'cl-struct-define' whose name clashes with a builtin type (e.g., 'integer' or 'hash-table') now signals an error. +** Non-error messages that were formerly sent to standard error are +now sent to standard output. For example, the 'message' function now +outputs to standard output. This helps prevent these output lines +from being broken up by the output of other processes. + ** When formatting a floating-point number as an octal or hexadecimal integer, Emacs now signals an error if the number is too large for the implementation to format. diff --git a/src/dispnew.c b/src/dispnew.c index 0131b63767..d354ce2b44 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -6154,8 +6154,7 @@ init_display_interactive (void) if (display_arg && !x_display_ok (display)) { - fprintf (stderr, "Display %s unavailable, simulating -nw\n", - display); + printf ("Display %s unavailable, simulating -nw\n", display); inhibit_window_system = 1; } } diff --git a/src/emacs.c b/src/emacs.c index 9c93748a0f..8bff66f073 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1306,7 +1306,7 @@ main (int argc, char **argv) fprintf (stderr, "%s: %s: not a tty\n", argv[0], term); exit (EXIT_FAILURE); } - fprintf (stderr, "Using %s\n", term); + printf ("Using %s\n", term); #ifdef HAVE_WINDOW_SYSTEM inhibit_window_system = true; /* -t => -nw */ #endif @@ -1416,7 +1416,7 @@ main (int argc, char **argv) fputs (("\n" "Warning: systemd passed more than one socket to Emacs.\n" "Try 'Accept=false' in the Emacs socket unit file.\n"), - stderr); + stdout); else if (systemd_socket == 1 && (0 < sd_is_socket (SD_LISTEN_FDS_START, AF_UNSPEC, SOCK_STREAM, 1))) @@ -1427,7 +1427,7 @@ main (int argc, char **argv) fputs ("\nWarning: due to a long standing Gtk+ bug\nhttps://gitlab.gnome.org/GNOME/gtk/issues/221\n\ Emacs might crash when run in daemon mode and the X11 connection is unexpectedly lost.\n\ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem.\n", - stderr); + stdout); #endif /* USE_GTK */ if (daemon_type == 2) @@ -2548,15 +2548,14 @@ DEFUN ("dump-emacs", Fdump_emacs, Sdump_emacs, 2, 2, 0, # define MAX_HEAP_BSS_DIFF (1024 * 1024) if (heap_bss_diff > MAX_HEAP_BSS_DIFF) - fprintf (stderr, - ("**************************************************\n" - "Warning: Your system has a gap between BSS and the\n" - "heap (%"PRIuMAX" bytes). This usually means that exec-shield\n" - "or something similar is in effect. The dump may\n" - "fail because of this. See the section about\n" - "exec-shield in etc/PROBLEMS for more information.\n" - "**************************************************\n"), - heap_bss_diff); + printf (("**************************************************\n" + "Warning: Your system has a gap between BSS and the\n" + "heap (%"PRIuMAX" bytes). This usually means that exec-shield\n" + "or something similar is in effect. The dump may\n" + "fail because of this. See the section about\n" + "exec-shield in etc/PROBLEMS for more information.\n" + "**************************************************\n"), + heap_bss_diff); } # endif diff --git a/src/gtkutil.c b/src/gtkutil.c index 1d15aec253..d96c193d08 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -829,7 +829,7 @@ my_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *msg, gpointer user_data) { if (!strstr (msg, "visible children")) - fprintf (stderr, "XX %s-WARNING **: %s\n", log_domain, msg); + printf ("XX %s-WARNING **: %s\n", log_domain, msg); } #endif @@ -894,7 +894,7 @@ xg_set_geometry (struct frame *f) if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), geom_str)) - fprintf (stderr, "Failed to parse: '%s'\n", geom_str); + printf ("Failed to parse: '%s'\n", geom_str); g_log_remove_handler ("Gtk", id); } @@ -2849,10 +2849,7 @@ xg_create_widget (const char *type, const char *name, struct frame *f, } } else - { - fprintf (stderr, "bad type in xg_create_widget: %s, doing nothing\n", - type); - } + printf ("bad type in xg_create_widget: %s, doing nothing\n", type); return w; } diff --git a/src/image.c b/src/image.c index e898a7364a..6609488758 100644 --- a/src/image.c +++ b/src/image.c @@ -3338,7 +3338,7 @@ convert_mono_to_color_image (struct frame *f, struct image *img, DeleteDC (new_img_dc); DeleteObject (img->pixmap); if (new_pixmap == 0) - fputs ("Failed to convert image to color.\n", stderr); + fputs ("Failed to convert image to color.\n", stdout); else img->pixmap = new_pixmap; } diff --git a/src/lread.c b/src/lread.c index e06eafcf6c..f32c56b573 100644 --- a/src/lread.c +++ b/src/lread.c @@ -4715,7 +4715,7 @@ init_lread (void) /* Print a warning that directory intended for use USE and with name DIRNAME cannot be accessed. On entry, errno should correspond to - the access failure. Print the warning on stderr and put it in + the access failure. Print the warning on stdout and put it in *Messages*. */ void @@ -4723,7 +4723,7 @@ dir_warning (char const *use, Lisp_Object dirname) { static char const format[] = "Warning: %s '%s': %s\n"; char *diagnostic = emacs_strerror (errno); - fprintf (stderr, format, use, SSDATA (ENCODE_SYSTEM (dirname)), diagnostic); + printf (format, use, SSDATA (ENCODE_SYSTEM (dirname)), diagnostic); /* Don't log the warning before we've initialized!! */ if (initialized) diff --git a/src/nsmenu.m b/src/nsmenu.m index 817f8cff18..d7274c0723 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -236,7 +236,7 @@ if (submenu && n == 0) { /* should have found a menu for this one but didn't */ - fprintf (stderr, "ERROR: did not find lisp menu for submenu '%s'.\n", + printf ("ERROR: did not find lisp menu for submenu '%s'.\n", [[submenu title] UTF8String]); discard_menu_items (); unbind_to (specpdl_count, Qnil); diff --git a/src/nsterm.m b/src/nsterm.m index 02331826d9..b202013577 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -2466,7 +2466,7 @@ so some key presses (TAB) are swallowed by the system. */ if (*fp == NULL) { - fputs ("Warning: ns_mouse_position () called with null *fp.\n", stderr); + fputs ("Warning: ns_mouse_position () called with null *fp.\n", stdout); return; } @@ -5032,8 +5032,8 @@ static Lisp_Object ns_string_to_lispmod (const char *s) *result = make_float (f); else if (is_modstring && value) *result = ns_string_to_lispmod (value); - else fprintf (stderr, - "Bad value for default \"%s\": \"%s\"\n", parameter, value); + else + printf ("Bad value for default \"%s\": \"%s\"\n", parameter, value); } } @@ -5613,7 +5613,7 @@ - (void)sendEvent: (NSEvent *)theEvent if (type == NSEventTypeCursorUpdate && window == nil) { - fputs ("Dropping external cursor update event.\n", stderr); + fputs ("Dropping external cursor update event.\n", stdout); return; } @@ -8291,7 +8291,7 @@ -(BOOL)performDragOperation: (id ) sender } else { - fputs ("Invalid data type in dragging pasteboard\n", stderr); + fputs ("Invalid data type in dragging pasteboard\n", stdout); return NO; } @@ -9035,8 +9035,7 @@ - (void)mouseDown: (NSEvent *)e case NSScrollerKnobSlot: /* GNUstep-only */ last_hit_part = scroll_bar_move_ratio; break; default: /* NSScrollerNoPart? */ - fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n", - (long) part); + printf ("EmacsScroller-mouseDown: unexpected part %ld\n", (long) part); return; } diff --git a/src/pdumper.c b/src/pdumper.c index 8b630d221b..cd4ec9fbcf 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -326,10 +326,10 @@ dump_reloc_set_offset (struct dump_reloc *reloc, dump_off offset) static void dump_fingerprint (const char *label, unsigned char const *xfingerprint) { - fprintf (stderr, "%s: ", label); + printf ("%s: ", label); for (int i = 0; i < 32; ++i) - fprintf (stderr, "%02x", (unsigned) xfingerprint[i]); - putc ('\n', stderr); + printf ("%02x", (unsigned) xfingerprint[i]); + putchar ('\n'); } /* Format of an Emacs portable dump file. All offsets are relative to @@ -1404,9 +1404,9 @@ print_paths_to_root_1 (struct dump_context *ctx, referrers = XCDR (referrers); Lisp_Object repr = Fprin1_to_string (referrer, Qnil); for (int i = 0; i < level; ++i) - putc (' ', stderr); - fwrite (SDATA (repr), 1, SBYTES (repr), stderr); - putc ('\n', stderr); + putchar (' '); + fwrite (SDATA (repr), 1, SBYTES (repr), stdout); + putchar ('\n'); print_paths_to_root_1 (ctx, referrer, level + 1); } } @@ -4226,16 +4226,15 @@ DEFUN ("dump-emacs-portable", dump_seek (ctx, 0); dump_write (ctx, &ctx->header, sizeof (ctx->header)); - fprintf (stderr, - ("Dump complete\n" - "Byte counts: header=%lu hot=%lu discardable=%lu cold=%lu\n" - "Reloc counts: hot=%u discardable=%u\n"), - (unsigned long) (header_end - header_start), - (unsigned long) (hot_end - hot_start), - (unsigned long) (discardable_end - ctx->header.discardable_start), - (unsigned long) (cold_end - ctx->header.cold_start), - number_hot_relocations, - number_discardable_relocations); + printf (("Dump complete\n" + "Byte counts: header=%lu hot=%lu discardable=%lu cold=%lu\n" + "Reloc counts: hot=%u discardable=%u\n"), + (unsigned long) (header_end - header_start), + (unsigned long) (hot_end - hot_start), + (unsigned long) (discardable_end - ctx->header.discardable_start), + (unsigned long) (cold_end - ctx->header.cold_start), + number_hot_relocations, + number_discardable_relocations); unblock_input (); return unbind_to (count, Qnil); diff --git a/src/xdisp.c b/src/xdisp.c index 2711e54382..04aad05413 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -10706,15 +10706,15 @@ message3 (Lisp_Object m) message3_nolog (m); } -/* Log the message M to stderr. Log an empty line if M is not a string. */ +/* Log the message M to stdout. Log an empty line if M is not a string. */ static void -message_to_stderr (Lisp_Object m) +message_to_stdout (Lisp_Object m) { if (noninteractive_need_newline) { noninteractive_need_newline = false; - putc ('\n', stderr); + putchar ('\n'); } if (STRINGP (m)) { @@ -10728,21 +10728,11 @@ message_to_stderr (Lisp_Object m) else s = m; - /* We want to write this out with a single call so that - output doesn't interleave with other processes writing to - stderr at the same time. */ - { - int length = min (INT_MAX, SBYTES (s) + 1); - char *string = xmalloc (length); - - memcpy (string, SSDATA (s), length - 1); - string[length - 1] = '\n'; - fwrite (string, 1, length, stderr); - xfree (string); - } + fwrite_unlocked (SDATA (s), 1, SBYTES (s), stdout); } - else if (!cursor_in_echo_area) - putc ('\n', stderr); + + if (STRINGP (m) || !cursor_in_echo_area) + putchar ('\n'); } /* The non-logging version of message3. @@ -10756,7 +10746,7 @@ message3_nolog (Lisp_Object m) struct frame *sf = SELECTED_FRAME (); if (FRAME_INITIAL_P (sf)) - message_to_stderr (m); + message_to_stdout (m); /* Error messages get reported properly by cmd_error, so this must be just an informative message; if the frame hasn't really been initialized yet, just toss it. */ @@ -10853,7 +10843,7 @@ message_with_string (const char *m, Lisp_Object string, bool log) Lisp_Object msg = CALLN (Fformat_message, fmt, string); if (noninteractive) - message_to_stderr (msg); + message_to_stdout (msg); else { if (log) @@ -10873,7 +10863,7 @@ message_with_string (const char *m, Lisp_Object string, bool log) any existing message, and let the mini-buffer text show through. The message must be safe ASCII (because when Emacs is - non-interactive the message is sent straight to stderr without + non-interactive the message is sent straight to stdout without encoding first) and the format must not contain ` or ' (because this function does not account for `text-quoting-style'). If your message and format do not fit into this category, convert your @@ -10887,12 +10877,12 @@ vmessage (const char *m, va_list ap) if (m) { if (noninteractive_need_newline) - putc ('\n', stderr); - noninteractive_need_newline = false; - vfprintf (stderr, m, ap); - if (!cursor_in_echo_area) - putc ('\n', stderr); - fflush (stderr); + { + noninteractive_need_newline = false; + putchar ('\n'); + } + vprintf (m, ap); + putchar ('\n'); } } else if (INTERACTIVE) diff --git a/src/xselect.c b/src/xselect.c index d74f064a1c..14ecfeddb7 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -2175,7 +2175,7 @@ x_clipboard_manager_error_2 (Lisp_Object err) fputs (("Error saving to X clipboard manager.\n" "If the problem persists," " set 'x-select-enable-clipboard-manager' to nil.\n"), - stderr); + stdout); return Qnil; } diff --git a/src/xsmfns.c b/src/xsmfns.c index 1706cddf27..8dfd60663f 100644 --- a/src/xsmfns.c +++ b/src/xsmfns.c @@ -404,8 +404,8 @@ #define SM_ERRORSTRING_LEN 512 char *pwd = emacs_get_current_dir_name (); if (!pwd) { - fprintf (stderr, "Disabling session management due to pwd error: %s\n", - emacs_strerror (errno)); + printf ("Disabling session management due to pwd error: %s\n", + emacs_strerror (errno)); return; } xfree (pwd); diff --git a/src/xterm.c b/src/xterm.c index c96aa74a7a..0cc2df6ecb 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -12465,7 +12465,7 @@ my_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *msg, gpointer user_data) { if (!strstr (msg, "g_set_prgname")) - fprintf (stderr, "%s-WARNING **: %s\n", log_domain, msg); + printf ("%s-WARNING **: %s\n", log_domain, msg); } #endif @@ -13442,7 +13442,7 @@ x_initialize (void) /* This must be called before any other Xlib routines. */ if (XInitThreads () == 0) fputs ("Warning: An error occurred initializing X11 thread support!\n", - stderr); + stdout); #endif #ifdef USE_X_TOOLKIT -- 2.21.0