aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2015-05-31 20:04:05 -0700
committerPaul Eggert2015-05-31 20:04:43 -0700
commit467af178f53798e4cd102e04eb2990121eb655df (patch)
tree1e6e2cec1eb87963ae796289ef9a1afdd060a668 /src
parent21d13bce38c2160bf21b3428cd8e56daadcf4698 (diff)
downloademacs-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.c3
-rw-r--r--src/dispnew.c1
-rw-r--r--src/print.c106
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.
11124Also used for decoding keyboard input on X Window system. */); 11124Also used for decoding keyboard input on X Window system, and for
11125encoding 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.
6248It is also used for standard output and error streams.
6248See `buffer-display-table' for more information. */); 6249See `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
201static void
202printchar_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
688to make it write to the debugging output. */) 759to 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