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