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