/* Lisp object printing and output streams.
- Copyright (C) 1985, 86, 88, 93, 94, 95, 97, 98, 1999, 2000, 01, 2003
+ Copyright (C) 1985, 86, 88, 93, 94, 95, 97, 98, 1999, 2000, 01, 03, 2004
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <stdio.h>
#include "lisp.h"
#include "buffer.h"
+#include "character.h"
#include "charset.h"
#include "keyboard.h"
#include "frame.h"
{
int chars;
+ if (print_escape_nonascii)
+ string = string_escape_byte8 (string);
+
if (STRING_MULTIBYTE (string))
chars = SCHARS (string);
- else if (EQ (printcharfun, Qt)
- ? ! NILP (buffer_defaults.enable_multibyte_characters)
- : ! NILP (current_buffer->enable_multibyte_characters))
+ else if (! print_escape_nonascii
+ && (EQ (printcharfun, Qt)
+ ? ! NILP (buffer_defaults.enable_multibyte_characters)
+ : ! NILP (current_buffer->enable_multibyte_characters)))
{
/* If unibyte string STRING contains 8-bit codes, we must
convert STRING to a multibyte string containing the same
int len;
int ch = STRING_CHAR_AND_LENGTH (SDATA (string) + i,
size_byte - i, len);
- if (!CHAR_VALID_P (ch, 0))
- {
- ch = SREF (string, i);
- len = 1;
- }
PRINTCHAR (ch);
i += len;
}
eassert (current_buffer->overlays_after == NULL);
current_buffer->enable_multibyte_characters
= buffer_defaults.enable_multibyte_characters;
+ specbind (Qinhibit_read_only, Qt);
+ specbind (Qinhibit_modification_hooks, Qt);
Ferase_buffer ();
XSETBUFFER (buf, current_buffer);
to get the buffer displayed instead of just displaying the non-selected
buffer and calling the hook. It gets one argument, the buffer to display.
-usage: (with-output-to-temp-buffer BUFFNAME BODY ...) */)
+usage: (with-output-to-temp-buffer BUFNAME BODY ...) */)
(args)
Lisp_Object args;
{
if (SBYTES (object) == SCHARS (object))
STRING_SET_UNIBYTE (object);
- /* Note that this won't make prepare_to_modify_buffer call
+ /* Note that this won't make prepare_to_modify_buffer call
ask-user-about-supersession-threat because this buffer
does not visit a file. */
Ferase_buffer ();
doc: /* Redirect debugging output (stderr stream) to file FILE.
If FILE is nil, reset target to the initial stderr stream.
Optional arg APPEND non-nil (interactively, with prefix arg) means
-append to existing target file. */)
+append to existing target file. */)
(file, append)
Lisp_Object file, append;
{
\f
DEFUN ("error-message-string", Ferror_message_string, Serror_message_string,
1, 1, 0,
- doc: /* Convert an error value (ERROR-SYMBOL . DATA) to an error message. */)
+ doc: /* Convert an error value (ERROR-SYMBOL . DATA) to an error message.
+See Info anchor `(elisp)Definition of signal' for some details on how this
+error message is constructed. */)
(obj)
Lisp_Object obj;
{
register Lisp_Object printcharfun;
int escapeflag;
{
- print_depth = 0;
old_backquote_output = 0;
/* Reset print_number_index and Vprint_number_table only when
start = index = print_number_index;
/* Construct Vprint_number_table.
This increments print_number_index for the objects added. */
+ print_depth = 0;
print_preprocess (obj);
/* Remove unnecessary objects, which appear only once in OBJ;
print_number_index = index;
}
+ print_depth = 0;
print_object (obj, printcharfun, escapeflag);
}
print_preprocess (obj)
Lisp_Object obj;
{
- int i, size;
+ int i;
+ EMACS_INT size;
+ int loop_count = 0;
+ Lisp_Object halftail;
+
+ /* Avoid infinite recursion for circular nested structure
+ in the case where Vprint_circle is nil. */
+ if (NILP (Vprint_circle))
+ {
+ for (i = 0; i < print_depth; i++)
+ if (EQ (obj, being_printed[i]))
+ return;
+ being_printed[print_depth] = obj;
+ }
+
+ /* Give up if we go so deep that print_object will get an error. */
+ /* See similar code in print_object. */
+ if (print_depth >= PRINT_CIRCLE)
+ return;
+
+ print_depth++;
+ halftail = obj;
loop:
if (STRINGP (obj) || CONSP (obj) || VECTORP (obj)
break;
case Lisp_Cons:
+ /* Use HALFTAIL and LOOP_COUNT to detect circular lists,
+ just as in print_object. */
+ if (loop_count && EQ (obj, halftail))
+ break;
print_preprocess (XCAR (obj));
obj = XCDR (obj);
+ loop_count++;
+ if (!(loop_count & 1))
+ halftail = XCDR (halftail);
goto loop;
case Lisp_Vectorlike:
- size = XVECTOR (obj)->size & PSEUDOVECTOR_SIZE_MASK;
+ size = XVECTOR (obj)->size;
+ if (size & PSEUDOVECTOR_FLAG)
+ size &= PSEUDOVECTOR_SIZE_MASK;
for (i = 0; i < size; i++)
print_preprocess (XVECTOR (obj)->contents[i]);
break;
break;
}
}
+ print_depth--;
}
static void
print_preprocess (interval->plist);
}
+/* A flag to control printing of `charset' text property.
+ The default value is Qdefault. */
+Lisp_Object Vprint_charset_text_property;
+extern Lisp_Object Qdefault;
+
+static void print_check_string_charset_prop ();
+
+#define PRINT_STRING_NON_CHARSET_FOUND 1
+#define PRINT_STRING_UNSAFE_CHARSET_FOUND 2
+
+/* Bitwize or of the abobe macros. */
+static int print_check_string_result;
+
+static void
+print_check_string_charset_prop (interval, string)
+ INTERVAL interval;
+ Lisp_Object string;
+{
+ Lisp_Object val;
+
+ if (NILP (interval->plist)
+ || (print_check_string_result == (PRINT_STRING_NON_CHARSET_FOUND
+ | PRINT_STRING_UNSAFE_CHARSET_FOUND)))
+ return;
+ for (val = interval->plist; CONSP (val) && ! EQ (XCAR (val), Qcharset);
+ val = XCDR (XCDR (val)));
+ if (! CONSP (val))
+ {
+ print_check_string_result |= PRINT_STRING_NON_CHARSET_FOUND;
+ return;
+ }
+ if (! (print_check_string_result & PRINT_STRING_NON_CHARSET_FOUND))
+ {
+ if (! EQ (val, interval->plist)
+ || CONSP (XCDR (XCDR (val))))
+ print_check_string_result |= PRINT_STRING_NON_CHARSET_FOUND;
+ }
+ if (NILP (Vprint_charset_text_property)
+ || ! (print_check_string_result & PRINT_STRING_UNSAFE_CHARSET_FOUND))
+ {
+ int i, c;
+ int charpos = interval->position;
+ int bytepos = string_char_to_byte (string, charpos);
+ Lisp_Object charset;
+
+ charset = XCAR (XCDR (val));
+ for (i = 0; i < LENGTH (interval); i++)
+ {
+ FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos);
+ if (! ASCII_CHAR_P (c)
+ && ! EQ (CHARSET_NAME (CHAR_CHARSET (c)), charset))
+ {
+ print_check_string_result |= PRINT_STRING_UNSAFE_CHARSET_FOUND;
+ break;
+ }
+ }
+ }
+}
+
+/* The value is (charset . nil). */
+static Lisp_Object print_prune_charset_plist;
+
+static Lisp_Object
+print_prune_string_charset (string)
+ Lisp_Object string;
+{
+ print_check_string_result = 0;
+ traverse_intervals (STRING_INTERVALS (string), 0,
+ print_check_string_charset_prop, string);
+ if (! (print_check_string_result & PRINT_STRING_UNSAFE_CHARSET_FOUND))
+ {
+ string = Fcopy_sequence (string);
+ if (print_check_string_result & PRINT_STRING_NON_CHARSET_FOUND)
+ {
+ if (NILP (print_prune_charset_plist))
+ print_prune_charset_plist = Fcons (Qcharset, Qnil);
+ Fremove_text_properties (make_number (0),
+ make_number (SCHARS (string)),
+ print_prune_charset_plist, string);
+ }
+ else
+ Fset_text_properties (make_number (0), make_number (SCHARS (string)),
+ Qnil, string);
+ }
+ return string;
+}
+
static void
print_object (obj, printcharfun, escapeflag)
Lisp_Object obj;
register Lisp_Object printcharfun;
int escapeflag;
{
- char buf[30];
+ char buf[40];
QUIT;
print_depth++;
+ /* See similar code in print_preprocess. */
if (print_depth > PRINT_CIRCLE)
error ("Apparently circular structure being printed");
#ifdef MAX_PRINT_CHARS
GCPRO1 (obj);
+ if (! EQ (Vprint_charset_text_property, Qt))
+ obj = print_prune_string_charset (obj);
+
if (!NULL_INTERVAL_P (STRING_INTERVALS (obj)))
{
PRINTCHAR ('#');
{
c = STRING_CHAR_AND_LENGTH (str + i_byte,
size_byte - i_byte, len);
- if (CHAR_VALID_P (c, 0))
- i_byte += len;
- else
- c = str[i_byte++];
+ i_byte += len;
}
else
c = str[i_byte++];
PRINTCHAR ('f');
}
else if (multibyte
- && ! ASCII_BYTE_P (c)
- && (SINGLE_BYTE_CHAR_P (c) || print_escape_multibyte))
+ && (CHAR_BYTE8_P (c)
+ || (! ASCII_CHAR_P (c) && print_escape_multibyte)))
{
/* When multibyte is disabled,
print multibyte string chars using hex escapes.
when found in a multibyte string, always use a hex escape
so it reads back as multibyte. */
unsigned char outbuf[50];
- sprintf (outbuf, "\\x%x", c);
+
+ if (CHAR_BYTE8_P (c))
+ sprintf (outbuf, "\\%03o", CHAR_TO_BYTE8 (c));
+ else
+ {
+ sprintf (outbuf, "\\x%04x", c);
+ need_nonhex = 1;
+ }
strout (outbuf, -1, -1, printcharfun, 0);
- need_nonhex = 1;
}
else if (! multibyte
&& SINGLE_BYTE_CHAR_P (c) && ! ASCII_BYTE_P (c)
register unsigned char c;
struct gcpro gcpro1;
int size_in_chars
- = (XBOOL_VECTOR (obj)->size + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
+ = ((XBOOL_VECTOR (obj)->size + BOOL_VECTOR_BITS_PER_CHAR - 1)
+ / BOOL_VECTOR_BITS_PER_CHAR);
GCPRO1 (obj);
PRINTCHAR ('#');
PRINTCHAR ('&');
- sprintf (buf, "%d", XBOOL_VECTOR (obj)->size);
+ sprintf (buf, "%ld", (long) XBOOL_VECTOR (obj)->size);
strout (buf, -1, -1, printcharfun, 0);
PRINTCHAR ('\"');
{
QUIT;
c = XBOOL_VECTOR (obj)->data[i];
- if (c == '\n' && print_escape_newlines)
+ if (! ASCII_BYTE_P (c))
+ {
+ sprintf (buf, "\\%03o", c);
+ strout (buf, -1, -1, printcharfun, 0);
+ }
+ else if (c == '\n' && print_escape_newlines)
{
PRINTCHAR ('\\');
PRINTCHAR ('n');
PRINTCHAR ('\\');
PRINTCHAR ('f');
}
+ else if (c > '\177')
+ {
+ /* Use octal escapes to avoid encoding issues. */
+ PRINTCHAR ('\\');
+ PRINTCHAR ('0' + ((c >> 6) & 3));
+ PRINTCHAR ('0' + ((c >> 3) & 7));
+ PRINTCHAR ('0' + (c & 7));
+ }
else
{
if (c == '\"' || c == '\\')
else if (WINDOWP (obj))
{
strout ("#<window ", -1, -1, printcharfun, 0);
- sprintf (buf, "%d", XFASTINT (XWINDOW (obj)->sequence_number));
+ sprintf (buf, "%ld", (long) XFASTINT (XWINDOW (obj)->sequence_number));
strout (buf, -1, -1, printcharfun, 0);
if (!NILP (XWINDOW (obj)->buffer))
{
PRINTCHAR (' ');
strout (SDATA (SYMBOL_NAME (h->weak)), -1, -1, printcharfun, 0);
PRINTCHAR (' ');
- sprintf (buf, "%d/%d", XFASTINT (h->count),
- XVECTOR (h->next)->size);
+ sprintf (buf, "%ld/%ld", (long) XFASTINT (h->count),
+ (long) XVECTOR (h->next)->size);
strout (buf, -1, -1, printcharfun, 0);
}
sprintf (buf, " 0x%lx", (unsigned long) h);
}
else
{
- int size = XVECTOR (obj)->size;
+ EMACS_INT size = XVECTOR (obj)->size;
if (COMPILEDP (obj))
{
PRINTCHAR ('#');
size &= PSEUDOVECTOR_SIZE_MASK;
}
- if (CHAR_TABLE_P (obj))
+ if (CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj))
{
/* We print a char-table as if it were a vector,
lumping the parent and default slots in with the
break;
case Lisp_Misc_Intfwd:
- sprintf (buf, "#<intfwd to %d>", *XINTFWD (obj)->intvar);
+ sprintf (buf, "#<intfwd to %ld>", (long) *XINTFWD (obj)->intvar);
strout (buf, -1, -1, printcharfun, 0);
break;
INTERVAL interval;
Lisp_Object printcharfun;
{
+ if (NILP (interval->plist))
+ return;
PRINTCHAR (' ');
print_object (make_number (interval->position), printcharfun, 1);
PRINTCHAR (' ');
that need to be recorded in the table. */);
Vprint_number_table = Qnil;
+ DEFVAR_LISP ("print-charset-text-property", &Vprint_charset_text_property,
+ doc: /* A flag to control printing of `charset' text property on printing a string.
+The value must be nil, t, or `default'.
+
+If the value is nil, don't print the text property `charset'.
+
+If the value is t, always print the text property `charset'.
+
+If the value is `default', print the text property `charset' only when
+the value is different from what is guessed in the current charset
+priorities. */);
+ Vprint_charset_text_property = Qdefault;
+
/* prin1_to_string_buffer initialized in init_buffer_once in buffer.c */
staticpro (&Vprin1_to_string_buffer);
Qprint_escape_nonascii = intern ("print-escape-nonascii");
staticpro (&Qprint_escape_nonascii);
+ print_prune_charset_plist = Qnil;
+ staticpro (&print_prune_charset_plist);
+
defsubr (&Swith_output_to_temp_buffer);
}