diff --git a/doc/emacs/mule.texi b/doc/emacs/mule.texi index 7336fdc8f47..80b1384feb6 100644 --- a/doc/emacs/mule.texi +++ b/doc/emacs/mule.texi @@ -1164,7 +1164,9 @@ current language environment. to use when encoding and decoding system strings such as system error messages and @code{format-time-string} formats and time stamps. That coding system is also used for decoding non-@acronym{ASCII} keyboard -input on the X Window System. You should choose a coding system that is compatible +input on the X Window System and for encoding text sent to the +standard output and error streams when in batch mode. You should +choose a coding system that is compatible with the underlying system's text representation, which is normally specified by one of the environment variables @env{LC_ALL}, @env{LC_CTYPE}, and @env{LANG}. (The first one, in the order diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index b12995be6ed..357a3c33fa3 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -6522,8 +6522,9 @@ no buffer display table. @defvar standard-display-table The value of this variable is the standard display table, which is used when Emacs is displaying a buffer in a window with neither a -window display table nor a buffer display table defined. Its default -is @code{nil}. +window display table nor a buffer display table defined, or when Emacs +is outputting text to the standard output or error streams. Its +default is @code{nil}. @end defvar The @file{disp-table} library defines several functions for changing diff --git a/doc/lispref/nonascii.texi b/doc/lispref/nonascii.texi index f16018417de..362c3a4dcbb 100644 --- a/doc/lispref/nonascii.texi +++ b/doc/lispref/nonascii.texi @@ -1959,6 +1959,7 @@ how Emacs interacts with these features. @cindex keyboard input decoding on X This variable specifies the coding system to use for decoding system error messages and---on X Window system only---keyboard input, for +sending batch output to the standard output and error streams, for encoding the format argument to @code{format-time-string}, and for decoding the return value of @code{format-time-string}. @end defvar diff --git a/etc/NEWS b/etc/NEWS index d07057ef4b2..57e63b1f208 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -947,6 +947,12 @@ integers. ** New function `set-binary-mode' allows to switch a standard stream of the Emacs process to binary I/O mode. +** In locales that cannot display curved quotes, ASCII approximations +are installed in standard-display-table. + +** Standard output and error streams now transliterate characters via +standard-display-table, and encode output using locale-coding-system. + ** Miscellaneous name change For consistency with the usual Emacs spelling, the Lisp variable diff --git a/src/coding.c b/src/coding.c index 776ecac62d9..9342c3841f6 100644 --- a/src/coding.c +++ b/src/coding.c @@ -11121,7 +11121,8 @@ See also the function `find-operation-coding-system'. */); DEFVAR_LISP ("locale-coding-system", Vlocale_coding_system, doc: /* Coding system to use with system messages. -Also used for decoding keyboard input on X Window system. */); +Also used for decoding keyboard input on X Window system, and for +encoding standard output and error streams. */); Vlocale_coding_system = Qnil; /* The eol mnemonics are reset in startup.el system-dependently. */ diff --git a/src/dispnew.c b/src/dispnew.c index 693dd49825c..7e7afa71d20 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -6245,6 +6245,7 @@ Each element can be: DEFVAR_LISP ("standard-display-table", Vstandard_display_table, doc: /* Display table to use for buffers that specify none. +It is also used for standard output and error streams. See `buffer-display-table' for more information. */); Vstandard_display_table = Qnil; diff --git a/src/print.c b/src/print.c index a182839ba7d..65c120dbb4f 100644 --- a/src/print.c +++ b/src/print.c @@ -31,6 +31,7 @@ along with GNU Emacs. If not, see . */ #include "window.h" #include "process.h" #include "dispextern.h" +#include "disptab.h" #include "termchar.h" #include "intervals.h" #include "blockinput.h" @@ -195,6 +196,61 @@ print_unwind (Lisp_Object saved_text) memcpy (print_buffer, SDATA (saved_text), SCHARS (saved_text)); } +/* Print character CH to the stdio stream STREAM. */ + +static void +printchar_to_stream (unsigned int ch, FILE *stream) +{ + Lisp_Object dv IF_LINT (= Qnil); + ptrdiff_t i = 0, n = 1; + + if (CHAR_VALID_P (ch) && DISP_TABLE_P (Vstandard_display_table)) + { + dv = DISP_CHAR_VECTOR (XCHAR_TABLE (Vstandard_display_table), ch); + if (VECTORP (dv)) + { + n = ASIZE (dv); + goto next_char; + } + } + + while (true) + { + if (ASCII_CHAR_P (ch)) + { + putc (ch, stream); +#ifdef WINDOWSNT + /* Send the output to a debugger (nothing happens if there + isn't one). */ + if (print_output_debug_flag && stream == stderr) + OutputDebugString ((char []) {ch, '\0'}); +#endif + } + else + { + unsigned char mbstr[MAX_MULTIBYTE_LENGTH]; + int len = CHAR_STRING (ch, mbstr); + Lisp_Object encoded_ch = + ENCODE_SYSTEM (make_multibyte_string ((char *) mbstr, 1, len)); + + fwrite (SSDATA (encoded_ch), 1, SBYTES (encoded_ch), stream); +#ifdef WINDOWSNT + if (print_output_debug_flag && stream == stderr) + OutputDebugString (SSDATA (encoded_ch)); +#endif + } + + i++; + + next_char: + for (; i < n; i++) + if (CHARACTERP (AREF (dv, i))) + break; + if (! (i < n)) + break; + ch = XFASTINT (AREF (dv, i)); + } +} /* Print character CH using method FUN. FUN nil means print to print_buffer. FUN t means print to echo area or stdout if @@ -226,7 +282,10 @@ printchar (unsigned int ch, Lisp_Object fun) else if (noninteractive) { printchar_stdout_last = ch; - fwrite (str, 1, len, stdout); + if (DISP_TABLE_P (Vstandard_display_table)) + printchar_to_stream (ch, stdout); + else + fwrite (str, 1, len, stdout); noninteractive_need_newline = 1; } else @@ -267,7 +326,19 @@ strout (const char *ptr, ptrdiff_t size, ptrdiff_t size_byte, } else if (noninteractive && EQ (printcharfun, Qt)) { - fwrite (ptr, 1, size_byte, stdout); + if (DISP_TABLE_P (Vstandard_display_table)) + { + int len; + for (ptrdiff_t i = 0; i < size_byte; i += len) + { + int ch = STRING_CHAR_AND_LENGTH ((const unsigned char *) ptr + i, + len); + printchar_to_stream (ch, stdout); + } + } + else + fwrite (ptr, 1, size_byte, stdout); + noninteractive_need_newline = 1; } else if (EQ (printcharfun, Qt)) @@ -688,37 +759,8 @@ You can call print while debugging emacs, and pass it this function to make it write to the debugging output. */) (Lisp_Object character) { - unsigned int ch; - CHECK_NUMBER (character); - ch = XINT (character); - if (ASCII_CHAR_P (ch)) - { - putc (ch, stderr); -#ifdef WINDOWSNT - /* Send the output to a debugger (nothing happens if there isn't - one). */ - if (print_output_debug_flag) - { - char buf[2] = {(char) XINT (character), '\0'}; - OutputDebugString (buf); - } -#endif - } - else - { - unsigned char mbstr[MAX_MULTIBYTE_LENGTH]; - ptrdiff_t len = CHAR_STRING (ch, mbstr); - Lisp_Object encoded_ch = - ENCODE_SYSTEM (make_multibyte_string ((char *) mbstr, 1, len)); - - fwrite (SSDATA (encoded_ch), SBYTES (encoded_ch), 1, stderr); -#ifdef WINDOWSNT - if (print_output_debug_flag) - OutputDebugString (SSDATA (encoded_ch)); -#endif - } - + printchar_to_stream (XINT (character), stderr); return character; }