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