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