(scm_newline, scm_write_char, scm_simple_format): Added texinfo markup.
[bpt/guile.git] / libguile / print.c
1 /* Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
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
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
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.
40 * If you do not wish that, delete this exception notice. */
41
42 /* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
45 \f
46
47 #include <stdio.h>
48 #include "libguile/_scm.h"
49 #include "libguile/chars.h"
50 #include "libguile/continuations.h"
51 #include "libguile/smob.h"
52 #include "libguile/eval.h"
53 #include "libguile/macros.h"
54 #include "libguile/procprop.h"
55 #include "libguile/read.h"
56 #include "libguile/weaks.h"
57 #include "libguile/unif.h"
58 #include "libguile/alist.h"
59 #include "libguile/struct.h"
60 #include "libguile/objects.h"
61 #include "libguile/ports.h"
62 #include "libguile/root.h"
63 #include "libguile/strings.h"
64 #include "libguile/strports.h"
65 #include "libguile/vectors.h"
66
67 #include "libguile/validate.h"
68 #include "libguile/print.h"
69 \f
70
71 /* {Names of immediate symbols}
72 *
73 * This table must agree with the declarations in scm.h: {Immediate Symbols}.
74 */
75
76 char *scm_isymnames[] =
77 {
78 /* This table must agree with the declarations */
79 "#@and",
80 "#@begin",
81 "#@case",
82 "#@cond",
83 "#@do",
84 "#@if",
85 "#@lambda",
86 "#@let",
87 "#@let*",
88 "#@letrec",
89 "#@or",
90 "#@quote",
91 "#@set!",
92 "#@define",
93 #if 0
94 "#@literal-variable-ref",
95 "#@literal-variable-set!",
96 #endif
97 "#@apply",
98 "#@call-with-current-continuation",
99
100 /* user visible ISYMS */
101 /* other keywords */
102 /* Flags */
103
104 "#f",
105 "#t",
106 "#<undefined>",
107 "#<eof>",
108 "()",
109 "#<unspecified>",
110 "#@dispatch",
111 "#@slot-ref",
112 "#@slot-set!",
113
114 /* Multi-language support */
115
116 "#@nil-cond",
117 "#@nil-ify",
118 "#@t-ify",
119 "#@0-cond",
120 "#@0-ify",
121 "#@1-ify",
122 "#@bind",
123
124 "#@delay",
125
126 "#<unbound>"
127 };
128
129 scm_option scm_print_opts[] = {
130 { SCM_OPTION_SCM, "closure-hook", SCM_UNPACK(SCM_BOOL_F),
131 "Hook for printing closures." },
132 { SCM_OPTION_BOOLEAN, "source", 0,
133 "Print closures with source." }
134 };
135
136 SCM_DEFINE (scm_print_options, "print-options-interface", 0, 1, 0,
137 (SCM setting),
138 "Option interface for the print options. Instead of using\n"
139 "this procedure directly, use the procedures @code{print-enable},\n"
140 "@code{print-disable}, @code{print-set!} and @var{print-options}.")
141 #define FUNC_NAME s_scm_print_options
142 {
143 SCM ans = scm_options (setting,
144 scm_print_opts,
145 SCM_N_PRINT_OPTIONS,
146 FUNC_NAME);
147 return ans;
148 }
149 #undef FUNC_NAME
150
151 \f
152 /* {Printing of Scheme Objects}
153 */
154
155 /* Detection of circular references.
156 *
157 * Due to other constraints in the implementation, this code has bad
158 * time complexity (O (depth * N)), The printer code can be
159 * rewritten to be O(N).
160 */
161 #define PUSH_REF(pstate, obj) \
162 do { \
163 pstate->ref_stack[pstate->top++] = (obj); \
164 if (pstate->top == pstate->ceiling) \
165 grow_ref_stack (pstate); \
166 } while(0)
167
168 #define ENTER_NESTED_DATA(pstate, obj, label) \
169 do { \
170 register unsigned long i; \
171 for (i = 0; i < pstate->top; ++i) \
172 if (SCM_EQ_P (pstate->ref_stack[i], (obj))) \
173 goto label; \
174 if (pstate->fancyp) \
175 { \
176 if (pstate->top - pstate->list_offset >= pstate->level) \
177 { \
178 scm_putc ('#', port); \
179 return; \
180 } \
181 } \
182 PUSH_REF(pstate, obj); \
183 } while(0)
184
185 #define EXIT_NESTED_DATA(pstate) { --pstate->top; }
186
187 SCM scm_print_state_vtable;
188
189 static SCM print_state_pool;
190
191 #ifdef GUILE_DEBUG /* Used for debugging purposes */
192
193 SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0,
194 (),
195 "Return the current-pstate--the `cadr' of the print_state_pool.\n"
196 "`current-pstate' is only included in GUILE_DEBUG builds.")
197 #define FUNC_NAME s_scm_current_pstate
198 {
199 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
200 return SCM_CADR (print_state_pool);
201 else
202 return SCM_BOOL_F;
203 }
204 #undef FUNC_NAME
205
206 #endif
207
208 #define PSTATE_SIZE 50L
209
210 static SCM
211 make_print_state (void)
212 {
213 SCM print_state = scm_make_struct (SCM_CAR (print_state_pool), /* pstate type */
214 SCM_INUM0,
215 SCM_EOL);
216 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
217 pstate->ref_vect = scm_c_make_vector (PSTATE_SIZE, SCM_UNDEFINED);
218 pstate->ref_stack = SCM_VELTS (pstate->ref_vect);
219 pstate->ceiling = SCM_VECTOR_LENGTH (pstate->ref_vect);
220 return print_state;
221 }
222
223 SCM
224 scm_make_print_state ()
225 {
226 SCM answer = SCM_BOOL_F;
227
228 /* First try to allocate a print state from the pool */
229 SCM_DEFER_INTS;
230 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
231 {
232 answer = SCM_CADR (print_state_pool);
233 SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
234 }
235 SCM_ALLOW_INTS;
236
237 return SCM_FALSEP (answer) ? make_print_state () : answer;
238 }
239
240 void
241 scm_free_print_state (SCM print_state)
242 {
243 SCM handle;
244 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
245 /* Cleanup before returning print state to pool.
246 * It is better to do it here. Doing it in scm_prin1
247 * would cost more since that function is called much more
248 * often.
249 */
250 pstate->fancyp = 0;
251 pstate->revealed = 0;
252 SCM_NEWCELL (handle);
253 SCM_DEFER_INTS;
254 SCM_SETCAR (handle, print_state);
255 SCM_SETCDR (handle, SCM_CDR (print_state_pool));
256 SCM_SETCDR (print_state_pool, handle);
257 SCM_ALLOW_INTS;
258 }
259
260 static void
261 grow_ref_stack (scm_print_state *pstate)
262 {
263 unsigned long int old_size = SCM_VECTOR_LENGTH (pstate->ref_vect);
264 SCM *old_elts = SCM_VELTS (pstate->ref_vect);
265 unsigned long int new_size = 2 * pstate->ceiling;
266 SCM new_vect = scm_c_make_vector (new_size, SCM_UNDEFINED);
267 SCM *new_elts = SCM_VELTS (new_vect);
268 unsigned long int i;
269
270 for (i = 0; i != old_size; ++i)
271 new_elts [i] = old_elts [i];
272
273 pstate->ref_vect = new_vect;
274 pstate->ref_stack = new_elts;
275 pstate->ceiling = new_size;
276 }
277
278
279 static void
280 print_circref (SCM port,scm_print_state *pstate,SCM ref)
281 {
282 register int i;
283 int self = pstate->top - 1;
284 i = pstate->top - 1;
285 if (SCM_CONSP (pstate->ref_stack[i]))
286 {
287 while (i > 0)
288 {
289 if (SCM_NCONSP (pstate->ref_stack[i - 1])
290 || !SCM_EQ_P (SCM_CDR (pstate->ref_stack[i - 1]),
291 pstate->ref_stack[i]))
292 break;
293 --i;
294 }
295 self = i;
296 }
297 for (i = pstate->top - 1; 1; --i)
298 if (SCM_EQ_P (pstate->ref_stack[i], ref))
299 break;
300 scm_putc ('#', port);
301 scm_intprint (i - self, 10, port);
302 scm_putc ('#', port);
303 }
304
305 /* Print generally. Handles both write and display according to PSTATE.
306 */
307 SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write);
308 SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display);
309
310 void
311 scm_iprin1 (SCM exp, SCM port, scm_print_state *pstate)
312 {
313 taloop:
314 switch (SCM_ITAG3 (exp))
315 {
316 case scm_tc3_closure:
317 case scm_tc3_tc7_1:
318 case scm_tc3_tc7_2:
319 /* These tc3 tags should never occur in an immediate value. They are
320 * only used in cell types of non-immediates, i. e. the value returned
321 * by SCM_CELL_TYPE (exp) can use these tags.
322 */
323 scm_ipruk ("immediate", exp, port);
324 break;
325 case scm_tc3_int_1:
326 case scm_tc3_int_2:
327 scm_intprint (SCM_INUM (exp), 10, port);
328 break;
329 case scm_tc3_imm24:
330 if (SCM_CHARP (exp))
331 {
332 long i = SCM_CHAR (exp);
333
334 if (SCM_WRITINGP (pstate))
335 {
336 scm_puts ("#\\", port);
337 if ((i >= 0) && (i <= ' ') && scm_charnames[i])
338 scm_puts (scm_charnames[i], port);
339 #ifndef EBCDIC
340 else if (i == '\177')
341 scm_puts (scm_charnames[scm_n_charnames - 1], port);
342 #endif
343 else if (i < 0 || i > '\177')
344 scm_intprint (i, 8, port);
345 else
346 scm_putc (i, port);
347 }
348 else
349 scm_putc (i, port);
350 }
351 else if (SCM_IFLAGP (exp)
352 && ((size_t) SCM_ISYMNUM (exp) < (sizeof scm_isymnames / sizeof (char *))))
353 scm_puts (SCM_ISYMCHARS (exp), port);
354 else if (SCM_ILOCP (exp))
355 {
356 scm_puts ("#@", port);
357 scm_intprint (SCM_IFRAME (exp), 10, port);
358 scm_putc (SCM_ICDRP (exp) ? '-' : '+', port);
359 scm_intprint (SCM_IDIST (exp), 10, port);
360 }
361 else
362 {
363 /* unknown immediate value */
364 scm_ipruk ("immediate", exp, port);
365 }
366 break;
367 case scm_tc3_cons_gloc:
368 /* gloc */
369 scm_puts ("#@", port);
370 exp = SCM_GLOC_SYM (exp);
371 goto taloop;
372 case scm_tc3_cons:
373 switch (SCM_TYP7 (exp))
374 {
375 case scm_tcs_cons_gloc:
376
377 if (SCM_STRUCT_VTABLE_DATA (exp) [scm_vtable_index_vcell] == 0)
378 {
379 ENTER_NESTED_DATA (pstate, exp, circref);
380 if (SCM_OBJ_CLASS_FLAGS (exp) & SCM_CLASSF_GOOPS)
381 {
382 SCM pwps, print = pstate->writingp ? g_write : g_display;
383 if (!print)
384 goto print_struct;
385 SCM_NEWSMOB (pwps,
386 scm_tc16_port_with_ps,
387 SCM_UNPACK (scm_cons (port, pstate->handle)));
388 scm_call_generic_2 (print, exp, pwps);
389 }
390 else
391 {
392 print_struct:
393 scm_print_struct (exp, port, pstate);
394 }
395 EXIT_NESTED_DATA (pstate);
396 break;
397 }
398
399 case scm_tcs_cons_imcar:
400 case scm_tcs_cons_nimcar:
401 ENTER_NESTED_DATA (pstate, exp, circref);
402 scm_iprlist ("(", exp, ')', port, pstate);
403 EXIT_NESTED_DATA (pstate);
404 break;
405 circref:
406 print_circref (port, pstate, exp);
407 break;
408 macros:
409 if (!SCM_CLOSUREP (SCM_CDR (exp)))
410 goto prinmacro;
411 case scm_tcs_closures:
412 /* The user supplied print closure procedure must handle
413 macro closures as well. */
414 if (SCM_FALSEP (scm_procedure_p (SCM_PRINT_CLOSURE))
415 || SCM_FALSEP (scm_printer_apply (SCM_PRINT_CLOSURE,
416 exp, port, pstate)))
417 {
418 SCM name, code, env;
419 if (SCM_TYP16 (exp) == scm_tc16_macro)
420 {
421 /* Printing a macro. */
422 prinmacro:
423 name = scm_macro_name (exp);
424 if (!SCM_CLOSUREP (SCM_CDR (exp)))
425 {
426 code = env = SCM_UNDEFINED;
427 scm_puts ("#<primitive-", port);
428 }
429 else
430 {
431 code = SCM_CODE (SCM_CDR (exp));
432 env = SCM_ENV (SCM_CDR (exp));
433 scm_puts ("#<", port);
434 }
435 if (SCM_CELL_WORD_0 (exp) & (3L << 16))
436 scm_puts ("macro", port);
437 else
438 scm_puts ("syntax", port);
439 if (SCM_CELL_WORD_0 (exp) & (2L << 16))
440 scm_putc ('!', port);
441 }
442 else
443 {
444 /* Printing a closure. */
445 name = scm_procedure_name (exp);
446 code = SCM_CODE (exp);
447 env = SCM_ENV (exp);
448 scm_puts ("#<procedure", port);
449 }
450 if (SCM_SYMBOLP (name))
451 {
452 scm_putc (' ', port);
453 scm_lfwrite (SCM_SYMBOL_CHARS (name), SCM_SYMBOL_LENGTH (name), port);
454 }
455 else if (SCM_STRINGP (name))
456 {
457 scm_putc (' ', port);
458 scm_lfwrite (SCM_STRING_CHARS (name), SCM_STRING_LENGTH (name), port);
459 }
460 if (!SCM_UNBNDP (code))
461 {
462 if (SCM_PRINT_SOURCE_P)
463 {
464 code = scm_unmemocopy (code,
465 SCM_EXTEND_ENV (SCM_CAR (code),
466 SCM_EOL,
467 env));
468 ENTER_NESTED_DATA (pstate, exp, circref);
469 scm_iprlist (" ", code, '>', port, pstate);
470 EXIT_NESTED_DATA (pstate);
471 }
472 else
473 {
474 if (SCM_TYP16 (exp) != scm_tc16_macro)
475 {
476 scm_putc (' ', port);
477 scm_iprin1 (SCM_CAR (code), port, pstate);
478 }
479 scm_putc ('>', port);
480 }
481 }
482 else
483 scm_putc ('>', port);
484 }
485 break;
486 case scm_tc7_substring:
487 case scm_tc7_string:
488 if (SCM_WRITINGP (pstate))
489 {
490 scm_sizet i;
491
492 scm_putc ('"', port);
493 for (i = 0; i < SCM_STRING_LENGTH (exp); ++i)
494 switch (SCM_STRING_CHARS (exp)[i])
495 {
496 case '"':
497 case '\\':
498 scm_putc ('\\', port);
499 default:
500 scm_putc (SCM_STRING_CHARS (exp)[i], port);
501 }
502 scm_putc ('"', port);
503 break;
504 }
505 else
506 scm_lfwrite (SCM_STRING_CHARS (exp), SCM_STRING_LENGTH (exp), port);
507 break;
508 case scm_tc7_symbol:
509 {
510 int pos;
511 int end;
512 int len;
513 char * str;
514 int weird;
515 int maybe_weird;
516 int mw_pos = 0;
517
518 len = SCM_SYMBOL_LENGTH (exp);
519 str = SCM_SYMBOL_CHARS (exp);
520 pos = 0;
521 weird = 0;
522 maybe_weird = 0;
523
524 if (len == 0)
525 scm_lfwrite ("#{}#", 4, port);
526
527 for (end = pos; end < len; ++end)
528 switch (str[end])
529 {
530 #ifdef BRACKETS_AS_PARENS
531 case '[':
532 case ']':
533 #endif
534 case '(':
535 case ')':
536 case '"':
537 case ';':
538 case SCM_WHITE_SPACES:
539 case SCM_LINE_INCREMENTORS:
540 weird_handler:
541 if (maybe_weird)
542 {
543 end = mw_pos;
544 maybe_weird = 0;
545 }
546 if (!weird)
547 {
548 scm_lfwrite ("#{", 2, port);
549 weird = 1;
550 }
551 if (pos < end)
552 {
553 scm_lfwrite (str + pos, end - pos, port);
554 }
555 {
556 char buf[2];
557 buf[0] = '\\';
558 buf[1] = str[end];
559 scm_lfwrite (buf, 2, port);
560 }
561 pos = end + 1;
562 break;
563 case '\\':
564 if (weird)
565 goto weird_handler;
566 if (!maybe_weird)
567 {
568 maybe_weird = 1;
569 mw_pos = pos;
570 }
571 break;
572 case '}':
573 case '#':
574 if (weird)
575 goto weird_handler;
576 break;
577 default:
578 break;
579 }
580 if (pos < end)
581 scm_lfwrite (str + pos, end - pos, port);
582 scm_remember_upto_here_1 (exp);
583 if (weird)
584 scm_lfwrite ("}#", 2, port);
585 break;
586 }
587 case scm_tc7_wvect:
588 ENTER_NESTED_DATA (pstate, exp, circref);
589 if (SCM_IS_WHVEC (exp))
590 scm_puts ("#wh(", port);
591 else
592 scm_puts ("#w(", port);
593 goto common_vector_printer;
594
595 case scm_tc7_vector:
596 ENTER_NESTED_DATA (pstate, exp, circref);
597 scm_puts ("#(", port);
598 common_vector_printer:
599 {
600 register long i;
601 int last = SCM_VECTOR_LENGTH (exp) - 1;
602 int cutp = 0;
603 if (pstate->fancyp && SCM_VECTOR_LENGTH (exp) > pstate->length)
604 {
605 last = pstate->length - 1;
606 cutp = 1;
607 }
608 for (i = 0; i < last; ++i)
609 {
610 /* CHECK_INTS; */
611 scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
612 scm_putc (' ', port);
613 }
614 if (i == last)
615 {
616 /* CHECK_INTS; */
617 scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
618 }
619 if (cutp)
620 scm_puts (" ...", port);
621 scm_putc (')', port);
622 }
623 EXIT_NESTED_DATA (pstate);
624 break;
625 #ifdef HAVE_ARRAYS
626 case scm_tc7_bvect:
627 case scm_tc7_byvect:
628 case scm_tc7_svect:
629 case scm_tc7_ivect:
630 case scm_tc7_uvect:
631 case scm_tc7_fvect:
632 case scm_tc7_dvect:
633 case scm_tc7_cvect:
634 #ifdef HAVE_LONG_LONGS
635 case scm_tc7_llvect:
636 #endif
637 scm_raprin1 (exp, port, pstate);
638 break;
639 #endif
640 case scm_tcs_subrs:
641 scm_puts (SCM_SUBR_GENERIC (exp) && *SCM_SUBR_GENERIC (exp)
642 ? "#<primitive-generic "
643 : "#<primitive-procedure ",
644 port);
645 scm_puts (SCM_SYMBOL_CHARS (SCM_SNAME (exp)), port);
646 scm_putc ('>', port);
647 break;
648 #ifdef CCLO
649 case scm_tc7_cclo:
650 {
651 SCM proc = SCM_CCLO_SUBR (exp);
652 if (SCM_EQ_P (proc, scm_f_gsubr_apply))
653 {
654 /* Print gsubrs as primitives */
655 SCM name = scm_procedure_name (exp);
656 scm_puts ("#<primitive-procedure", port);
657 if (SCM_NFALSEP (name))
658 {
659 scm_putc (' ', port);
660 scm_puts (SCM_SYMBOL_CHARS (name), port);
661 }
662 }
663 else
664 {
665 scm_puts ("#<compiled-closure ", port);
666 scm_iprin1 (proc, port, pstate);
667 }
668 scm_putc ('>', port);
669 }
670 break;
671 #endif
672 case scm_tc7_pws:
673 scm_puts ("#<procedure-with-setter", port);
674 {
675 SCM name = scm_procedure_name (exp);
676 if (SCM_NFALSEP (name))
677 {
678 scm_putc (' ', port);
679 scm_display (name, port);
680 }
681 }
682 scm_putc ('>', port);
683 break;
684 case scm_tc7_port:
685 {
686 register long i = SCM_PTOBNUM (exp);
687 if (i < scm_numptob
688 && scm_ptobs[i].print
689 && (scm_ptobs[i].print) (exp, port, pstate))
690 break;
691 goto punk;
692 }
693 case scm_tc7_smob:
694 {
695 register long i;
696 ENTER_NESTED_DATA (pstate, exp, circref);
697 i = SCM_SMOBNUM (exp);
698 if (i < scm_numsmob && scm_smobs[i].print
699 && (scm_smobs[i].print) (exp, port, pstate))
700 {
701 EXIT_NESTED_DATA (pstate);
702 break;
703 }
704 EXIT_NESTED_DATA (pstate);
705 /* Macros have their print field set to NULL. They are
706 handled at the same place as closures in order to achieve
707 non-redundancy. Placing the condition here won't slow
708 down printing of other smobs. */
709 if (SCM_TYP16 (exp) == scm_tc16_macro)
710 goto macros;
711 }
712 default:
713 punk:
714 scm_ipruk ("type", exp, port);
715 }
716 }
717 }
718
719 /* Print states are necessary for circular reference safe printing.
720 * They are also expensive to allocate. Therefore print states are
721 * kept in a pool so that they can be reused.
722 */
723
724 /* The PORT argument can also be a print-state/port pair, which will
725 * then be used instead of allocating a new print state. This is
726 * useful for continuing a chain of print calls from Scheme. */
727
728 void
729 scm_prin1 (SCM exp, SCM port, int writingp)
730 {
731 SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
732 SCM pstate_scm;
733 scm_print_state *pstate;
734
735 /* If PORT is a print-state/port pair, use that. Else create a new
736 print-state. */
737
738 if (SCM_PORT_WITH_PS_P (port))
739 {
740 pstate_scm = SCM_PORT_WITH_PS_PS (port);
741 port = SCM_PORT_WITH_PS_PORT (port);
742 }
743 else
744 {
745 /* First try to allocate a print state from the pool */
746 SCM_DEFER_INTS;
747 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
748 {
749 handle = SCM_CDR (print_state_pool);
750 SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
751 }
752 SCM_ALLOW_INTS;
753 if (SCM_FALSEP (handle))
754 handle = scm_cons (make_print_state (), SCM_EOL);
755 pstate_scm = SCM_CAR (handle);
756 }
757
758 pstate = SCM_PRINT_STATE (pstate_scm);
759 pstate->writingp = writingp;
760 scm_iprin1 (exp, port, pstate);
761
762 /* Return print state to pool if it has been created above and
763 hasn't escaped to Scheme. */
764
765 if (!SCM_FALSEP (handle) && !pstate->revealed)
766 {
767 SCM_DEFER_INTS;
768 SCM_SETCDR (handle, SCM_CDR (print_state_pool));
769 SCM_SETCDR (print_state_pool, handle);
770 SCM_ALLOW_INTS;
771 }
772 }
773
774
775 /* Print an integer.
776 */
777
778 void
779 scm_intprint (long n, int radix, SCM port)
780 {
781 char num_buf[SCM_INTBUFLEN];
782 scm_lfwrite (num_buf, scm_iint2str (n, radix, num_buf), port);
783 }
784
785 /* Print an object of unrecognized type.
786 */
787
788 void
789 scm_ipruk (char *hdr, SCM ptr, SCM port)
790 {
791 scm_puts ("#<unknown-", port);
792 scm_puts (hdr, port);
793 if (SCM_CELLP (ptr))
794 {
795 scm_puts (" (0x", port);
796 scm_intprint (SCM_CELL_WORD_0 (ptr), 16, port);
797 scm_puts (" . 0x", port);
798 scm_intprint (SCM_CELL_WORD_1 (ptr), 16, port);
799 scm_puts (") @", port);
800 }
801 scm_puts (" 0x", port);
802 scm_intprint (SCM_UNPACK (ptr), 16, port);
803 scm_putc ('>', port);
804 }
805
806 /* Print a list.
807 */
808
809
810 void
811 scm_iprlist (char *hdr,SCM exp,int tlr,SCM port,scm_print_state *pstate)
812 {
813 register SCM hare, tortoise;
814 int floor = pstate->top - 2;
815 scm_puts (hdr, port);
816 /* CHECK_INTS; */
817 if (pstate->fancyp)
818 goto fancy_printing;
819
820 /* Run a hare and tortoise so that total time complexity will be
821 O(depth * N) instead of O(N^2). */
822 hare = SCM_CDR (exp);
823 tortoise = exp;
824 while (SCM_ECONSP (hare))
825 {
826 if (SCM_EQ_P (hare, tortoise))
827 goto fancy_printing;
828 hare = SCM_CDR (hare);
829 if (SCM_IMP (hare) || SCM_NECONSP (hare))
830 break;
831 hare = SCM_CDR (hare);
832 tortoise = SCM_CDR (tortoise);
833 }
834
835 /* No cdr cycles intrinsic to this list */
836 scm_iprin1 (SCM_CAR (exp), port, pstate);
837 exp = SCM_CDR (exp);
838 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
839 {
840 register int i;
841
842 if (SCM_NECONSP (exp))
843 break;
844 for (i = floor; i >= 0; --i)
845 if (SCM_EQ_P (pstate->ref_stack[i], exp))
846 goto circref;
847 PUSH_REF (pstate, exp);
848 scm_putc (' ', port);
849 /* CHECK_INTS; */
850 scm_iprin1 (SCM_CAR (exp), port, pstate);
851 }
852 if (SCM_NNULLP (exp))
853 {
854 scm_puts (" . ", port);
855 scm_iprin1 (exp, port, pstate);
856 }
857
858 end:
859 scm_putc (tlr, port);
860 pstate->top = floor + 2;
861 return;
862
863 fancy_printing:
864 {
865 int n = pstate->length;
866
867 scm_iprin1 (SCM_CAR (exp), port, pstate);
868 exp = SCM_CDR (exp); --n;
869 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
870 {
871 register unsigned long i;
872
873 if (SCM_NECONSP (exp))
874 break;
875 for (i = 0; i < pstate->top; ++i)
876 if (SCM_EQ_P (pstate->ref_stack[i], exp))
877 goto fancy_circref;
878 if (pstate->fancyp)
879 {
880 if (n == 0)
881 {
882 scm_puts (" ...", port);
883 goto skip_tail;
884 }
885 else
886 --n;
887 }
888 PUSH_REF(pstate, exp);
889 ++pstate->list_offset;
890 scm_putc (' ', port);
891 /* CHECK_INTS; */
892 scm_iprin1 (SCM_CAR (exp), port, pstate);
893 }
894 }
895 if (SCM_NNULLP (exp))
896 {
897 scm_puts (" . ", port);
898 scm_iprin1 (exp, port, pstate);
899 }
900 skip_tail:
901 pstate->list_offset -= pstate->top - floor - 2;
902 goto end;
903
904 fancy_circref:
905 pstate->list_offset -= pstate->top - floor - 2;
906
907 circref:
908 scm_puts (" . ", port);
909 print_circref (port, pstate, exp);
910 goto end;
911 }
912
913 \f
914
915 int
916 scm_valid_oport_value_p (SCM val)
917 {
918 return (SCM_OPOUTPORTP (val)
919 || (SCM_PORT_WITH_PS_P (val)
920 && SCM_OPOUTPORTP (SCM_PORT_WITH_PS_PORT (val))));
921 }
922
923 /* SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write); */
924
925 SCM
926 scm_write (SCM obj, SCM port)
927 {
928 if (SCM_UNBNDP (port))
929 port = scm_cur_outp;
930
931 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
932
933 scm_prin1 (obj, port, 1);
934 #ifdef HAVE_PIPE
935 # ifdef EPIPE
936 if (EPIPE == errno)
937 scm_close_port (port);
938 # endif
939 #endif
940 return SCM_UNSPECIFIED;
941 }
942
943
944 /* SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display); */
945
946 SCM
947 scm_display (SCM obj, SCM port)
948 {
949 if (SCM_UNBNDP (port))
950 port = scm_cur_outp;
951
952 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
953
954 scm_prin1 (obj, port, 0);
955 #ifdef HAVE_PIPE
956 # ifdef EPIPE
957 if (EPIPE == errno)
958 scm_close_port (port);
959 # endif
960 #endif
961 return SCM_UNSPECIFIED;
962 }
963
964
965 SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
966 (SCM destination, SCM message, SCM args),
967 "Write @var{message} to @var{destination}, defaulting to\n"
968 "the current output port.\n"
969 "@var{message} can contain @code{~A} (was @code{%s}) and\n"
970 "@code{~S} (was @code{%S}) escapes. When printed,\n"
971 "the escapes are replaced with corresponding members of\n"
972 "@var{ARGS}:\n"
973 "@code{~A} formats using @code{display} and @code{~S} formats\n"
974 "using @code{write}.\n"
975 "If @var{destination} is @code{#t}, then use the current output\n"
976 "port, if @var{destination} is @code{#f}, then return a string\n"
977 "containing the formatted text. Does not add a trailing newline.")
978 #define FUNC_NAME s_scm_simple_format
979 {
980 SCM answer = SCM_UNSPECIFIED;
981 int fReturnString = 0;
982 int writingp;
983 char *start;
984 char *end;
985 char *p;
986
987 if (SCM_EQ_P (destination, SCM_BOOL_T))
988 {
989 destination = scm_cur_outp;
990 }
991 else if (SCM_FALSEP (destination))
992 {
993 fReturnString = 1;
994 destination = scm_mkstrport (SCM_INUM0,
995 scm_make_string (SCM_INUM0, SCM_UNDEFINED),
996 SCM_OPN | SCM_WRTNG,
997 FUNC_NAME);
998 }
999 else
1000 {
1001 SCM_VALIDATE_OPORT_VALUE (1, destination);
1002 destination = SCM_COERCE_OUTPORT (destination);
1003 }
1004 SCM_VALIDATE_STRING (2, message);
1005 SCM_VALIDATE_REST_ARGUMENT (args);
1006
1007 start = SCM_STRING_CHARS (message);
1008 end = start + SCM_STRING_LENGTH (message);
1009 for (p = start; p != end; ++p)
1010 if (*p == '~')
1011 {
1012 if (!SCM_CONSP (args))
1013 continue;
1014
1015 if (++p == end)
1016 continue;
1017
1018 if (*p == 'A' || *p == 'a')
1019 writingp = 0;
1020 else if (*p == 'S' || *p == 's')
1021 writingp = 1;
1022 else
1023 continue;
1024
1025 scm_lfwrite (start, p - start - 1, destination);
1026 scm_prin1 (SCM_CAR (args), destination, writingp);
1027 args = SCM_CDR (args);
1028 start = p + 1;
1029 }
1030 scm_lfwrite (start, p - start, destination);
1031
1032 if (fReturnString)
1033 answer = scm_strport_to_string (destination);
1034
1035 return scm_return_first (answer, message);
1036 }
1037 #undef FUNC_NAME
1038
1039
1040 SCM_DEFINE (scm_newline, "newline", 0, 1, 0,
1041 (SCM port),
1042 "Send a newline to @var{port}.")
1043 #define FUNC_NAME s_scm_newline
1044 {
1045 if (SCM_UNBNDP (port))
1046 port = scm_cur_outp;
1047
1048 SCM_VALIDATE_OPORT_VALUE (1,port);
1049
1050 scm_putc ('\n', SCM_COERCE_OUTPORT (port));
1051 return SCM_UNSPECIFIED;
1052 }
1053 #undef FUNC_NAME
1054
1055 SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
1056 (SCM chr, SCM port),
1057 "Send character @var{chr} to @var{port}.")
1058 #define FUNC_NAME s_scm_write_char
1059 {
1060 if (SCM_UNBNDP (port))
1061 port = scm_cur_outp;
1062
1063 SCM_VALIDATE_CHAR (1,chr);
1064 SCM_VALIDATE_OPORT_VALUE (2,port);
1065
1066 scm_putc ((int) SCM_CHAR (chr), SCM_COERCE_OUTPORT (port));
1067 #ifdef HAVE_PIPE
1068 # ifdef EPIPE
1069 if (EPIPE == errno)
1070 scm_close_port (port);
1071 # endif
1072 #endif
1073 return SCM_UNSPECIFIED;
1074 }
1075 #undef FUNC_NAME
1076
1077 \f
1078
1079 /* Call back to Scheme code to do the printing of special objects
1080 * (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a smob
1081 * containing PORT and PSTATE. This object can be used as the port for
1082 * display/write etc to continue the current print chain. The REVEALED
1083 * field of PSTATE is set to true to indicate that the print state has
1084 * escaped to Scheme and thus has to be freed by the GC.
1085 */
1086
1087 scm_bits_t scm_tc16_port_with_ps;
1088
1089 /* Print exactly as the port itself would */
1090
1091 static int
1092 port_with_ps_print (SCM obj, SCM port, scm_print_state *pstate)
1093 {
1094 obj = SCM_PORT_WITH_PS_PORT (obj);
1095 return scm_ptobs[SCM_PTOBNUM (obj)].print (obj, port, pstate);
1096 }
1097
1098 SCM
1099 scm_printer_apply (SCM proc, SCM exp, SCM port, scm_print_state *pstate)
1100 {
1101 SCM pwps;
1102 SCM pair = scm_cons (port, pstate->handle);
1103 SCM_NEWSMOB (pwps, scm_tc16_port_with_ps, SCM_UNPACK (pair));
1104 pstate->revealed = 1;
1105 return scm_apply (proc, exp, scm_cons (pwps, scm_listofnull));
1106 }
1107
1108 SCM_DEFINE (scm_port_with_print_state, "port-with-print-state", 2, 0, 0,
1109 (SCM port, SCM pstate),
1110 "Create a new port which behaves like @var{port}, but with an\n"
1111 "included print state @var{pstate}.")
1112 #define FUNC_NAME s_scm_port_with_print_state
1113 {
1114 SCM pwps;
1115 SCM_VALIDATE_OPORT_VALUE (1,port);
1116 SCM_VALIDATE_PRINTSTATE (2,pstate);
1117 port = SCM_COERCE_OUTPORT (port);
1118 SCM_NEWSMOB (pwps, scm_tc16_port_with_ps, SCM_UNPACK (scm_cons (port, pstate)));
1119 return pwps;
1120 }
1121 #undef FUNC_NAME
1122
1123 SCM_DEFINE (scm_get_print_state, "get-print-state", 1, 0, 0,
1124 (SCM port),
1125 "Return the print state of the port @var{port}. If @var{port}\n"
1126 "has no associated print state, @code{#f} is returned.")
1127 #define FUNC_NAME s_scm_get_print_state
1128 {
1129 if (SCM_PORT_WITH_PS_P (port))
1130 return SCM_PORT_WITH_PS_PS (port);
1131 if (SCM_OUTPUT_PORT_P (port))
1132 return SCM_BOOL_F;
1133 RETURN_SCM_WTA (1,port);
1134 }
1135 #undef FUNC_NAME
1136
1137 \f
1138
1139 void
1140 scm_init_print ()
1141 {
1142 SCM vtable, layout, type;
1143
1144 scm_init_opts (scm_print_options, scm_print_opts, SCM_N_PRINT_OPTIONS);
1145 vtable = scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
1146 layout = scm_make_struct_layout (scm_makfrom0str (SCM_PRINT_STATE_LAYOUT));
1147 type = scm_make_struct (vtable, SCM_INUM0, SCM_LIST1 (layout));
1148 scm_set_struct_vtable_name_x (type, scm_str2symbol ("print-state"));
1149 print_state_pool = scm_permanent_object (scm_cons (type, SCM_EOL));
1150
1151 scm_print_state_vtable = type;
1152
1153 /* Don't want to bind a wrapper class in GOOPS, so pass 0 as arg1. */
1154 scm_tc16_port_with_ps = scm_make_smob_type (0, 0);
1155 scm_set_smob_mark (scm_tc16_port_with_ps, scm_markcdr);
1156 scm_set_smob_print (scm_tc16_port_with_ps, port_with_ps_print);
1157
1158 #ifndef SCM_MAGIC_SNARFER
1159 #include "libguile/print.x"
1160 #endif
1161 }
1162
1163 /*
1164 Local Variables:
1165 c-file-style: "gnu"
1166 End:
1167 */