mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-07-02 15:40:38 +02:00
Remove print state objects, and ports-with-print-state
The goal was that, as part of a print operation, all nested prints of contained data would be able to use the same parameters (e.g. write or not), and also detect cycles, highlight objects, etc. The mechanism was a heap-allocated data structure. However, given that: 1. Nobody accessed print states from Scheme 2. `write` and `display` should move to Scheme anyway, in order to be suspendable 3. The "fancyp" and "highlight" options were unused 4. A simple stack-allocated data structure with a per-thread key could do the trick just as well, without needing the weird freelist structure 5. Ports-with-print-states were a source of bugs In the end we switch print states to be something completely internal to print.c. There are no more SCM print-state objects, and no more ports-with-print-state. * libguile/print.h: Remove print state from API. * libguile/print.c (struct scm_print_state): Move definition here. (scm_print_opts): Remove "highlight-prefix" and "highlight-suffix" options, as they were not used. (ENTER_NESTED_DATA): Remove "fancyp" case. (init_print_state_key, get_print_state, push_print_state) (maybe_push_print_state, pop_print_state): New facility to manage stack of active print states. (scm_iprin1, print_vector): No more fancyp. (iprin1): Access "writingp" member directly. Don't make ports with print states. (scm_prin1): Manage print state stack. (scm_iprlist): No more fancyp. (scm_valid_oport_value_p): Remove; valid outports are SCM_OPOUTPORTP. * libguile/backtrace.c: * libguile/filesys.c: * libguile/fports.c: * libguile/goops.c: * libguile/ioext.c: * libguile/ports.c: * libguile/posix.c: * libguile/promises.c: * libguile/socket.c: * libguile/struct.c: Remove cases that dealt with ports-with-print-states. * libguile/private-options.h: Remove highlight options. * module/ice-9/ports.scm (inherit-print-state): Deprecate. * libguile/deprecated.c: * libguile/deprecated.h: Add deprecation shims for print states, as far as that is possible.
This commit is contained in:
parent
d1b548033c
commit
3cf4ca187c
16 changed files with 181 additions and 425 deletions
350
libguile/print.c
350
libguile/print.c
|
@ -39,8 +39,10 @@
|
|||
#include "chars.h"
|
||||
#include "continuations-internal.h"
|
||||
#include "control.h"
|
||||
#include "dynwind.h"
|
||||
#include "ephemerons.h"
|
||||
#include "eval.h"
|
||||
#include "extensions.h"
|
||||
#include "finalizers.h"
|
||||
#include "filesys.h"
|
||||
#include "fluids.h"
|
||||
|
@ -111,10 +113,6 @@ static const char *iflagnames[] =
|
|||
SCM_SYMBOL (sym_reader, "reader");
|
||||
|
||||
scm_t_option scm_print_opts[] = {
|
||||
{ SCM_OPTION_SCM, "highlight-prefix", (scm_t_bits)SCM_BOOL_F_BITS,
|
||||
"The string to print before highlighted values." },
|
||||
{ SCM_OPTION_SCM, "highlight-suffix", (scm_t_bits)SCM_BOOL_F_BITS,
|
||||
"The string to print after highlighted values." },
|
||||
{ SCM_OPTION_SCM, "quote-keywordish-symbols", (scm_t_bits)SCM_BOOL_F_BITS,
|
||||
"How to print symbols that have a colon as their first or last character. "
|
||||
"The value '#f' does not quote the colons; '#t' quotes them; "
|
||||
|
@ -145,6 +143,23 @@ SCM_DEFINE (scm_print_options, "print-options-interface", 0, 1, 0,
|
|||
/* {Printing of Scheme Objects}
|
||||
*/
|
||||
|
||||
/* State information passed around during printing.
|
||||
*/
|
||||
struct scm_print_state
|
||||
{
|
||||
struct scm_print_state *prev;
|
||||
SCM port; /* The port we are writing to */
|
||||
int writingp; /* Writing? */
|
||||
size_t level; /* Max level */
|
||||
size_t length; /* Max number of objects per level */
|
||||
size_t list_offset;
|
||||
size_t top; /* Top of reference stack */
|
||||
size_t ceiling; /* Max size of reference stack */
|
||||
SCM ref_vect; /* Stack of references used during
|
||||
circular reference detection;
|
||||
a vector. */
|
||||
};
|
||||
|
||||
/* Detection of circular references.
|
||||
*
|
||||
* Due to other constraints in the implementation, this code has bad
|
||||
|
@ -167,14 +182,6 @@ do \
|
|||
for (i = 0; i < pstate->top; ++i) \
|
||||
if (scm_is_eq (PSTATE_STACK_REF (pstate, i), (obj))) \
|
||||
goto label; \
|
||||
if (pstate->fancyp) \
|
||||
{ \
|
||||
if (pstate->top - pstate->list_offset >= pstate->level) \
|
||||
{ \
|
||||
scm_putc ('#', port); \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
PUSH_REF(pstate, obj); \
|
||||
} while(0)
|
||||
|
||||
|
@ -186,93 +193,51 @@ do \
|
|||
} \
|
||||
while (0)
|
||||
|
||||
SCM scm_print_state_vtable = SCM_BOOL_F;
|
||||
static SCM print_state_pool = SCM_EOL;
|
||||
scm_i_pthread_mutex_t print_state_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
#ifdef GUILE_DEBUG /* Used for debugging purposes */
|
||||
|
||||
SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0,
|
||||
(),
|
||||
"Return the current-pstate -- the car of the\n"
|
||||
"@code{print_state_pool}. @code{current-pstate} is only\n"
|
||||
"included in @code{--enable-guile-debug} builds.")
|
||||
#define FUNC_NAME s_scm_current_pstate
|
||||
{
|
||||
if (!scm_is_null (print_state_pool))
|
||||
return SCM_CAR (print_state_pool);
|
||||
else
|
||||
return SCM_BOOL_F;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
#endif
|
||||
|
||||
#define PSTATE_SIZE 50L
|
||||
|
||||
static SCM
|
||||
make_print_state (void)
|
||||
static scm_i_pthread_key_t print_state_key;
|
||||
static scm_i_pthread_once_t print_state_once = SCM_I_PTHREAD_ONCE_INIT;
|
||||
|
||||
static void
|
||||
init_print_state_key (void)
|
||||
{
|
||||
SCM print_state = scm_make_struct_no_tail (scm_print_state_vtable, SCM_EOL);
|
||||
scm_print_state *pstate = SCM_PRINT_STATE (print_state);
|
||||
pstate->handle = print_state;
|
||||
pstate->ref_vect = scm_c_make_vector (PSTATE_SIZE, SCM_UNDEFINED);
|
||||
pstate->ceiling = SCM_SIMPLE_VECTOR_LENGTH (pstate->ref_vect);
|
||||
pstate->highlight_objects = SCM_EOL;
|
||||
return print_state;
|
||||
scm_i_pthread_key_create (&print_state_key, NULL);
|
||||
}
|
||||
|
||||
SCM
|
||||
scm_make_print_state ()
|
||||
static struct scm_print_state*
|
||||
get_print_state (void)
|
||||
{
|
||||
SCM answer = SCM_BOOL_F;
|
||||
|
||||
/* First try to allocate a print state from the pool */
|
||||
scm_i_pthread_mutex_lock (&print_state_mutex);
|
||||
if (!scm_is_null (print_state_pool))
|
||||
{
|
||||
answer = SCM_CAR (print_state_pool);
|
||||
print_state_pool = SCM_CDR (print_state_pool);
|
||||
}
|
||||
scm_i_pthread_mutex_unlock (&print_state_mutex);
|
||||
|
||||
return scm_is_false (answer) ? make_print_state () : answer;
|
||||
scm_i_pthread_once (&print_state_once, init_print_state_key);
|
||||
return scm_i_pthread_getspecific (print_state_key);
|
||||
}
|
||||
|
||||
void
|
||||
scm_free_print_state (SCM print_state)
|
||||
static void
|
||||
push_print_state (SCM port, struct scm_print_state *state,
|
||||
struct scm_print_state *prev)
|
||||
{
|
||||
SCM handle;
|
||||
scm_print_state *pstate = SCM_PRINT_STATE (print_state);
|
||||
/* Cleanup before returning print state to pool.
|
||||
* It is better to do it here. Doing it in scm_prin1
|
||||
* would cost more since that function is called much more
|
||||
* often.
|
||||
*/
|
||||
pstate->fancyp = 0;
|
||||
pstate->revealed = 0;
|
||||
pstate->highlight_objects = SCM_EOL;
|
||||
scm_i_pthread_mutex_lock (&print_state_mutex);
|
||||
handle = scm_cons (print_state, print_state_pool);
|
||||
print_state_pool = handle;
|
||||
scm_i_pthread_mutex_unlock (&print_state_mutex);
|
||||
memset (state, 0, sizeof (*state));
|
||||
state->prev = prev;
|
||||
state->port = port;
|
||||
state->ref_vect = scm_c_make_vector (PSTATE_SIZE, SCM_UNDEFINED);
|
||||
state->ceiling = SCM_SIMPLE_VECTOR_LENGTH (state->ref_vect);
|
||||
scm_i_pthread_setspecific (print_state_key, state);
|
||||
}
|
||||
|
||||
SCM
|
||||
scm_i_port_with_print_state (SCM port, SCM print_state)
|
||||
static struct scm_print_state *
|
||||
maybe_push_print_state (SCM port, struct scm_print_state *state)
|
||||
{
|
||||
if (SCM_UNBNDP (print_state))
|
||||
{
|
||||
if (SCM_PORT_WITH_PS_P (port))
|
||||
return port;
|
||||
else
|
||||
print_state = scm_make_print_state ();
|
||||
/* port does not need to be coerced since it doesn't have ps */
|
||||
}
|
||||
else
|
||||
port = SCM_COERCE_OUTPORT (port);
|
||||
return scm_new_double_smob (scm_tc16_port_with_ps,
|
||||
SCM_UNPACK (port), SCM_UNPACK (print_state), 0);
|
||||
struct scm_print_state *prev = get_print_state ();
|
||||
for (struct scm_print_state *walk = prev; walk; walk = walk->prev)
|
||||
if (scm_is_eq (walk->port, port))
|
||||
return walk;
|
||||
push_print_state (port, state, prev);
|
||||
return state;
|
||||
}
|
||||
|
||||
static void
|
||||
pop_print_state (struct scm_print_state *state)
|
||||
{
|
||||
scm_i_pthread_setspecific (print_state_key, state->prev);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -552,15 +517,7 @@ static void iprin1 (SCM exp, SCM port, scm_print_state *pstate);
|
|||
void
|
||||
scm_iprin1 (SCM exp, SCM port, scm_print_state *pstate)
|
||||
{
|
||||
if (pstate->fancyp
|
||||
&& scm_is_true (scm_memq (exp, pstate->highlight_objects)))
|
||||
{
|
||||
scm_display (SCM_PRINT_HIGHLIGHT_PREFIX, port);
|
||||
iprin1 (exp, port, pstate);
|
||||
scm_display (SCM_PRINT_HIGHLIGHT_SUFFIX, port);
|
||||
}
|
||||
else
|
||||
iprin1 (exp, port, pstate);
|
||||
iprin1 (exp, port, pstate);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -569,12 +526,6 @@ print_vector (SCM v, size_t len, SCM (*ref) (SCM, size_t),
|
|||
{
|
||||
long i;
|
||||
long last = len - 1;
|
||||
int cutp = 0;
|
||||
if (pstate->fancyp && len > pstate->length)
|
||||
{
|
||||
last = pstate->length - 1;
|
||||
cutp = 1;
|
||||
}
|
||||
for (i = 0; i < last; ++i)
|
||||
{
|
||||
scm_iprin1 (ref (v, i), port, pstate);
|
||||
|
@ -585,8 +536,6 @@ print_vector (SCM v, size_t len, SCM (*ref) (SCM, size_t),
|
|||
/* CHECK_INTS; */
|
||||
scm_iprin1 (ref (v, i), port, pstate);
|
||||
}
|
||||
if (cutp)
|
||||
scm_puts (" ...", port);
|
||||
scm_putc (')', port);
|
||||
}
|
||||
|
||||
|
@ -610,7 +559,7 @@ iprin1 (SCM exp, SCM port, scm_print_state *pstate)
|
|||
case scm_tc3_imm24:
|
||||
if (SCM_CHARP (exp))
|
||||
{
|
||||
if (SCM_WRITINGP (pstate))
|
||||
if (pstate->writingp)
|
||||
write_character (SCM_CHAR (exp), port);
|
||||
else
|
||||
scm_c_put_char (port, SCM_CHAR (exp));
|
||||
|
@ -634,12 +583,10 @@ iprin1 (SCM exp, SCM port, scm_print_state *pstate)
|
|||
ENTER_NESTED_DATA (pstate, exp, circref);
|
||||
if (SCM_OBJ_CLASS_FLAGS (exp) & SCM_CLASSF_GOOPS)
|
||||
{
|
||||
SCM pwps, print = pstate->writingp ? g_write : g_display;
|
||||
SCM print = pstate->writingp ? g_write : g_display;
|
||||
if (SCM_UNPACK (print) == 0)
|
||||
goto print_struct;
|
||||
pwps = scm_i_port_with_print_state (port, pstate->handle);
|
||||
pstate->revealed = 1;
|
||||
scm_call_2 (print, exp, pwps);
|
||||
scm_call_2 (print, exp, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -681,7 +628,7 @@ iprin1 (SCM exp, SCM port, scm_print_state *pstate)
|
|||
{
|
||||
size_t len = scm_i_string_length (exp);
|
||||
|
||||
if (SCM_WRITINGP (pstate))
|
||||
if (pstate->writingp)
|
||||
write_string (scm_i_string_data (exp),
|
||||
scm_i_is_narrow_string (exp),
|
||||
len, port);
|
||||
|
@ -820,62 +767,44 @@ iprin1 (SCM exp, SCM port, scm_print_state *pstate)
|
|||
}
|
||||
}
|
||||
|
||||
/* Print states are necessary for circular reference safe printing.
|
||||
* They are also expensive to allocate. Therefore print states are
|
||||
* kept in a pool so that they can be reused.
|
||||
*/
|
||||
static void
|
||||
dynwind_pop_state (void *data)
|
||||
{
|
||||
scm_print_state *state = data;
|
||||
pop_print_state (state);
|
||||
}
|
||||
|
||||
/* The PORT argument can also be a print-state/port pair, which will
|
||||
* then be used instead of allocating a new print state. This is
|
||||
* useful for continuing a chain of print calls from Scheme. */
|
||||
static void
|
||||
dynwind_flip_writingp (void *data)
|
||||
{
|
||||
scm_print_state *state = data;
|
||||
state->writingp = !state->writingp;
|
||||
}
|
||||
|
||||
void
|
||||
scm_prin1 (SCM exp, SCM port, int writingp)
|
||||
{
|
||||
SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
|
||||
SCM pstate_scm;
|
||||
scm_print_state *pstate;
|
||||
int old_writingp;
|
||||
scm_print_state fresh_state;
|
||||
scm_print_state *state = maybe_push_print_state (port, &fresh_state);
|
||||
|
||||
/* If PORT is a print-state/port pair, use that. Else create a new
|
||||
print-state. */
|
||||
scm_dynwind_begin (0);
|
||||
|
||||
if (SCM_PORT_WITH_PS_P (port))
|
||||
if (state == &fresh_state)
|
||||
{
|
||||
pstate_scm = SCM_PORT_WITH_PS_PS (port);
|
||||
port = SCM_PORT_WITH_PS_PORT (port);
|
||||
state->writingp = writingp;
|
||||
scm_dynwind_unwind_handler (dynwind_pop_state, state,
|
||||
SCM_F_WIND_EXPLICITLY);
|
||||
}
|
||||
else
|
||||
else if (state->writingp != writingp)
|
||||
{
|
||||
/* First try to allocate a print state from the pool */
|
||||
scm_i_pthread_mutex_lock (&print_state_mutex);
|
||||
if (!scm_is_null (print_state_pool))
|
||||
{
|
||||
handle = print_state_pool;
|
||||
print_state_pool = SCM_CDR (print_state_pool);
|
||||
}
|
||||
scm_i_pthread_mutex_unlock (&print_state_mutex);
|
||||
if (scm_is_false (handle))
|
||||
handle = scm_list_1 (make_print_state ());
|
||||
pstate_scm = SCM_CAR (handle);
|
||||
dynwind_flip_writingp (state);
|
||||
scm_dynwind_unwind_handler (dynwind_flip_writingp, state,
|
||||
SCM_F_WIND_EXPLICITLY);
|
||||
}
|
||||
|
||||
pstate = SCM_PRINT_STATE (pstate_scm);
|
||||
old_writingp = pstate->writingp;
|
||||
pstate->writingp = writingp;
|
||||
scm_iprin1 (exp, port, pstate);
|
||||
pstate->writingp = old_writingp;
|
||||
scm_iprin1 (exp, port, state);
|
||||
|
||||
/* Return print state to pool if it has been created above and
|
||||
hasn't escaped to Scheme. */
|
||||
|
||||
if (scm_is_true (handle) && !pstate->revealed)
|
||||
{
|
||||
scm_i_pthread_mutex_lock (&print_state_mutex);
|
||||
SCM_SETCDR (handle, print_state_pool);
|
||||
print_state_pool = handle;
|
||||
scm_i_pthread_mutex_unlock (&print_state_mutex);
|
||||
}
|
||||
scm_dynwind_end ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1012,9 +941,6 @@ scm_iprlist (char *hdr, SCM exp, int tlr, SCM port, scm_print_state *pstate)
|
|||
long floor = pstate->top - 2;
|
||||
scm_puts (hdr, port);
|
||||
/* CHECK_INTS; */
|
||||
if (pstate->fancyp)
|
||||
goto fancy_printing;
|
||||
|
||||
/* Run a hare and tortoise so that total time complexity will be
|
||||
O(depth * N) instead of O(N^2). */
|
||||
hare = SCM_CDR (exp);
|
||||
|
@ -1063,21 +989,9 @@ fancy_printing:
|
|||
exp = SCM_CDR (exp); --n;
|
||||
for (; scm_is_pair (exp); exp = SCM_CDR (exp))
|
||||
{
|
||||
register unsigned long i;
|
||||
|
||||
for (i = 0; i < pstate->top; ++i)
|
||||
for (unsigned long i = 0; i < pstate->top; ++i)
|
||||
if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
|
||||
goto fancy_circref;
|
||||
if (pstate->fancyp)
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
scm_puts (" ...", port);
|
||||
goto skip_tail;
|
||||
}
|
||||
else
|
||||
--n;
|
||||
}
|
||||
PUSH_REF(pstate, exp);
|
||||
++pstate->list_offset;
|
||||
scm_putc (' ', port);
|
||||
|
@ -1090,7 +1004,6 @@ fancy_printing:
|
|||
scm_puts (" . ", port);
|
||||
scm_iprin1 (exp, port, pstate);
|
||||
}
|
||||
skip_tail:
|
||||
pstate->list_offset -= pstate->top - floor - 2;
|
||||
goto end;
|
||||
|
||||
|
@ -1105,14 +1018,6 @@ circref:
|
|||
|
||||
|
||||
|
||||
int
|
||||
scm_valid_oport_value_p (SCM val)
|
||||
{
|
||||
return (SCM_OPOUTPORTP (val)
|
||||
|| (SCM_PORT_WITH_PS_P (val)
|
||||
&& SCM_OPOUTPORTP (SCM_PORT_WITH_PS_PORT (val))));
|
||||
}
|
||||
|
||||
/* SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write); */
|
||||
|
||||
SCM
|
||||
|
@ -1121,7 +1026,7 @@ scm_write (SCM obj, SCM port)
|
|||
if (SCM_UNBNDP (port))
|
||||
port = scm_current_output_port ();
|
||||
|
||||
SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
|
||||
SCM_ASSERT (SCM_OPOUTPORTP (port), port, SCM_ARG2, s_write);
|
||||
scm_prin1 (obj, port, 1);
|
||||
|
||||
return SCM_UNSPECIFIED;
|
||||
|
@ -1136,7 +1041,7 @@ scm_display (SCM obj, SCM port)
|
|||
if (SCM_UNBNDP (port))
|
||||
port = scm_current_output_port ();
|
||||
|
||||
SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
|
||||
SCM_ASSERT (SCM_OPOUTPORTP (port), port, SCM_ARG2, s_display);
|
||||
scm_prin1 (obj, port, 0);
|
||||
|
||||
return SCM_UNSPECIFIED;
|
||||
|
@ -1166,7 +1071,7 @@ SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
|
|||
if (scm_is_eq (destination, SCM_BOOL_T))
|
||||
{
|
||||
destination = port = scm_current_output_port ();
|
||||
SCM_VALIDATE_OPORT_VALUE (1, destination);
|
||||
SCM_VALIDATE_OPOUTPORT (1, destination);
|
||||
}
|
||||
else if (scm_is_false (destination))
|
||||
{
|
||||
|
@ -1176,8 +1081,8 @@ SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
|
|||
}
|
||||
else
|
||||
{
|
||||
SCM_VALIDATE_OPORT_VALUE (1, destination);
|
||||
port = SCM_COERCE_OUTPORT (destination);
|
||||
SCM_VALIDATE_OPOUTPORT (1, destination);
|
||||
port = destination;
|
||||
}
|
||||
SCM_VALIDATE_STRING (2, message);
|
||||
SCM_VALIDATE_REST_ARGUMENT (args);
|
||||
|
@ -1248,9 +1153,9 @@ SCM_DEFINE (scm_newline, "newline", 0, 1, 0,
|
|||
if (SCM_UNBNDP (port))
|
||||
port = scm_current_output_port ();
|
||||
|
||||
SCM_VALIDATE_OPORT_VALUE (1, port);
|
||||
SCM_VALIDATE_OPOUTPORT (1, port);
|
||||
|
||||
scm_putc ('\n', SCM_COERCE_OUTPORT (port));
|
||||
scm_putc ('\n', port);
|
||||
return SCM_UNSPECIFIED;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
@ -1262,8 +1167,6 @@ SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
|
|||
{
|
||||
if (SCM_UNBNDP (port))
|
||||
port = scm_current_output_port ();
|
||||
else
|
||||
port = SCM_COERCE_OUTPORT (port);
|
||||
|
||||
SCM_VALIDATE_CHAR (1, chr);
|
||||
SCM_VALIDATE_OPOUTPORT (2, port);
|
||||
|
@ -1276,84 +1179,11 @@ SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
|
|||
|
||||
|
||||
|
||||
/* Call back to Scheme code to do the printing of special objects
|
||||
* (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a smob
|
||||
* containing PORT and PSTATE. This object can be used as the port for
|
||||
* display/write etc to continue the current print chain. The REVEALED
|
||||
* field of PSTATE is set to true to indicate that the print state has
|
||||
* escaped to Scheme and thus has to be freed by the GC.
|
||||
*/
|
||||
|
||||
scm_t_bits scm_tc16_port_with_ps;
|
||||
|
||||
/* Print exactly as the port itself would */
|
||||
|
||||
static int
|
||||
port_with_ps_print (SCM obj, SCM port, scm_print_state *pstate)
|
||||
{
|
||||
obj = SCM_PORT_WITH_PS_PORT (obj);
|
||||
return SCM_PORT_TYPE (obj)->print (obj, port, pstate);
|
||||
}
|
||||
|
||||
SCM
|
||||
scm_printer_apply (SCM proc, SCM exp, SCM port, scm_print_state *pstate)
|
||||
{
|
||||
pstate->revealed = 1;
|
||||
return scm_call_2 (proc, exp,
|
||||
scm_i_port_with_print_state (port, pstate->handle));
|
||||
}
|
||||
|
||||
SCM_DEFINE (scm_port_with_print_state, "port-with-print-state", 1, 1, 0,
|
||||
(SCM port, SCM pstate),
|
||||
"Create a new port which behaves like @var{port}, but with an\n"
|
||||
"included print state @var{pstate}. @var{pstate} is optional.\n"
|
||||
"If @var{pstate} isn't supplied and @var{port} already has\n"
|
||||
"a print state, the old print state is reused.")
|
||||
#define FUNC_NAME s_scm_port_with_print_state
|
||||
{
|
||||
SCM_VALIDATE_OPORT_VALUE (1, port);
|
||||
if (!SCM_UNBNDP (pstate))
|
||||
SCM_VALIDATE_PRINTSTATE (2, pstate);
|
||||
return scm_i_port_with_print_state (port, pstate);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (scm_get_print_state, "get-print-state", 1, 0, 0,
|
||||
(SCM port),
|
||||
"Return the print state of the port @var{port}. If @var{port}\n"
|
||||
"has no associated print state, @code{#f} is returned.")
|
||||
#define FUNC_NAME s_scm_get_print_state
|
||||
{
|
||||
if (SCM_PORT_WITH_PS_P (port))
|
||||
return SCM_PORT_WITH_PS_PS (port);
|
||||
if (SCM_OUTPUT_PORT_P (port))
|
||||
return SCM_BOOL_F;
|
||||
SCM_WRONG_TYPE_ARG (1, port);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
||||
|
||||
void
|
||||
scm_init_print ()
|
||||
{
|
||||
SCM type;
|
||||
|
||||
type = scm_make_vtable (scm_from_utf8_string (SCM_PRINT_STATE_LAYOUT),
|
||||
SCM_BOOL_F);
|
||||
scm_set_struct_vtable_name_x (type, scm_from_utf8_symbol ("print-state"));
|
||||
scm_print_state_vtable = type;
|
||||
|
||||
/* Don't want to bind a wrapper class in GOOPS, so pass 0 as arg1. */
|
||||
scm_tc16_port_with_ps = scm_make_smob_type (0, 0);
|
||||
scm_set_smob_print (scm_tc16_port_with_ps, port_with_ps_print);
|
||||
|
||||
#include "print.x"
|
||||
|
||||
scm_init_opts (scm_print_options, scm_print_opts);
|
||||
scm_print_opts[SCM_PRINT_HIGHLIGHT_PREFIX_I].val =
|
||||
SCM_UNPACK (scm_from_utf8_string ("{"));
|
||||
scm_print_opts[SCM_PRINT_HIGHLIGHT_SUFFIX_I].val =
|
||||
SCM_UNPACK (scm_from_utf8_string ("}"));
|
||||
scm_print_opts[SCM_PRINT_KEYWORD_STYLE_I].val = SCM_UNPACK (sym_reader);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue