aboutsummaryrefslogtreecommitdiffstats
path: root/src/print.c
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/print.c
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/print.c')
-rw-r--r--src/print.c106
1 files changed, 74 insertions, 32 deletions
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