Merge branch 'master' into boehm-demers-weiser-gc
[bpt/guile.git] / libguile / print.c
1 /* Copyright (C) 1995-1999,2000,2001, 2002, 2003, 2004, 2006, 2008 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library 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 GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18
19 \f
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <errno.h>
25
26 #include "libguile/_scm.h"
27 #include "libguile/chars.h"
28 #include "libguile/continuations.h"
29 #include "libguile/smob.h"
30 #include "libguile/eval.h"
31 #include "libguile/macros.h"
32 #include "libguile/procprop.h"
33 #include "libguile/read.h"
34 #include "libguile/weaks.h"
35 #include "libguile/unif.h"
36 #include "libguile/alist.h"
37 #include "libguile/struct.h"
38 #include "libguile/objects.h"
39 #include "libguile/ports.h"
40 #include "libguile/root.h"
41 #include "libguile/strings.h"
42 #include "libguile/strports.h"
43 #include "libguile/vectors.h"
44 #include "libguile/lang.h"
45 #include "libguile/numbers.h"
46
47 #include "libguile/validate.h"
48 #include "libguile/print.h"
49
50 #include "libguile/private-options.h"
51
52 \f
53
54 /* {Names of immediate symbols}
55 *
56 * This table must agree with the declarations in scm.h: {Immediate Symbols}.
57 */
58
59 /* This table must agree with the list of flags in tags.h. */
60 static const char *iflagnames[] =
61 {
62 "#f",
63 "#t",
64 "#<undefined>",
65 "#<eof>",
66 "()",
67 "#<unspecified>",
68
69 /* Unbound slot marker for GOOPS. For internal use in GOOPS only. */
70 "#<unbound>",
71
72 /* Elisp nil value. This is its Scheme name; whenever it's printed in
73 * Elisp, it should appear as the symbol `nil'. */
74 "#nil"
75 };
76
77 SCM_SYMBOL (sym_reader, "reader");
78
79 scm_t_option scm_print_opts[] = {
80 { SCM_OPTION_SCM, "closure-hook", SCM_UNPACK (SCM_BOOL_F),
81 "Hook for printing closures (should handle macros as well)." },
82 { SCM_OPTION_BOOLEAN, "source", 0,
83 "Print closures with source." },
84 { SCM_OPTION_SCM, "highlight-prefix", (unsigned long)SCM_BOOL_F,
85 "The string to print before highlighted values." },
86 { SCM_OPTION_SCM, "highlight-suffix", (unsigned long)SCM_BOOL_F,
87 "The string to print after highlighted values." },
88 { SCM_OPTION_SCM, "quote-keywordish-symbols", (unsigned long)SCM_BOOL_F,
89 "How to print symbols that have a colon as their first or last character. "
90 "The value '#f' does not quote the colons; '#t' quotes them; "
91 "'reader' quotes them when the reader option 'keywords' is not '#f'."
92 },
93 { 0 },
94
95 };
96
97 SCM_DEFINE (scm_print_options, "print-options-interface", 0, 1, 0,
98 (SCM setting),
99 "Option interface for the print options. Instead of using\n"
100 "this procedure directly, use the procedures\n"
101 "@code{print-enable}, @code{print-disable}, @code{print-set!}\n"
102 "and @code{print-options}.")
103 #define FUNC_NAME s_scm_print_options
104 {
105 SCM ans = scm_options (setting,
106 scm_print_opts,
107 FUNC_NAME);
108 return ans;
109 }
110 #undef FUNC_NAME
111
112 \f
113 /* {Printing of Scheme Objects}
114 */
115
116 /* Detection of circular references.
117 *
118 * Due to other constraints in the implementation, this code has bad
119 * time complexity (O (depth * N)), The printer code can be
120 * rewritten to be O(N).
121 */
122 #define PUSH_REF(pstate, obj) \
123 do \
124 { \
125 PSTATE_STACK_SET (pstate, pstate->top, obj); \
126 pstate->top++; \
127 if (pstate->top == pstate->ceiling) \
128 grow_ref_stack (pstate); \
129 } while(0)
130
131 #define ENTER_NESTED_DATA(pstate, obj, label) \
132 do \
133 { \
134 register unsigned long i; \
135 for (i = 0; i < pstate->top; ++i) \
136 if (scm_is_eq (PSTATE_STACK_REF (pstate, i), (obj))) \
137 goto label; \
138 if (pstate->fancyp) \
139 { \
140 if (pstate->top - pstate->list_offset >= pstate->level) \
141 { \
142 scm_putc ('#', port); \
143 return; \
144 } \
145 } \
146 PUSH_REF(pstate, obj); \
147 } while(0)
148
149 #define EXIT_NESTED_DATA(pstate) \
150 do \
151 { \
152 --pstate->top; \
153 PSTATE_STACK_SET (pstate, pstate->top, SCM_UNDEFINED); \
154 } \
155 while (0)
156
157 SCM scm_print_state_vtable = SCM_BOOL_F;
158 static SCM print_state_pool = SCM_EOL;
159 scm_i_pthread_mutex_t print_state_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
160
161 #ifdef GUILE_DEBUG /* Used for debugging purposes */
162
163 SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0,
164 (),
165 "Return the current-pstate -- the car of the\n"
166 "@code{print_state_pool}. @code{current-pstate} is only\n"
167 "included in @code{--enable-guile-debug} builds.")
168 #define FUNC_NAME s_scm_current_pstate
169 {
170 if (!scm_is_null (print_state_pool))
171 return SCM_CAR (print_state_pool);
172 else
173 return SCM_BOOL_F;
174 }
175 #undef FUNC_NAME
176
177 #endif
178
179 #define PSTATE_SIZE 50L
180
181 static SCM
182 make_print_state (void)
183 {
184 SCM print_state
185 = scm_make_struct (scm_print_state_vtable, SCM_INUM0, SCM_EOL);
186 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
187 pstate->ref_vect = scm_c_make_vector (PSTATE_SIZE, SCM_UNDEFINED);
188 pstate->ceiling = SCM_SIMPLE_VECTOR_LENGTH (pstate->ref_vect);
189 pstate->highlight_objects = SCM_EOL;
190 return print_state;
191 }
192
193 SCM
194 scm_make_print_state ()
195 {
196 SCM answer = SCM_BOOL_F;
197
198 /* First try to allocate a print state from the pool */
199 scm_i_pthread_mutex_lock (&print_state_mutex);
200 if (!scm_is_null (print_state_pool))
201 {
202 answer = SCM_CAR (print_state_pool);
203 print_state_pool = SCM_CDR (print_state_pool);
204 }
205 scm_i_pthread_mutex_unlock (&print_state_mutex);
206
207 return scm_is_false (answer) ? make_print_state () : answer;
208 }
209
210 void
211 scm_free_print_state (SCM print_state)
212 {
213 SCM handle;
214 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
215 /* Cleanup before returning print state to pool.
216 * It is better to do it here. Doing it in scm_prin1
217 * would cost more since that function is called much more
218 * often.
219 */
220 pstate->fancyp = 0;
221 pstate->revealed = 0;
222 pstate->highlight_objects = SCM_EOL;
223 scm_i_pthread_mutex_lock (&print_state_mutex);
224 handle = scm_cons (print_state, print_state_pool);
225 print_state_pool = handle;
226 scm_i_pthread_mutex_unlock (&print_state_mutex);
227 }
228
229 SCM
230 scm_i_port_with_print_state (SCM port, SCM print_state)
231 {
232 if (SCM_UNBNDP (print_state))
233 {
234 if (SCM_PORT_WITH_PS_P (port))
235 return port;
236 else
237 print_state = scm_make_print_state ();
238 /* port does not need to be coerced since it doesn't have ps */
239 }
240 else
241 port = SCM_COERCE_OUTPORT (port);
242 SCM_RETURN_NEWSMOB (scm_tc16_port_with_ps,
243 SCM_UNPACK (scm_cons (port, print_state)));
244 }
245
246 static void
247 grow_ref_stack (scm_print_state *pstate)
248 {
249 SCM old_vect = pstate->ref_vect;
250 size_t old_size = SCM_SIMPLE_VECTOR_LENGTH (old_vect);
251 size_t new_size = 2 * pstate->ceiling;
252 SCM new_vect = scm_c_make_vector (new_size, SCM_UNDEFINED);
253 unsigned long int i;
254
255 for (i = 0; i != old_size; ++i)
256 SCM_SIMPLE_VECTOR_SET (new_vect, i, SCM_SIMPLE_VECTOR_REF (old_vect, i));
257
258 pstate->ref_vect = new_vect;
259 pstate->ceiling = new_size;
260 }
261
262 #define PSTATE_STACK_REF(p,i) SCM_SIMPLE_VECTOR_REF((p)->ref_vect, (i))
263 #define PSTATE_STACK_SET(p,i,v) SCM_SIMPLE_VECTOR_SET((p)->ref_vect, (i), (v))
264
265 static void
266 print_circref (SCM port, scm_print_state *pstate, SCM ref)
267 {
268 register long i;
269 long self = pstate->top - 1;
270 i = pstate->top - 1;
271 if (scm_is_pair (PSTATE_STACK_REF (pstate, i)))
272 {
273 while (i > 0)
274 {
275 if (!scm_is_pair (PSTATE_STACK_REF (pstate, i-1))
276 || !scm_is_eq (SCM_CDR (PSTATE_STACK_REF (pstate, i-1)),
277 SCM_CDR (PSTATE_STACK_REF (pstate, i))))
278 break;
279 --i;
280 }
281 self = i;
282 }
283 for (i = pstate->top - 1; 1; --i)
284 if (scm_is_eq (PSTATE_STACK_REF(pstate, i), ref))
285 break;
286 scm_putc ('#', port);
287 scm_intprint (i - self, 10, port);
288 scm_putc ('#', port);
289 }
290
291 /* Print the name of a symbol. */
292
293 static int
294 quote_keywordish_symbol (const char *str, size_t len)
295 {
296 SCM option;
297
298 /* LEN is guaranteed to be > 0.
299 */
300 if (str[0] != ':' && str[len-1] != ':')
301 return 0;
302
303 option = SCM_PRINT_KEYWORD_STYLE;
304 if (scm_is_false (option))
305 return 0;
306 if (scm_is_eq (option, sym_reader))
307 return scm_is_true (SCM_PACK (SCM_KEYWORD_STYLE));
308 return 1;
309 }
310
311 void
312 scm_print_symbol_name (const char *str, size_t len, SCM port)
313 {
314 /* This points to the first character that has not yet been written to the
315 * port. */
316 size_t pos = 0;
317 /* This points to the character we're currently looking at. */
318 size_t end;
319 /* If the name contains weird characters, we'll escape them with
320 * backslashes and set this flag; it indicates that we should surround the
321 * name with "#{" and "}#". */
322 int weird = 0;
323 /* Backslashes are not sufficient to make a name weird, but if a name is
324 * weird because of other characters, backslahes need to be escaped too.
325 * The first time we see a backslash, we set maybe_weird, and mw_pos points
326 * to the backslash. Then if the name turns out to be weird, we re-process
327 * everything starting from mw_pos.
328 * We could instead make backslashes always weird. This is not necessary
329 * to ensure that the output is (read)-able, but it would make this code
330 * simpler and faster. */
331 int maybe_weird = 0;
332 size_t mw_pos = 0;
333
334 if (len == 0 || str[0] == '\'' || str[0] == '`' || str[0] == ','
335 || quote_keywordish_symbol (str, len)
336 || (str[0] == '.' && len == 1)
337 || scm_is_true (scm_c_locale_stringn_to_number (str, len, 10)))
338 {
339 scm_lfwrite ("#{", 2, port);
340 weird = 1;
341 }
342
343 for (end = pos; end < len; ++end)
344 switch (str[end])
345 {
346 #ifdef BRACKETS_AS_PARENS
347 case '[':
348 case ']':
349 #endif
350 case '(':
351 case ')':
352 case '"':
353 case ';':
354 case '#':
355 case SCM_WHITE_SPACES:
356 case SCM_LINE_INCREMENTORS:
357 weird_handler:
358 if (maybe_weird)
359 {
360 end = mw_pos;
361 maybe_weird = 0;
362 }
363 if (!weird)
364 {
365 scm_lfwrite ("#{", 2, port);
366 weird = 1;
367 }
368 if (pos < end)
369 scm_lfwrite (str + pos, end - pos, port);
370 {
371 char buf[2];
372 buf[0] = '\\';
373 buf[1] = str[end];
374 scm_lfwrite (buf, 2, port);
375 }
376 pos = end + 1;
377 break;
378 case '\\':
379 if (weird)
380 goto weird_handler;
381 if (!maybe_weird)
382 {
383 maybe_weird = 1;
384 mw_pos = pos;
385 }
386 break;
387 default:
388 break;
389 }
390 if (pos < end)
391 scm_lfwrite (str + pos, end - pos, port);
392 if (weird)
393 scm_lfwrite ("}#", 2, port);
394 }
395
396 /* Print generally. Handles both write and display according to PSTATE.
397 */
398 SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write);
399 SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display);
400
401 static void iprin1 (SCM exp, SCM port, scm_print_state *pstate);
402
403 void
404 scm_iprin1 (SCM exp, SCM port, scm_print_state *pstate)
405 {
406 if (pstate->fancyp
407 && scm_is_true (scm_memq (exp, pstate->highlight_objects)))
408 {
409 scm_display (SCM_PRINT_HIGHLIGHT_PREFIX, port);
410 iprin1 (exp, port, pstate);
411 scm_display (SCM_PRINT_HIGHLIGHT_SUFFIX, port);
412 }
413 else
414 iprin1 (exp, port, pstate);
415 }
416
417 static void
418 iprin1 (SCM exp, SCM port, scm_print_state *pstate)
419 {
420 switch (SCM_ITAG3 (exp))
421 {
422 case scm_tc3_closure:
423 case scm_tc3_tc7_1:
424 case scm_tc3_tc7_2:
425 /* These tc3 tags should never occur in an immediate value. They are
426 * only used in cell types of non-immediates, i. e. the value returned
427 * by SCM_CELL_TYPE (exp) can use these tags.
428 */
429 scm_ipruk ("immediate", exp, port);
430 break;
431 case scm_tc3_int_1:
432 case scm_tc3_int_2:
433 scm_intprint (SCM_I_INUM (exp), 10, port);
434 break;
435 case scm_tc3_imm24:
436 if (SCM_CHARP (exp))
437 {
438 long i = SCM_CHAR (exp);
439
440 if (SCM_WRITINGP (pstate))
441 {
442 scm_puts ("#\\", port);
443 if ((i >= 0) && (i <= ' ') && scm_charnames[i])
444 scm_puts (scm_charnames[i], port);
445 #ifndef EBCDIC
446 else if (i == '\177')
447 scm_puts (scm_charnames[scm_n_charnames - 1], port);
448 #endif
449 else if (i < 0 || i > '\177')
450 scm_intprint (i, 8, port);
451 else
452 scm_putc (i, port);
453 }
454 else
455 scm_putc (i, port);
456 }
457 else if (SCM_IFLAGP (exp)
458 && ((size_t) SCM_IFLAGNUM (exp) < (sizeof iflagnames / sizeof (char *))))
459 {
460 scm_puts (iflagnames [SCM_IFLAGNUM (exp)], port);
461 }
462 else if (SCM_ISYMP (exp))
463 {
464 scm_i_print_isym (exp, port);
465 }
466 else if (SCM_ILOCP (exp))
467 {
468 scm_i_print_iloc (exp, port);
469 }
470 else
471 {
472 /* unknown immediate value */
473 scm_ipruk ("immediate", exp, port);
474 }
475 break;
476 case scm_tc3_cons:
477 switch (SCM_TYP7 (exp))
478 {
479 case scm_tcs_struct:
480 {
481 ENTER_NESTED_DATA (pstate, exp, circref);
482 if (SCM_OBJ_CLASS_FLAGS (exp) & SCM_CLASSF_GOOPS)
483 {
484 SCM pwps, print = pstate->writingp ? g_write : g_display;
485 if (!print)
486 goto print_struct;
487 pwps = scm_i_port_with_print_state (port, pstate->handle);
488 pstate->revealed = 1;
489 scm_call_generic_2 (print, exp, pwps);
490 }
491 else
492 {
493 print_struct:
494 scm_print_struct (exp, port, pstate);
495 }
496 EXIT_NESTED_DATA (pstate);
497 }
498 break;
499 case scm_tcs_cons_imcar:
500 case scm_tcs_cons_nimcar:
501 ENTER_NESTED_DATA (pstate, exp, circref);
502 scm_iprlist ("(", exp, ')', port, pstate);
503 EXIT_NESTED_DATA (pstate);
504 break;
505 circref:
506 print_circref (port, pstate, exp);
507 break;
508 case scm_tcs_closures:
509 if (scm_is_false (scm_procedure_p (SCM_PRINT_CLOSURE))
510 || scm_is_false (scm_printer_apply (SCM_PRINT_CLOSURE,
511 exp, port, pstate)))
512 {
513 SCM formals = SCM_CLOSURE_FORMALS (exp);
514 scm_puts ("#<procedure", port);
515 scm_putc (' ', port);
516 scm_iprin1 (scm_procedure_name (exp), port, pstate);
517 scm_putc (' ', port);
518 if (SCM_PRINT_SOURCE_P)
519 {
520 SCM env = SCM_ENV (exp);
521 SCM xenv = SCM_EXTEND_ENV (formals, SCM_EOL, env);
522 SCM src = scm_i_unmemocopy_body (SCM_CODE (exp), xenv);
523 ENTER_NESTED_DATA (pstate, exp, circref);
524 scm_iprin1 (src, port, pstate);
525 EXIT_NESTED_DATA (pstate);
526 }
527 else
528 scm_iprin1 (formals, port, pstate);
529 scm_putc ('>', port);
530 }
531 break;
532 case scm_tc7_number:
533 switch SCM_TYP16 (exp) {
534 case scm_tc16_big:
535 scm_bigprint (exp, port, pstate);
536 break;
537 case scm_tc16_real:
538 scm_print_real (exp, port, pstate);
539 break;
540 case scm_tc16_complex:
541 scm_print_complex (exp, port, pstate);
542 break;
543 case scm_tc16_fraction:
544 scm_i_print_fraction (exp, port, pstate);
545 break;
546 }
547 break;
548 case scm_tc7_string:
549 if (SCM_WRITINGP (pstate))
550 {
551 size_t i, j, len;
552 const char *data;
553
554 scm_putc ('"', port);
555 len = scm_i_string_length (exp);
556 data = scm_i_string_chars (exp);
557 for (i = 0, j = 0; i < len; ++i)
558 {
559 unsigned char ch = data[i];
560 if ((ch < 32 && ch != '\n') || (127 <= ch && ch < 148))
561 {
562 static char const hex[]="0123456789abcdef";
563 char buf[4];
564
565 scm_lfwrite (data+j, i-j, port);
566 buf[0] = '\\';
567 buf[1] = 'x';
568 buf[2] = hex [ch / 16];
569 buf[3] = hex [ch % 16];
570 scm_lfwrite (buf, 4, port);
571 data = scm_i_string_chars (exp);
572 j = i+1;
573 }
574 else if (ch == '"' || ch == '\\')
575 {
576 scm_lfwrite (data+j, i-j, port);
577 scm_putc ('\\', port);
578 data = scm_i_string_chars (exp);
579 j = i;
580 }
581 }
582 scm_lfwrite (data+j, i-j, port);
583 scm_putc ('"', port);
584 scm_remember_upto_here_1 (exp);
585 }
586 else
587 scm_lfwrite (scm_i_string_chars (exp), scm_i_string_length (exp),
588 port);
589 scm_remember_upto_here_1 (exp);
590 break;
591 case scm_tc7_symbol:
592 if (scm_i_symbol_is_interned (exp))
593 {
594 scm_print_symbol_name (scm_i_symbol_chars (exp),
595 scm_i_symbol_length (exp),
596 port);
597 scm_remember_upto_here_1 (exp);
598 }
599 else
600 {
601 scm_puts ("#<uninterned-symbol ", port);
602 scm_print_symbol_name (scm_i_symbol_chars (exp),
603 scm_i_symbol_length (exp),
604 port);
605 scm_putc (' ', port);
606 scm_uintprint (SCM_UNPACK (exp), 16, port);
607 scm_putc ('>', port);
608 }
609 break;
610 case scm_tc7_variable:
611 scm_i_variable_print (exp, port, pstate);
612 break;
613 case scm_tc7_wvect:
614 ENTER_NESTED_DATA (pstate, exp, circref);
615 if (SCM_IS_WHVEC (exp))
616 scm_puts ("#wh(", port);
617 else
618 scm_puts ("#w(", port);
619 goto common_vector_printer;
620
621 case scm_tc7_vector:
622 ENTER_NESTED_DATA (pstate, exp, circref);
623 scm_puts ("#(", port);
624 common_vector_printer:
625 {
626 register long i;
627 long last = SCM_SIMPLE_VECTOR_LENGTH (exp) - 1;
628 int cutp = 0;
629 if (pstate->fancyp
630 && SCM_SIMPLE_VECTOR_LENGTH (exp) > pstate->length)
631 {
632 last = pstate->length - 1;
633 cutp = 1;
634 }
635 if (SCM_I_WVECTP (exp))
636 {
637 /* Elements of weak vectors may not be accessed via the
638 `SIMPLE_VECTOR_REF ()' macro. */
639 for (i = 0; i < last; ++i)
640 {
641 scm_iprin1 (scm_c_vector_ref (exp, i),
642 port, pstate);
643 scm_putc (' ', port);
644 }
645 }
646 else
647 {
648 for (i = 0; i < last; ++i)
649 {
650 scm_iprin1 (SCM_SIMPLE_VECTOR_REF (exp, i), port, pstate);
651 scm_putc (' ', port);
652 }
653 }
654
655 if (i == last)
656 {
657 /* CHECK_INTS; */
658 scm_iprin1 (scm_c_vector_ref (exp, i), port, pstate);
659 }
660 if (cutp)
661 scm_puts (" ...", port);
662 scm_putc (')', port);
663 }
664 EXIT_NESTED_DATA (pstate);
665 break;
666 case scm_tcs_subrs:
667 scm_puts (SCM_SUBR_GENERIC (exp)
668 ? "#<primitive-generic "
669 : "#<primitive-procedure ",
670 port);
671 scm_puts (scm_i_symbol_chars (SCM_SNAME (exp)), port);
672 scm_putc ('>', port);
673 break;
674 #ifdef CCLO
675 case scm_tc7_cclo:
676 {
677 SCM proc = SCM_CCLO_SUBR (exp);
678 if (scm_is_eq (proc, scm_f_gsubr_apply))
679 {
680 /* Print gsubrs as primitives */
681 SCM name = scm_procedure_name (exp);
682 scm_puts ("#<primitive-procedure", port);
683 if (scm_is_true (name))
684 {
685 scm_putc (' ', port);
686 scm_puts (scm_i_symbol_chars (name), port);
687 }
688 }
689 else
690 {
691 scm_puts ("#<compiled-closure ", port);
692 scm_iprin1 (proc, port, pstate);
693 }
694 scm_putc ('>', port);
695 }
696 break;
697 #endif
698 case scm_tc7_pws:
699 scm_puts ("#<procedure-with-setter", port);
700 {
701 SCM name = scm_procedure_name (exp);
702 if (scm_is_true (name))
703 {
704 scm_putc (' ', port);
705 scm_display (name, port);
706 }
707 }
708 scm_putc ('>', port);
709 break;
710 case scm_tc7_port:
711 {
712 register long i = SCM_PTOBNUM (exp);
713 if (i < scm_numptob
714 && scm_ptobs[i].print
715 && (scm_ptobs[i].print) (exp, port, pstate))
716 break;
717 goto punk;
718 }
719 case scm_tc7_smob:
720 ENTER_NESTED_DATA (pstate, exp, circref);
721 SCM_SMOB_DESCRIPTOR (exp).print (exp, port, pstate);
722 EXIT_NESTED_DATA (pstate);
723 break;
724 default:
725 punk:
726 scm_ipruk ("type", exp, port);
727 }
728 }
729 }
730
731 /* Print states are necessary for circular reference safe printing.
732 * They are also expensive to allocate. Therefore print states are
733 * kept in a pool so that they can be reused.
734 */
735
736 /* The PORT argument can also be a print-state/port pair, which will
737 * then be used instead of allocating a new print state. This is
738 * useful for continuing a chain of print calls from Scheme. */
739
740 void
741 scm_prin1 (SCM exp, SCM port, int writingp)
742 {
743 SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
744 SCM pstate_scm;
745 scm_print_state *pstate;
746 int old_writingp;
747
748 /* If PORT is a print-state/port pair, use that. Else create a new
749 print-state. */
750
751 if (SCM_PORT_WITH_PS_P (port))
752 {
753 pstate_scm = SCM_PORT_WITH_PS_PS (port);
754 port = SCM_PORT_WITH_PS_PORT (port);
755 }
756 else
757 {
758 /* First try to allocate a print state from the pool */
759 scm_i_pthread_mutex_lock (&print_state_mutex);
760 if (!scm_is_null (print_state_pool))
761 {
762 handle = print_state_pool;
763 print_state_pool = SCM_CDR (print_state_pool);
764 }
765 scm_i_pthread_mutex_unlock (&print_state_mutex);
766 if (scm_is_false (handle))
767 handle = scm_list_1 (make_print_state ());
768 pstate_scm = SCM_CAR (handle);
769 }
770
771 pstate = SCM_PRINT_STATE (pstate_scm);
772 old_writingp = pstate->writingp;
773 pstate->writingp = writingp;
774 scm_iprin1 (exp, port, pstate);
775 pstate->writingp = old_writingp;
776
777 /* Return print state to pool if it has been created above and
778 hasn't escaped to Scheme. */
779
780 if (scm_is_true (handle) && !pstate->revealed)
781 {
782 scm_i_pthread_mutex_lock (&print_state_mutex);
783 SCM_SETCDR (handle, print_state_pool);
784 print_state_pool = handle;
785 scm_i_pthread_mutex_unlock (&print_state_mutex);
786 }
787 }
788
789
790 /* Print an integer.
791 */
792
793 void
794 scm_intprint (scm_t_intmax n, int radix, SCM port)
795 {
796 char num_buf[SCM_INTBUFLEN];
797 scm_lfwrite (num_buf, scm_iint2str (n, radix, num_buf), port);
798 }
799
800 void
801 scm_uintprint (scm_t_uintmax n, int radix, SCM port)
802 {
803 char num_buf[SCM_INTBUFLEN];
804 scm_lfwrite (num_buf, scm_iuint2str (n, radix, num_buf), port);
805 }
806
807 /* Print an object of unrecognized type.
808 */
809
810 void
811 scm_ipruk (char *hdr, SCM ptr, SCM port)
812 {
813 scm_puts ("#<unknown-", port);
814 scm_puts (hdr, port);
815 if (1) /* (scm_in_heap_p (ptr)) */ /* FIXME */
816 {
817 scm_puts (" (0x", port);
818 scm_uintprint (SCM_CELL_WORD_0 (ptr), 16, port);
819 scm_puts (" . 0x", port);
820 scm_uintprint (SCM_CELL_WORD_1 (ptr), 16, port);
821 scm_puts (") @", port);
822 }
823 scm_puts (" 0x", port);
824 scm_uintprint (SCM_UNPACK (ptr), 16, port);
825 scm_putc ('>', port);
826 }
827
828
829 /* Print a list.
830 */
831 void
832 scm_iprlist (char *hdr, SCM exp, int tlr, SCM port, scm_print_state *pstate)
833 {
834 register SCM hare, tortoise;
835 long floor = pstate->top - 2;
836 scm_puts (hdr, port);
837 /* CHECK_INTS; */
838 if (pstate->fancyp)
839 goto fancy_printing;
840
841 /* Run a hare and tortoise so that total time complexity will be
842 O(depth * N) instead of O(N^2). */
843 hare = SCM_CDR (exp);
844 tortoise = exp;
845 while (scm_is_pair (hare))
846 {
847 if (scm_is_eq (hare, tortoise))
848 goto fancy_printing;
849 hare = SCM_CDR (hare);
850 if (!scm_is_pair (hare))
851 break;
852 hare = SCM_CDR (hare);
853 tortoise = SCM_CDR (tortoise);
854 }
855
856 /* No cdr cycles intrinsic to this list */
857 scm_iprin1 (SCM_CAR (exp), port, pstate);
858 for (exp = SCM_CDR (exp); scm_is_pair (exp); exp = SCM_CDR (exp))
859 {
860 register long i;
861
862 for (i = floor; i >= 0; --i)
863 if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
864 goto circref;
865 PUSH_REF (pstate, exp);
866 scm_putc (' ', port);
867 /* CHECK_INTS; */
868 scm_iprin1 (SCM_CAR (exp), port, pstate);
869 }
870 if (!SCM_NULL_OR_NIL_P (exp))
871 {
872 scm_puts (" . ", port);
873 scm_iprin1 (exp, port, pstate);
874 }
875
876 end:
877 scm_putc (tlr, port);
878 pstate->top = floor + 2;
879 return;
880
881 fancy_printing:
882 {
883 long n = pstate->length;
884
885 scm_iprin1 (SCM_CAR (exp), port, pstate);
886 exp = SCM_CDR (exp); --n;
887 for (; scm_is_pair (exp); exp = SCM_CDR (exp))
888 {
889 register unsigned long i;
890
891 for (i = 0; i < pstate->top; ++i)
892 if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
893 goto fancy_circref;
894 if (pstate->fancyp)
895 {
896 if (n == 0)
897 {
898 scm_puts (" ...", port);
899 goto skip_tail;
900 }
901 else
902 --n;
903 }
904 PUSH_REF(pstate, exp);
905 ++pstate->list_offset;
906 scm_putc (' ', port);
907 /* CHECK_INTS; */
908 scm_iprin1 (SCM_CAR (exp), port, pstate);
909 }
910 }
911 if (!SCM_NULL_OR_NIL_P (exp))
912 {
913 scm_puts (" . ", port);
914 scm_iprin1 (exp, port, pstate);
915 }
916 skip_tail:
917 pstate->list_offset -= pstate->top - floor - 2;
918 goto end;
919
920 fancy_circref:
921 pstate->list_offset -= pstate->top - floor - 2;
922
923 circref:
924 scm_puts (" . ", port);
925 print_circref (port, pstate, exp);
926 goto end;
927 }
928
929 \f
930
931 int
932 scm_valid_oport_value_p (SCM val)
933 {
934 return (SCM_OPOUTPORTP (val)
935 || (SCM_PORT_WITH_PS_P (val)
936 && SCM_OPOUTPORTP (SCM_PORT_WITH_PS_PORT (val))));
937 }
938
939 /* SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write); */
940
941 SCM
942 scm_write (SCM obj, SCM port)
943 {
944 if (SCM_UNBNDP (port))
945 port = scm_current_output_port ();
946
947 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
948
949 scm_prin1 (obj, port, 1);
950 #if 0
951 #ifdef HAVE_PIPE
952 # ifdef EPIPE
953 if (EPIPE == errno)
954 scm_close_port (port);
955 # endif
956 #endif
957 #endif
958 return SCM_UNSPECIFIED;
959 }
960
961
962 /* SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display); */
963
964 SCM
965 scm_display (SCM obj, SCM port)
966 {
967 if (SCM_UNBNDP (port))
968 port = scm_current_output_port ();
969
970 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
971
972 scm_prin1 (obj, port, 0);
973 #if 0
974 #ifdef HAVE_PIPE
975 # ifdef EPIPE
976 if (EPIPE == errno)
977 scm_close_port (port);
978 # endif
979 #endif
980 #endif
981 return SCM_UNSPECIFIED;
982 }
983
984
985 SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
986 (SCM destination, SCM message, SCM args),
987 "Write @var{message} to @var{destination}, defaulting to\n"
988 "the current output port.\n"
989 "@var{message} can contain @code{~A} (was @code{%s}) and\n"
990 "@code{~S} (was @code{%S}) escapes. When printed,\n"
991 "the escapes are replaced with corresponding members of\n"
992 "@var{ARGS}:\n"
993 "@code{~A} formats using @code{display} and @code{~S} formats\n"
994 "using @code{write}.\n"
995 "If @var{destination} is @code{#t}, then use the current output\n"
996 "port, if @var{destination} is @code{#f}, then return a string\n"
997 "containing the formatted text. Does not add a trailing newline.")
998 #define FUNC_NAME s_scm_simple_format
999 {
1000 SCM port, answer = SCM_UNSPECIFIED;
1001 int fReturnString = 0;
1002 int writingp;
1003 const char *start;
1004 const char *end;
1005 const char *p;
1006
1007 if (scm_is_eq (destination, SCM_BOOL_T))
1008 {
1009 destination = port = scm_current_output_port ();
1010 }
1011 else if (scm_is_false (destination))
1012 {
1013 fReturnString = 1;
1014 port = scm_mkstrport (SCM_INUM0,
1015 scm_make_string (SCM_INUM0, SCM_UNDEFINED),
1016 SCM_OPN | SCM_WRTNG,
1017 FUNC_NAME);
1018 destination = port;
1019 }
1020 else
1021 {
1022 SCM_VALIDATE_OPORT_VALUE (1, destination);
1023 port = SCM_COERCE_OUTPORT (destination);
1024 }
1025 SCM_VALIDATE_STRING (2, message);
1026 SCM_VALIDATE_REST_ARGUMENT (args);
1027
1028 start = scm_i_string_chars (message);
1029 end = start + scm_i_string_length (message);
1030 for (p = start; p != end; ++p)
1031 if (*p == '~')
1032 {
1033 if (++p == end)
1034 break;
1035
1036 switch (*p)
1037 {
1038 case 'A': case 'a':
1039 writingp = 0;
1040 break;
1041 case 'S': case 's':
1042 writingp = 1;
1043 break;
1044 case '~':
1045 scm_lfwrite (start, p - start, port);
1046 start = p + 1;
1047 continue;
1048 case '%':
1049 scm_lfwrite (start, p - start - 1, port);
1050 scm_newline (port);
1051 start = p + 1;
1052 continue;
1053 default:
1054 SCM_MISC_ERROR ("FORMAT: Unsupported format option ~~~A - use (ice-9 format) instead",
1055 scm_list_1 (SCM_MAKE_CHAR (*p)));
1056
1057 }
1058
1059
1060 if (!scm_is_pair (args))
1061 SCM_MISC_ERROR ("FORMAT: Missing argument for ~~~A",
1062 scm_list_1 (SCM_MAKE_CHAR (*p)));
1063
1064 scm_lfwrite (start, p - start - 1, port);
1065 /* we pass destination here */
1066 scm_prin1 (SCM_CAR (args), destination, writingp);
1067 args = SCM_CDR (args);
1068 start = p + 1;
1069 }
1070
1071 scm_lfwrite (start, p - start, port);
1072 if (!scm_is_eq (args, SCM_EOL))
1073 SCM_MISC_ERROR ("FORMAT: ~A superfluous arguments",
1074 scm_list_1 (scm_length (args)));
1075
1076 if (fReturnString)
1077 answer = scm_strport_to_string (destination);
1078
1079 return scm_return_first (answer, message);
1080 }
1081 #undef FUNC_NAME
1082
1083
1084 SCM_DEFINE (scm_newline, "newline", 0, 1, 0,
1085 (SCM port),
1086 "Send a newline to @var{port}.\n"
1087 "If @var{port} is omitted, send to the current output port.")
1088 #define FUNC_NAME s_scm_newline
1089 {
1090 if (SCM_UNBNDP (port))
1091 port = scm_current_output_port ();
1092
1093 SCM_VALIDATE_OPORT_VALUE (1, port);
1094
1095 scm_putc ('\n', SCM_COERCE_OUTPORT (port));
1096 return SCM_UNSPECIFIED;
1097 }
1098 #undef FUNC_NAME
1099
1100 SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
1101 (SCM chr, SCM port),
1102 "Send character @var{chr} to @var{port}.")
1103 #define FUNC_NAME s_scm_write_char
1104 {
1105 if (SCM_UNBNDP (port))
1106 port = scm_current_output_port ();
1107
1108 SCM_VALIDATE_CHAR (1, chr);
1109 SCM_VALIDATE_OPORT_VALUE (2, port);
1110
1111 scm_putc ((int) SCM_CHAR (chr), SCM_COERCE_OUTPORT (port));
1112 #if 0
1113 #ifdef HAVE_PIPE
1114 # ifdef EPIPE
1115 if (EPIPE == errno)
1116 scm_close_port (port);
1117 # endif
1118 #endif
1119 #endif
1120 return SCM_UNSPECIFIED;
1121 }
1122 #undef FUNC_NAME
1123
1124 \f
1125
1126 /* Call back to Scheme code to do the printing of special objects
1127 * (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a smob
1128 * containing PORT and PSTATE. This object can be used as the port for
1129 * display/write etc to continue the current print chain. The REVEALED
1130 * field of PSTATE is set to true to indicate that the print state has
1131 * escaped to Scheme and thus has to be freed by the GC.
1132 */
1133
1134 scm_t_bits scm_tc16_port_with_ps;
1135
1136 /* Print exactly as the port itself would */
1137
1138 static int
1139 port_with_ps_print (SCM obj, SCM port, scm_print_state *pstate)
1140 {
1141 obj = SCM_PORT_WITH_PS_PORT (obj);
1142 return scm_ptobs[SCM_PTOBNUM (obj)].print (obj, port, pstate);
1143 }
1144
1145 SCM
1146 scm_printer_apply (SCM proc, SCM exp, SCM port, scm_print_state *pstate)
1147 {
1148 pstate->revealed = 1;
1149 return scm_call_2 (proc, exp,
1150 scm_i_port_with_print_state (port, pstate->handle));
1151 }
1152
1153 SCM_DEFINE (scm_port_with_print_state, "port-with-print-state", 1, 1, 0,
1154 (SCM port, SCM pstate),
1155 "Create a new port which behaves like @var{port}, but with an\n"
1156 "included print state @var{pstate}. @var{pstate} is optional.\n"
1157 "If @var{pstate} isn't supplied and @var{port} already has\n"
1158 "a print state, the old print state is reused.")
1159 #define FUNC_NAME s_scm_port_with_print_state
1160 {
1161 SCM_VALIDATE_OPORT_VALUE (1, port);
1162 if (!SCM_UNBNDP (pstate))
1163 SCM_VALIDATE_PRINTSTATE (2, pstate);
1164 return scm_i_port_with_print_state (port, pstate);
1165 }
1166 #undef FUNC_NAME
1167
1168 SCM_DEFINE (scm_get_print_state, "get-print-state", 1, 0, 0,
1169 (SCM port),
1170 "Return the print state of the port @var{port}. If @var{port}\n"
1171 "has no associated print state, @code{#f} is returned.")
1172 #define FUNC_NAME s_scm_get_print_state
1173 {
1174 if (SCM_PORT_WITH_PS_P (port))
1175 return SCM_PORT_WITH_PS_PS (port);
1176 if (SCM_OUTPUT_PORT_P (port))
1177 return SCM_BOOL_F;
1178 SCM_WRONG_TYPE_ARG (1, port);
1179 }
1180 #undef FUNC_NAME
1181
1182 \f
1183
1184 void
1185 scm_init_print ()
1186 {
1187 SCM vtable, layout, type;
1188
1189 scm_init_opts (scm_print_options, scm_print_opts);
1190
1191 scm_print_options (scm_list_4 (scm_from_locale_symbol ("highlight-prefix"),
1192 scm_from_locale_string ("{"),
1193 scm_from_locale_symbol ("highlight-suffix"),
1194 scm_from_locale_string ("}")));
1195
1196 scm_gc_register_root (&print_state_pool);
1197 scm_gc_register_root (&scm_print_state_vtable);
1198 vtable = scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
1199 layout =
1200 scm_make_struct_layout (scm_from_locale_string (SCM_PRINT_STATE_LAYOUT));
1201 type = scm_make_struct (vtable, SCM_INUM0, scm_list_1 (layout));
1202 scm_set_struct_vtable_name_x (type, scm_from_locale_symbol ("print-state"));
1203 scm_print_state_vtable = type;
1204
1205 /* Don't want to bind a wrapper class in GOOPS, so pass 0 as arg1. */
1206 scm_tc16_port_with_ps = scm_make_smob_type (0, 0);
1207 scm_set_smob_print (scm_tc16_port_with_ps, port_with_ps_print);
1208
1209 #include "libguile/print.x"
1210
1211 scm_print_opts[SCM_PRINT_KEYWORD_STYLE_I].val = SCM_UNPACK (sym_reader);
1212 }
1213
1214 /*
1215 Local Variables:
1216 c-file-style: "gnu"
1217 End:
1218 */