mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-26 23:31:55 -08:00
strings with intervals. [USE_TEXT_PROPERTIES] (print): Don't print a space before the interval property lists. [USE_TEXT_PROPERTIES] (print_interval): Print a space before this internal's properties, not after.
1071 lines
26 KiB
C
1071 lines
26 KiB
C
/* Lisp object printing and output streams.
|
||
Copyright (C) 1985, 1986, 1988, 1993 Free Software Foundation, Inc.
|
||
|
||
This file is part of GNU Emacs.
|
||
|
||
GNU Emacs is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2, or (at your option)
|
||
any later version.
|
||
|
||
GNU Emacs is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with GNU Emacs; see the file COPYING. If not, write to
|
||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||
|
||
|
||
#include "config.h"
|
||
#include <stdio.h>
|
||
#undef NULL
|
||
#include "lisp.h"
|
||
|
||
#ifndef standalone
|
||
#include "buffer.h"
|
||
#include "frame.h"
|
||
#include "window.h"
|
||
#include "process.h"
|
||
#include "dispextern.h"
|
||
#include "termchar.h"
|
||
#endif /* not standalone */
|
||
|
||
#ifdef USE_TEXT_PROPERTIES
|
||
#include "intervals.h"
|
||
#endif
|
||
|
||
Lisp_Object Vstandard_output, Qstandard_output;
|
||
|
||
#ifdef LISP_FLOAT_TYPE
|
||
Lisp_Object Vfloat_output_format, Qfloat_output_format;
|
||
#endif /* LISP_FLOAT_TYPE */
|
||
|
||
/* Avoid actual stack overflow in print. */
|
||
int print_depth;
|
||
|
||
/* Detect most circularities to print finite output. */
|
||
#define PRINT_CIRCLE 200
|
||
Lisp_Object being_printed[PRINT_CIRCLE];
|
||
|
||
/* Maximum length of list to print in full; noninteger means
|
||
effectively infinity */
|
||
|
||
Lisp_Object Vprint_length;
|
||
|
||
/* Maximum depth of list to print in full; noninteger means
|
||
effectively infinity. */
|
||
|
||
Lisp_Object Vprint_level;
|
||
|
||
/* Nonzero means print newlines in strings as \n. */
|
||
|
||
int print_escape_newlines;
|
||
|
||
Lisp_Object Qprint_escape_newlines;
|
||
|
||
/* Nonzero means print newline before next minibuffer message.
|
||
Defined in xdisp.c */
|
||
|
||
extern int noninteractive_need_newline;
|
||
#ifdef MAX_PRINT_CHARS
|
||
static int print_chars;
|
||
static int max_print;
|
||
#endif /* MAX_PRINT_CHARS */
|
||
|
||
void print_interval ();
|
||
|
||
#if 0
|
||
/* Convert between chars and GLYPHs */
|
||
|
||
int
|
||
glyphlen (glyphs)
|
||
register GLYPH *glyphs;
|
||
{
|
||
register int i = 0;
|
||
|
||
while (glyphs[i])
|
||
i++;
|
||
return i;
|
||
}
|
||
|
||
void
|
||
str_to_glyph_cpy (str, glyphs)
|
||
char *str;
|
||
GLYPH *glyphs;
|
||
{
|
||
register GLYPH *gp = glyphs;
|
||
register char *cp = str;
|
||
|
||
while (*cp)
|
||
*gp++ = *cp++;
|
||
}
|
||
|
||
void
|
||
str_to_glyph_ncpy (str, glyphs, n)
|
||
char *str;
|
||
GLYPH *glyphs;
|
||
register int n;
|
||
{
|
||
register GLYPH *gp = glyphs;
|
||
register char *cp = str;
|
||
|
||
while (n-- > 0)
|
||
*gp++ = *cp++;
|
||
}
|
||
|
||
void
|
||
glyph_to_str_cpy (glyphs, str)
|
||
GLYPH *glyphs;
|
||
char *str;
|
||
{
|
||
register GLYPH *gp = glyphs;
|
||
register char *cp = str;
|
||
|
||
while (*gp)
|
||
*str++ = *gp++ & 0377;
|
||
}
|
||
#endif
|
||
|
||
/* Low level output routines for characters and strings */
|
||
|
||
/* Lisp functions to do output using a stream
|
||
must have the stream in a variable called printcharfun
|
||
and must start with PRINTPREPARE and end with PRINTFINISH.
|
||
Use PRINTCHAR to output one character,
|
||
or call strout to output a block of characters.
|
||
Also, each one must have the declarations
|
||
struct buffer *old = current_buffer;
|
||
int old_point = -1, start_point;
|
||
Lisp_Object original;
|
||
*/
|
||
|
||
#define PRINTPREPARE \
|
||
original = printcharfun; \
|
||
if (NILP (printcharfun)) printcharfun = Qt; \
|
||
if (XTYPE (printcharfun) == Lisp_Buffer) \
|
||
{ if (XBUFFER (printcharfun) != current_buffer) \
|
||
Fset_buffer (printcharfun); \
|
||
printcharfun = Qnil;} \
|
||
if (XTYPE (printcharfun) == Lisp_Marker) \
|
||
{ if (!(XMARKER (original)->buffer)) \
|
||
error ("Marker does not point anywhere"); \
|
||
if (XMARKER (original)->buffer != current_buffer) \
|
||
set_buffer_internal (XMARKER (original)->buffer); \
|
||
old_point = point; \
|
||
SET_PT (marker_position (printcharfun)); \
|
||
start_point = point; \
|
||
printcharfun = Qnil;}
|
||
|
||
#define PRINTFINISH \
|
||
if (XTYPE (original) == Lisp_Marker) \
|
||
Fset_marker (original, make_number (point), Qnil); \
|
||
if (old_point >= 0) \
|
||
SET_PT (old_point + (old_point >= start_point \
|
||
? point - start_point : 0)); \
|
||
if (old != current_buffer) \
|
||
set_buffer_internal (old)
|
||
|
||
#define PRINTCHAR(ch) printchar (ch, printcharfun)
|
||
|
||
/* Index of first unused element of FRAME_MESSAGE_BUF(selected_frame). */
|
||
static int printbufidx;
|
||
|
||
static void
|
||
printchar (ch, fun)
|
||
unsigned char ch;
|
||
Lisp_Object fun;
|
||
{
|
||
Lisp_Object ch1;
|
||
|
||
#ifdef MAX_PRINT_CHARS
|
||
if (max_print)
|
||
print_chars++;
|
||
#endif /* MAX_PRINT_CHARS */
|
||
#ifndef standalone
|
||
if (EQ (fun, Qnil))
|
||
{
|
||
QUIT;
|
||
insert (&ch, 1);
|
||
return;
|
||
}
|
||
|
||
if (EQ (fun, Qt))
|
||
{
|
||
if (noninteractive)
|
||
{
|
||
putchar (ch);
|
||
noninteractive_need_newline = 1;
|
||
return;
|
||
}
|
||
|
||
if (echo_area_glyphs != FRAME_MESSAGE_BUF (selected_frame)
|
||
|| !message_buf_print)
|
||
{
|
||
echo_area_glyphs = FRAME_MESSAGE_BUF (selected_frame);
|
||
printbufidx = 0;
|
||
message_buf_print = 1;
|
||
}
|
||
|
||
if (printbufidx < FRAME_WIDTH (selected_frame) - 1)
|
||
FRAME_MESSAGE_BUF (selected_frame)[printbufidx++] = ch;
|
||
FRAME_MESSAGE_BUF (selected_frame)[printbufidx] = 0;
|
||
|
||
return;
|
||
}
|
||
#endif /* not standalone */
|
||
|
||
XFASTINT (ch1) = ch;
|
||
call1 (fun, ch1);
|
||
}
|
||
|
||
static void
|
||
strout (ptr, size, printcharfun)
|
||
char *ptr;
|
||
int size;
|
||
Lisp_Object printcharfun;
|
||
{
|
||
int i = 0;
|
||
|
||
if (EQ (printcharfun, Qnil))
|
||
{
|
||
insert (ptr, size >= 0 ? size : strlen (ptr));
|
||
#ifdef MAX_PRINT_CHARS
|
||
if (max_print)
|
||
print_chars += size >= 0 ? size : strlen(ptr);
|
||
#endif /* MAX_PRINT_CHARS */
|
||
return;
|
||
}
|
||
if (EQ (printcharfun, Qt))
|
||
{
|
||
i = size >= 0 ? size : strlen (ptr);
|
||
#ifdef MAX_PRINT_CHARS
|
||
if (max_print)
|
||
print_chars += i;
|
||
#endif /* MAX_PRINT_CHARS */
|
||
|
||
if (noninteractive)
|
||
{
|
||
fwrite (ptr, 1, i, stdout);
|
||
noninteractive_need_newline = 1;
|
||
return;
|
||
}
|
||
|
||
if (echo_area_glyphs != FRAME_MESSAGE_BUF (selected_frame)
|
||
|| !message_buf_print)
|
||
{
|
||
echo_area_glyphs = FRAME_MESSAGE_BUF (selected_frame);
|
||
printbufidx = 0;
|
||
message_buf_print = 1;
|
||
}
|
||
|
||
if (i > FRAME_WIDTH (selected_frame) - printbufidx - 1)
|
||
i = FRAME_WIDTH (selected_frame) - printbufidx - 1;
|
||
bcopy (ptr, &FRAME_MESSAGE_BUF (selected_frame) [printbufidx], i);
|
||
printbufidx += i;
|
||
FRAME_MESSAGE_BUF (selected_frame) [printbufidx] = 0;
|
||
|
||
return;
|
||
}
|
||
|
||
if (size >= 0)
|
||
while (i < size)
|
||
PRINTCHAR (ptr[i++]);
|
||
else
|
||
while (ptr[i])
|
||
PRINTCHAR (ptr[i++]);
|
||
}
|
||
|
||
/* Print the contents of a string STRING using PRINTCHARFUN.
|
||
It isn't safe to use strout, because printing one char can relocate. */
|
||
|
||
print_string (string, printcharfun)
|
||
Lisp_Object string;
|
||
Lisp_Object printcharfun;
|
||
{
|
||
if (EQ (printcharfun, Qnil) || EQ (printcharfun, Qt))
|
||
/* In predictable cases, strout is safe: output to buffer or frame. */
|
||
strout (XSTRING (string)->data, XSTRING (string)->size, printcharfun);
|
||
else
|
||
{
|
||
/* Otherwise, fetch the string address for each character. */
|
||
int i;
|
||
int size = XSTRING (string)->size;
|
||
struct gcpro gcpro1;
|
||
GCPRO1 (string);
|
||
for (i = 0; i < size; i++)
|
||
PRINTCHAR (XSTRING (string)->data[i]);
|
||
UNGCPRO;
|
||
}
|
||
}
|
||
|
||
DEFUN ("write-char", Fwrite_char, Swrite_char, 1, 2, 0,
|
||
"Output character CHAR to stream STREAM.\n\
|
||
STREAM defaults to the value of `standard-output' (which see).")
|
||
(ch, printcharfun)
|
||
Lisp_Object ch, printcharfun;
|
||
{
|
||
struct buffer *old = current_buffer;
|
||
int old_point = -1;
|
||
int start_point;
|
||
Lisp_Object original;
|
||
|
||
if (NILP (printcharfun))
|
||
printcharfun = Vstandard_output;
|
||
CHECK_NUMBER (ch, 0);
|
||
PRINTPREPARE;
|
||
PRINTCHAR (XINT (ch));
|
||
PRINTFINISH;
|
||
return ch;
|
||
}
|
||
|
||
/* Used from outside of print.c to print a block of SIZE chars at DATA
|
||
on the default output stream.
|
||
Do not use this on the contents of a Lisp string. */
|
||
|
||
write_string (data, size)
|
||
char *data;
|
||
int size;
|
||
{
|
||
struct buffer *old = current_buffer;
|
||
Lisp_Object printcharfun;
|
||
int old_point = -1;
|
||
int start_point;
|
||
Lisp_Object original;
|
||
|
||
printcharfun = Vstandard_output;
|
||
|
||
PRINTPREPARE;
|
||
strout (data, size, printcharfun);
|
||
PRINTFINISH;
|
||
}
|
||
|
||
/* Used from outside of print.c to print a block of SIZE chars at DATA
|
||
on a specified stream PRINTCHARFUN.
|
||
Do not use this on the contents of a Lisp string. */
|
||
|
||
write_string_1 (data, size, printcharfun)
|
||
char *data;
|
||
int size;
|
||
Lisp_Object printcharfun;
|
||
{
|
||
struct buffer *old = current_buffer;
|
||
int old_point = -1;
|
||
int start_point;
|
||
Lisp_Object original;
|
||
|
||
PRINTPREPARE;
|
||
strout (data, size, printcharfun);
|
||
PRINTFINISH;
|
||
}
|
||
|
||
|
||
#ifndef standalone
|
||
|
||
void
|
||
temp_output_buffer_setup (bufname)
|
||
char *bufname;
|
||
{
|
||
register struct buffer *old = current_buffer;
|
||
register Lisp_Object buf;
|
||
|
||
Fset_buffer (Fget_buffer_create (build_string (bufname)));
|
||
|
||
current_buffer->read_only = Qnil;
|
||
Ferase_buffer ();
|
||
|
||
XSET (buf, Lisp_Buffer, current_buffer);
|
||
specbind (Qstandard_output, buf);
|
||
|
||
set_buffer_internal (old);
|
||
}
|
||
|
||
Lisp_Object
|
||
internal_with_output_to_temp_buffer (bufname, function, args)
|
||
char *bufname;
|
||
Lisp_Object (*function) ();
|
||
Lisp_Object args;
|
||
{
|
||
int count = specpdl_ptr - specpdl;
|
||
Lisp_Object buf, val;
|
||
|
||
record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
|
||
temp_output_buffer_setup (bufname);
|
||
buf = Vstandard_output;
|
||
|
||
val = (*function) (args);
|
||
|
||
temp_output_buffer_show (buf);
|
||
|
||
return unbind_to (count, val);
|
||
}
|
||
|
||
DEFUN ("with-output-to-temp-buffer", Fwith_output_to_temp_buffer, Swith_output_to_temp_buffer,
|
||
1, UNEVALLED, 0,
|
||
"Bind `standard-output' to buffer BUFNAME, eval BODY, then show that buffer.\n\
|
||
The buffer is cleared out initially, and marked as unmodified when done.\n\
|
||
All output done by BODY is inserted in that buffer by default.\n\
|
||
The buffer is displayed in another window, but not selected.\n\
|
||
The value of the last form in BODY is returned.\n\
|
||
If BODY does not finish normally, the buffer BUFNAME is not displayed.\n\n\
|
||
If variable `temp-buffer-show-function' is non-nil, call it at the end\n\
|
||
to get the buffer displayed. It gets one argument, the buffer to display.")
|
||
(args)
|
||
Lisp_Object args;
|
||
{
|
||
struct gcpro gcpro1;
|
||
Lisp_Object name;
|
||
int count = specpdl_ptr - specpdl;
|
||
Lisp_Object buf, val;
|
||
|
||
GCPRO1(args);
|
||
name = Feval (Fcar (args));
|
||
UNGCPRO;
|
||
|
||
CHECK_STRING (name, 0);
|
||
temp_output_buffer_setup (XSTRING (name)->data);
|
||
buf = Vstandard_output;
|
||
|
||
val = Fprogn (Fcdr (args));
|
||
|
||
temp_output_buffer_show (buf);
|
||
|
||
return unbind_to (count, val);
|
||
}
|
||
#endif /* not standalone */
|
||
|
||
static void print ();
|
||
|
||
DEFUN ("terpri", Fterpri, Sterpri, 0, 1, 0,
|
||
"Output a newline to STREAM.\n\
|
||
If STREAM is omitted or nil, the value of `standard-output' is used.")
|
||
(printcharfun)
|
||
Lisp_Object printcharfun;
|
||
{
|
||
struct buffer *old = current_buffer;
|
||
int old_point = -1;
|
||
int start_point;
|
||
Lisp_Object original;
|
||
|
||
if (NILP (printcharfun))
|
||
printcharfun = Vstandard_output;
|
||
PRINTPREPARE;
|
||
PRINTCHAR ('\n');
|
||
PRINTFINISH;
|
||
return Qt;
|
||
}
|
||
|
||
DEFUN ("prin1", Fprin1, Sprin1, 1, 2, 0,
|
||
"Output the printed representation of OBJECT, any Lisp object.\n\
|
||
Quoting characters are printed when needed to make output that `read'\n\
|
||
can handle, whenever this is possible.\n\
|
||
Output stream is STREAM, or value of `standard-output' (which see).")
|
||
(obj, printcharfun)
|
||
Lisp_Object obj, printcharfun;
|
||
{
|
||
struct buffer *old = current_buffer;
|
||
int old_point = -1;
|
||
int start_point;
|
||
Lisp_Object original;
|
||
|
||
#ifdef MAX_PRINT_CHARS
|
||
max_print = 0;
|
||
#endif /* MAX_PRINT_CHARS */
|
||
if (NILP (printcharfun))
|
||
printcharfun = Vstandard_output;
|
||
PRINTPREPARE;
|
||
print_depth = 0;
|
||
print (obj, printcharfun, 1);
|
||
PRINTFINISH;
|
||
return obj;
|
||
}
|
||
|
||
/* a buffer which is used to hold output being built by prin1-to-string */
|
||
Lisp_Object Vprin1_to_string_buffer;
|
||
|
||
DEFUN ("prin1-to-string", Fprin1_to_string, Sprin1_to_string, 1, 2, 0,
|
||
"Return a string containing the printed representation of OBJECT,\n\
|
||
any Lisp object. Quoting characters are used when needed to make output\n\
|
||
that `read' can handle, whenever this is possible, unless the optional\n\
|
||
second argument NOESCAPE is non-nil.")
|
||
(obj, noescape)
|
||
Lisp_Object obj, noescape;
|
||
{
|
||
struct buffer *old = current_buffer;
|
||
int old_point = -1;
|
||
int start_point;
|
||
Lisp_Object original, printcharfun;
|
||
struct gcpro gcpro1;
|
||
|
||
printcharfun = Vprin1_to_string_buffer;
|
||
PRINTPREPARE;
|
||
print_depth = 0;
|
||
print (obj, printcharfun, NILP (noescape));
|
||
/* Make Vprin1_to_string_buffer be the default buffer after PRINTFINSH */
|
||
PRINTFINISH;
|
||
set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
|
||
obj = Fbuffer_string ();
|
||
|
||
GCPRO1 (obj);
|
||
Ferase_buffer ();
|
||
set_buffer_internal (old);
|
||
UNGCPRO;
|
||
|
||
return obj;
|
||
}
|
||
|
||
DEFUN ("princ", Fprinc, Sprinc, 1, 2, 0,
|
||
"Output the printed representation of OBJECT, any Lisp object.\n\
|
||
No quoting characters are used; no delimiters are printed around\n\
|
||
the contents of strings.\n\
|
||
Output stream is STREAM, or value of standard-output (which see).")
|
||
(obj, printcharfun)
|
||
Lisp_Object obj, printcharfun;
|
||
{
|
||
struct buffer *old = current_buffer;
|
||
int old_point = -1;
|
||
int start_point;
|
||
Lisp_Object original;
|
||
|
||
if (NILP (printcharfun))
|
||
printcharfun = Vstandard_output;
|
||
PRINTPREPARE;
|
||
print_depth = 0;
|
||
print (obj, printcharfun, 0);
|
||
PRINTFINISH;
|
||
return obj;
|
||
}
|
||
|
||
DEFUN ("print", Fprint, Sprint, 1, 2, 0,
|
||
"Output the printed representation of OBJECT, with newlines around it.\n\
|
||
Quoting characters are printed when needed to make output that `read'\n\
|
||
can handle, whenever this is possible.\n\
|
||
Output stream is STREAM, or value of `standard-output' (which see).")
|
||
(obj, printcharfun)
|
||
Lisp_Object obj, printcharfun;
|
||
{
|
||
struct buffer *old = current_buffer;
|
||
int old_point = -1;
|
||
int start_point;
|
||
Lisp_Object original;
|
||
struct gcpro gcpro1;
|
||
|
||
#ifdef MAX_PRINT_CHARS
|
||
print_chars = 0;
|
||
max_print = MAX_PRINT_CHARS;
|
||
#endif /* MAX_PRINT_CHARS */
|
||
if (NILP (printcharfun))
|
||
printcharfun = Vstandard_output;
|
||
GCPRO1 (obj);
|
||
PRINTPREPARE;
|
||
print_depth = 0;
|
||
PRINTCHAR ('\n');
|
||
print (obj, printcharfun, 1);
|
||
PRINTCHAR ('\n');
|
||
PRINTFINISH;
|
||
#ifdef MAX_PRINT_CHARS
|
||
max_print = 0;
|
||
print_chars = 0;
|
||
#endif /* MAX_PRINT_CHARS */
|
||
UNGCPRO;
|
||
return obj;
|
||
}
|
||
|
||
/* The subroutine object for external-debugging-output is kept here
|
||
for the convenience of the debugger. */
|
||
Lisp_Object Qexternal_debugging_output;
|
||
|
||
DEFUN ("external-debugging-output", Fexternal_debugging_output, Sexternal_debugging_output, 1, 1, 0,
|
||
"Write CHARACTER to stderr.\n\
|
||
You can call print while debugging emacs, and pass it this function\n\
|
||
to make it write to the debugging output.\n")
|
||
(character)
|
||
Lisp_Object character;
|
||
{
|
||
CHECK_NUMBER (character, 0);
|
||
putc (XINT (character), stderr);
|
||
|
||
return character;
|
||
}
|
||
|
||
#ifdef LISP_FLOAT_TYPE
|
||
|
||
/*
|
||
* The buffer should be at least as large as the max string size of the
|
||
* largest float, printed in the biggest notation. This is undoubtably
|
||
* 20d float_output_format, with the negative of the C-constant "HUGE"
|
||
* from <math.h>.
|
||
*
|
||
* On the vax the worst case is -1e38 in 20d format which takes 61 bytes.
|
||
*
|
||
* I assume that IEEE-754 format numbers can take 329 bytes for the worst
|
||
* case of -1e307 in 20d float_output_format. What is one to do (short of
|
||
* re-writing _doprnt to be more sane)?
|
||
* -wsr
|
||
*/
|
||
|
||
void
|
||
float_to_string (buf, data)
|
||
unsigned char *buf;
|
||
double data;
|
||
{
|
||
register unsigned char *cp, c;
|
||
register int width;
|
||
|
||
if (NILP (Vfloat_output_format)
|
||
|| XTYPE (Vfloat_output_format) != Lisp_String)
|
||
lose:
|
||
sprintf (buf, "%.20g", data);
|
||
else /* oink oink */
|
||
{
|
||
/* Check that the spec we have is fully valid.
|
||
This means not only valid for printf,
|
||
but meant for floats, and reasonable. */
|
||
cp = XSTRING (Vfloat_output_format)->data;
|
||
|
||
if (cp[0] != '%')
|
||
goto lose;
|
||
if (cp[1] != '.')
|
||
goto lose;
|
||
|
||
cp += 2;
|
||
for (width = 0;
|
||
((c = *cp) >= '0' && c <= '9');
|
||
cp++)
|
||
{
|
||
width *= 10;
|
||
width += c - '0';
|
||
}
|
||
|
||
if (*cp != 'e' && *cp != 'f' && *cp != 'g')
|
||
goto lose;
|
||
|
||
if (width < (*cp != 'e') || width > DBL_DIG)
|
||
goto lose;
|
||
|
||
if (cp[1] != 0)
|
||
goto lose;
|
||
|
||
sprintf (buf, XSTRING (Vfloat_output_format)->data, data);
|
||
}
|
||
|
||
/* Make sure there is a decimal point with digit after, or an exponent,
|
||
so that the value is readable as a float. */
|
||
for (cp = buf; *cp; cp++)
|
||
if ((*cp < '0' || *cp > '9') && *cp != '-')
|
||
break;
|
||
|
||
if (*cp == '.' && cp[1] == 0)
|
||
{
|
||
cp[1] = '0';
|
||
cp[2] = 0;
|
||
}
|
||
|
||
if (*cp == 0)
|
||
{
|
||
*cp++ = '.';
|
||
*cp++ = '0';
|
||
*cp++ = 0;
|
||
}
|
||
}
|
||
#endif /* LISP_FLOAT_TYPE */
|
||
|
||
static void
|
||
print (obj, printcharfun, escapeflag)
|
||
Lisp_Object obj;
|
||
register Lisp_Object printcharfun;
|
||
int escapeflag;
|
||
{
|
||
char buf[30];
|
||
|
||
QUIT;
|
||
|
||
#if 1 /* I'm not sure this is really worth doing. */
|
||
/* Detect circularities and truncate them.
|
||
No need to offer any alternative--this is better than an error. */
|
||
if (XTYPE (obj) == Lisp_Cons || XTYPE (obj) == Lisp_Vector
|
||
|| XTYPE (obj) == Lisp_Compiled)
|
||
{
|
||
int i;
|
||
for (i = 0; i < print_depth; i++)
|
||
if (EQ (obj, being_printed[i]))
|
||
{
|
||
sprintf (buf, "#%d", i);
|
||
strout (buf, -1, printcharfun);
|
||
return;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
being_printed[print_depth] = obj;
|
||
print_depth++;
|
||
|
||
if (print_depth > PRINT_CIRCLE)
|
||
error ("Apparently circular structure being printed");
|
||
#ifdef MAX_PRINT_CHARS
|
||
if (max_print && print_chars > max_print)
|
||
{
|
||
PRINTCHAR ('\n');
|
||
print_chars = 0;
|
||
}
|
||
#endif /* MAX_PRINT_CHARS */
|
||
|
||
#ifdef SWITCH_ENUM_BUG
|
||
switch ((int) XTYPE (obj))
|
||
#else
|
||
switch (XTYPE (obj))
|
||
#endif
|
||
{
|
||
default:
|
||
/* We're in trouble if this happens!
|
||
Probably should just abort () */
|
||
strout ("#<EMACS BUG: INVALID DATATYPE ", -1, printcharfun);
|
||
sprintf (buf, "(#o%3o)", (int) XTYPE (obj));
|
||
strout (buf, -1, printcharfun);
|
||
strout (" Save your buffers immediately and please report this bug>",
|
||
-1, printcharfun);
|
||
break;
|
||
|
||
#ifdef LISP_FLOAT_TYPE
|
||
case Lisp_Float:
|
||
{
|
||
char pigbuf[350]; /* see comments in float_to_string */
|
||
|
||
float_to_string (pigbuf, XFLOAT(obj)->data);
|
||
strout (pigbuf, -1, printcharfun);
|
||
}
|
||
break;
|
||
#endif /* LISP_FLOAT_TYPE */
|
||
|
||
case Lisp_Int:
|
||
sprintf (buf, "%d", XINT (obj));
|
||
strout (buf, -1, printcharfun);
|
||
break;
|
||
|
||
case Lisp_String:
|
||
if (!escapeflag)
|
||
print_string (obj, printcharfun);
|
||
else
|
||
{
|
||
register int i;
|
||
register unsigned char c;
|
||
struct gcpro gcpro1;
|
||
|
||
GCPRO1 (obj);
|
||
|
||
#ifdef USE_TEXT_PROPERTIES
|
||
if (!NULL_INTERVAL_P (XSTRING (obj)->intervals))
|
||
{
|
||
PRINTCHAR ('#');
|
||
PRINTCHAR ('(');
|
||
}
|
||
#endif
|
||
|
||
PRINTCHAR ('\"');
|
||
for (i = 0; i < XSTRING (obj)->size; i++)
|
||
{
|
||
QUIT;
|
||
c = XSTRING (obj)->data[i];
|
||
if (c == '\n' && print_escape_newlines)
|
||
{
|
||
PRINTCHAR ('\\');
|
||
PRINTCHAR ('n');
|
||
}
|
||
else
|
||
{
|
||
if (c == '\"' || c == '\\')
|
||
PRINTCHAR ('\\');
|
||
PRINTCHAR (c);
|
||
}
|
||
}
|
||
PRINTCHAR ('\"');
|
||
|
||
#ifdef USE_TEXT_PROPERTIES
|
||
if (!NULL_INTERVAL_P (XSTRING (obj)->intervals))
|
||
{
|
||
traverse_intervals (XSTRING (obj)->intervals,
|
||
0, 0, print_interval, printcharfun);
|
||
PRINTCHAR (')');
|
||
}
|
||
#endif
|
||
|
||
UNGCPRO;
|
||
}
|
||
break;
|
||
|
||
case Lisp_Symbol:
|
||
{
|
||
register int confusing;
|
||
register unsigned char *p = XSYMBOL (obj)->name->data;
|
||
register unsigned char *end = p + XSYMBOL (obj)->name->size;
|
||
register unsigned char c;
|
||
|
||
if (p != end && (*p == '-' || *p == '+')) p++;
|
||
if (p == end)
|
||
confusing = 0;
|
||
else
|
||
{
|
||
while (p != end && *p >= '0' && *p <= '9')
|
||
p++;
|
||
confusing = (end == p);
|
||
}
|
||
|
||
p = XSYMBOL (obj)->name->data;
|
||
while (p != end)
|
||
{
|
||
QUIT;
|
||
c = *p++;
|
||
if (escapeflag)
|
||
{
|
||
if (c == '\"' || c == '\\' || c == '\'' || c == ';' || c == '#' ||
|
||
c == '(' || c == ')' || c == ',' || c =='.' || c == '`' ||
|
||
c == '[' || c == ']' || c == '?' || c <= 040 || confusing)
|
||
PRINTCHAR ('\\'), confusing = 0;
|
||
}
|
||
PRINTCHAR (c);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case Lisp_Cons:
|
||
/* If deeper than spec'd depth, print placeholder. */
|
||
if (XTYPE (Vprint_level) == Lisp_Int
|
||
&& print_depth > XINT (Vprint_level))
|
||
{
|
||
strout ("...", -1, printcharfun);
|
||
break;
|
||
}
|
||
|
||
PRINTCHAR ('(');
|
||
{
|
||
register int i = 0;
|
||
register int max = 0;
|
||
|
||
if (XTYPE (Vprint_length) == Lisp_Int)
|
||
max = XINT (Vprint_length);
|
||
/* Could recognize circularities in cdrs here,
|
||
but that would make printing of long lists quadratic.
|
||
It's not worth doing. */
|
||
while (CONSP (obj))
|
||
{
|
||
if (i++)
|
||
PRINTCHAR (' ');
|
||
if (max && i > max)
|
||
{
|
||
strout ("...", 3, printcharfun);
|
||
break;
|
||
}
|
||
print (Fcar (obj), printcharfun, escapeflag);
|
||
obj = Fcdr (obj);
|
||
}
|
||
}
|
||
if (!NILP (obj) && !CONSP (obj))
|
||
{
|
||
strout (" . ", 3, printcharfun);
|
||
print (obj, printcharfun, escapeflag);
|
||
}
|
||
PRINTCHAR (')');
|
||
break;
|
||
|
||
case Lisp_Compiled:
|
||
strout ("#", -1, printcharfun);
|
||
case Lisp_Vector:
|
||
PRINTCHAR ('[');
|
||
{
|
||
register int i;
|
||
register Lisp_Object tem;
|
||
for (i = 0; i < XVECTOR (obj)->size; i++)
|
||
{
|
||
if (i) PRINTCHAR (' ');
|
||
tem = XVECTOR (obj)->contents[i];
|
||
print (tem, printcharfun, escapeflag);
|
||
}
|
||
}
|
||
PRINTCHAR (']');
|
||
break;
|
||
|
||
#ifndef standalone
|
||
case Lisp_Buffer:
|
||
if (NILP (XBUFFER (obj)->name))
|
||
strout ("#<killed buffer>", -1, printcharfun);
|
||
else if (escapeflag)
|
||
{
|
||
strout ("#<buffer ", -1, printcharfun);
|
||
print_string (XBUFFER (obj)->name, printcharfun);
|
||
PRINTCHAR ('>');
|
||
}
|
||
else
|
||
print_string (XBUFFER (obj)->name, printcharfun);
|
||
break;
|
||
|
||
case Lisp_Process:
|
||
if (escapeflag)
|
||
{
|
||
strout ("#<process ", -1, printcharfun);
|
||
print_string (XPROCESS (obj)->name, printcharfun);
|
||
PRINTCHAR ('>');
|
||
}
|
||
else
|
||
print_string (XPROCESS (obj)->name, printcharfun);
|
||
break;
|
||
|
||
case Lisp_Window:
|
||
strout ("#<window ", -1, printcharfun);
|
||
sprintf (buf, "%d", XFASTINT (XWINDOW (obj)->sequence_number));
|
||
strout (buf, -1, printcharfun);
|
||
if (!NILP (XWINDOW (obj)->buffer))
|
||
{
|
||
strout (" on ", -1, printcharfun);
|
||
print_string (XBUFFER (XWINDOW (obj)->buffer)->name, printcharfun);
|
||
}
|
||
PRINTCHAR ('>');
|
||
break;
|
||
|
||
case Lisp_Window_Configuration:
|
||
strout ("#<window-configuration>", -1, printcharfun);
|
||
break;
|
||
|
||
#ifdef MULTI_FRAME
|
||
case Lisp_Frame:
|
||
strout ((FRAME_LIVE_P (XFRAME (obj))
|
||
? "#<frame " : "#<dead frame "),
|
||
-1, printcharfun);
|
||
print_string (XFRAME (obj)->name, printcharfun);
|
||
sprintf (buf, " 0x%x", (unsigned int) (XFRAME (obj)));
|
||
strout (buf, -1, printcharfun);
|
||
strout (">", -1, printcharfun);
|
||
break;
|
||
#endif /* MULTI_FRAME */
|
||
|
||
case Lisp_Marker:
|
||
strout ("#<marker ", -1, printcharfun);
|
||
if (!(XMARKER (obj)->buffer))
|
||
strout ("in no buffer", -1, printcharfun);
|
||
else
|
||
{
|
||
sprintf (buf, "at %d", marker_position (obj));
|
||
strout (buf, -1, printcharfun);
|
||
strout (" in ", -1, printcharfun);
|
||
print_string (XMARKER (obj)->buffer->name, printcharfun);
|
||
}
|
||
PRINTCHAR ('>');
|
||
break;
|
||
|
||
case Lisp_Overlay:
|
||
strout ("#<overlay ", -1, printcharfun);
|
||
if (!(XMARKER (OVERLAY_START (obj))->buffer))
|
||
strout ("in no buffer", -1, printcharfun);
|
||
else
|
||
{
|
||
sprintf (buf, "from %d to %d in ",
|
||
marker_position (OVERLAY_START (obj)),
|
||
marker_position (OVERLAY_END (obj)));
|
||
strout (buf, -1, printcharfun);
|
||
print_string (XMARKER (OVERLAY_START (obj))->buffer->name,
|
||
printcharfun);
|
||
}
|
||
PRINTCHAR ('>');
|
||
break;
|
||
|
||
#endif /* standalone */
|
||
|
||
case Lisp_Subr:
|
||
strout ("#<subr ", -1, printcharfun);
|
||
strout (XSUBR (obj)->symbol_name, -1, printcharfun);
|
||
PRINTCHAR ('>');
|
||
break;
|
||
}
|
||
|
||
print_depth--;
|
||
}
|
||
|
||
#ifdef USE_TEXT_PROPERTIES
|
||
|
||
/* Print a description of INTERVAL using PRINTCHARFUN.
|
||
This is part of printing a string that has text properties. */
|
||
|
||
void
|
||
print_interval (interval, printcharfun)
|
||
INTERVAL interval;
|
||
Lisp_Object printcharfun;
|
||
{
|
||
PRINTCHAR (' ');
|
||
print (make_number (interval->position), printcharfun, 1);
|
||
PRINTCHAR (' ');
|
||
print (make_number (interval->position + LENGTH (interval)),
|
||
printcharfun, 1);
|
||
PRINTCHAR (' ');
|
||
print (interval->plist, printcharfun, 1);
|
||
}
|
||
|
||
#endif /* USE_TEXT_PROPERTIES */
|
||
|
||
void
|
||
syms_of_print ()
|
||
{
|
||
staticpro (&Qprint_escape_newlines);
|
||
Qprint_escape_newlines = intern ("print-escape-newlines");
|
||
|
||
DEFVAR_LISP ("standard-output", &Vstandard_output,
|
||
"Output stream `print' uses by default for outputting a character.\n\
|
||
This may be any function of one argument.\n\
|
||
It may also be a buffer (output is inserted before point)\n\
|
||
or a marker (output is inserted and the marker is advanced)\n\
|
||
or the symbol t (output appears in the minibuffer line).");
|
||
Vstandard_output = Qt;
|
||
Qstandard_output = intern ("standard-output");
|
||
staticpro (&Qstandard_output);
|
||
|
||
#ifdef LISP_FLOAT_TYPE
|
||
DEFVAR_LISP ("float-output-format", &Vfloat_output_format,
|
||
"The format descriptor string used to print floats.\n\
|
||
This is a %-spec like those accepted by `printf' in C,\n\
|
||
but with some restrictions. It must start with the two characters `%.'.\n\
|
||
After that comes an integer precision specification,\n\
|
||
and then a letter which controls the format.\n\
|
||
The letters allowed are `e', `f' and `g'.\n\
|
||
Use `e' for exponential notation \"DIG.DIGITSeEXPT\"\n\
|
||
Use `f' for decimal point notation \"DIGITS.DIGITS\".\n\
|
||
Use `g' to choose the shorter of those two formats for the number at hand.\n\
|
||
The precision in any of these cases is the number of digits following\n\
|
||
the decimal point. With `f', a precision of 0 means to omit the\n\
|
||
decimal point. 0 is not allowed with `f' or `g'.\n\n\
|
||
A value of nil means to use `%.20g'.");
|
||
Vfloat_output_format = Qnil;
|
||
Qfloat_output_format = intern ("float-output-format");
|
||
staticpro (&Qfloat_output_format);
|
||
#endif /* LISP_FLOAT_TYPE */
|
||
|
||
DEFVAR_LISP ("print-length", &Vprint_length,
|
||
"Maximum length of list to print before abbreviating.\n\
|
||
A value of nil means no limit.");
|
||
Vprint_length = Qnil;
|
||
|
||
DEFVAR_LISP ("print-level", &Vprint_level,
|
||
"Maximum depth of list nesting to print before abbreviating.\n\
|
||
A value of nil means no limit.");
|
||
Vprint_level = Qnil;
|
||
|
||
DEFVAR_BOOL ("print-escape-newlines", &print_escape_newlines,
|
||
"Non-nil means print newlines in strings as backslash-n.");
|
||
print_escape_newlines = 0;
|
||
|
||
/* prin1_to_string_buffer initialized in init_buffer_once in buffer.c */
|
||
staticpro (&Vprin1_to_string_buffer);
|
||
|
||
defsubr (&Sprin1);
|
||
defsubr (&Sprin1_to_string);
|
||
defsubr (&Sprinc);
|
||
defsubr (&Sprint);
|
||
defsubr (&Sterpri);
|
||
defsubr (&Swrite_char);
|
||
defsubr (&Sexternal_debugging_output);
|
||
|
||
Qexternal_debugging_output = intern ("external-debugging-output");
|
||
staticpro (&Qexternal_debugging_output);
|
||
|
||
#ifndef standalone
|
||
defsubr (&Swith_output_to_temp_buffer);
|
||
#endif /* not standalone */
|
||
}
|