* objects.h (scm_si_redefined, scm_si_hashsets): Shifted.
[bpt/guile.git] / libguile / print.c
CommitLineData
7dc6e754 1/* Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
0f2d19dd
JB
41\f
42
43#include <stdio.h>
44#include "_scm.h"
20e6290e
JB
45#include "chars.h"
46#include "genio.h"
20e6290e
JB
47#include "smob.h"
48#include "eval.h"
ddeae7ca 49#include "macros.h"
20e6290e
JB
50#include "procprop.h"
51#include "read.h"
52#include "weaks.h"
53#include "unif.h"
dbef8851 54#include "alist.h"
c62fbfe1 55#include "struct.h"
0f2d19dd 56
20e6290e 57#include "print.h"
0f2d19dd
JB
58\f
59
60/* {Names of immediate symbols}
61 *
62 * This table must agree with the declarations in scm.h: {Immediate Symbols}.
63 */
64
65char *scm_isymnames[] =
66{
67 /* This table must agree with the declarations */
68 "#@and",
69 "#@begin",
70 "#@case",
71 "#@cond",
72 "#@do",
73 "#@if",
74 "#@lambda",
75 "#@let",
76 "#@let*",
77 "#@letrec",
78 "#@or",
79 "#@quote",
80 "#@set!",
81 "#@define",
82#if 0
83 "#@literal-variable-ref",
84 "#@literal-variable-set!",
85#endif
86 "#@apply",
87 "#@call-with-current-continuation",
88
89 /* user visible ISYMS */
90 /* other keywords */
91 /* Flags */
92
93 "#f",
94 "#t",
95 "#<undefined>",
96 "#<eof>",
97 "()",
98 "#<unspecified>"
99};
100
e6e4c9af 101scm_option scm_print_opts[] = {
b7ff98dd 102 { SCM_OPTION_SCM, "closure-hook", SCM_BOOL_F,
84f6a34a
MD
103 "Hook for printing closures." },
104 { SCM_OPTION_BOOLEAN, "source", 0,
105 "Print closures with source." }
e6e4c9af
MD
106};
107
b7ff98dd 108SCM_PROC (s_print_options, "print-options-interface", 0, 1, 0, scm_print_options);
1cc91f1b 109
e6e4c9af 110SCM
a51ea417
MD
111scm_print_options (setting)
112 SCM setting;
e6e4c9af 113{
a51ea417 114 SCM ans = scm_options (setting,
b7ff98dd
MD
115 scm_print_opts,
116 SCM_N_PRINT_OPTIONS,
117 s_print_options);
e6e4c9af
MD
118 return ans;
119}
e6e4c9af 120
0f2d19dd
JB
121\f
122/* {Printing of Scheme Objects}
123 */
124
a51ea417 125/* Detection of circular references.
c62fbfe1
MD
126 *
127 * Due to other constraints in the implementation, this code has bad
128 * time complexity (O (depth * N)), The printer code will be
129 * completely rewritten before next release of Guile. The new code
130 * will be O(N).
a51ea417 131 */
c62fbfe1 132#define PUSH_REF(pstate, obj) \
a51ea417 133{ \
c62fbfe1
MD
134 pstate->ref_stack[pstate->top++] = (obj); \
135 if (pstate->top == pstate->ceiling) \
136 grow_ref_stack (pstate); \
137}
a51ea417 138
c62fbfe1 139#define ENTER_NESTED_DATA(pstate, obj, label) \
a51ea417 140{ \
5ca6dc39 141 register unsigned long i; \
c62fbfe1
MD
142 for (i = 0; i < pstate->top; ++i) \
143 if (pstate->ref_stack[i] == (obj)) \
144 goto label; \
145 if (pstate->fancyp) \
146 { \
147 if (pstate->top - pstate->list_offset >= pstate->level) \
148 { \
b7f3516f 149 scm_putc ('#', port); \
c62fbfe1
MD
150 return; \
151 } \
152 } \
153 PUSH_REF(pstate, obj); \
a51ea417
MD
154} \
155
c62fbfe1
MD
156#define EXIT_NESTED_DATA(pstate) { --pstate->top; }
157
bb35f315 158SCM scm_print_state_vtable;
c4f37e80 159
bb35f315 160static SCM print_state_pool;
c4f37e80 161
f843a84c 162#ifdef GUILE_DEBUG /* Used for debugging purposes */
c62fbfe1 163SCM_PROC(s_current_pstate, "current-pstate", 0, 0, 0, scm_current_pstate);
1cc91f1b 164
c62fbfe1
MD
165SCM
166scm_current_pstate ()
c62fbfe1
MD
167{
168 return SCM_CADR (print_state_pool);
169}
170#endif
171
172#define PSTATE_SIZE 50L
173
698c0295
MD
174static SCM make_print_state SCM_P ((void));
175
176static SCM
177make_print_state ()
178{
179 SCM print_state = scm_make_struct (SCM_CAR (print_state_pool), /* pstate type */
bf685b6d 180 SCM_INUM0,
698c0295 181 SCM_EOL);
bf685b6d
MD
182 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
183 pstate->ref_vect = scm_make_vector (SCM_MAKINUM (PSTATE_SIZE),
bf685b6d
MD
184 SCM_UNDEFINED);
185 pstate->ref_stack = SCM_VELTS (pstate->ref_vect);
186 pstate->ceiling = SCM_LENGTH (pstate->ref_vect);
698c0295
MD
187 return print_state;
188}
1cc91f1b 189
c62fbfe1
MD
190SCM
191scm_make_print_state ()
c62fbfe1 192{
698c0295
MD
193 SCM answer = 0;
194
195 /* First try to allocate a print state from the pool */
196 SCM_DEFER_INTS;
197 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
198 {
199 answer = SCM_CADR (print_state_pool);
200 SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
201 }
202 SCM_ALLOW_INTS;
203
204 return answer ? answer : make_print_state ();
c62fbfe1 205}
a51ea417 206
4bfdf158
MD
207static char s_print_state_printer[] = "print-state-printer";
208static SCM
209print_state_printer (obj, port)
210 SCM obj;
211 SCM port;
212{
213 /* This function can be made visible by means of struct-ref, so
214 we need to make sure that it gets what it wants. */
215 SCM_ASSERT (SCM_NIMP (obj) && SCM_PRINT_STATE_P (obj),
216 obj,
217 SCM_ARG1,
218 s_print_state_printer);
219 SCM_ASSERT (scm_valid_oport_value_p (port),
220 port,
221 SCM_ARG2,
222 s_print_state_printer);
0ef4ae82 223 port = SCM_COERCE_OUTPORT (port);
b7f3516f 224 scm_puts ("#<print-state ", port);
4bfdf158 225 scm_intprint (obj, 16, port);
b7f3516f 226 scm_putc ('>', port);
4bfdf158
MD
227 return SCM_UNSPECIFIED;
228}
229
698c0295
MD
230void
231scm_free_print_state (print_state)
232 SCM print_state;
233{
234 SCM handle;
235 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
236 /* Cleanup before returning print state to pool.
237 * It is better to do it here. Doing it in scm_prin1
238 * would cost more since that function is called much more
239 * often.
240 */
241 pstate->fancyp = 0;
bb35f315 242 pstate->revealed = 0;
698c0295
MD
243 SCM_NEWCELL (handle);
244 SCM_DEFER_INTS;
245 SCM_SETCAR (handle, print_state);
246 SCM_SETCDR (handle, SCM_CDR (print_state_pool));
247 SCM_SETCDR (print_state_pool, handle);
248 SCM_ALLOW_INTS;
249}
1cc91f1b
JB
250
251static void grow_ref_stack SCM_P ((scm_print_state *pstate));
252
a51ea417 253static void
c62fbfe1
MD
254grow_ref_stack (pstate)
255 scm_print_state *pstate;
a51ea417 256{
bf685b6d
MD
257 int new_size = 2 * pstate->ceiling;
258 scm_vector_set_length_x (pstate->ref_vect, SCM_MAKINUM (new_size));
259 pstate->ref_stack = SCM_VELTS (pstate->ref_vect);
260 pstate->ceiling = new_size;
a51ea417
MD
261}
262
1cc91f1b
JB
263
264static void print_circref SCM_P ((SCM port, scm_print_state *pstate, SCM ref));
265
a51ea417 266static void
c62fbfe1
MD
267print_circref (port, pstate, ref)
268 SCM port;
269 scm_print_state *pstate;
270 SCM ref;
a51ea417 271{
c62fbfe1
MD
272 register int i;
273 int self = pstate->top - 1;
274 i = pstate->top - 1;
275 if (SCM_CONSP (pstate->ref_stack[i]))
276 {
277 while (i > 0)
278 {
279 if (SCM_NCONSP (pstate->ref_stack[i - 1])
280 || SCM_CDR (pstate->ref_stack[i - 1]) != pstate->ref_stack[i])
281 break;
282 --i;
283 }
284 self = i;
285 }
286 for (i = pstate->top - 1; 1; --i)
287 if (pstate->ref_stack[i] == ref)
288 break;
b7f3516f 289 scm_putc ('#', port);
c62fbfe1 290 scm_intprint (i - self, 10, port);
b7f3516f 291 scm_putc ('#', port);
a51ea417
MD
292}
293
c62fbfe1 294/* Print generally. Handles both write and display according to PSTATE.
0f2d19dd 295 */
a51ea417 296
1cc91f1b 297
0f2d19dd 298void
c62fbfe1 299scm_iprin1 (exp, port, pstate)
0f2d19dd
JB
300 SCM exp;
301 SCM port;
c62fbfe1 302 scm_print_state *pstate;
0f2d19dd 303{
0f2d19dd
JB
304taloop:
305 switch (7 & (int) exp)
306 {
307 case 2:
308 case 6:
309 scm_intprint (SCM_INUM (exp), 10, port);
310 break;
311 case 4:
312 if (SCM_ICHRP (exp))
313 {
5ca6dc39
JB
314 register long i;
315
0f2d19dd 316 i = SCM_ICHR (exp);
b7f3516f
TT
317 if (SCM_WRITINGP (pstate))
318 {
319 scm_puts ("#\\", port);
320 if ((i >= 0) && (i <= ' ') && scm_charnames[i])
321 scm_puts (scm_charnames[i], port);
322 else if (i < 0 || i > '\177')
323 scm_intprint (i, 8, port);
324 else
325 scm_putc (i, port);
326 }
327 else
328 scm_putc (i, port);
0f2d19dd 329 }
a51ea417 330 else if (SCM_IFLAGP (exp)
5ca6dc39 331 && ((size_t) SCM_ISYMNUM (exp) < (sizeof scm_isymnames / sizeof (char *))))
b7f3516f 332 scm_puts (SCM_ISYMCHARS (exp), port);
0f2d19dd
JB
333 else if (SCM_ILOCP (exp))
334 {
b7f3516f 335 scm_puts ("#@", port);
0f2d19dd 336 scm_intprint ((long) SCM_IFRAME (exp), 10, port);
b7f3516f 337 scm_putc (SCM_ICDRP (exp) ? '-' : '+', port);
0f2d19dd
JB
338 scm_intprint ((long) SCM_IDIST (exp), 10, port);
339 }
340 else
341 goto idef;
342 break;
343 case 1:
344 /* gloc */
b7f3516f 345 scm_puts ("#@", port);
0f2d19dd
JB
346 exp = SCM_CAR (exp - 1);
347 goto taloop;
348 default:
349 idef:
350 scm_ipruk ("immediate", exp, port);
351 break;
352 case 0:
353 switch (SCM_TYP7 (exp))
354 {
355 case scm_tcs_cons_gloc:
356
357 if (SCM_CDR (SCM_CAR (exp) - 1L) == 0)
358 {
c4f37e80 359 ENTER_NESTED_DATA (pstate, exp, circref);
bafcafb2 360 scm_print_struct (exp, port, pstate);
c4f37e80 361 EXIT_NESTED_DATA (pstate);
0f2d19dd
JB
362 break;
363 }
364
365 case scm_tcs_cons_imcar:
366 case scm_tcs_cons_nimcar:
c62fbfe1
MD
367 ENTER_NESTED_DATA (pstate, exp, circref);
368 scm_iprlist ("(", exp, ')', port, pstate);
369 EXIT_NESTED_DATA (pstate);
a51ea417
MD
370 break;
371 circref:
c62fbfe1 372 print_circref (port, pstate, exp);
0f2d19dd 373 break;
7332df66 374 macros:
80ea260c 375 if (!SCM_CLOSUREP (SCM_CDR (exp)))
7332df66 376 goto prinmacro;
0f2d19dd 377 case scm_tcs_closures:
7332df66
MD
378 /* The user supplied print closure procedure must handle
379 macro closures as well. */
bb35f315
MV
380 if (SCM_FALSEP (scm_procedure_p (SCM_PRINT_CLOSURE))
381 || SCM_FALSEP (scm_printer_apply (SCM_PRINT_CLOSURE,
77c25af7 382 exp, port, pstate)))
bb35f315 383 {
ba031394 384 SCM name, code, env;
bb35f315
MV
385 if (SCM_TYP16 (exp) == scm_tc16_macro)
386 {
387 /* Printing a macro. */
388 prinmacro:
389 name = scm_macro_name (exp);
390 if (!SCM_CLOSUREP (SCM_CDR (exp)))
391 {
f44dd64b 392 code = env = 0;
b7f3516f 393 scm_puts ("#<primitive-", port);
bb35f315
MV
394 }
395 else
396 {
397 code = SCM_CODE (SCM_CDR (exp));
ba031394 398 env = SCM_ENV (SCM_CDR (exp));
b7f3516f 399 scm_puts ("#<", port);
bb35f315
MV
400 }
401 if (SCM_CAR (exp) & (3L << 16))
b7f3516f 402 scm_puts ("macro", port);
bb35f315 403 else
b7f3516f 404 scm_puts ("syntax", port);
bb35f315 405 if (SCM_CAR (exp) & (2L << 16))
b7f3516f 406 scm_putc ('!', port);
bb35f315
MV
407 }
408 else
409 {
410 /* Printing a closure. */
411 name = scm_procedure_name (exp);
412 code = SCM_CODE (exp);
ba031394 413 env = SCM_ENV (exp);
b7f3516f 414 scm_puts ("#<procedure", port);
bb35f315
MV
415 }
416 if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
417 {
b7f3516f
TT
418 scm_putc (' ', port);
419 scm_puts (SCM_ROCHARS (name), port);
bb35f315
MV
420 }
421 if (code)
422 {
ba031394
MD
423 if (SCM_PRINT_SOURCE_P)
424 {
425 code = scm_unmemocopy (code,
426 SCM_EXTEND_ENV (SCM_CAR (code),
427 SCM_EOL,
428 env));
429 ENTER_NESTED_DATA (pstate, exp, circref);
430 scm_iprlist (" ", code, '>', port, pstate);
431 EXIT_NESTED_DATA (pstate);
432 }
433 else
434 {
435 if (SCM_TYP16 (exp) != scm_tc16_macro)
436 {
b7f3516f 437 scm_putc (' ', port);
ba031394
MD
438 scm_iprin1 (SCM_CAR (code), port, pstate);
439 }
b7f3516f 440 scm_putc ('>', port);
ba031394 441 }
bb35f315
MV
442 }
443 else
b7f3516f 444 scm_putc ('>', port);
bb35f315 445 }
0f2d19dd 446 break;
0f2d19dd
JB
447 case scm_tc7_substring:
448 case scm_tc7_string:
c62fbfe1 449 if (SCM_WRITINGP (pstate))
0f2d19dd 450 {
5ca6dc39
JB
451 scm_sizet i;
452
b7f3516f 453 scm_putc ('"', port);
0f2d19dd
JB
454 for (i = 0; i < SCM_ROLENGTH (exp); ++i)
455 switch (SCM_ROCHARS (exp)[i])
456 {
dbef8851 457 case '"':
0f2d19dd 458 case '\\':
b7f3516f 459 scm_putc ('\\', port);
0f2d19dd 460 default:
b7f3516f 461 scm_putc (SCM_ROCHARS (exp)[i], port);
0f2d19dd 462 }
b7f3516f 463 scm_putc ('"', port);
0f2d19dd
JB
464 break;
465 }
466 else
b7f3516f
TT
467 scm_lfwrite (SCM_ROCHARS (exp), (scm_sizet) SCM_ROLENGTH (exp),
468 port);
0f2d19dd
JB
469 break;
470 case scm_tcs_symbols:
0f2d19dd
JB
471 {
472 int pos;
473 int end;
474 int len;
475 char * str;
476 int weird;
477 int maybe_weird;
4dc2435a 478 int mw_pos = 0;
0f2d19dd
JB
479
480 len = SCM_LENGTH (exp);
481 str = SCM_CHARS (exp);
482 scm_remember (&exp);
483 pos = 0;
484 weird = 0;
485 maybe_weird = 0;
486
487 if (len == 0)
b7f3516f 488 scm_lfwrite ("#{}#", 4, port);
0f2d19dd
JB
489
490 for (end = pos; end < len; ++end)
491 switch (str[end])
492 {
493#ifdef BRACKETS_AS_PARENS
494 case '[':
495 case ']':
496#endif
497 case '(':
498 case ')':
dbef8851 499 case '"':
0f2d19dd
JB
500 case ';':
501 case SCM_WHITE_SPACES:
502 case SCM_LINE_INCREMENTORS:
503 weird_handler:
504 if (maybe_weird)
505 {
506 end = mw_pos;
507 maybe_weird = 0;
508 }
509 if (!weird)
510 {
b7f3516f 511 scm_lfwrite ("#{", 2, port);
0f2d19dd
JB
512 weird = 1;
513 }
514 if (pos < end)
515 {
b7f3516f 516 scm_lfwrite (str + pos, end - pos, port);
0f2d19dd
JB
517 }
518 {
519 char buf[2];
520 buf[0] = '\\';
521 buf[1] = str[end];
b7f3516f 522 scm_lfwrite (buf, 2, port);
0f2d19dd
JB
523 }
524 pos = end + 1;
525 break;
526 case '\\':
527 if (weird)
528 goto weird_handler;
529 if (!maybe_weird)
530 {
531 maybe_weird = 1;
532 mw_pos = pos;
533 }
534 break;
535 case '}':
536 case '#':
537 if (weird)
538 goto weird_handler;
539 break;
540 default:
541 break;
542 }
543 if (pos < end)
b7f3516f 544 scm_lfwrite (str + pos, end - pos, port);
0f2d19dd 545 if (weird)
b7f3516f 546 scm_lfwrite ("}#", 2, port);
0f2d19dd
JB
547 break;
548 }
549 case scm_tc7_wvect:
c62fbfe1 550 ENTER_NESTED_DATA (pstate, exp, circref);
0f2d19dd 551 if (SCM_IS_WHVEC (exp))
b7f3516f 552 scm_puts ("#wh(", port);
0f2d19dd 553 else
b7f3516f 554 scm_puts ("#w(", port);
0f2d19dd
JB
555 goto common_vector_printer;
556
557 case scm_tc7_vector:
c62fbfe1 558 ENTER_NESTED_DATA (pstate, exp, circref);
b7f3516f 559 scm_puts ("#(", port);
0f2d19dd 560 common_vector_printer:
9fbaf27c 561 {
5ca6dc39 562 register long i;
9fbaf27c
MD
563 int last = SCM_LENGTH (exp) - 1;
564 int cutp = 0;
565 if (pstate->fancyp && SCM_LENGTH (exp) > pstate->length)
566 {
567 last = pstate->length - 1;
568 cutp = 1;
569 }
570 for (i = 0; i < last; ++i)
571 {
572 /* CHECK_INTS; */
573 scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
b7f3516f 574 scm_putc (' ', port);
9fbaf27c
MD
575 }
576 if (i == last)
577 {
578 /* CHECK_INTS; */
579 scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
580 }
581 if (cutp)
b7f3516f
TT
582 scm_puts (" ...", port);
583 scm_putc (')', port);
9fbaf27c 584 }
c62fbfe1 585 EXIT_NESTED_DATA (pstate);
0f2d19dd
JB
586 break;
587 case scm_tc7_bvect:
588 case scm_tc7_byvect:
589 case scm_tc7_svect:
590 case scm_tc7_ivect:
591 case scm_tc7_uvect:
592 case scm_tc7_fvect:
593 case scm_tc7_dvect:
594 case scm_tc7_cvect:
595#ifdef LONGLONGS
596 case scm_tc7_llvect:
597#endif
c62fbfe1 598 scm_raprin1 (exp, port, pstate);
0f2d19dd
JB
599 break;
600 case scm_tcs_subrs:
b7f3516f
TT
601 scm_puts ("#<primitive-procedure ", port);
602 scm_puts (SCM_CHARS (SCM_SNAME (exp)), port);
603 scm_putc ('>', port);
0f2d19dd
JB
604 break;
605#ifdef CCLO
606 case scm_tc7_cclo:
56977059
MD
607 {
608 SCM proc = SCM_CCLO_SUBR (exp);
609 if (proc == scm_f_gsubr_apply)
610 {
611 /* Print gsubrs as primitives */
612 SCM name = scm_procedure_property (exp, scm_i_name);
613 scm_puts ("#<primitive-procedure", port);
614 if (SCM_NFALSEP (name))
615 {
616 scm_putc (' ', port);
617 scm_puts (SCM_CHARS (name), port);
618 }
619 }
620 else
621 {
622 scm_puts ("#<compiled-closure ", port);
623 scm_iprin1 (proc, port, pstate);
624 }
625 scm_putc ('>', port);
626 }
0f2d19dd
JB
627 break;
628#endif
629 case scm_tc7_contin:
b7f3516f 630 scm_puts ("#<continuation ", port);
0f2d19dd 631 scm_intprint (SCM_LENGTH (exp), 10, port);
b7f3516f 632 scm_puts (" @ ", port);
0f2d19dd 633 scm_intprint ((long) SCM_CHARS (exp), 16, port);
b7f3516f 634 scm_putc ('>', port);
0f2d19dd
JB
635 break;
636 case scm_tc7_port:
5ca6dc39
JB
637 {
638 register long i = SCM_PTOBNUM (exp);
639 if (i < scm_numptob
640 && scm_ptobs[i].print
641 && (scm_ptobs[i].print) (exp, port, pstate))
a51ea417 642 break;
5ca6dc39
JB
643 goto punk;
644 }
645 case scm_tc7_smob:
646 {
647 register long i;
648 ENTER_NESTED_DATA (pstate, exp, circref);
649 i = SCM_SMOBNUM (exp);
650 if (i < scm_numsmob && scm_smobs[i].print
651 && (scm_smobs[i].print) (exp, port, pstate))
652 {
653 EXIT_NESTED_DATA (pstate);
654 break;
655 }
656 EXIT_NESTED_DATA (pstate);
657 /* Macros have their print field set to NULL. They are
658 handled at the same place as closures in order to achieve
659 non-redundancy. Placing the condition here won't slow
660 down printing of other smobs. */
661 if (SCM_TYP16 (exp) == scm_tc16_macro)
662 goto macros;
663 }
0f2d19dd 664 default:
a51ea417
MD
665 punk:
666 scm_ipruk ("type", exp, port);
0f2d19dd
JB
667 }
668 }
669}
670
c62fbfe1
MD
671/* Print states are necessary for circular reference safe printing.
672 * They are also expensive to allocate. Therefore print states are
673 * kept in a pool so that they can be reused.
674 */
1cc91f1b 675
bb35f315
MV
676/* The PORT argument can also be a print-state/port pair, which will
677 * then be used instead of allocating a new print state. This is
678 * useful for continuing a chain of print calls from Scheme. */
679
a51ea417 680void
c62fbfe1 681scm_prin1 (exp, port, writingp)
a51ea417
MD
682 SCM exp;
683 SCM port;
c62fbfe1 684 int writingp;
a51ea417 685{
c4f37e80
MV
686 SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
687 SCM pstate_scm;
c62fbfe1
MD
688 scm_print_state *pstate;
689
bb35f315
MV
690 /* If PORT is a print-state/port pair, use that. Else create a new
691 print-state. */
c4f37e80 692
bb35f315
MV
693 if (SCM_NIMP (port) && SCM_CONSP (port))
694 {
695 pstate_scm = SCM_CDR (port);
696 port = SCM_CAR (port);
697 }
698 else
c62fbfe1 699 {
c4f37e80
MV
700 /* First try to allocate a print state from the pool */
701 SCM_DEFER_INTS;
702 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
703 {
704 handle = SCM_CDR (print_state_pool);
705 SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
706 }
707 SCM_ALLOW_INTS;
708 if (handle == SCM_BOOL_F)
709 handle = scm_cons (make_print_state (), SCM_EOL);
710 pstate_scm = SCM_CAR (handle);
c62fbfe1 711 }
c62fbfe1 712
c4f37e80 713 pstate = SCM_PRINT_STATE (pstate_scm);
c62fbfe1
MD
714 pstate->writingp = writingp;
715 scm_iprin1 (exp, port, pstate);
716
bb35f315
MV
717 /* Return print state to pool if it has been created above and
718 hasn't escaped to Scheme. */
719
720 if (handle != SCM_BOOL_F && !pstate->revealed)
c4f37e80
MV
721 {
722 SCM_DEFER_INTS;
723 SCM_SETCDR (handle, SCM_CDR (print_state_pool));
724 SCM_SETCDR (print_state_pool, handle);
725 SCM_ALLOW_INTS;
726 }
a51ea417
MD
727}
728
0f2d19dd
JB
729
730/* Print an integer.
731 */
1cc91f1b 732
0f2d19dd
JB
733void
734scm_intprint (n, radix, port)
735 long n;
736 int radix;
737 SCM port;
0f2d19dd
JB
738{
739 char num_buf[SCM_INTBUFLEN];
b7f3516f 740 scm_lfwrite (num_buf, scm_iint2str (n, radix, num_buf), port);
0f2d19dd
JB
741}
742
743/* Print an object of unrecognized type.
744 */
1cc91f1b 745
0f2d19dd
JB
746void
747scm_ipruk (hdr, ptr, port)
748 char *hdr;
749 SCM ptr;
750 SCM port;
0f2d19dd 751{
b7f3516f
TT
752 scm_puts ("#<unknown-", port);
753 scm_puts (hdr, port);
0f2d19dd
JB
754 if (SCM_CELLP (ptr))
755 {
b7f3516f 756 scm_puts (" (0x", port);
0f2d19dd 757 scm_intprint (SCM_CAR (ptr), 16, port);
b7f3516f 758 scm_puts (" . 0x", port);
0f2d19dd 759 scm_intprint (SCM_CDR (ptr), 16, port);
b7f3516f 760 scm_puts (") @", port);
0f2d19dd 761 }
b7f3516f 762 scm_puts (" 0x", port);
0f2d19dd 763 scm_intprint (ptr, 16, port);
b7f3516f 764 scm_putc ('>', port);
0f2d19dd
JB
765}
766
767/* Print a list.
768 */
a51ea417 769
1cc91f1b 770
0f2d19dd 771void
c62fbfe1 772scm_iprlist (hdr, exp, tlr, port, pstate)
0f2d19dd
JB
773 char *hdr;
774 SCM exp;
805df3e8 775 int tlr;
0f2d19dd 776 SCM port;
c62fbfe1 777 scm_print_state *pstate;
0f2d19dd 778{
c62fbfe1
MD
779 register SCM hare, tortoise;
780 int floor = pstate->top - 2;
b7f3516f 781 scm_puts (hdr, port);
0f2d19dd 782 /* CHECK_INTS; */
c62fbfe1
MD
783 if (pstate->fancyp)
784 goto fancy_printing;
785
786 /* Run a hare and tortoise so that total time complexity will be
787 O(depth * N) instead of O(N^2). */
788 hare = SCM_CDR (exp);
789 tortoise = exp;
2fab3faa 790 while (SCM_NIMP (hare) && SCM_ECONSP (hare))
c62fbfe1
MD
791 {
792 if (hare == tortoise)
793 goto fancy_printing;
794 hare = SCM_CDR (hare);
2fab3faa 795 if (SCM_IMP (hare) || SCM_NECONSP (hare))
c62fbfe1
MD
796 break;
797 hare = SCM_CDR (hare);
798 tortoise = SCM_CDR (tortoise);
799 }
800
801 /* No cdr cycles intrinsic to this list */
802 scm_iprin1 (SCM_CAR (exp), port, pstate);
0f2d19dd
JB
803 exp = SCM_CDR (exp);
804 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
805 {
5ca6dc39
JB
806 register int i;
807
0f2d19dd
JB
808 if (SCM_NECONSP (exp))
809 break;
c62fbfe1
MD
810 for (i = floor; i >= 0; --i)
811 if (pstate->ref_stack[i] == exp)
812 goto circref;
813 PUSH_REF (pstate, exp);
b7f3516f 814 scm_putc (' ', port);
0f2d19dd 815 /* CHECK_INTS; */
c62fbfe1 816 scm_iprin1 (SCM_CAR (exp), port, pstate);
0f2d19dd
JB
817 }
818 if (SCM_NNULLP (exp))
819 {
b7f3516f 820 scm_puts (" . ", port);
c62fbfe1 821 scm_iprin1 (exp, port, pstate);
0f2d19dd 822 }
c62fbfe1 823
a51ea417 824end:
b7f3516f 825 scm_putc (tlr, port);
c62fbfe1 826 pstate->top = floor + 2;
a51ea417 827 return;
c62fbfe1
MD
828
829fancy_printing:
830 {
831 int n = pstate->length;
832
833 scm_iprin1 (SCM_CAR (exp), port, pstate);
834 exp = SCM_CDR (exp); --n;
835 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
836 {
5ca6dc39
JB
837 register unsigned long i;
838
c62fbfe1
MD
839 if (SCM_NECONSP (exp))
840 break;
841 for (i = 0; i < pstate->top; ++i)
842 if (pstate->ref_stack[i] == exp)
843 goto fancy_circref;
844 if (pstate->fancyp)
845 {
846 if (n == 0)
847 {
b7f3516f 848 scm_puts (" ...", port);
c62fbfe1
MD
849 goto skip_tail;
850 }
851 else
852 --n;
853 }
854 PUSH_REF(pstate, exp);
855 ++pstate->list_offset;
b7f3516f 856 scm_putc (' ', port);
c62fbfe1
MD
857 /* CHECK_INTS; */
858 scm_iprin1 (SCM_CAR (exp), port, pstate);
859 }
860 }
861 if (SCM_NNULLP (exp))
862 {
b7f3516f 863 scm_puts (" . ", port);
c62fbfe1
MD
864 scm_iprin1 (exp, port, pstate);
865 }
866skip_tail:
867 pstate->list_offset -= pstate->top - floor - 2;
a51ea417 868 goto end;
a51ea417 869
c62fbfe1
MD
870fancy_circref:
871 pstate->list_offset -= pstate->top - floor - 2;
872
873circref:
b7f3516f 874 scm_puts (" . ", port);
c62fbfe1
MD
875 print_circref (port, pstate, exp);
876 goto end;
0f2d19dd
JB
877}
878
879\f
880
bb35f315
MV
881int
882scm_valid_oport_value_p (SCM val)
883{
4bfdf158
MD
884 return (SCM_NIMP (val)
885 && (SCM_OPOUTPORTP (val)
886 || (SCM_CONSP (val)
887 && SCM_NIMP (SCM_CAR (val))
888 && SCM_OPOUTPORTP (SCM_CAR (val))
889 && SCM_NIMP (SCM_CDR (val))
890 && SCM_PRINT_STATE_P (SCM_CDR (val)))));
bb35f315
MV
891}
892
0f2d19dd 893SCM_PROC(s_write, "write", 1, 1, 0, scm_write);
1cc91f1b 894
0f2d19dd
JB
895SCM
896scm_write (obj, port)
897 SCM obj;
898 SCM port;
0f2d19dd
JB
899{
900 if (SCM_UNBNDP (port))
901 port = scm_cur_outp;
902 else
bb35f315
MV
903 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
904
a51ea417 905 scm_prin1 (obj, port, 1);
0f2d19dd
JB
906#ifdef HAVE_PIPE
907# ifdef EPIPE
908 if (EPIPE == errno)
909 scm_close_port (port);
910# endif
911#endif
912 return SCM_UNSPECIFIED;
913}
914
915
916SCM_PROC(s_display, "display", 1, 1, 0, scm_display);
1cc91f1b 917
0f2d19dd
JB
918SCM
919scm_display (obj, port)
920 SCM obj;
921 SCM port;
0f2d19dd
JB
922{
923 if (SCM_UNBNDP (port))
924 port = scm_cur_outp;
925 else
bb35f315
MV
926 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
927
a51ea417 928 scm_prin1 (obj, port, 0);
0f2d19dd
JB
929#ifdef HAVE_PIPE
930# ifdef EPIPE
931 if (EPIPE == errno)
932 scm_close_port (port);
933# endif
934#endif
935 return SCM_UNSPECIFIED;
936}
937
938SCM_PROC(s_newline, "newline", 0, 1, 0, scm_newline);
1cc91f1b 939
0f2d19dd
JB
940SCM
941scm_newline (port)
942 SCM port;
0f2d19dd
JB
943{
944 if (SCM_UNBNDP (port))
bb35f315 945 port = scm_cur_outp;
0f2d19dd 946 else
bb35f315
MV
947 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG1, s_newline);
948
0ef4ae82 949 scm_putc ('\n', SCM_COERCE_OUTPORT (port));
0f2d19dd
JB
950#ifdef HAVE_PIPE
951# ifdef EPIPE
952 if (EPIPE == errno)
953 scm_close_port (port);
954 else
955# endif
956#endif
957 if (port == scm_cur_outp)
958 scm_fflush (port);
959 return SCM_UNSPECIFIED;
960}
961
962SCM_PROC(s_write_char, "write-char", 1, 1, 0, scm_write_char);
1cc91f1b 963
0f2d19dd
JB
964SCM
965scm_write_char (chr, port)
966 SCM chr;
967 SCM port;
0f2d19dd
JB
968{
969 if (SCM_UNBNDP (port))
bb35f315 970 port = scm_cur_outp;
0f2d19dd 971 else
bb35f315
MV
972 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write_char);
973
0f2d19dd 974 SCM_ASSERT (SCM_ICHRP (chr), chr, SCM_ARG1, s_write_char);
0ef4ae82 975 scm_putc ((int) SCM_ICHR (chr), SCM_COERCE_OUTPORT (port));
0f2d19dd
JB
976#ifdef HAVE_PIPE
977# ifdef EPIPE
978 if (EPIPE == errno)
979 scm_close_port (port);
980# endif
981#endif
982 return SCM_UNSPECIFIED;
983}
984
0f2d19dd
JB
985\f
986
bb35f315
MV
987/* Call back to Scheme code to do the printing of special objects
988(like structs). SCM_PRINTER_APPLY applies PROC to EXP and a pair
989containing PORT and PSTATE. This pair can be used as the port for
990display/write etc to continue the current print chain. The REVEALED
991field of PSTATE is set to true to indicate that the print state has
992escaped to Scheme and thus has to be freed by the GC. */
c4f37e80
MV
993
994SCM
995scm_printer_apply (proc, exp, port, pstate)
996 SCM proc, exp, port;
997 scm_print_state *pstate;
998{
bb35f315
MV
999 SCM pair = scm_cons (port, pstate->handle);
1000 pstate->revealed = 1;
1001 return scm_apply (proc, exp, scm_cons (pair, scm_listofnull));
c4f37e80 1002}
bb35f315 1003
c4f37e80 1004\f
1cc91f1b 1005
0f2d19dd
JB
1006void
1007scm_init_print ()
0f2d19dd 1008{
4bfdf158
MD
1009 SCM vtable, layout, printer, type;
1010
b7ff98dd 1011 scm_init_opts (scm_print_options, scm_print_opts, SCM_N_PRINT_OPTIONS);
4bfdf158
MD
1012 vtable = scm_make_vtable_vtable (scm_make_struct_layout (scm_nullstr),
1013 SCM_INUM0,
1014 SCM_EOL);
1015 layout = scm_make_struct_layout (scm_makfrom0str (SCM_PRINT_STATE_LAYOUT));
1016 printer = scm_make_subr_opt (s_print_state_printer,
1017 scm_tc7_subr_2,
1018 (SCM (*) ()) print_state_printer,
1019 0 /* Don't bind the name. */);
1020 type = scm_make_struct (vtable, SCM_INUM0, SCM_LIST2 (layout, printer));
c62fbfe1 1021 print_state_pool = scm_permanent_object (scm_cons (type, SCM_EOL));
c4f37e80 1022
bb35f315 1023 scm_print_state_vtable = type;
c4f37e80 1024
0f2d19dd
JB
1025#include "print.x"
1026}