diff options
| author | Paul Eggert | 2015-05-31 20:04:05 -0700 |
|---|---|---|
| committer | Paul Eggert | 2015-05-31 20:04:43 -0700 |
| commit | 467af178f53798e4cd102e04eb2990121eb655df (patch) | |
| tree | 1e6e2cec1eb87963ae796289ef9a1afdd060a668 /src | |
| parent | 21d13bce38c2160bf21b3428cd8e56daadcf4698 (diff) | |
| download | emacs-467af178f53798e4cd102e04eb2990121eb655df.tar.gz emacs-467af178f53798e4cd102e04eb2990121eb655df.zip | |
Treat batch stdout/stderr like standard display
Calls like (print FOO) could generate improperly encoded or
hard-to-read output if FOO contains characters outside the system
locale. Fix this by treating batch stdout and stderr like
interactive standard display, when it comes to transliterating and
encoding characters (Bug#20545).
* doc/emacs/mule.texi (Communication Coding):
* doc/lispref/display.texi (Active Display Table):
* doc/lispref/nonascii.texi (Locales):
* etc/NEWS:
* src/coding.c (syms_of_coding):
* src/dispnew.c (syms_of_display):
Document this.
* src/print.c: Include disptab.h.
(printchar_to_stream): New function, with much of the guts of the
old Fexternal_debugging_output, except this one also uses the
standard display table.
(printchar, strout, Fexternal_debugging_output): Use it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/coding.c | 3 | ||||
| -rw-r--r-- | src/dispnew.c | 1 | ||||
| -rw-r--r-- | src/print.c | 106 |
3 files changed, 77 insertions, 33 deletions
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'. */); | |||
| 11121 | 11121 | ||
| 11122 | DEFVAR_LISP ("locale-coding-system", Vlocale_coding_system, | 11122 | DEFVAR_LISP ("locale-coding-system", Vlocale_coding_system, |
| 11123 | doc: /* Coding system to use with system messages. | 11123 | doc: /* Coding system to use with system messages. |
| 11124 | Also used for decoding keyboard input on X Window system. */); | 11124 | Also used for decoding keyboard input on X Window system, and for |
| 11125 | encoding standard output and error streams. */); | ||
| 11125 | Vlocale_coding_system = Qnil; | 11126 | Vlocale_coding_system = Qnil; |
| 11126 | 11127 | ||
| 11127 | /* The eol mnemonics are reset in startup.el system-dependently. */ | 11128 | /* 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: | |||
| 6245 | 6245 | ||
| 6246 | DEFVAR_LISP ("standard-display-table", Vstandard_display_table, | 6246 | DEFVAR_LISP ("standard-display-table", Vstandard_display_table, |
| 6247 | doc: /* Display table to use for buffers that specify none. | 6247 | doc: /* Display table to use for buffers that specify none. |
| 6248 | It is also used for standard output and error streams. | ||
| 6248 | See `buffer-display-table' for more information. */); | 6249 | See `buffer-display-table' for more information. */); |
| 6249 | Vstandard_display_table = Qnil; | 6250 | Vstandard_display_table = Qnil; |
| 6250 | 6251 | ||
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 <http://www.gnu.org/licenses/>. */ | |||
| 31 | #include "window.h" | 31 | #include "window.h" |
| 32 | #include "process.h" | 32 | #include "process.h" |
| 33 | #include "dispextern.h" | 33 | #include "dispextern.h" |
| 34 | #include "disptab.h" | ||
| 34 | #include "termchar.h" | 35 | #include "termchar.h" |
| 35 | #include "intervals.h" | 36 | #include "intervals.h" |
| 36 | #include "blockinput.h" | 37 | #include "blockinput.h" |
| @@ -195,6 +196,61 @@ print_unwind (Lisp_Object saved_text) | |||
| 195 | memcpy (print_buffer, SDATA (saved_text), SCHARS (saved_text)); | 196 | memcpy (print_buffer, SDATA (saved_text), SCHARS (saved_text)); |
| 196 | } | 197 | } |
| 197 | 198 | ||
| 199 | /* Print character CH to the stdio stream STREAM. */ | ||
| 200 | |||
| 201 | static void | ||
| 202 | printchar_to_stream (unsigned int ch, FILE *stream) | ||
| 203 | { | ||
| 204 | Lisp_Object dv IF_LINT (= Qnil); | ||
| 205 | ptrdiff_t i = 0, n = 1; | ||
| 206 | |||
| 207 | if (CHAR_VALID_P (ch) && DISP_TABLE_P (Vstandard_display_table)) | ||
| 208 | { | ||
| 209 | dv = DISP_CHAR_VECTOR (XCHAR_TABLE (Vstandard_display_table), ch); | ||
| 210 | if (VECTORP (dv)) | ||
| 211 | { | ||
| 212 | n = ASIZE (dv); | ||
| 213 | goto next_char; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | while (true) | ||
| 218 | { | ||
| 219 | if (ASCII_CHAR_P (ch)) | ||
| 220 | { | ||
| 221 | putc (ch, stream); | ||
| 222 | #ifdef WINDOWSNT | ||
| 223 | /* Send the output to a debugger (nothing happens if there | ||
| 224 | isn't one). */ | ||
| 225 | if (print_output_debug_flag && stream == stderr) | ||
| 226 | OutputDebugString ((char []) {ch, '\0'}); | ||
| 227 | #endif | ||
| 228 | } | ||
| 229 | else | ||
| 230 | { | ||
| 231 | unsigned char mbstr[MAX_MULTIBYTE_LENGTH]; | ||
| 232 | int len = CHAR_STRING (ch, mbstr); | ||
| 233 | Lisp_Object encoded_ch = | ||
| 234 | ENCODE_SYSTEM (make_multibyte_string ((char *) mbstr, 1, len)); | ||
| 235 | |||
| 236 | fwrite (SSDATA (encoded_ch), 1, SBYTES (encoded_ch), stream); | ||
| 237 | #ifdef WINDOWSNT | ||
| 238 | if (print_output_debug_flag && stream == stderr) | ||
| 239 | OutputDebugString (SSDATA (encoded_ch)); | ||
| 240 | #endif | ||
| 241 | } | ||
| 242 | |||
| 243 | i++; | ||
| 244 | |||
| 245 | next_char: | ||
| 246 | for (; i < n; i++) | ||
| 247 | if (CHARACTERP (AREF (dv, i))) | ||
| 248 | break; | ||
| 249 | if (! (i < n)) | ||
| 250 | break; | ||
| 251 | ch = XFASTINT (AREF (dv, i)); | ||
| 252 | } | ||
| 253 | } | ||
| 198 | 254 | ||
| 199 | /* Print character CH using method FUN. FUN nil means print to | 255 | /* Print character CH using method FUN. FUN nil means print to |
| 200 | print_buffer. FUN t means print to echo area or stdout if | 256 | print_buffer. FUN t means print to echo area or stdout if |
| @@ -226,7 +282,10 @@ printchar (unsigned int ch, Lisp_Object fun) | |||
| 226 | else if (noninteractive) | 282 | else if (noninteractive) |
| 227 | { | 283 | { |
| 228 | printchar_stdout_last = ch; | 284 | printchar_stdout_last = ch; |
| 229 | fwrite (str, 1, len, stdout); | 285 | if (DISP_TABLE_P (Vstandard_display_table)) |
| 286 | printchar_to_stream (ch, stdout); | ||
| 287 | else | ||
| 288 | fwrite (str, 1, len, stdout); | ||
| 230 | noninteractive_need_newline = 1; | 289 | noninteractive_need_newline = 1; |
| 231 | } | 290 | } |
| 232 | else | 291 | else |
| @@ -267,7 +326,19 @@ strout (const char *ptr, ptrdiff_t size, ptrdiff_t size_byte, | |||
| 267 | } | 326 | } |
| 268 | else if (noninteractive && EQ (printcharfun, Qt)) | 327 | else if (noninteractive && EQ (printcharfun, Qt)) |
| 269 | { | 328 | { |
| 270 | fwrite (ptr, 1, size_byte, stdout); | 329 | if (DISP_TABLE_P (Vstandard_display_table)) |
| 330 | { | ||
| 331 | int len; | ||
| 332 | for (ptrdiff_t i = 0; i < size_byte; i += len) | ||
| 333 | { | ||
| 334 | int ch = STRING_CHAR_AND_LENGTH ((const unsigned char *) ptr + i, | ||
| 335 | len); | ||
| 336 | printchar_to_stream (ch, stdout); | ||
| 337 | } | ||
| 338 | } | ||
| 339 | else | ||
| 340 | fwrite (ptr, 1, size_byte, stdout); | ||
| 341 | |||
| 271 | noninteractive_need_newline = 1; | 342 | noninteractive_need_newline = 1; |
| 272 | } | 343 | } |
| 273 | else if (EQ (printcharfun, Qt)) | 344 | else if (EQ (printcharfun, Qt)) |
| @@ -688,37 +759,8 @@ You can call print while debugging emacs, and pass it this function | |||
| 688 | to make it write to the debugging output. */) | 759 | to make it write to the debugging output. */) |
| 689 | (Lisp_Object character) | 760 | (Lisp_Object character) |
| 690 | { | 761 | { |
| 691 | unsigned int ch; | ||
| 692 | |||
| 693 | CHECK_NUMBER (character); | 762 | CHECK_NUMBER (character); |
| 694 | ch = XINT (character); | 763 | printchar_to_stream (XINT (character), stderr); |
| 695 | if (ASCII_CHAR_P (ch)) | ||
| 696 | { | ||
| 697 | putc (ch, stderr); | ||
| 698 | #ifdef WINDOWSNT | ||
| 699 | /* Send the output to a debugger (nothing happens if there isn't | ||
| 700 | one). */ | ||
| 701 | if (print_output_debug_flag) | ||
| 702 | { | ||
| 703 | char buf[2] = {(char) XINT (character), '\0'}; | ||
| 704 | OutputDebugString (buf); | ||
| 705 | } | ||
| 706 | #endif | ||
| 707 | } | ||
| 708 | else | ||
| 709 | { | ||
| 710 | unsigned char mbstr[MAX_MULTIBYTE_LENGTH]; | ||
| 711 | ptrdiff_t len = CHAR_STRING (ch, mbstr); | ||
| 712 | Lisp_Object encoded_ch = | ||
| 713 | ENCODE_SYSTEM (make_multibyte_string ((char *) mbstr, 1, len)); | ||
| 714 | |||
| 715 | fwrite (SSDATA (encoded_ch), SBYTES (encoded_ch), 1, stderr); | ||
| 716 | #ifdef WINDOWSNT | ||
| 717 | if (print_output_debug_flag) | ||
| 718 | OutputDebugString (SSDATA (encoded_ch)); | ||
| 719 | #endif | ||
| 720 | } | ||
| 721 | |||
| 722 | return character; | 764 | return character; |
| 723 | } | 765 | } |
| 724 | 766 | ||