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