*** empty log message ***
[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 {
351 SCM name, code;
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));
366 scm_gen_puts (scm_regular_string, "#<", port);
367 }
368 if (SCM_CAR (exp) & (3L << 16))
369 scm_gen_puts (scm_regular_string, "macro", port);
370 else
371 scm_gen_puts (scm_regular_string, "syntax", port);
372 if (SCM_CAR (exp) & (2L << 16))
373 scm_gen_putc ('!', port);
374 }
375 else
376 {
377 /* Printing a closure. */
378 name = scm_procedure_name (exp);
379 code = SCM_CODE (exp);
380 scm_gen_puts (scm_regular_string, "#<procedure",
381 port);
382 }
383 if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
384 {
385 scm_gen_putc (' ', port);
386 scm_gen_puts (scm_regular_string, SCM_ROCHARS (name), port);
387 }
388 if (code)
389 {
390 scm_gen_putc (' ', port);
391 scm_iprin1 (SCM_CAR (code), port, pstate);
392 }
393 if (code && SCM_PRINT_SOURCE_P)
394 {
395 code = scm_unmemocopy (SCM_CDR (code),
396 SCM_EXTEND_ENV (SCM_CAR (code),
397 SCM_EOL,
398 SCM_ENV (exp)));
399 ENTER_NESTED_DATA (pstate, exp, circref);
400 scm_iprlist (" ", code, '>', port, pstate);
401 EXIT_NESTED_DATA (pstate);
402 }
403 else
404 scm_gen_putc ('>', port);
405 }
0f2d19dd
JB
406 break;
407 case scm_tc7_mb_string:
408 case scm_tc7_mb_substring:
c62fbfe1 409 scm_print_mb_string (exp, port, SCM_WRITINGP (pstate));
0f2d19dd
JB
410 break;
411 case scm_tc7_substring:
412 case scm_tc7_string:
c62fbfe1 413 if (SCM_WRITINGP (pstate))
0f2d19dd 414 {
dbef8851 415 scm_gen_putc ('"', port);
0f2d19dd
JB
416 for (i = 0; i < SCM_ROLENGTH (exp); ++i)
417 switch (SCM_ROCHARS (exp)[i])
418 {
dbef8851 419 case '"':
0f2d19dd
JB
420 case '\\':
421 scm_gen_putc ('\\', port);
422 default:
423 scm_gen_putc (SCM_ROCHARS (exp)[i], port);
424 }
dbef8851 425 scm_gen_putc ('"', port);
0f2d19dd
JB
426 break;
427 }
428 else
429 scm_gen_write (scm_regular_string, SCM_ROCHARS (exp),
430 (scm_sizet) SCM_ROLENGTH (exp),
431 port);
432 break;
433 case scm_tcs_symbols:
434 if (SCM_MB_STRINGP (exp))
435 {
436 scm_print_mb_symbol (exp, port);
437 break;
438 }
439 else
440 {
441 int pos;
442 int end;
443 int len;
444 char * str;
445 int weird;
446 int maybe_weird;
4dc2435a 447 int mw_pos = 0;
0f2d19dd
JB
448
449 len = SCM_LENGTH (exp);
450 str = SCM_CHARS (exp);
451 scm_remember (&exp);
452 pos = 0;
453 weird = 0;
454 maybe_weird = 0;
455
456 if (len == 0)
457 scm_gen_write (scm_regular_string, "#{}#", 4, port);
458
459 for (end = pos; end < len; ++end)
460 switch (str[end])
461 {
462#ifdef BRACKETS_AS_PARENS
463 case '[':
464 case ']':
465#endif
466 case '(':
467 case ')':
dbef8851 468 case '"':
0f2d19dd
JB
469 case ';':
470 case SCM_WHITE_SPACES:
471 case SCM_LINE_INCREMENTORS:
472 weird_handler:
473 if (maybe_weird)
474 {
475 end = mw_pos;
476 maybe_weird = 0;
477 }
478 if (!weird)
479 {
480 scm_gen_write (scm_regular_string, "#{", 2, port);
481 weird = 1;
482 }
483 if (pos < end)
484 {
485 scm_gen_write (scm_regular_string, str + pos, end - pos, port);
486 }
487 {
488 char buf[2];
489 buf[0] = '\\';
490 buf[1] = str[end];
491 scm_gen_write (scm_regular_string, buf, 2, port);
492 }
493 pos = end + 1;
494 break;
495 case '\\':
496 if (weird)
497 goto weird_handler;
498 if (!maybe_weird)
499 {
500 maybe_weird = 1;
501 mw_pos = pos;
502 }
503 break;
504 case '}':
505 case '#':
506 if (weird)
507 goto weird_handler;
508 break;
509 default:
510 break;
511 }
512 if (pos < end)
513 scm_gen_write (scm_regular_string, str + pos, end - pos, port);
514 if (weird)
515 scm_gen_write (scm_regular_string, "}#", 2, port);
516 break;
517 }
518 case scm_tc7_wvect:
c62fbfe1 519 ENTER_NESTED_DATA (pstate, exp, circref);
0f2d19dd
JB
520 if (SCM_IS_WHVEC (exp))
521 scm_gen_puts (scm_regular_string, "#wh(", port);
522 else
523 scm_gen_puts (scm_regular_string, "#w(", port);
524 goto common_vector_printer;
525
526 case scm_tc7_vector:
c62fbfe1 527 ENTER_NESTED_DATA (pstate, exp, circref);
0f2d19dd
JB
528 scm_gen_puts (scm_regular_string, "#(", port);
529 common_vector_printer:
9fbaf27c
MD
530 {
531 int last = SCM_LENGTH (exp) - 1;
532 int cutp = 0;
533 if (pstate->fancyp && SCM_LENGTH (exp) > pstate->length)
534 {
535 last = pstate->length - 1;
536 cutp = 1;
537 }
538 for (i = 0; i < last; ++i)
539 {
540 /* CHECK_INTS; */
541 scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
542 scm_gen_putc (' ', port);
543 }
544 if (i == last)
545 {
546 /* CHECK_INTS; */
547 scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
548 }
549 if (cutp)
550 scm_gen_puts (scm_regular_string, " ...", port);
551 scm_gen_putc (')', port);
552 }
c62fbfe1 553 EXIT_NESTED_DATA (pstate);
0f2d19dd
JB
554 break;
555 case scm_tc7_bvect:
556 case scm_tc7_byvect:
557 case scm_tc7_svect:
558 case scm_tc7_ivect:
559 case scm_tc7_uvect:
560 case scm_tc7_fvect:
561 case scm_tc7_dvect:
562 case scm_tc7_cvect:
563#ifdef LONGLONGS
564 case scm_tc7_llvect:
565#endif
c62fbfe1 566 scm_raprin1 (exp, port, pstate);
0f2d19dd
JB
567 break;
568 case scm_tcs_subrs:
569 scm_gen_puts (scm_regular_string, "#<primitive-procedure ", port);
570 scm_gen_puts ((SCM_MB_STRINGP (SCM_SNAME(exp))
571 ? scm_mb_string
572 : scm_regular_string),
573 SCM_CHARS (SCM_SNAME (exp)), port);
574 scm_gen_putc ('>', port);
575 break;
576#ifdef CCLO
577 case scm_tc7_cclo:
578 scm_gen_puts (scm_regular_string, "#<compiled-closure ", port);
c62fbfe1 579 scm_iprin1 (SCM_CCLO_SUBR (exp), port, pstate);
0f2d19dd
JB
580 scm_gen_putc ('>', port);
581 break;
582#endif
583 case scm_tc7_contin:
584 scm_gen_puts (scm_regular_string, "#<continuation ", port);
585 scm_intprint (SCM_LENGTH (exp), 10, port);
586 scm_gen_puts (scm_regular_string, " @ ", port);
587 scm_intprint ((long) SCM_CHARS (exp), 16, port);
588 scm_gen_putc ('>', port);
589 break;
590 case scm_tc7_port:
591 i = SCM_PTOBNUM (exp);
c62fbfe1
MD
592 if (i < scm_numptob
593 && scm_ptobs[i].print
594 && (scm_ptobs[i].print) (exp, port, pstate))
0f2d19dd
JB
595 break;
596 goto punk;
597 case scm_tc7_smob:
c62fbfe1 598 ENTER_NESTED_DATA (pstate, exp, circref);
0f2d19dd
JB
599 i = SCM_SMOBNUM (exp);
600 if (i < scm_numsmob && scm_smobs[i].print
c62fbfe1 601 && (scm_smobs[i].print) (exp, port, pstate))
a51ea417 602 {
c62fbfe1 603 EXIT_NESTED_DATA (pstate);
a51ea417
MD
604 break;
605 }
c62fbfe1 606 EXIT_NESTED_DATA (pstate);
7332df66
MD
607 /* Macros have their print field set to NULL. They are
608 handled at the same place as closures in order to achieve
609 non-redundancy. Placing the condition here won't slow
610 down printing of other smobs. */
611 if (SCM_TYP16 (exp) == scm_tc16_macro)
612 goto macros;
0f2d19dd 613 default:
a51ea417
MD
614 punk:
615 scm_ipruk ("type", exp, port);
0f2d19dd
JB
616 }
617 }
618}
619
c62fbfe1
MD
620/* Print states are necessary for circular reference safe printing.
621 * They are also expensive to allocate. Therefore print states are
622 * kept in a pool so that they can be reused.
623 */
1cc91f1b 624
bb35f315
MV
625/* The PORT argument can also be a print-state/port pair, which will
626 * then be used instead of allocating a new print state. This is
627 * useful for continuing a chain of print calls from Scheme. */
628
a51ea417 629void
c62fbfe1 630scm_prin1 (exp, port, writingp)
a51ea417
MD
631 SCM exp;
632 SCM port;
c62fbfe1 633 int writingp;
a51ea417 634{
c4f37e80
MV
635 SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
636 SCM pstate_scm;
c62fbfe1
MD
637 scm_print_state *pstate;
638
bb35f315
MV
639 /* If PORT is a print-state/port pair, use that. Else create a new
640 print-state. */
c4f37e80 641
bb35f315
MV
642 if (SCM_NIMP (port) && SCM_CONSP (port))
643 {
644 pstate_scm = SCM_CDR (port);
645 port = SCM_CAR (port);
646 }
647 else
c62fbfe1 648 {
c4f37e80
MV
649 /* First try to allocate a print state from the pool */
650 SCM_DEFER_INTS;
651 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
652 {
653 handle = SCM_CDR (print_state_pool);
654 SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
655 }
656 SCM_ALLOW_INTS;
657 if (handle == SCM_BOOL_F)
658 handle = scm_cons (make_print_state (), SCM_EOL);
659 pstate_scm = SCM_CAR (handle);
c62fbfe1 660 }
c62fbfe1 661
c4f37e80 662 pstate = SCM_PRINT_STATE (pstate_scm);
c62fbfe1
MD
663 pstate->writingp = writingp;
664 scm_iprin1 (exp, port, pstate);
665
bb35f315
MV
666 /* Return print state to pool if it has been created above and
667 hasn't escaped to Scheme. */
668
669 if (handle != SCM_BOOL_F && !pstate->revealed)
c4f37e80
MV
670 {
671 SCM_DEFER_INTS;
672 SCM_SETCDR (handle, SCM_CDR (print_state_pool));
673 SCM_SETCDR (print_state_pool, handle);
674 SCM_ALLOW_INTS;
675 }
a51ea417
MD
676}
677
0f2d19dd
JB
678
679/* Print an integer.
680 */
1cc91f1b 681
0f2d19dd
JB
682void
683scm_intprint (n, radix, port)
684 long n;
685 int radix;
686 SCM port;
0f2d19dd
JB
687{
688 char num_buf[SCM_INTBUFLEN];
689 scm_gen_write (scm_regular_string, num_buf, scm_iint2str (n, radix, num_buf), port);
690}
691
692/* Print an object of unrecognized type.
693 */
1cc91f1b 694
0f2d19dd
JB
695void
696scm_ipruk (hdr, ptr, port)
697 char *hdr;
698 SCM ptr;
699 SCM port;
0f2d19dd
JB
700{
701 scm_gen_puts (scm_regular_string, "#<unknown-", port);
702 scm_gen_puts (scm_regular_string, hdr, port);
703 if (SCM_CELLP (ptr))
704 {
705 scm_gen_puts (scm_regular_string, " (0x", port);
706 scm_intprint (SCM_CAR (ptr), 16, port);
707 scm_gen_puts (scm_regular_string, " . 0x", port);
708 scm_intprint (SCM_CDR (ptr), 16, port);
709 scm_gen_puts (scm_regular_string, ") @", port);
710 }
711 scm_gen_puts (scm_regular_string, " 0x", port);
712 scm_intprint (ptr, 16, port);
713 scm_gen_putc ('>', port);
714}
715
716/* Print a list.
717 */
a51ea417 718
1cc91f1b 719
0f2d19dd 720void
c62fbfe1 721scm_iprlist (hdr, exp, tlr, port, pstate)
0f2d19dd
JB
722 char *hdr;
723 SCM exp;
805df3e8 724 int tlr;
0f2d19dd 725 SCM port;
c62fbfe1 726 scm_print_state *pstate;
0f2d19dd 727{
c62fbfe1
MD
728 register int i;
729 register SCM hare, tortoise;
730 int floor = pstate->top - 2;
0f2d19dd
JB
731 scm_gen_puts (scm_regular_string, hdr, port);
732 /* CHECK_INTS; */
c62fbfe1
MD
733 if (pstate->fancyp)
734 goto fancy_printing;
735
736 /* Run a hare and tortoise so that total time complexity will be
737 O(depth * N) instead of O(N^2). */
738 hare = SCM_CDR (exp);
739 tortoise = exp;
2fab3faa 740 while (SCM_NIMP (hare) && SCM_ECONSP (hare))
c62fbfe1
MD
741 {
742 if (hare == tortoise)
743 goto fancy_printing;
744 hare = SCM_CDR (hare);
2fab3faa 745 if (SCM_IMP (hare) || SCM_NECONSP (hare))
c62fbfe1
MD
746 break;
747 hare = SCM_CDR (hare);
748 tortoise = SCM_CDR (tortoise);
749 }
750
751 /* No cdr cycles intrinsic to this list */
752 scm_iprin1 (SCM_CAR (exp), port, pstate);
0f2d19dd
JB
753 exp = SCM_CDR (exp);
754 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
755 {
756 if (SCM_NECONSP (exp))
757 break;
c62fbfe1
MD
758 for (i = floor; i >= 0; --i)
759 if (pstate->ref_stack[i] == exp)
760 goto circref;
761 PUSH_REF (pstate, exp);
0f2d19dd
JB
762 scm_gen_putc (' ', port);
763 /* CHECK_INTS; */
c62fbfe1 764 scm_iprin1 (SCM_CAR (exp), port, pstate);
0f2d19dd
JB
765 }
766 if (SCM_NNULLP (exp))
767 {
768 scm_gen_puts (scm_regular_string, " . ", port);
c62fbfe1 769 scm_iprin1 (exp, port, pstate);
0f2d19dd 770 }
c62fbfe1 771
a51ea417 772end:
0f2d19dd 773 scm_gen_putc (tlr, port);
c62fbfe1 774 pstate->top = floor + 2;
a51ea417 775 return;
c62fbfe1
MD
776
777fancy_printing:
778 {
779 int n = pstate->length;
780
781 scm_iprin1 (SCM_CAR (exp), port, pstate);
782 exp = SCM_CDR (exp); --n;
783 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
784 {
785 if (SCM_NECONSP (exp))
786 break;
787 for (i = 0; i < pstate->top; ++i)
788 if (pstate->ref_stack[i] == exp)
789 goto fancy_circref;
790 if (pstate->fancyp)
791 {
792 if (n == 0)
793 {
794 scm_gen_puts (scm_regular_string, " ...", port);
795 goto skip_tail;
796 }
797 else
798 --n;
799 }
800 PUSH_REF(pstate, exp);
801 ++pstate->list_offset;
802 scm_gen_putc (' ', port);
803 /* CHECK_INTS; */
804 scm_iprin1 (SCM_CAR (exp), port, pstate);
805 }
806 }
807 if (SCM_NNULLP (exp))
808 {
809 scm_gen_puts (scm_regular_string, " . ", port);
810 scm_iprin1 (exp, port, pstate);
811 }
812skip_tail:
813 pstate->list_offset -= pstate->top - floor - 2;
a51ea417 814 goto end;
a51ea417 815
c62fbfe1
MD
816fancy_circref:
817 pstate->list_offset -= pstate->top - floor - 2;
818
819circref:
820 scm_gen_puts (scm_regular_string, " . ", port);
821 print_circref (port, pstate, exp);
822 goto end;
0f2d19dd
JB
823}
824
825\f
826
bb35f315
MV
827int
828scm_valid_oport_value_p (SCM val)
829{
830 return SCM_NIMP (val) &&
831 (SCM_OPOUTPORTP (val) || (SCM_CONSP (val) && SCM_NIMP (SCM_CAR (val)) &&
832 SCM_OPOUTPORTP (SCM_CAR (val)) &&
833 SCM_PRINT_STATE_P (SCM_CDR (val))));
834}
835
0f2d19dd 836SCM_PROC(s_write, "write", 1, 1, 0, scm_write);
1cc91f1b 837
0f2d19dd
JB
838SCM
839scm_write (obj, port)
840 SCM obj;
841 SCM port;
0f2d19dd
JB
842{
843 if (SCM_UNBNDP (port))
844 port = scm_cur_outp;
845 else
bb35f315
MV
846 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
847
a51ea417 848 scm_prin1 (obj, port, 1);
0f2d19dd
JB
849#ifdef HAVE_PIPE
850# ifdef EPIPE
851 if (EPIPE == errno)
852 scm_close_port (port);
853# endif
854#endif
855 return SCM_UNSPECIFIED;
856}
857
858
859SCM_PROC(s_display, "display", 1, 1, 0, scm_display);
1cc91f1b 860
0f2d19dd
JB
861SCM
862scm_display (obj, port)
863 SCM obj;
864 SCM port;
0f2d19dd
JB
865{
866 if (SCM_UNBNDP (port))
867 port = scm_cur_outp;
868 else
bb35f315
MV
869 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
870
a51ea417 871 scm_prin1 (obj, port, 0);
0f2d19dd
JB
872#ifdef HAVE_PIPE
873# ifdef EPIPE
874 if (EPIPE == errno)
875 scm_close_port (port);
876# endif
877#endif
878 return SCM_UNSPECIFIED;
879}
880
881SCM_PROC(s_newline, "newline", 0, 1, 0, scm_newline);
1cc91f1b 882
0f2d19dd
JB
883SCM
884scm_newline (port)
885 SCM port;
0f2d19dd
JB
886{
887 if (SCM_UNBNDP (port))
bb35f315 888 port = scm_cur_outp;
0f2d19dd 889 else
bb35f315
MV
890 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG1, s_newline);
891
892 scm_gen_putc ('\n', SCM_COERCE_OPORT (port));
0f2d19dd
JB
893#ifdef HAVE_PIPE
894# ifdef EPIPE
895 if (EPIPE == errno)
896 scm_close_port (port);
897 else
898# endif
899#endif
900 if (port == scm_cur_outp)
901 scm_fflush (port);
902 return SCM_UNSPECIFIED;
903}
904
905SCM_PROC(s_write_char, "write-char", 1, 1, 0, scm_write_char);
1cc91f1b 906
0f2d19dd
JB
907SCM
908scm_write_char (chr, port)
909 SCM chr;
910 SCM port;
0f2d19dd
JB
911{
912 if (SCM_UNBNDP (port))
bb35f315 913 port = scm_cur_outp;
0f2d19dd 914 else
bb35f315
MV
915 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write_char);
916
0f2d19dd 917 SCM_ASSERT (SCM_ICHRP (chr), chr, SCM_ARG1, s_write_char);
bb35f315 918 scm_gen_putc ((int) SCM_ICHR (chr), SCM_COERCE_OPORT (port));
0f2d19dd
JB
919#ifdef HAVE_PIPE
920# ifdef EPIPE
921 if (EPIPE == errno)
922 scm_close_port (port);
923# endif
924#endif
925 return SCM_UNSPECIFIED;
926}
927
0f2d19dd
JB
928\f
929
bb35f315
MV
930/* Call back to Scheme code to do the printing of special objects
931(like structs). SCM_PRINTER_APPLY applies PROC to EXP and a pair
932containing PORT and PSTATE. This pair can be used as the port for
933display/write etc to continue the current print chain. The REVEALED
934field of PSTATE is set to true to indicate that the print state has
935escaped to Scheme and thus has to be freed by the GC. */
c4f37e80
MV
936
937SCM
938scm_printer_apply (proc, exp, port, pstate)
939 SCM proc, exp, port;
940 scm_print_state *pstate;
941{
bb35f315
MV
942 SCM pair = scm_cons (port, pstate->handle);
943 pstate->revealed = 1;
944 return scm_apply (proc, exp, scm_cons (pair, scm_listofnull));
c4f37e80 945}
bb35f315 946
c4f37e80 947\f
1cc91f1b 948
0f2d19dd
JB
949void
950scm_init_print ()
0f2d19dd 951{
c62fbfe1 952 SCM vtable, type;
c4f37e80 953
b7ff98dd 954 scm_init_opts (scm_print_options, scm_print_opts, SCM_N_PRINT_OPTIONS);
2dfc85c0 955 vtable = scm_make_vtable_vtable (scm_make_struct_layout (scm_nullstr), SCM_INUM0, SCM_EOL);
c62fbfe1
MD
956 type = scm_make_struct (vtable,
957 SCM_INUM0,
958 scm_cons (scm_make_struct_layout (scm_makfrom0str (SCM_PRINT_STATE_LAYOUT)),
959 SCM_EOL));
960 print_state_pool = scm_permanent_object (scm_cons (type, SCM_EOL));
c4f37e80 961
bb35f315 962 scm_print_state_vtable = type;
c4f37e80 963
0f2d19dd
JB
964#include "print.x"
965}