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