Revert "(scm_shell_usage): Note need for subscription to bug-guile@gnu.org."
[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 for (i = 0; i < last; ++i)
636 {
637 /* CHECK_INTS; */
638 scm_iprin1 (SCM_SIMPLE_VECTOR_REF (exp, i), port, pstate);
639 scm_putc (' ', port);
640 }
641 if (i == last)
642 {
643 /* CHECK_INTS; */
644 scm_iprin1 (SCM_SIMPLE_VECTOR_REF (exp, i), port, pstate);
645 }
646 if (cutp)
647 scm_puts (" ...", port);
648 scm_putc (')', port);
649 }
650 EXIT_NESTED_DATA (pstate);
651 break;
652 case scm_tcs_subrs:
653 scm_puts (SCM_SUBR_GENERIC (exp)
654 ? "#<primitive-generic "
655 : "#<primitive-procedure ",
656 port);
657 scm_puts (scm_i_symbol_chars (SCM_SNAME (exp)), port);
658 scm_putc ('>', port);
659 break;
660 #ifdef CCLO
661 case scm_tc7_cclo:
662 {
663 SCM proc = SCM_CCLO_SUBR (exp);
664 if (scm_is_eq (proc, scm_f_gsubr_apply))
665 {
666 /* Print gsubrs as primitives */
667 SCM name = scm_procedure_name (exp);
668 scm_puts ("#<primitive-procedure", port);
669 if (scm_is_true (name))
670 {
671 scm_putc (' ', port);
672 scm_puts (scm_i_symbol_chars (name), port);
673 }
674 }
675 else
676 {
677 scm_puts ("#<compiled-closure ", port);
678 scm_iprin1 (proc, port, pstate);
679 }
680 scm_putc ('>', port);
681 }
682 break;
683 #endif
684 case scm_tc7_pws:
685 scm_puts ("#<procedure-with-setter", port);
686 {
687 SCM name = scm_procedure_name (exp);
688 if (scm_is_true (name))
689 {
690 scm_putc (' ', port);
691 scm_display (name, port);
692 }
693 }
694 scm_putc ('>', port);
695 break;
696 case scm_tc7_port:
697 {
698 register long i = SCM_PTOBNUM (exp);
699 if (i < scm_numptob
700 && scm_ptobs[i].print
701 && (scm_ptobs[i].print) (exp, port, pstate))
702 break;
703 goto punk;
704 }
705 case scm_tc7_smob:
706 ENTER_NESTED_DATA (pstate, exp, circref);
707 SCM_SMOB_DESCRIPTOR (exp).print (exp, port, pstate);
708 EXIT_NESTED_DATA (pstate);
709 break;
710 default:
711 punk:
712 scm_ipruk ("type", exp, port);
713 }
714 }
715 }
716
717 /* Print states are necessary for circular reference safe printing.
718 * They are also expensive to allocate. Therefore print states are
719 * kept in a pool so that they can be reused.
720 */
721
722 /* The PORT argument can also be a print-state/port pair, which will
723 * then be used instead of allocating a new print state. This is
724 * useful for continuing a chain of print calls from Scheme. */
725
726 void
727 scm_prin1 (SCM exp, SCM port, int writingp)
728 {
729 SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
730 SCM pstate_scm;
731 scm_print_state *pstate;
732 int old_writingp;
733
734 /* If PORT is a print-state/port pair, use that. Else create a new
735 print-state. */
736
737 if (SCM_PORT_WITH_PS_P (port))
738 {
739 pstate_scm = SCM_PORT_WITH_PS_PS (port);
740 port = SCM_PORT_WITH_PS_PORT (port);
741 }
742 else
743 {
744 /* First try to allocate a print state from the pool */
745 scm_i_pthread_mutex_lock (&print_state_mutex);
746 if (!scm_is_null (print_state_pool))
747 {
748 handle = print_state_pool;
749 print_state_pool = SCM_CDR (print_state_pool);
750 }
751 scm_i_pthread_mutex_unlock (&print_state_mutex);
752 if (scm_is_false (handle))
753 handle = scm_list_1 (make_print_state ());
754 pstate_scm = SCM_CAR (handle);
755 }
756
757 pstate = SCM_PRINT_STATE (pstate_scm);
758 old_writingp = pstate->writingp;
759 pstate->writingp = writingp;
760 scm_iprin1 (exp, port, pstate);
761 pstate->writingp = old_writingp;
762
763 /* Return print state to pool if it has been created above and
764 hasn't escaped to Scheme. */
765
766 if (scm_is_true (handle) && !pstate->revealed)
767 {
768 scm_i_pthread_mutex_lock (&print_state_mutex);
769 SCM_SETCDR (handle, print_state_pool);
770 print_state_pool = handle;
771 scm_i_pthread_mutex_unlock (&print_state_mutex);
772 }
773 }
774
775
776 /* Print an integer.
777 */
778
779 void
780 scm_intprint (scm_t_intmax n, int radix, SCM port)
781 {
782 char num_buf[SCM_INTBUFLEN];
783 scm_lfwrite (num_buf, scm_iint2str (n, radix, num_buf), port);
784 }
785
786 void
787 scm_uintprint (scm_t_uintmax n, int radix, SCM port)
788 {
789 char num_buf[SCM_INTBUFLEN];
790 scm_lfwrite (num_buf, scm_iuint2str (n, radix, num_buf), port);
791 }
792
793 /* Print an object of unrecognized type.
794 */
795
796 void
797 scm_ipruk (char *hdr, SCM ptr, SCM port)
798 {
799 scm_puts ("#<unknown-", port);
800 scm_puts (hdr, port);
801 if (scm_in_heap_p (ptr))
802 {
803 scm_puts (" (0x", port);
804 scm_uintprint (SCM_CELL_WORD_0 (ptr), 16, port);
805 scm_puts (" . 0x", port);
806 scm_uintprint (SCM_CELL_WORD_1 (ptr), 16, port);
807 scm_puts (") @", port);
808 }
809 scm_puts (" 0x", port);
810 scm_uintprint (SCM_UNPACK (ptr), 16, port);
811 scm_putc ('>', port);
812 }
813
814
815 /* Print a list.
816 */
817 void
818 scm_iprlist (char *hdr, SCM exp, int tlr, SCM port, scm_print_state *pstate)
819 {
820 register SCM hare, tortoise;
821 long floor = pstate->top - 2;
822 scm_puts (hdr, port);
823 /* CHECK_INTS; */
824 if (pstate->fancyp)
825 goto fancy_printing;
826
827 /* Run a hare and tortoise so that total time complexity will be
828 O(depth * N) instead of O(N^2). */
829 hare = SCM_CDR (exp);
830 tortoise = exp;
831 while (scm_is_pair (hare))
832 {
833 if (scm_is_eq (hare, tortoise))
834 goto fancy_printing;
835 hare = SCM_CDR (hare);
836 if (!scm_is_pair (hare))
837 break;
838 hare = SCM_CDR (hare);
839 tortoise = SCM_CDR (tortoise);
840 }
841
842 /* No cdr cycles intrinsic to this list */
843 scm_iprin1 (SCM_CAR (exp), port, pstate);
844 for (exp = SCM_CDR (exp); scm_is_pair (exp); exp = SCM_CDR (exp))
845 {
846 register long i;
847
848 for (i = floor; i >= 0; --i)
849 if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
850 goto circref;
851 PUSH_REF (pstate, exp);
852 scm_putc (' ', port);
853 /* CHECK_INTS; */
854 scm_iprin1 (SCM_CAR (exp), port, pstate);
855 }
856 if (!SCM_NULL_OR_NIL_P (exp))
857 {
858 scm_puts (" . ", port);
859 scm_iprin1 (exp, port, pstate);
860 }
861
862 end:
863 scm_putc (tlr, port);
864 pstate->top = floor + 2;
865 return;
866
867 fancy_printing:
868 {
869 long n = pstate->length;
870
871 scm_iprin1 (SCM_CAR (exp), port, pstate);
872 exp = SCM_CDR (exp); --n;
873 for (; scm_is_pair (exp); exp = SCM_CDR (exp))
874 {
875 register unsigned long i;
876
877 for (i = 0; i < pstate->top; ++i)
878 if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
879 goto fancy_circref;
880 if (pstate->fancyp)
881 {
882 if (n == 0)
883 {
884 scm_puts (" ...", port);
885 goto skip_tail;
886 }
887 else
888 --n;
889 }
890 PUSH_REF(pstate, exp);
891 ++pstate->list_offset;
892 scm_putc (' ', port);
893 /* CHECK_INTS; */
894 scm_iprin1 (SCM_CAR (exp), port, pstate);
895 }
896 }
897 if (!SCM_NULL_OR_NIL_P (exp))
898 {
899 scm_puts (" . ", port);
900 scm_iprin1 (exp, port, pstate);
901 }
902 skip_tail:
903 pstate->list_offset -= pstate->top - floor - 2;
904 goto end;
905
906 fancy_circref:
907 pstate->list_offset -= pstate->top - floor - 2;
908
909 circref:
910 scm_puts (" . ", port);
911 print_circref (port, pstate, exp);
912 goto end;
913 }
914
915 \f
916
917 int
918 scm_valid_oport_value_p (SCM val)
919 {
920 return (SCM_OPOUTPORTP (val)
921 || (SCM_PORT_WITH_PS_P (val)
922 && SCM_OPOUTPORTP (SCM_PORT_WITH_PS_PORT (val))));
923 }
924
925 /* SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write); */
926
927 SCM
928 scm_write (SCM obj, SCM port)
929 {
930 if (SCM_UNBNDP (port))
931 port = scm_current_output_port ();
932
933 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
934
935 scm_prin1 (obj, port, 1);
936 #if 0
937 #ifdef HAVE_PIPE
938 # ifdef EPIPE
939 if (EPIPE == errno)
940 scm_close_port (port);
941 # endif
942 #endif
943 #endif
944 return SCM_UNSPECIFIED;
945 }
946
947
948 /* SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display); */
949
950 SCM
951 scm_display (SCM obj, SCM port)
952 {
953 if (SCM_UNBNDP (port))
954 port = scm_current_output_port ();
955
956 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
957
958 scm_prin1 (obj, port, 0);
959 #if 0
960 #ifdef HAVE_PIPE
961 # ifdef EPIPE
962 if (EPIPE == errno)
963 scm_close_port (port);
964 # endif
965 #endif
966 #endif
967 return SCM_UNSPECIFIED;
968 }
969
970
971 SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
972 (SCM destination, SCM message, SCM args),
973 "Write @var{message} to @var{destination}, defaulting to\n"
974 "the current output port.\n"
975 "@var{message} can contain @code{~A} (was @code{%s}) and\n"
976 "@code{~S} (was @code{%S}) escapes. When printed,\n"
977 "the escapes are replaced with corresponding members of\n"
978 "@var{ARGS}:\n"
979 "@code{~A} formats using @code{display} and @code{~S} formats\n"
980 "using @code{write}.\n"
981 "If @var{destination} is @code{#t}, then use the current output\n"
982 "port, if @var{destination} is @code{#f}, then return a string\n"
983 "containing the formatted text. Does not add a trailing newline.")
984 #define FUNC_NAME s_scm_simple_format
985 {
986 SCM port, answer = SCM_UNSPECIFIED;
987 int fReturnString = 0;
988 int writingp;
989 const char *start;
990 const char *end;
991 const char *p;
992
993 if (scm_is_eq (destination, SCM_BOOL_T))
994 {
995 destination = port = scm_current_output_port ();
996 }
997 else if (scm_is_false (destination))
998 {
999 fReturnString = 1;
1000 port = scm_mkstrport (SCM_INUM0,
1001 scm_make_string (SCM_INUM0, SCM_UNDEFINED),
1002 SCM_OPN | SCM_WRTNG,
1003 FUNC_NAME);
1004 destination = port;
1005 }
1006 else
1007 {
1008 SCM_VALIDATE_OPORT_VALUE (1, destination);
1009 port = SCM_COERCE_OUTPORT (destination);
1010 }
1011 SCM_VALIDATE_STRING (2, message);
1012 SCM_VALIDATE_REST_ARGUMENT (args);
1013
1014 start = scm_i_string_chars (message);
1015 end = start + scm_i_string_length (message);
1016 for (p = start; p != end; ++p)
1017 if (*p == '~')
1018 {
1019 if (++p == end)
1020 break;
1021
1022 switch (*p)
1023 {
1024 case 'A': case 'a':
1025 writingp = 0;
1026 break;
1027 case 'S': case 's':
1028 writingp = 1;
1029 break;
1030 case '~':
1031 scm_lfwrite (start, p - start, port);
1032 start = p + 1;
1033 continue;
1034 case '%':
1035 scm_lfwrite (start, p - start - 1, port);
1036 scm_newline (port);
1037 start = p + 1;
1038 continue;
1039 default:
1040 SCM_MISC_ERROR ("FORMAT: Unsupported format option ~~~A - use (ice-9 format) instead",
1041 scm_list_1 (SCM_MAKE_CHAR (*p)));
1042
1043 }
1044
1045
1046 if (!scm_is_pair (args))
1047 SCM_MISC_ERROR ("FORMAT: Missing argument for ~~~A",
1048 scm_list_1 (SCM_MAKE_CHAR (*p)));
1049
1050 scm_lfwrite (start, p - start - 1, port);
1051 /* we pass destination here */
1052 scm_prin1 (SCM_CAR (args), destination, writingp);
1053 args = SCM_CDR (args);
1054 start = p + 1;
1055 }
1056
1057 scm_lfwrite (start, p - start, port);
1058 if (!scm_is_eq (args, SCM_EOL))
1059 SCM_MISC_ERROR ("FORMAT: ~A superfluous arguments",
1060 scm_list_1 (scm_length (args)));
1061
1062 if (fReturnString)
1063 answer = scm_strport_to_string (destination);
1064
1065 return scm_return_first (answer, message);
1066 }
1067 #undef FUNC_NAME
1068
1069
1070 SCM_DEFINE (scm_newline, "newline", 0, 1, 0,
1071 (SCM port),
1072 "Send a newline to @var{port}.\n"
1073 "If @var{port} is omitted, send to the current output port.")
1074 #define FUNC_NAME s_scm_newline
1075 {
1076 if (SCM_UNBNDP (port))
1077 port = scm_current_output_port ();
1078
1079 SCM_VALIDATE_OPORT_VALUE (1, port);
1080
1081 scm_putc ('\n', SCM_COERCE_OUTPORT (port));
1082 return SCM_UNSPECIFIED;
1083 }
1084 #undef FUNC_NAME
1085
1086 SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
1087 (SCM chr, SCM port),
1088 "Send character @var{chr} to @var{port}.")
1089 #define FUNC_NAME s_scm_write_char
1090 {
1091 if (SCM_UNBNDP (port))
1092 port = scm_current_output_port ();
1093
1094 SCM_VALIDATE_CHAR (1, chr);
1095 SCM_VALIDATE_OPORT_VALUE (2, port);
1096
1097 scm_putc ((int) SCM_CHAR (chr), SCM_COERCE_OUTPORT (port));
1098 #if 0
1099 #ifdef HAVE_PIPE
1100 # ifdef EPIPE
1101 if (EPIPE == errno)
1102 scm_close_port (port);
1103 # endif
1104 #endif
1105 #endif
1106 return SCM_UNSPECIFIED;
1107 }
1108 #undef FUNC_NAME
1109
1110 \f
1111
1112 /* Call back to Scheme code to do the printing of special objects
1113 * (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a smob
1114 * containing PORT and PSTATE. This object can be used as the port for
1115 * display/write etc to continue the current print chain. The REVEALED
1116 * field of PSTATE is set to true to indicate that the print state has
1117 * escaped to Scheme and thus has to be freed by the GC.
1118 */
1119
1120 scm_t_bits scm_tc16_port_with_ps;
1121
1122 /* Print exactly as the port itself would */
1123
1124 static int
1125 port_with_ps_print (SCM obj, SCM port, scm_print_state *pstate)
1126 {
1127 obj = SCM_PORT_WITH_PS_PORT (obj);
1128 return scm_ptobs[SCM_PTOBNUM (obj)].print (obj, port, pstate);
1129 }
1130
1131 SCM
1132 scm_printer_apply (SCM proc, SCM exp, SCM port, scm_print_state *pstate)
1133 {
1134 pstate->revealed = 1;
1135 return scm_call_2 (proc, exp,
1136 scm_i_port_with_print_state (port, pstate->handle));
1137 }
1138
1139 SCM_DEFINE (scm_port_with_print_state, "port-with-print-state", 1, 1, 0,
1140 (SCM port, SCM pstate),
1141 "Create a new port which behaves like @var{port}, but with an\n"
1142 "included print state @var{pstate}. @var{pstate} is optional.\n"
1143 "If @var{pstate} isn't supplied and @var{port} already has\n"
1144 "a print state, the old print state is reused.")
1145 #define FUNC_NAME s_scm_port_with_print_state
1146 {
1147 SCM_VALIDATE_OPORT_VALUE (1, port);
1148 if (!SCM_UNBNDP (pstate))
1149 SCM_VALIDATE_PRINTSTATE (2, pstate);
1150 return scm_i_port_with_print_state (port, pstate);
1151 }
1152 #undef FUNC_NAME
1153
1154 SCM_DEFINE (scm_get_print_state, "get-print-state", 1, 0, 0,
1155 (SCM port),
1156 "Return the print state of the port @var{port}. If @var{port}\n"
1157 "has no associated print state, @code{#f} is returned.")
1158 #define FUNC_NAME s_scm_get_print_state
1159 {
1160 if (SCM_PORT_WITH_PS_P (port))
1161 return SCM_PORT_WITH_PS_PS (port);
1162 if (SCM_OUTPUT_PORT_P (port))
1163 return SCM_BOOL_F;
1164 SCM_WRONG_TYPE_ARG (1, port);
1165 }
1166 #undef FUNC_NAME
1167
1168 \f
1169
1170 void
1171 scm_init_print ()
1172 {
1173 SCM vtable, layout, type;
1174
1175 scm_init_opts (scm_print_options, scm_print_opts);
1176
1177 scm_print_options (scm_list_4 (scm_from_locale_symbol ("highlight-prefix"),
1178 scm_from_locale_string ("{"),
1179 scm_from_locale_symbol ("highlight-suffix"),
1180 scm_from_locale_string ("}")));
1181
1182 scm_gc_register_root (&print_state_pool);
1183 scm_gc_register_root (&scm_print_state_vtable);
1184 vtable = scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
1185 layout =
1186 scm_make_struct_layout (scm_from_locale_string (SCM_PRINT_STATE_LAYOUT));
1187 type = scm_make_struct (vtable, SCM_INUM0, scm_list_1 (layout));
1188 scm_set_struct_vtable_name_x (type, scm_from_locale_symbol ("print-state"));
1189 scm_print_state_vtable = type;
1190
1191 /* Don't want to bind a wrapper class in GOOPS, so pass 0 as arg1. */
1192 scm_tc16_port_with_ps = scm_make_smob_type (0, 0);
1193 scm_set_smob_mark (scm_tc16_port_with_ps, scm_markcdr);
1194 scm_set_smob_print (scm_tc16_port_with_ps, port_with_ps_print);
1195
1196 #include "libguile/print.x"
1197
1198 scm_print_opts[SCM_PRINT_KEYWORD_STYLE_I].val = SCM_UNPACK (sym_reader);
1199 }
1200
1201 /*
1202 Local Variables:
1203 c-file-style: "gnu"
1204 End:
1205 */