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