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