*** empty log message ***
[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 */
c180dfd3 612 SCM name = scm_procedure_name (exp);
56977059
MD
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
c180dfd3
MD
629 case scm_tc7_pws:
630 scm_puts ("#<procedure-with-setter", port);
631 {
632 SCM name = scm_procedure_name (exp);
633 if (SCM_NFALSEP (name))
634 {
635 scm_putc (' ', port);
636 scm_puts (SCM_ROCHARS (name), port);
637 }
638 }
639 scm_putc ('>', port);
640 break;
0f2d19dd 641 case scm_tc7_contin:
b7f3516f 642 scm_puts ("#<continuation ", port);
0f2d19dd 643 scm_intprint (SCM_LENGTH (exp), 10, port);
b7f3516f 644 scm_puts (" @ ", port);
0f2d19dd 645 scm_intprint ((long) SCM_CHARS (exp), 16, port);
b7f3516f 646 scm_putc ('>', port);
0f2d19dd
JB
647 break;
648 case scm_tc7_port:
5ca6dc39
JB
649 {
650 register long i = SCM_PTOBNUM (exp);
651 if (i < scm_numptob
652 && scm_ptobs[i].print
653 && (scm_ptobs[i].print) (exp, port, pstate))
a51ea417 654 break;
5ca6dc39
JB
655 goto punk;
656 }
657 case scm_tc7_smob:
658 {
659 register long i;
660 ENTER_NESTED_DATA (pstate, exp, circref);
661 i = SCM_SMOBNUM (exp);
662 if (i < scm_numsmob && scm_smobs[i].print
663 && (scm_smobs[i].print) (exp, port, pstate))
664 {
665 EXIT_NESTED_DATA (pstate);
666 break;
667 }
668 EXIT_NESTED_DATA (pstate);
669 /* Macros have their print field set to NULL. They are
670 handled at the same place as closures in order to achieve
671 non-redundancy. Placing the condition here won't slow
672 down printing of other smobs. */
673 if (SCM_TYP16 (exp) == scm_tc16_macro)
674 goto macros;
675 }
0f2d19dd 676 default:
a51ea417
MD
677 punk:
678 scm_ipruk ("type", exp, port);
0f2d19dd
JB
679 }
680 }
681}
682
c62fbfe1
MD
683/* Print states are necessary for circular reference safe printing.
684 * They are also expensive to allocate. Therefore print states are
685 * kept in a pool so that they can be reused.
686 */
1cc91f1b 687
bb35f315
MV
688/* The PORT argument can also be a print-state/port pair, which will
689 * then be used instead of allocating a new print state. This is
690 * useful for continuing a chain of print calls from Scheme. */
691
a51ea417 692void
c62fbfe1 693scm_prin1 (exp, port, writingp)
a51ea417
MD
694 SCM exp;
695 SCM port;
c62fbfe1 696 int writingp;
a51ea417 697{
c4f37e80
MV
698 SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
699 SCM pstate_scm;
c62fbfe1
MD
700 scm_print_state *pstate;
701
bb35f315
MV
702 /* If PORT is a print-state/port pair, use that. Else create a new
703 print-state. */
c4f37e80 704
bb35f315
MV
705 if (SCM_NIMP (port) && SCM_CONSP (port))
706 {
707 pstate_scm = SCM_CDR (port);
708 port = SCM_CAR (port);
709 }
710 else
c62fbfe1 711 {
c4f37e80
MV
712 /* First try to allocate a print state from the pool */
713 SCM_DEFER_INTS;
714 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
715 {
716 handle = SCM_CDR (print_state_pool);
717 SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
718 }
719 SCM_ALLOW_INTS;
720 if (handle == SCM_BOOL_F)
721 handle = scm_cons (make_print_state (), SCM_EOL);
722 pstate_scm = SCM_CAR (handle);
c62fbfe1 723 }
c62fbfe1 724
c4f37e80 725 pstate = SCM_PRINT_STATE (pstate_scm);
c62fbfe1
MD
726 pstate->writingp = writingp;
727 scm_iprin1 (exp, port, pstate);
728
bb35f315
MV
729 /* Return print state to pool if it has been created above and
730 hasn't escaped to Scheme. */
731
732 if (handle != SCM_BOOL_F && !pstate->revealed)
c4f37e80
MV
733 {
734 SCM_DEFER_INTS;
735 SCM_SETCDR (handle, SCM_CDR (print_state_pool));
736 SCM_SETCDR (print_state_pool, handle);
737 SCM_ALLOW_INTS;
738 }
a51ea417
MD
739}
740
0f2d19dd
JB
741
742/* Print an integer.
743 */
1cc91f1b 744
0f2d19dd
JB
745void
746scm_intprint (n, radix, port)
747 long n;
748 int radix;
749 SCM port;
0f2d19dd
JB
750{
751 char num_buf[SCM_INTBUFLEN];
b7f3516f 752 scm_lfwrite (num_buf, scm_iint2str (n, radix, num_buf), port);
0f2d19dd
JB
753}
754
755/* Print an object of unrecognized type.
756 */
1cc91f1b 757
0f2d19dd
JB
758void
759scm_ipruk (hdr, ptr, port)
760 char *hdr;
761 SCM ptr;
762 SCM port;
0f2d19dd 763{
b7f3516f
TT
764 scm_puts ("#<unknown-", port);
765 scm_puts (hdr, port);
0f2d19dd
JB
766 if (SCM_CELLP (ptr))
767 {
b7f3516f 768 scm_puts (" (0x", port);
0f2d19dd 769 scm_intprint (SCM_CAR (ptr), 16, port);
b7f3516f 770 scm_puts (" . 0x", port);
0f2d19dd 771 scm_intprint (SCM_CDR (ptr), 16, port);
b7f3516f 772 scm_puts (") @", port);
0f2d19dd 773 }
b7f3516f 774 scm_puts (" 0x", port);
0f2d19dd 775 scm_intprint (ptr, 16, port);
b7f3516f 776 scm_putc ('>', port);
0f2d19dd
JB
777}
778
779/* Print a list.
780 */
a51ea417 781
1cc91f1b 782
0f2d19dd 783void
c62fbfe1 784scm_iprlist (hdr, exp, tlr, port, pstate)
0f2d19dd
JB
785 char *hdr;
786 SCM exp;
805df3e8 787 int tlr;
0f2d19dd 788 SCM port;
c62fbfe1 789 scm_print_state *pstate;
0f2d19dd 790{
c62fbfe1
MD
791 register SCM hare, tortoise;
792 int floor = pstate->top - 2;
b7f3516f 793 scm_puts (hdr, port);
0f2d19dd 794 /* CHECK_INTS; */
c62fbfe1
MD
795 if (pstate->fancyp)
796 goto fancy_printing;
797
798 /* Run a hare and tortoise so that total time complexity will be
799 O(depth * N) instead of O(N^2). */
800 hare = SCM_CDR (exp);
801 tortoise = exp;
2fab3faa 802 while (SCM_NIMP (hare) && SCM_ECONSP (hare))
c62fbfe1
MD
803 {
804 if (hare == tortoise)
805 goto fancy_printing;
806 hare = SCM_CDR (hare);
2fab3faa 807 if (SCM_IMP (hare) || SCM_NECONSP (hare))
c62fbfe1
MD
808 break;
809 hare = SCM_CDR (hare);
810 tortoise = SCM_CDR (tortoise);
811 }
812
813 /* No cdr cycles intrinsic to this list */
814 scm_iprin1 (SCM_CAR (exp), port, pstate);
0f2d19dd
JB
815 exp = SCM_CDR (exp);
816 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
817 {
5ca6dc39
JB
818 register int i;
819
0f2d19dd
JB
820 if (SCM_NECONSP (exp))
821 break;
c62fbfe1
MD
822 for (i = floor; i >= 0; --i)
823 if (pstate->ref_stack[i] == exp)
824 goto circref;
825 PUSH_REF (pstate, exp);
b7f3516f 826 scm_putc (' ', port);
0f2d19dd 827 /* CHECK_INTS; */
c62fbfe1 828 scm_iprin1 (SCM_CAR (exp), port, pstate);
0f2d19dd
JB
829 }
830 if (SCM_NNULLP (exp))
831 {
b7f3516f 832 scm_puts (" . ", port);
c62fbfe1 833 scm_iprin1 (exp, port, pstate);
0f2d19dd 834 }
c62fbfe1 835
a51ea417 836end:
b7f3516f 837 scm_putc (tlr, port);
c62fbfe1 838 pstate->top = floor + 2;
a51ea417 839 return;
c62fbfe1
MD
840
841fancy_printing:
842 {
843 int n = pstate->length;
844
845 scm_iprin1 (SCM_CAR (exp), port, pstate);
846 exp = SCM_CDR (exp); --n;
847 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
848 {
5ca6dc39
JB
849 register unsigned long i;
850
c62fbfe1
MD
851 if (SCM_NECONSP (exp))
852 break;
853 for (i = 0; i < pstate->top; ++i)
854 if (pstate->ref_stack[i] == exp)
855 goto fancy_circref;
856 if (pstate->fancyp)
857 {
858 if (n == 0)
859 {
b7f3516f 860 scm_puts (" ...", port);
c62fbfe1
MD
861 goto skip_tail;
862 }
863 else
864 --n;
865 }
866 PUSH_REF(pstate, exp);
867 ++pstate->list_offset;
b7f3516f 868 scm_putc (' ', port);
c62fbfe1
MD
869 /* CHECK_INTS; */
870 scm_iprin1 (SCM_CAR (exp), port, pstate);
871 }
872 }
873 if (SCM_NNULLP (exp))
874 {
b7f3516f 875 scm_puts (" . ", port);
c62fbfe1
MD
876 scm_iprin1 (exp, port, pstate);
877 }
878skip_tail:
879 pstate->list_offset -= pstate->top - floor - 2;
a51ea417 880 goto end;
a51ea417 881
c62fbfe1
MD
882fancy_circref:
883 pstate->list_offset -= pstate->top - floor - 2;
884
885circref:
b7f3516f 886 scm_puts (" . ", port);
c62fbfe1
MD
887 print_circref (port, pstate, exp);
888 goto end;
0f2d19dd
JB
889}
890
891\f
892
bb35f315
MV
893int
894scm_valid_oport_value_p (SCM val)
895{
4bfdf158
MD
896 return (SCM_NIMP (val)
897 && (SCM_OPOUTPORTP (val)
898 || (SCM_CONSP (val)
899 && SCM_NIMP (SCM_CAR (val))
900 && SCM_OPOUTPORTP (SCM_CAR (val))
901 && SCM_NIMP (SCM_CDR (val))
902 && SCM_PRINT_STATE_P (SCM_CDR (val)))));
bb35f315
MV
903}
904
0f2d19dd 905SCM_PROC(s_write, "write", 1, 1, 0, scm_write);
1cc91f1b 906
0f2d19dd
JB
907SCM
908scm_write (obj, port)
909 SCM obj;
910 SCM port;
0f2d19dd
JB
911{
912 if (SCM_UNBNDP (port))
913 port = scm_cur_outp;
914 else
bb35f315
MV
915 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
916
a51ea417 917 scm_prin1 (obj, port, 1);
0f2d19dd
JB
918#ifdef HAVE_PIPE
919# ifdef EPIPE
920 if (EPIPE == errno)
921 scm_close_port (port);
922# endif
923#endif
924 return SCM_UNSPECIFIED;
925}
926
927
928SCM_PROC(s_display, "display", 1, 1, 0, scm_display);
1cc91f1b 929
0f2d19dd
JB
930SCM
931scm_display (obj, port)
932 SCM obj;
933 SCM port;
0f2d19dd
JB
934{
935 if (SCM_UNBNDP (port))
936 port = scm_cur_outp;
937 else
bb35f315
MV
938 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
939
a51ea417 940 scm_prin1 (obj, port, 0);
0f2d19dd
JB
941#ifdef HAVE_PIPE
942# ifdef EPIPE
943 if (EPIPE == errno)
944 scm_close_port (port);
945# endif
946#endif
947 return SCM_UNSPECIFIED;
948}
949
950SCM_PROC(s_newline, "newline", 0, 1, 0, scm_newline);
1cc91f1b 951
0f2d19dd
JB
952SCM
953scm_newline (port)
954 SCM port;
0f2d19dd
JB
955{
956 if (SCM_UNBNDP (port))
bb35f315 957 port = scm_cur_outp;
0f2d19dd 958 else
bb35f315
MV
959 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG1, s_newline);
960
0ef4ae82 961 scm_putc ('\n', SCM_COERCE_OUTPORT (port));
0f2d19dd
JB
962#ifdef HAVE_PIPE
963# ifdef EPIPE
964 if (EPIPE == errno)
965 scm_close_port (port);
966 else
967# endif
968#endif
969 if (port == scm_cur_outp)
970 scm_fflush (port);
971 return SCM_UNSPECIFIED;
972}
973
974SCM_PROC(s_write_char, "write-char", 1, 1, 0, scm_write_char);
1cc91f1b 975
0f2d19dd
JB
976SCM
977scm_write_char (chr, port)
978 SCM chr;
979 SCM port;
0f2d19dd
JB
980{
981 if (SCM_UNBNDP (port))
bb35f315 982 port = scm_cur_outp;
0f2d19dd 983 else
bb35f315
MV
984 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write_char);
985
0f2d19dd 986 SCM_ASSERT (SCM_ICHRP (chr), chr, SCM_ARG1, s_write_char);
0ef4ae82 987 scm_putc ((int) SCM_ICHR (chr), SCM_COERCE_OUTPORT (port));
0f2d19dd
JB
988#ifdef HAVE_PIPE
989# ifdef EPIPE
990 if (EPIPE == errno)
991 scm_close_port (port);
992# endif
993#endif
994 return SCM_UNSPECIFIED;
995}
996
0f2d19dd
JB
997\f
998
bb35f315
MV
999/* Call back to Scheme code to do the printing of special objects
1000(like structs). SCM_PRINTER_APPLY applies PROC to EXP and a pair
1001containing PORT and PSTATE. This pair can be used as the port for
1002display/write etc to continue the current print chain. The REVEALED
1003field of PSTATE is set to true to indicate that the print state has
1004escaped to Scheme and thus has to be freed by the GC. */
c4f37e80
MV
1005
1006SCM
1007scm_printer_apply (proc, exp, port, pstate)
1008 SCM proc, exp, port;
1009 scm_print_state *pstate;
1010{
bb35f315
MV
1011 SCM pair = scm_cons (port, pstate->handle);
1012 pstate->revealed = 1;
1013 return scm_apply (proc, exp, scm_cons (pair, scm_listofnull));
c4f37e80 1014}
bb35f315 1015
c4f37e80 1016\f
1cc91f1b 1017
0f2d19dd
JB
1018void
1019scm_init_print ()
0f2d19dd 1020{
4bfdf158
MD
1021 SCM vtable, layout, printer, type;
1022
b7ff98dd 1023 scm_init_opts (scm_print_options, scm_print_opts, SCM_N_PRINT_OPTIONS);
4bfdf158
MD
1024 vtable = scm_make_vtable_vtable (scm_make_struct_layout (scm_nullstr),
1025 SCM_INUM0,
1026 SCM_EOL);
1027 layout = scm_make_struct_layout (scm_makfrom0str (SCM_PRINT_STATE_LAYOUT));
1028 printer = scm_make_subr_opt (s_print_state_printer,
1029 scm_tc7_subr_2,
1030 (SCM (*) ()) print_state_printer,
1031 0 /* Don't bind the name. */);
1032 type = scm_make_struct (vtable, SCM_INUM0, SCM_LIST2 (layout, printer));
c62fbfe1 1033 print_state_pool = scm_permanent_object (scm_cons (type, SCM_EOL));
c4f37e80 1034
bb35f315 1035 scm_print_state_vtable = type;
c4f37e80 1036
0f2d19dd
JB
1037#include "print.x"
1038}