Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / libguile / print.c
1 /* Copyright (C) 1995-1999, 2000, 2001, 2002, 2003, 2004, 2006, 2008,
2 * 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
18 */
19
20
21 \f
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <iconv.h>
28 #include <stdio.h>
29 #include <assert.h>
30
31 #include <uniconv.h>
32 #include <unictype.h>
33
34 #include "libguile/_scm.h"
35 #include "libguile/chars.h"
36 #include "libguile/continuations.h"
37 #include "libguile/smob.h"
38 #include "libguile/control.h"
39 #include "libguile/eval.h"
40 #include "libguile/macros.h"
41 #include "libguile/procprop.h"
42 #include "libguile/read.h"
43 #include "libguile/programs.h"
44 #include "libguile/alist.h"
45 #include "libguile/struct.h"
46 #include "libguile/ports.h"
47 #include "libguile/root.h"
48 #include "libguile/strings.h"
49 #include "libguile/strports.h"
50 #include "libguile/vectors.h"
51 #include "libguile/numbers.h"
52 #include "libguile/vm.h"
53
54 #include "libguile/validate.h"
55 #include "libguile/print.h"
56
57 #include "libguile/private-options.h"
58
59 \f
60
61 /* Character printers. */
62
63 static size_t display_string (const void *, int, size_t, SCM,
64 scm_t_string_failed_conversion_handler);
65
66 static int display_character (scm_t_wchar, SCM,
67 scm_t_string_failed_conversion_handler);
68
69 static void write_character (scm_t_wchar, SCM, int);
70
71 static void write_character_escaped (scm_t_wchar, int, SCM);
72
73 \f
74
75 /* {Names of immediate symbols}
76 *
77 * This table must agree with the declarations in scm.h: {Immediate Symbols}.
78 */
79
80 /* This table must agree with the list of flags in tags.h. */
81 static const char *iflagnames[] =
82 {
83 "#f",
84 "#nil", /* Elisp nil value. Should print from elisp as symbol `nil'. */
85 "#<XXX UNUSED LISP FALSE -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
86 "()",
87 "#t",
88 "#<XXX UNUSED BOOLEAN 0 -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
89 "#<XXX UNUSED BOOLEAN 1 -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
90 "#<XXX UNUSED BOOLEAN 2 -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
91 "#<unspecified>",
92 "#<undefined>",
93 "#<eof>",
94
95 /* Unbound slot marker for GOOPS. For internal use in GOOPS only. */
96 "#<unbound>",
97 };
98
99 SCM_SYMBOL (sym_reader, "reader");
100
101 scm_t_option scm_print_opts[] = {
102 { SCM_OPTION_SCM, "highlight-prefix", (scm_t_bits)SCM_BOOL_F_BITS,
103 "The string to print before highlighted values." },
104 { SCM_OPTION_SCM, "highlight-suffix", (scm_t_bits)SCM_BOOL_F_BITS,
105 "The string to print after highlighted values." },
106 { SCM_OPTION_SCM, "quote-keywordish-symbols", (scm_t_bits)SCM_BOOL_F_BITS,
107 "How to print symbols that have a colon as their first or last character. "
108 "The value '#f' does not quote the colons; '#t' quotes them; "
109 "'reader' quotes them when the reader option 'keywords' is not '#f'." },
110 { SCM_OPTION_BOOLEAN, "escape-newlines", 1,
111 "Render newlines as \\n when printing using `write'." },
112 { 0 },
113 };
114
115 SCM_DEFINE (scm_print_options, "print-options-interface", 0, 1, 0,
116 (SCM setting),
117 "Option interface for the print options. Instead of using\n"
118 "this procedure directly, use the procedures\n"
119 "@code{print-enable}, @code{print-disable}, @code{print-set!}\n"
120 "and @code{print-options}.")
121 #define FUNC_NAME s_scm_print_options
122 {
123 SCM ans = scm_options (setting,
124 scm_print_opts,
125 FUNC_NAME);
126 return ans;
127 }
128 #undef FUNC_NAME
129
130 \f
131 /* {Printing of Scheme Objects}
132 */
133
134 /* Detection of circular references.
135 *
136 * Due to other constraints in the implementation, this code has bad
137 * time complexity (O (depth * N)), The printer code can be
138 * rewritten to be O(N).
139 */
140 #define PUSH_REF(pstate, obj) \
141 do \
142 { \
143 PSTATE_STACK_SET (pstate, pstate->top, obj); \
144 pstate->top++; \
145 if (pstate->top == pstate->ceiling) \
146 grow_ref_stack (pstate); \
147 } while(0)
148
149 #define ENTER_NESTED_DATA(pstate, obj, label) \
150 do \
151 { \
152 register unsigned long i; \
153 for (i = 0; i < pstate->top; ++i) \
154 if (scm_is_eq (PSTATE_STACK_REF (pstate, i), (obj))) \
155 goto label; \
156 if (pstate->fancyp) \
157 { \
158 if (pstate->top - pstate->list_offset >= pstate->level) \
159 { \
160 scm_putc_unlocked ('#', port); \
161 return; \
162 } \
163 } \
164 PUSH_REF(pstate, obj); \
165 } while(0)
166
167 #define EXIT_NESTED_DATA(pstate) \
168 do \
169 { \
170 --pstate->top; \
171 PSTATE_STACK_SET (pstate, pstate->top, SCM_UNDEFINED); \
172 } \
173 while (0)
174
175 SCM scm_print_state_vtable = SCM_BOOL_F;
176 static SCM print_state_pool = SCM_EOL;
177 scm_i_pthread_mutex_t print_state_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
178
179 #ifdef GUILE_DEBUG /* Used for debugging purposes */
180
181 SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0,
182 (),
183 "Return the current-pstate -- the car of the\n"
184 "@code{print_state_pool}. @code{current-pstate} is only\n"
185 "included in @code{--enable-guile-debug} builds.")
186 #define FUNC_NAME s_scm_current_pstate
187 {
188 if (!scm_is_null (print_state_pool))
189 return SCM_CAR (print_state_pool);
190 else
191 return SCM_BOOL_F;
192 }
193 #undef FUNC_NAME
194
195 #endif
196
197 #define PSTATE_SIZE 50L
198
199 static SCM
200 make_print_state (void)
201 {
202 SCM print_state
203 = scm_make_struct (scm_print_state_vtable, SCM_INUM0, SCM_EOL);
204 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
205 pstate->ref_vect = scm_c_make_vector (PSTATE_SIZE, SCM_UNDEFINED);
206 pstate->ceiling = SCM_SIMPLE_VECTOR_LENGTH (pstate->ref_vect);
207 pstate->highlight_objects = SCM_EOL;
208 return print_state;
209 }
210
211 SCM
212 scm_make_print_state ()
213 {
214 SCM answer = SCM_BOOL_F;
215
216 /* First try to allocate a print state from the pool */
217 scm_i_pthread_mutex_lock (&print_state_mutex);
218 if (!scm_is_null (print_state_pool))
219 {
220 answer = SCM_CAR (print_state_pool);
221 print_state_pool = SCM_CDR (print_state_pool);
222 }
223 scm_i_pthread_mutex_unlock (&print_state_mutex);
224
225 return scm_is_false (answer) ? make_print_state () : answer;
226 }
227
228 void
229 scm_free_print_state (SCM print_state)
230 {
231 SCM handle;
232 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
233 /* Cleanup before returning print state to pool.
234 * It is better to do it here. Doing it in scm_prin1
235 * would cost more since that function is called much more
236 * often.
237 */
238 pstate->fancyp = 0;
239 pstate->revealed = 0;
240 pstate->highlight_objects = SCM_EOL;
241 scm_i_pthread_mutex_lock (&print_state_mutex);
242 handle = scm_cons (print_state, print_state_pool);
243 print_state_pool = handle;
244 scm_i_pthread_mutex_unlock (&print_state_mutex);
245 }
246
247 SCM
248 scm_i_port_with_print_state (SCM port, SCM print_state)
249 {
250 if (SCM_UNBNDP (print_state))
251 {
252 if (SCM_PORT_WITH_PS_P (port))
253 return port;
254 else
255 print_state = scm_make_print_state ();
256 /* port does not need to be coerced since it doesn't have ps */
257 }
258 else
259 port = SCM_COERCE_OUTPORT (port);
260 SCM_RETURN_NEWSMOB (scm_tc16_port_with_ps,
261 SCM_UNPACK (scm_cons (port, print_state)));
262 }
263
264 static void
265 grow_ref_stack (scm_print_state *pstate)
266 {
267 SCM old_vect = pstate->ref_vect;
268 size_t old_size = SCM_SIMPLE_VECTOR_LENGTH (old_vect);
269 size_t new_size = 2 * pstate->ceiling;
270 SCM new_vect = scm_c_make_vector (new_size, SCM_UNDEFINED);
271 unsigned long int i;
272
273 for (i = 0; i != old_size; ++i)
274 SCM_SIMPLE_VECTOR_SET (new_vect, i, SCM_SIMPLE_VECTOR_REF (old_vect, i));
275
276 pstate->ref_vect = new_vect;
277 pstate->ceiling = new_size;
278 }
279
280 #define PSTATE_STACK_REF(p,i) SCM_SIMPLE_VECTOR_REF((p)->ref_vect, (i))
281 #define PSTATE_STACK_SET(p,i,v) SCM_SIMPLE_VECTOR_SET((p)->ref_vect, (i), (v))
282
283 static void
284 print_circref (SCM port, scm_print_state *pstate, SCM ref)
285 {
286 register long i;
287 long self = pstate->top - 1;
288 i = pstate->top - 1;
289 if (scm_is_pair (PSTATE_STACK_REF (pstate, i)))
290 {
291 while (i > 0)
292 {
293 if (!scm_is_pair (PSTATE_STACK_REF (pstate, i-1))
294 || !scm_is_eq (SCM_CDR (PSTATE_STACK_REF (pstate, i-1)),
295 SCM_CDR (PSTATE_STACK_REF (pstate, i))))
296 break;
297 --i;
298 }
299 self = i;
300 }
301 for (i = pstate->top - 1; 1; --i)
302 if (scm_is_eq (PSTATE_STACK_REF(pstate, i), ref))
303 break;
304 scm_putc_unlocked ('#', port);
305 scm_intprint (i - self, 10, port);
306 scm_putc_unlocked ('#', port);
307 }
308
309 /* Print the name of a symbol. */
310
311 static int
312 quote_keywordish_symbols (void)
313 {
314 SCM option = SCM_PRINT_KEYWORD_STYLE;
315
316 if (scm_is_false (option))
317 return 0;
318 if (scm_is_eq (option, sym_reader))
319 return scm_is_true (SCM_PACK (SCM_KEYWORD_STYLE));
320 return 1;
321 }
322
323 #define INITIAL_IDENTIFIER_MASK \
324 (UC_CATEGORY_MASK_Lu | UC_CATEGORY_MASK_Ll | UC_CATEGORY_MASK_Lt \
325 | UC_CATEGORY_MASK_Lm | UC_CATEGORY_MASK_Lo | UC_CATEGORY_MASK_Mn \
326 | UC_CATEGORY_MASK_Nl | UC_CATEGORY_MASK_No | UC_CATEGORY_MASK_Pd \
327 | UC_CATEGORY_MASK_Pc | UC_CATEGORY_MASK_Po | UC_CATEGORY_MASK_Sc \
328 | UC_CATEGORY_MASK_Sm | UC_CATEGORY_MASK_Sk | UC_CATEGORY_MASK_So \
329 | UC_CATEGORY_MASK_Co)
330
331 #define SUBSEQUENT_IDENTIFIER_MASK \
332 (INITIAL_IDENTIFIER_MASK \
333 | UC_CATEGORY_MASK_Nd | UC_CATEGORY_MASK_Mc | UC_CATEGORY_MASK_Me)
334
335 /* FIXME: Cache this information on the symbol, somehow. */
336 static int
337 symbol_has_extended_read_syntax (SCM sym)
338 {
339 size_t pos, len = scm_i_symbol_length (sym);
340 scm_t_wchar c;
341
342 /* The empty symbol. */
343 if (len == 0)
344 return 1;
345
346 c = scm_i_symbol_ref (sym, 0);
347
348 switch (c)
349 {
350 case '\'':
351 case '`':
352 case ',':
353 case '"':
354 case ';':
355 case '#':
356 /* Some initial-character constraints. */
357 return 1;
358
359 case ':':
360 /* Symbols that look like keywords. */
361 return quote_keywordish_symbols ();
362
363 case '.':
364 /* Single dot conflicts with dotted-pair notation. */
365 if (len == 1)
366 return 1;
367 /* Fall through to check numbers. */
368 case '+':
369 case '-':
370 case '0':
371 case '1':
372 case '2':
373 case '3':
374 case '4':
375 case '5':
376 case '6':
377 case '7':
378 case '8':
379 case '9':
380 /* Number-ish symbols. Numbers with radixes already caught be #
381 above. */
382 if (scm_is_true (scm_i_string_to_number (scm_symbol_to_string (sym), 10)))
383 return 1;
384 break;
385
386 default:
387 break;
388 }
389
390 /* Other disallowed first characters. */
391 if (!uc_is_general_category_withtable (c, INITIAL_IDENTIFIER_MASK))
392 return 1;
393
394 /* Keywords can be identified by trailing colons too. */
395 if (scm_i_symbol_ref (sym, len - 1) == ':')
396 return quote_keywordish_symbols ();
397
398 /* Otherwise, any character that's in the identifier category mask is
399 fine to pass through as-is, provided it's not one of the ASCII
400 delimiters like `;'. */
401 for (pos = 1; pos < len; pos++)
402 {
403 c = scm_i_symbol_ref (sym, pos);
404 if (!uc_is_general_category_withtable (c, SUBSEQUENT_IDENTIFIER_MASK))
405 return 1;
406 else if (c == '"' || c == ';' || c == '#')
407 return 1;
408 }
409
410 return 0;
411 }
412
413 static void
414 print_normal_symbol (SCM sym, SCM port)
415 {
416 size_t len;
417 scm_t_string_failed_conversion_handler strategy;
418
419 len = scm_i_symbol_length (sym);
420 strategy = scm_i_get_conversion_strategy (port);
421
422 if (scm_i_is_narrow_symbol (sym))
423 display_string (scm_i_symbol_chars (sym), 1, len, port, strategy);
424 else
425 display_string (scm_i_symbol_wide_chars (sym), 0, len, port, strategy);
426 }
427
428 static void
429 print_extended_symbol (SCM sym, SCM port)
430 {
431 size_t pos, len;
432 scm_t_string_failed_conversion_handler strategy;
433
434 len = scm_i_symbol_length (sym);
435 strategy = scm_i_get_conversion_strategy (port);
436
437 scm_lfwrite_unlocked ("#{", 2, port);
438
439 for (pos = 0; pos < len; pos++)
440 {
441 scm_t_wchar c = scm_i_symbol_ref (sym, pos);
442
443 if (uc_is_general_category_withtable (c,
444 SUBSEQUENT_IDENTIFIER_MASK
445 | UC_CATEGORY_MASK_Zs))
446 {
447 if (!display_character (c, port, strategy))
448 scm_encoding_error ("print_extended_symbol", errno,
449 "cannot convert to output locale",
450 port, SCM_MAKE_CHAR (c));
451 }
452 else
453 {
454 display_string ("\\x", 1, 2, port, iconveh_question_mark);
455 scm_intprint (c, 16, port);
456 display_character (';', port, iconveh_question_mark);
457 }
458 }
459
460 scm_lfwrite_unlocked ("}#", 2, port);
461 }
462
463 /* FIXME: allow R6RS hex escapes instead of #{...}#. */
464 static void
465 print_symbol (SCM sym, SCM port)
466 {
467 if (symbol_has_extended_read_syntax (sym))
468 print_extended_symbol (sym, port);
469 else
470 print_normal_symbol (sym, port);
471 }
472
473 void
474 scm_print_symbol_name (const char *str, size_t len, SCM port)
475 {
476 SCM symbol = scm_from_utf8_symboln (str, len);
477 print_symbol (symbol, port);
478 }
479
480 /* Print generally. Handles both write and display according to PSTATE.
481 */
482 SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write);
483 SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display);
484
485 static void iprin1 (SCM exp, SCM port, scm_print_state *pstate);
486
487
488 /* Print a character as an octal or hex escape. */
489 #define PRINT_CHAR_ESCAPE(i, port) \
490 do \
491 { \
492 if (!SCM_R6RS_ESCAPES_P) \
493 scm_intprint (i, 8, port); \
494 else \
495 { \
496 scm_puts_unlocked ("x", port); \
497 scm_intprint (i, 16, port); \
498 } \
499 } \
500 while (0)
501
502
503 void
504 scm_iprin1 (SCM exp, SCM port, scm_print_state *pstate)
505 {
506 if (pstate->fancyp
507 && scm_is_true (scm_memq (exp, pstate->highlight_objects)))
508 {
509 scm_display (SCM_PRINT_HIGHLIGHT_PREFIX, port);
510 iprin1 (exp, port, pstate);
511 scm_display (SCM_PRINT_HIGHLIGHT_SUFFIX, port);
512 }
513 else
514 iprin1 (exp, port, pstate);
515 }
516
517 static void
518 iprin1 (SCM exp, SCM port, scm_print_state *pstate)
519 {
520 switch (SCM_ITAG3 (exp))
521 {
522 case scm_tc3_tc7_1:
523 case scm_tc3_tc7_2:
524 /* These tc3 tags should never occur in an immediate value. They are
525 * only used in cell types of non-immediates, i. e. the value returned
526 * by SCM_CELL_TYPE (exp) can use these tags.
527 */
528 scm_ipruk ("immediate", exp, port);
529 break;
530 case scm_tc3_int_1:
531 case scm_tc3_int_2:
532 scm_intprint (SCM_I_INUM (exp), 10, port);
533 break;
534 case scm_tc3_imm24:
535 if (SCM_CHARP (exp))
536 {
537 if (SCM_WRITINGP (pstate))
538 write_character (SCM_CHAR (exp), port, 0);
539 else
540 {
541 if (!display_character (SCM_CHAR (exp), port,
542 scm_i_get_conversion_strategy (port)))
543 scm_encoding_error (__func__, errno,
544 "cannot convert to output locale",
545 port, exp);
546 }
547 }
548 else if (SCM_IFLAGP (exp)
549 && ((size_t) SCM_IFLAGNUM (exp) < (sizeof iflagnames / sizeof (char *))))
550 {
551 scm_puts_unlocked (iflagnames [SCM_IFLAGNUM (exp)], port);
552 }
553 else
554 {
555 /* unknown immediate value */
556 scm_ipruk ("immediate", exp, port);
557 }
558 break;
559 case scm_tc3_cons:
560 switch (SCM_TYP7 (exp))
561 {
562 case scm_tcs_struct:
563 {
564 ENTER_NESTED_DATA (pstate, exp, circref);
565 if (SCM_OBJ_CLASS_FLAGS (exp) & SCM_CLASSF_GOOPS)
566 {
567 SCM pwps, print = pstate->writingp ? g_write : g_display;
568 if (SCM_UNPACK (print) == 0)
569 goto print_struct;
570 pwps = scm_i_port_with_print_state (port, pstate->handle);
571 pstate->revealed = 1;
572 scm_call_2 (print, exp, pwps);
573 }
574 else
575 {
576 print_struct:
577 scm_print_struct (exp, port, pstate);
578 }
579 EXIT_NESTED_DATA (pstate);
580 }
581 break;
582 case scm_tcs_cons_imcar:
583 case scm_tcs_cons_nimcar:
584 ENTER_NESTED_DATA (pstate, exp, circref);
585 scm_iprlist ("(", exp, ')', port, pstate);
586 EXIT_NESTED_DATA (pstate);
587 break;
588 circref:
589 print_circref (port, pstate, exp);
590 break;
591 case scm_tc7_number:
592 switch SCM_TYP16 (exp) {
593 case scm_tc16_big:
594 scm_bigprint (exp, port, pstate);
595 break;
596 case scm_tc16_real:
597 scm_print_real (exp, port, pstate);
598 break;
599 case scm_tc16_complex:
600 scm_print_complex (exp, port, pstate);
601 break;
602 case scm_tc16_fraction:
603 scm_i_print_fraction (exp, port, pstate);
604 break;
605 }
606 break;
607 case scm_tc7_string:
608 if (SCM_WRITINGP (pstate))
609 {
610 size_t len, i;
611
612 display_character ('"', port, iconveh_question_mark);
613 len = scm_i_string_length (exp);
614 for (i = 0; i < len; ++i)
615 write_character (scm_i_string_ref (exp, i), port, 1);
616
617 display_character ('"', port, iconveh_question_mark);
618 scm_remember_upto_here_1 (exp);
619 }
620 else
621 {
622 size_t len, printed;
623
624 len = scm_i_string_length (exp);
625 printed = display_string (scm_i_string_data (exp),
626 scm_i_is_narrow_string (exp),
627 len, port,
628 scm_i_get_conversion_strategy (port));
629 if (SCM_UNLIKELY (printed < len))
630 scm_encoding_error (__func__, errno,
631 "cannot convert to output locale",
632 port, scm_c_string_ref (exp, printed));
633 }
634
635 scm_remember_upto_here_1 (exp);
636 break;
637 case scm_tc7_symbol:
638 if (scm_i_symbol_is_interned (exp))
639 {
640 print_symbol (exp, port);
641 scm_remember_upto_here_1 (exp);
642 }
643 else
644 {
645 scm_puts_unlocked ("#<uninterned-symbol ", port);
646 print_symbol (exp, port);
647 scm_putc_unlocked (' ', port);
648 scm_uintprint (SCM_UNPACK (exp), 16, port);
649 scm_putc_unlocked ('>', port);
650 }
651 break;
652 case scm_tc7_variable:
653 scm_i_variable_print (exp, port, pstate);
654 break;
655 case scm_tc7_program:
656 scm_i_program_print (exp, port, pstate);
657 break;
658 case scm_tc7_pointer:
659 scm_i_pointer_print (exp, port, pstate);
660 break;
661 case scm_tc7_hashtable:
662 scm_i_hashtable_print (exp, port, pstate);
663 break;
664 case scm_tc7_weak_set:
665 scm_i_weak_set_print (exp, port, pstate);
666 break;
667 case scm_tc7_weak_table:
668 scm_i_weak_table_print (exp, port, pstate);
669 break;
670 case scm_tc7_fluid:
671 scm_i_fluid_print (exp, port, pstate);
672 break;
673 case scm_tc7_dynamic_state:
674 scm_i_dynamic_state_print (exp, port, pstate);
675 break;
676 case scm_tc7_frame:
677 scm_i_frame_print (exp, port, pstate);
678 break;
679 case scm_tc7_objcode:
680 scm_i_objcode_print (exp, port, pstate);
681 break;
682 case scm_tc7_vm:
683 scm_i_vm_print (exp, port, pstate);
684 break;
685 case scm_tc7_vm_cont:
686 scm_i_vm_cont_print (exp, port, pstate);
687 break;
688 case scm_tc7_array:
689 ENTER_NESTED_DATA (pstate, exp, circref);
690 scm_i_print_array (exp, port, pstate);
691 EXIT_NESTED_DATA (pstate);
692 break;
693 case scm_tc7_bytevector:
694 scm_i_print_bytevector (exp, port, pstate);
695 break;
696 case scm_tc7_bitvector:
697 scm_i_print_bitvector (exp, port, pstate);
698 break;
699 case scm_tc7_wvect:
700 ENTER_NESTED_DATA (pstate, exp, circref);
701 scm_puts_unlocked ("#w(", port);
702 goto common_vector_printer;
703 case scm_tc7_vector:
704 ENTER_NESTED_DATA (pstate, exp, circref);
705 scm_puts_unlocked ("#(", port);
706 common_vector_printer:
707 {
708 register long i;
709 long last = SCM_SIMPLE_VECTOR_LENGTH (exp) - 1;
710 int cutp = 0;
711 if (pstate->fancyp
712 && SCM_SIMPLE_VECTOR_LENGTH (exp) > pstate->length)
713 {
714 last = pstate->length - 1;
715 cutp = 1;
716 }
717 for (i = 0; i < last; ++i)
718 {
719 scm_iprin1 (scm_c_vector_ref (exp, i), port, pstate);
720 scm_putc_unlocked (' ', port);
721 }
722 if (i == last)
723 {
724 /* CHECK_INTS; */
725 scm_iprin1 (scm_c_vector_ref (exp, i), port, pstate);
726 }
727 if (cutp)
728 scm_puts_unlocked (" ...", port);
729 scm_putc_unlocked (')', port);
730 }
731 EXIT_NESTED_DATA (pstate);
732 break;
733 case scm_tc7_port:
734 {
735 scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (exp);
736 if (ptob->print && ptob->print (exp, port, pstate))
737 break;
738 goto punk;
739 }
740 case scm_tc7_smob:
741 ENTER_NESTED_DATA (pstate, exp, circref);
742 SCM_SMOB_DESCRIPTOR (exp).print (exp, port, pstate);
743 EXIT_NESTED_DATA (pstate);
744 break;
745 default:
746 /* case scm_tcs_closures: */
747 punk:
748 scm_ipruk ("type", exp, port);
749 }
750 }
751 }
752
753 /* Print states are necessary for circular reference safe printing.
754 * They are also expensive to allocate. Therefore print states are
755 * kept in a pool so that they can be reused.
756 */
757
758 /* The PORT argument can also be a print-state/port pair, which will
759 * then be used instead of allocating a new print state. This is
760 * useful for continuing a chain of print calls from Scheme. */
761
762 void
763 scm_prin1 (SCM exp, SCM port, int writingp)
764 {
765 SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
766 SCM pstate_scm;
767 scm_print_state *pstate;
768 int old_writingp;
769
770 /* If PORT is a print-state/port pair, use that. Else create a new
771 print-state. */
772
773 if (SCM_PORT_WITH_PS_P (port))
774 {
775 pstate_scm = SCM_PORT_WITH_PS_PS (port);
776 port = SCM_PORT_WITH_PS_PORT (port);
777 }
778 else
779 {
780 /* First try to allocate a print state from the pool */
781 scm_i_pthread_mutex_lock (&print_state_mutex);
782 if (!scm_is_null (print_state_pool))
783 {
784 handle = print_state_pool;
785 print_state_pool = SCM_CDR (print_state_pool);
786 }
787 scm_i_pthread_mutex_unlock (&print_state_mutex);
788 if (scm_is_false (handle))
789 handle = scm_list_1 (make_print_state ());
790 pstate_scm = SCM_CAR (handle);
791 }
792
793 pstate = SCM_PRINT_STATE (pstate_scm);
794 old_writingp = pstate->writingp;
795 pstate->writingp = writingp;
796 scm_iprin1 (exp, port, pstate);
797 pstate->writingp = old_writingp;
798
799 /* Return print state to pool if it has been created above and
800 hasn't escaped to Scheme. */
801
802 if (scm_is_true (handle) && !pstate->revealed)
803 {
804 scm_i_pthread_mutex_lock (&print_state_mutex);
805 SCM_SETCDR (handle, print_state_pool);
806 print_state_pool = handle;
807 scm_i_pthread_mutex_unlock (&print_state_mutex);
808 }
809 }
810
811 /* Convert codepoint CH to UTF-8 and store the result in UTF8. Return
812 the number of bytes of the UTF-8-encoded string. */
813 static size_t
814 codepoint_to_utf8 (scm_t_wchar ch, scm_t_uint8 utf8[4])
815 {
816 size_t len;
817 scm_t_uint32 codepoint;
818
819 codepoint = (scm_t_uint32) ch;
820
821 if (codepoint <= 0x7f)
822 {
823 len = 1;
824 utf8[0] = (scm_t_uint8) codepoint;
825 }
826 else if (codepoint <= 0x7ffUL)
827 {
828 len = 2;
829 utf8[0] = 0xc0 | (codepoint >> 6);
830 utf8[1] = 0x80 | (codepoint & 0x3f);
831 }
832 else if (codepoint <= 0xffffUL)
833 {
834 len = 3;
835 utf8[0] = 0xe0 | (codepoint >> 12);
836 utf8[1] = 0x80 | ((codepoint >> 6) & 0x3f);
837 utf8[2] = 0x80 | (codepoint & 0x3f);
838 }
839 else
840 {
841 len = 4;
842 utf8[0] = 0xf0 | (codepoint >> 18);
843 utf8[1] = 0x80 | ((codepoint >> 12) & 0x3f);
844 utf8[2] = 0x80 | ((codepoint >> 6) & 0x3f);
845 utf8[3] = 0x80 | (codepoint & 0x3f);
846 }
847
848 return len;
849 }
850
851 #define STR_REF(s, x) \
852 (narrow_p \
853 ? (scm_t_wchar) ((unsigned char *) (s))[x] \
854 : ((scm_t_wchar *) (s))[x])
855
856 /* Write STR to PORT as UTF-8. STR is a LEN-codepoint string; it is
857 narrow if NARROW_P is true, wide otherwise. Return LEN. */
858 static size_t
859 display_string_as_utf8 (const void *str, int narrow_p, size_t len,
860 SCM port)
861 {
862 size_t printed = 0;
863
864 while (len > printed)
865 {
866 size_t utf8_len, i;
867 char *input, utf8_buf[256];
868
869 /* Convert STR to UTF-8. */
870 for (i = printed, utf8_len = 0, input = utf8_buf;
871 i < len && utf8_len + 4 < sizeof (utf8_buf);
872 i++)
873 {
874 utf8_len += codepoint_to_utf8 (STR_REF (str, i),
875 (scm_t_uint8 *) input);
876 input = utf8_buf + utf8_len;
877 }
878
879 /* INPUT was successfully converted, entirely; print the
880 result. */
881 scm_lfwrite_unlocked (utf8_buf, utf8_len, port);
882 printed += i - printed;
883 }
884
885 assert (printed == len);
886
887 return len;
888 }
889
890 /* Write STR to PORT as ISO-8859-1. STR is a LEN-codepoint string; it
891 is narrow if NARROW_P is true, wide otherwise. Return LEN. */
892 static size_t
893 display_string_as_latin1 (const void *str, int narrow_p, size_t len,
894 SCM port,
895 scm_t_string_failed_conversion_handler strategy)
896 {
897 size_t printed = 0;
898
899 if (narrow_p)
900 {
901 scm_lfwrite_unlocked (str, len, port);
902 return len;
903 }
904
905 while (printed < len)
906 {
907 char buf[256];
908 size_t i;
909
910 for (i = 0; i < sizeof(buf) && printed < len; i++, printed++)
911 {
912 scm_t_wchar c = STR_REF (str, printed);
913
914 if (c < 256)
915 buf[i] = c;
916 else
917 break;
918 }
919
920 scm_lfwrite_unlocked (buf, i, port);
921
922 if (i < sizeof(buf) && printed < len)
923 {
924 if (strategy == SCM_FAILED_CONVERSION_ERROR)
925 break;
926 else if (strategy == SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE)
927 write_character_escaped (STR_REF (str, printed), 1, port);
928 else
929 /* STRATEGY is `SCM_FAILED_CONVERSION_QUESTION_MARK'. */
930 display_string ("?", 1, 1, port, strategy);
931 printed++;
932 }
933 }
934
935 return printed;
936 }
937
938 /* Convert STR through PORT's output conversion descriptor and write the
939 output to PORT. Return the number of codepoints written. */
940 static size_t
941 display_string_using_iconv (const void *str, int narrow_p, size_t len,
942 SCM port,
943 scm_t_string_failed_conversion_handler strategy)
944 {
945 size_t printed;
946 scm_t_iconv_descriptors *id;
947
948 id = scm_i_port_iconv_descriptors (port);
949
950 printed = 0;
951
952 while (len > printed)
953 {
954 size_t done, utf8_len, input_left, output_left, i;
955 size_t codepoints_read, output_len;
956 char *input, *output;
957 char utf8_buf[256], encoded_output[256];
958 size_t offsets[256];
959
960 /* Convert STR to UTF-8. */
961 for (i = printed, utf8_len = 0, input = utf8_buf;
962 i < len && utf8_len + 4 < sizeof (utf8_buf);
963 i++)
964 {
965 offsets[utf8_len] = i;
966 utf8_len += codepoint_to_utf8 (STR_REF (str, i),
967 (scm_t_uint8 *) input);
968 input = utf8_buf + utf8_len;
969 }
970
971 input = utf8_buf;
972 input_left = utf8_len;
973
974 output = encoded_output;
975 output_left = sizeof (encoded_output);
976
977 done = iconv (id->output_cd, &input, &input_left,
978 &output, &output_left);
979
980 output_len = sizeof (encoded_output) - output_left;
981
982 if (SCM_UNLIKELY (done == (size_t) -1))
983 {
984 int errno_save = errno;
985
986 /* Reset the `iconv' state. */
987 iconv (id->output_cd, NULL, NULL, NULL, NULL);
988
989 /* Print the OUTPUT_LEN bytes successfully converted. */
990 scm_lfwrite_unlocked (encoded_output, output_len, port);
991
992 /* See how many input codepoints these OUTPUT_LEN bytes
993 corresponds to. */
994 codepoints_read = offsets[input - utf8_buf] - printed;
995 printed += codepoints_read;
996
997 if (errno_save == EILSEQ &&
998 strategy != SCM_FAILED_CONVERSION_ERROR)
999 {
1000 /* Conversion failed somewhere in INPUT and we want to
1001 escape or substitute the offending input character. */
1002
1003 if (strategy == SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE)
1004 {
1005 scm_t_wchar ch;
1006
1007 /* Find CH, the offending codepoint, and escape it. */
1008 ch = STR_REF (str, offsets[input - utf8_buf]);
1009 write_character_escaped (ch, 1, port);
1010 }
1011 else
1012 /* STRATEGY is `SCM_FAILED_CONVERSION_QUESTION_MARK'. */
1013 display_string ("?", 1, 1, port, strategy);
1014
1015 printed++;
1016 }
1017 else
1018 /* Something bad happened that we can't handle: bail out. */
1019 break;
1020 }
1021 else
1022 {
1023 /* INPUT was successfully converted, entirely; print the
1024 result. */
1025 scm_lfwrite_unlocked (encoded_output, output_len, port);
1026 codepoints_read = i - printed;
1027 printed += codepoints_read;
1028 }
1029 }
1030
1031 return printed;
1032 }
1033
1034 #undef STR_REF
1035
1036 /* Display the LEN codepoints in STR to PORT according to STRATEGY;
1037 return the number of codepoints successfully displayed. If NARROW_P,
1038 then STR is interpreted as a sequence of `char', denoting a Latin-1
1039 string; otherwise it's interpreted as a sequence of
1040 `scm_t_wchar'. */
1041 static size_t
1042 display_string (const void *str, int narrow_p,
1043 size_t len, SCM port,
1044 scm_t_string_failed_conversion_handler strategy)
1045 {
1046 scm_t_port *pt;
1047
1048 pt = SCM_PTAB_ENTRY (port);
1049
1050 if (pt->encoding_mode == SCM_PORT_ENCODING_MODE_UTF8)
1051 return display_string_as_utf8 (str, narrow_p, len, port);
1052 else if (pt->encoding_mode == SCM_PORT_ENCODING_MODE_LATIN1)
1053 return display_string_as_latin1 (str, narrow_p, len, port, strategy);
1054 else
1055 return display_string_using_iconv (str, narrow_p, len, port, strategy);
1056 }
1057
1058 /* Attempt to display CH to PORT according to STRATEGY. Return non-zero
1059 if CH was successfully displayed, zero otherwise (e.g., if it was not
1060 representable in PORT's encoding.) */
1061 static int
1062 display_character (scm_t_wchar ch, SCM port,
1063 scm_t_string_failed_conversion_handler strategy)
1064 {
1065 return display_string (&ch, 0, 1, port, strategy) == 1;
1066 }
1067
1068 /* Attempt to pretty-print CH, a combining character, to PORT. Return
1069 zero upon failure, non-zero otherwise. The idea is to print CH above
1070 a dotted circle to make it more visible. */
1071 static int
1072 write_combining_character (scm_t_wchar ch, SCM port)
1073 {
1074 scm_t_wchar str[2];
1075
1076 str[0] = SCM_CODEPOINT_DOTTED_CIRCLE;
1077 str[1] = ch;
1078
1079 return display_string (str, 0, 2, port, iconveh_error) == 2;
1080 }
1081
1082 /* Write CH to PORT in its escaped form, using the string escape syntax
1083 if STRING_ESCAPES_P is non-zero. */
1084 static void
1085 write_character_escaped (scm_t_wchar ch, int string_escapes_p, SCM port)
1086 {
1087 if (string_escapes_p)
1088 {
1089 /* Represent CH using the in-string escape syntax. */
1090
1091 static const char hex[] = "0123456789abcdef";
1092 static const char escapes[7] = "abtnvfr";
1093 char buf[9];
1094
1095 if (ch >= 0x07 && ch <= 0x0D && ch != 0x0A)
1096 {
1097 /* Use special escapes for some C0 controls. */
1098 buf[0] = '\\';
1099 buf[1] = escapes[ch - 0x07];
1100 scm_lfwrite_unlocked (buf, 2, port);
1101 }
1102 else if (!SCM_R6RS_ESCAPES_P)
1103 {
1104 if (ch <= 0xFF)
1105 {
1106 buf[0] = '\\';
1107 buf[1] = 'x';
1108 buf[2] = hex[ch / 16];
1109 buf[3] = hex[ch % 16];
1110 scm_lfwrite_unlocked (buf, 4, port);
1111 }
1112 else if (ch <= 0xFFFF)
1113 {
1114 buf[0] = '\\';
1115 buf[1] = 'u';
1116 buf[2] = hex[(ch & 0xF000) >> 12];
1117 buf[3] = hex[(ch & 0xF00) >> 8];
1118 buf[4] = hex[(ch & 0xF0) >> 4];
1119 buf[5] = hex[(ch & 0xF)];
1120 scm_lfwrite_unlocked (buf, 6, port);
1121 }
1122 else if (ch > 0xFFFF)
1123 {
1124 buf[0] = '\\';
1125 buf[1] = 'U';
1126 buf[2] = hex[(ch & 0xF00000) >> 20];
1127 buf[3] = hex[(ch & 0xF0000) >> 16];
1128 buf[4] = hex[(ch & 0xF000) >> 12];
1129 buf[5] = hex[(ch & 0xF00) >> 8];
1130 buf[6] = hex[(ch & 0xF0) >> 4];
1131 buf[7] = hex[(ch & 0xF)];
1132 scm_lfwrite_unlocked (buf, 8, port);
1133 }
1134 }
1135 else
1136 {
1137 /* Print an R6RS variable-length hex escape: "\xNNNN;". */
1138 scm_t_wchar ch2 = ch;
1139
1140 int i = 8;
1141 buf[i] = ';';
1142 i --;
1143 if (ch == 0)
1144 buf[i--] = '0';
1145 else
1146 while (ch2 > 0)
1147 {
1148 buf[i] = hex[ch2 & 0xF];
1149 ch2 >>= 4;
1150 i --;
1151 }
1152 buf[i] = 'x';
1153 i --;
1154 buf[i] = '\\';
1155 scm_lfwrite_unlocked (buf + i, 9 - i, port);
1156 }
1157 }
1158 else
1159 {
1160 /* Represent CH using the character escape syntax. */
1161 const char *name;
1162
1163 name = scm_i_charname (SCM_MAKE_CHAR (ch));
1164 if (name != NULL)
1165 scm_puts_unlocked (name, port);
1166 else
1167 PRINT_CHAR_ESCAPE (ch, port);
1168 }
1169 }
1170
1171 /* Write CH to PORT, escaping it if it's non-graphic or not
1172 representable in PORT's encoding. If STRING_ESCAPES_P is true and CH
1173 needs to be escaped, it is escaped using the in-string escape syntax;
1174 otherwise the character escape syntax is used. */
1175 static void
1176 write_character (scm_t_wchar ch, SCM port, int string_escapes_p)
1177 {
1178 int printed = 0;
1179 scm_t_string_failed_conversion_handler strategy;
1180
1181 strategy = scm_i_get_conversion_strategy (port);
1182
1183 if (string_escapes_p)
1184 {
1185 /* Check if CH deserves special treatment. */
1186 if (ch == '"' || ch == '\\')
1187 {
1188 display_character ('\\', port, iconveh_question_mark);
1189 display_character (ch, port, strategy);
1190 printed = 1;
1191 }
1192 else if (ch == '\n' && SCM_PRINT_ESCAPE_NEWLINES_P)
1193 {
1194 display_character ('\\', port, iconveh_question_mark);
1195 display_character ('n', port, strategy);
1196 printed = 1;
1197 }
1198 else if (ch == ' ' || ch == '\n')
1199 {
1200 display_character (ch, port, strategy);
1201 printed = 1;
1202 }
1203 }
1204 else
1205 {
1206 display_string ("#\\", 1, 2, port, iconveh_question_mark);
1207
1208 if (uc_combining_class (ch) != UC_CCC_NR)
1209 /* Character is a combining character, so attempt to
1210 pretty-print it. */
1211 printed = write_combining_character (ch, port);
1212 }
1213
1214 if (!printed
1215 && uc_is_general_category_withtable (ch,
1216 UC_CATEGORY_MASK_L |
1217 UC_CATEGORY_MASK_M |
1218 UC_CATEGORY_MASK_N |
1219 UC_CATEGORY_MASK_P |
1220 UC_CATEGORY_MASK_S))
1221 /* CH is graphic; attempt to display it. */
1222 printed = display_character (ch, port, iconveh_error);
1223
1224 if (!printed)
1225 /* CH isn't graphic or cannot be represented in PORT's encoding. */
1226 write_character_escaped (ch, string_escapes_p, port);
1227 }
1228
1229 /* Print an integer.
1230 */
1231
1232 void
1233 scm_intprint (scm_t_intmax n, int radix, SCM port)
1234 {
1235 char num_buf[SCM_INTBUFLEN];
1236 scm_lfwrite_unlocked (num_buf, scm_iint2str (n, radix, num_buf), port);
1237 }
1238
1239 void
1240 scm_uintprint (scm_t_uintmax n, int radix, SCM port)
1241 {
1242 char num_buf[SCM_INTBUFLEN];
1243 scm_lfwrite_unlocked (num_buf, scm_iuint2str (n, radix, num_buf), port);
1244 }
1245
1246 /* Print an object of unrecognized type.
1247 */
1248
1249 void
1250 scm_ipruk (char *hdr, SCM ptr, SCM port)
1251 {
1252 scm_puts_unlocked ("#<unknown-", port);
1253 scm_puts_unlocked (hdr, port);
1254 if (1) /* (scm_in_heap_p (ptr)) */ /* FIXME */
1255 {
1256 scm_puts_unlocked (" (0x", port);
1257 scm_uintprint (SCM_CELL_WORD_0 (ptr), 16, port);
1258 scm_puts_unlocked (" . 0x", port);
1259 scm_uintprint (SCM_CELL_WORD_1 (ptr), 16, port);
1260 scm_puts_unlocked (") @", port);
1261 }
1262 scm_puts_unlocked (" 0x", port);
1263 scm_uintprint (SCM_UNPACK (ptr), 16, port);
1264 scm_putc_unlocked ('>', port);
1265 }
1266
1267
1268 /* Print a list.
1269 */
1270 void
1271 scm_iprlist (char *hdr, SCM exp, int tlr, SCM port, scm_print_state *pstate)
1272 {
1273 register SCM hare, tortoise;
1274 long floor = pstate->top - 2;
1275 scm_puts_unlocked (hdr, port);
1276 /* CHECK_INTS; */
1277 if (pstate->fancyp)
1278 goto fancy_printing;
1279
1280 /* Run a hare and tortoise so that total time complexity will be
1281 O(depth * N) instead of O(N^2). */
1282 hare = SCM_CDR (exp);
1283 tortoise = exp;
1284 while (scm_is_pair (hare))
1285 {
1286 if (scm_is_eq (hare, tortoise))
1287 goto fancy_printing;
1288 hare = SCM_CDR (hare);
1289 if (!scm_is_pair (hare))
1290 break;
1291 hare = SCM_CDR (hare);
1292 tortoise = SCM_CDR (tortoise);
1293 }
1294
1295 /* No cdr cycles intrinsic to this list */
1296 scm_iprin1 (SCM_CAR (exp), port, pstate);
1297 for (exp = SCM_CDR (exp); scm_is_pair (exp); exp = SCM_CDR (exp))
1298 {
1299 register long i;
1300
1301 for (i = floor; i >= 0; --i)
1302 if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
1303 goto circref;
1304 PUSH_REF (pstate, exp);
1305 scm_putc_unlocked (' ', port);
1306 /* CHECK_INTS; */
1307 scm_iprin1 (SCM_CAR (exp), port, pstate);
1308 }
1309 if (!SCM_NULL_OR_NIL_P (exp))
1310 {
1311 scm_puts_unlocked (" . ", port);
1312 scm_iprin1 (exp, port, pstate);
1313 }
1314
1315 end:
1316 scm_putc_unlocked (tlr, port);
1317 pstate->top = floor + 2;
1318 return;
1319
1320 fancy_printing:
1321 {
1322 long n = pstate->length;
1323
1324 scm_iprin1 (SCM_CAR (exp), port, pstate);
1325 exp = SCM_CDR (exp); --n;
1326 for (; scm_is_pair (exp); exp = SCM_CDR (exp))
1327 {
1328 register unsigned long i;
1329
1330 for (i = 0; i < pstate->top; ++i)
1331 if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
1332 goto fancy_circref;
1333 if (pstate->fancyp)
1334 {
1335 if (n == 0)
1336 {
1337 scm_puts_unlocked (" ...", port);
1338 goto skip_tail;
1339 }
1340 else
1341 --n;
1342 }
1343 PUSH_REF(pstate, exp);
1344 ++pstate->list_offset;
1345 scm_putc_unlocked (' ', port);
1346 /* CHECK_INTS; */
1347 scm_iprin1 (SCM_CAR (exp), port, pstate);
1348 }
1349 }
1350 if (!SCM_NULL_OR_NIL_P (exp))
1351 {
1352 scm_puts_unlocked (" . ", port);
1353 scm_iprin1 (exp, port, pstate);
1354 }
1355 skip_tail:
1356 pstate->list_offset -= pstate->top - floor - 2;
1357 goto end;
1358
1359 fancy_circref:
1360 pstate->list_offset -= pstate->top - floor - 2;
1361
1362 circref:
1363 scm_puts_unlocked (" . ", port);
1364 print_circref (port, pstate, exp);
1365 goto end;
1366 }
1367
1368 \f
1369
1370 int
1371 scm_valid_oport_value_p (SCM val)
1372 {
1373 return (SCM_OPOUTPORTP (val)
1374 || (SCM_PORT_WITH_PS_P (val)
1375 && SCM_OPOUTPORTP (SCM_PORT_WITH_PS_PORT (val))));
1376 }
1377
1378 /* SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write); */
1379
1380 SCM
1381 scm_write (SCM obj, SCM port)
1382 {
1383 if (SCM_UNBNDP (port))
1384 port = scm_current_output_port ();
1385
1386 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
1387
1388 scm_dynwind_begin (0);
1389 scm_dynwind_lock_port (SCM_COERCE_OUTPORT (port));
1390 scm_prin1 (obj, port, 1);
1391 scm_dynwind_end ();
1392
1393 return SCM_UNSPECIFIED;
1394 }
1395
1396
1397 /* SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display); */
1398
1399 SCM
1400 scm_display (SCM obj, SCM port)
1401 {
1402 if (SCM_UNBNDP (port))
1403 port = scm_current_output_port ();
1404
1405 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
1406
1407 scm_dynwind_begin (0);
1408 scm_dynwind_lock_port (SCM_COERCE_OUTPORT (port));
1409 scm_prin1 (obj, port, 0);
1410 scm_dynwind_end ();
1411
1412 return SCM_UNSPECIFIED;
1413 }
1414
1415
1416 SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
1417 (SCM destination, SCM message, SCM args),
1418 "Write @var{message} to @var{destination}, defaulting to\n"
1419 "the current output port.\n"
1420 "@var{message} can contain @code{~A} (was @code{%s}) and\n"
1421 "@code{~S} (was @code{%S}) escapes. When printed,\n"
1422 "the escapes are replaced with corresponding members of\n"
1423 "@var{args}:\n"
1424 "@code{~A} formats using @code{display} and @code{~S} formats\n"
1425 "using @code{write}.\n"
1426 "If @var{destination} is @code{#t}, then use the current output\n"
1427 "port, if @var{destination} is @code{#f}, then return a string\n"
1428 "containing the formatted text. Does not add a trailing newline.")
1429 #define FUNC_NAME s_scm_simple_format
1430 {
1431 SCM port, answer = SCM_UNSPECIFIED;
1432 int fReturnString = 0;
1433 int writingp;
1434 size_t start, p, end;
1435
1436 if (scm_is_eq (destination, SCM_BOOL_T))
1437 {
1438 destination = port = scm_current_output_port ();
1439 }
1440 else if (scm_is_false (destination))
1441 {
1442 fReturnString = 1;
1443 port = scm_mkstrport (SCM_INUM0, SCM_BOOL_F,
1444 SCM_OPN | SCM_WRTNG,
1445 FUNC_NAME);
1446 destination = port;
1447 }
1448 else
1449 {
1450 SCM_VALIDATE_OPORT_VALUE (1, destination);
1451 port = SCM_COERCE_OUTPORT (destination);
1452 }
1453 SCM_VALIDATE_STRING (2, message);
1454 SCM_VALIDATE_REST_ARGUMENT (args);
1455
1456 p = 0;
1457 start = 0;
1458 end = scm_i_string_length (message);
1459 for (p = start; p != end; ++p)
1460 if (scm_i_string_ref (message, p) == '~')
1461 {
1462 if (++p == end)
1463 break;
1464
1465 switch (scm_i_string_ref (message, p))
1466 {
1467 case 'A': case 'a':
1468 writingp = 0;
1469 break;
1470 case 'S': case 's':
1471 writingp = 1;
1472 break;
1473 case '~':
1474 scm_lfwrite_substr (message, start, p, port);
1475 start = p + 1;
1476 continue;
1477 case '%':
1478 scm_lfwrite_substr (message, start, p - 1, port);
1479 scm_newline (port);
1480 start = p + 1;
1481 continue;
1482 default:
1483 SCM_MISC_ERROR ("FORMAT: Unsupported format option ~~~A - use (ice-9 format) instead",
1484 scm_list_1 (SCM_MAKE_CHAR (scm_i_string_ref (message, p))));
1485
1486 }
1487
1488
1489 if (!scm_is_pair (args))
1490 SCM_MISC_ERROR ("FORMAT: Missing argument for ~~~A",
1491 scm_list_1 (SCM_MAKE_CHAR (scm_i_string_ref (message, p))));
1492
1493 scm_lfwrite_substr (message, start, p - 1, port);
1494 /* we pass destination here */
1495 scm_prin1 (SCM_CAR (args), destination, writingp);
1496 args = SCM_CDR (args);
1497 start = p + 1;
1498 }
1499
1500 scm_lfwrite_substr (message, start, p, port);
1501 if (!scm_is_eq (args, SCM_EOL))
1502 SCM_MISC_ERROR ("FORMAT: ~A superfluous arguments",
1503 scm_list_1 (scm_length (args)));
1504
1505 if (fReturnString)
1506 answer = scm_strport_to_string (destination);
1507
1508 return scm_return_first (answer, message);
1509 }
1510 #undef FUNC_NAME
1511
1512
1513 SCM_DEFINE (scm_newline, "newline", 0, 1, 0,
1514 (SCM port),
1515 "Send a newline to @var{port}.\n"
1516 "If @var{port} is omitted, send to the current output port.")
1517 #define FUNC_NAME s_scm_newline
1518 {
1519 if (SCM_UNBNDP (port))
1520 port = scm_current_output_port ();
1521
1522 SCM_VALIDATE_OPORT_VALUE (1, port);
1523
1524 scm_putc_unlocked ('\n', SCM_COERCE_OUTPORT (port));
1525 return SCM_UNSPECIFIED;
1526 }
1527 #undef FUNC_NAME
1528
1529 SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
1530 (SCM chr, SCM port),
1531 "Send character @var{chr} to @var{port}.")
1532 #define FUNC_NAME s_scm_write_char
1533 {
1534 if (SCM_UNBNDP (port))
1535 port = scm_current_output_port ();
1536
1537 SCM_VALIDATE_CHAR (1, chr);
1538 SCM_VALIDATE_OPORT_VALUE (2, port);
1539
1540 port = SCM_COERCE_OUTPORT (port);
1541 if (!display_character (SCM_CHAR (chr), port,
1542 scm_i_get_conversion_strategy (port)))
1543 scm_encoding_error (__func__, errno,
1544 "cannot convert to output locale",
1545 port, chr);
1546
1547 return SCM_UNSPECIFIED;
1548 }
1549 #undef FUNC_NAME
1550
1551 \f
1552
1553 /* Call back to Scheme code to do the printing of special objects
1554 * (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a smob
1555 * containing PORT and PSTATE. This object can be used as the port for
1556 * display/write etc to continue the current print chain. The REVEALED
1557 * field of PSTATE is set to true to indicate that the print state has
1558 * escaped to Scheme and thus has to be freed by the GC.
1559 */
1560
1561 scm_t_bits scm_tc16_port_with_ps;
1562
1563 /* Print exactly as the port itself would */
1564
1565 static int
1566 port_with_ps_print (SCM obj, SCM port, scm_print_state *pstate)
1567 {
1568 obj = SCM_PORT_WITH_PS_PORT (obj);
1569 return SCM_PORT_DESCRIPTOR (obj)->print (obj, port, pstate);
1570 }
1571
1572 SCM
1573 scm_printer_apply (SCM proc, SCM exp, SCM port, scm_print_state *pstate)
1574 {
1575 pstate->revealed = 1;
1576 return scm_call_2 (proc, exp,
1577 scm_i_port_with_print_state (port, pstate->handle));
1578 }
1579
1580 SCM_DEFINE (scm_port_with_print_state, "port-with-print-state", 1, 1, 0,
1581 (SCM port, SCM pstate),
1582 "Create a new port which behaves like @var{port}, but with an\n"
1583 "included print state @var{pstate}. @var{pstate} is optional.\n"
1584 "If @var{pstate} isn't supplied and @var{port} already has\n"
1585 "a print state, the old print state is reused.")
1586 #define FUNC_NAME s_scm_port_with_print_state
1587 {
1588 SCM_VALIDATE_OPORT_VALUE (1, port);
1589 if (!SCM_UNBNDP (pstate))
1590 SCM_VALIDATE_PRINTSTATE (2, pstate);
1591 return scm_i_port_with_print_state (port, pstate);
1592 }
1593 #undef FUNC_NAME
1594
1595 SCM_DEFINE (scm_get_print_state, "get-print-state", 1, 0, 0,
1596 (SCM port),
1597 "Return the print state of the port @var{port}. If @var{port}\n"
1598 "has no associated print state, @code{#f} is returned.")
1599 #define FUNC_NAME s_scm_get_print_state
1600 {
1601 if (SCM_PORT_WITH_PS_P (port))
1602 return SCM_PORT_WITH_PS_PS (port);
1603 if (SCM_OUTPUT_PORT_P (port))
1604 return SCM_BOOL_F;
1605 SCM_WRONG_TYPE_ARG (1, port);
1606 }
1607 #undef FUNC_NAME
1608
1609 \f
1610
1611 void
1612 scm_init_print ()
1613 {
1614 SCM type;
1615
1616 type = scm_make_vtable (scm_from_locale_string (SCM_PRINT_STATE_LAYOUT),
1617 SCM_BOOL_F);
1618 scm_set_struct_vtable_name_x (type, scm_from_latin1_symbol ("print-state"));
1619 scm_print_state_vtable = type;
1620
1621 /* Don't want to bind a wrapper class in GOOPS, so pass 0 as arg1. */
1622 scm_tc16_port_with_ps = scm_make_smob_type (0, 0);
1623 scm_set_smob_print (scm_tc16_port_with_ps, port_with_ps_print);
1624
1625 #include "libguile/print.x"
1626
1627 scm_init_opts (scm_print_options, scm_print_opts);
1628 scm_print_opts[SCM_PRINT_HIGHLIGHT_PREFIX_I].val =
1629 SCM_UNPACK (scm_from_locale_string ("{"));
1630 scm_print_opts[SCM_PRINT_HIGHLIGHT_SUFFIX_I].val =
1631 SCM_UNPACK (scm_from_locale_string ("}"));
1632 scm_print_opts[SCM_PRINT_KEYWORD_STYLE_I].val = SCM_UNPACK (sym_reader);
1633 }
1634
1635 /*
1636 Local Variables:
1637 c-file-style: "gnu"
1638 End:
1639 */