*** empty log message ***
[bpt/guile.git] / libguile / print.c
CommitLineData
f2c9fcb0 1/* Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program 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
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46
47#include <stdio.h>
a0599745
MD
48#include "libguile/_scm.h"
49#include "libguile/chars.h"
a002f1a2 50#include "libguile/continuations.h"
a0599745
MD
51#include "libguile/smob.h"
52#include "libguile/eval.h"
53#include "libguile/macros.h"
54#include "libguile/procprop.h"
55#include "libguile/read.h"
56#include "libguile/weaks.h"
57#include "libguile/unif.h"
58#include "libguile/alist.h"
59#include "libguile/struct.h"
60#include "libguile/objects.h"
61#include "libguile/ports.h"
62#include "libguile/root.h"
63#include "libguile/strings.h"
64#include "libguile/strports.h"
65#include "libguile/vectors.h"
66
67#include "libguile/validate.h"
68#include "libguile/print.h"
0f2d19dd
JB
69\f
70
71/* {Names of immediate symbols}
72 *
73 * This table must agree with the declarations in scm.h: {Immediate Symbols}.
74 */
75
76char *scm_isymnames[] =
77{
78 /* This table must agree with the declarations */
79 "#@and",
80 "#@begin",
81 "#@case",
82 "#@cond",
83 "#@do",
84 "#@if",
85 "#@lambda",
86 "#@let",
87 "#@let*",
88 "#@letrec",
89 "#@or",
90 "#@quote",
91 "#@set!",
92 "#@define",
93#if 0
94 "#@literal-variable-ref",
95 "#@literal-variable-set!",
96#endif
97 "#@apply",
98 "#@call-with-current-continuation",
99
100 /* user visible ISYMS */
101 /* other keywords */
102 /* Flags */
103
104 "#f",
105 "#t",
106 "#<undefined>",
107 "#<eof>",
108 "()",
4df91bd6
MD
109 "#<unspecified>",
110 "#@dispatch",
43c667e9
MD
111 "#@slot-ref",
112 "#@slot-set!",
159500fb 113
159500fb
MD
114 /* Multi-language support */
115
116 "#@nil-cond",
117 "#@nil-ify",
118 "#@t-ify",
119 "#@0-cond",
120 "#@0-ify",
121 "#@1-ify",
ccd0e478
MD
122 "#@bind",
123
5623a9b4
MD
124 "#@delay",
125
126 "#<unbound>"
0f2d19dd
JB
127};
128
e6e4c9af 129scm_option scm_print_opts[] = {
f1267706 130 { SCM_OPTION_SCM, "closure-hook", SCM_UNPACK(SCM_BOOL_F),
84f6a34a
MD
131 "Hook for printing closures." },
132 { SCM_OPTION_BOOLEAN, "source", 0,
133 "Print closures with source." }
e6e4c9af
MD
134};
135
a1ec6916 136SCM_DEFINE (scm_print_options, "print-options-interface", 0, 1, 0,
1bbd0b84 137 (SCM setting),
71331188
MG
138 "Option interface for the print options. Instead of using\n"
139 "this procedure directly, use the procedures @code{print-enable},\n"
140 "@code{print-disable}, @code{print-set!} and @var{print-options}.")
1bbd0b84 141#define FUNC_NAME s_scm_print_options
e6e4c9af 142{
a51ea417 143 SCM ans = scm_options (setting,
b7ff98dd
MD
144 scm_print_opts,
145 SCM_N_PRINT_OPTIONS,
1bbd0b84 146 FUNC_NAME);
e6e4c9af
MD
147 return ans;
148}
1bbd0b84 149#undef FUNC_NAME
e6e4c9af 150
0f2d19dd
JB
151\f
152/* {Printing of Scheme Objects}
153 */
154
a51ea417 155/* Detection of circular references.
c62fbfe1
MD
156 *
157 * Due to other constraints in the implementation, this code has bad
5d46ebe3
MD
158 * time complexity (O (depth * N)), The printer code can be
159 * rewritten to be O(N).
a51ea417 160 */
c62fbfe1 161#define PUSH_REF(pstate, obj) \
1bbd0b84 162do { \
c62fbfe1
MD
163 pstate->ref_stack[pstate->top++] = (obj); \
164 if (pstate->top == pstate->ceiling) \
165 grow_ref_stack (pstate); \
1bbd0b84 166} while(0)
a51ea417 167
c62fbfe1 168#define ENTER_NESTED_DATA(pstate, obj, label) \
1bbd0b84 169do { \
5ca6dc39 170 register unsigned long i; \
c62fbfe1 171 for (i = 0; i < pstate->top; ++i) \
230d095f 172 if (SCM_EQ_P (pstate->ref_stack[i], (obj))) \
c62fbfe1
MD
173 goto label; \
174 if (pstate->fancyp) \
175 { \
176 if (pstate->top - pstate->list_offset >= pstate->level) \
177 { \
b7f3516f 178 scm_putc ('#', port); \
c62fbfe1
MD
179 return; \
180 } \
181 } \
182 PUSH_REF(pstate, obj); \
1bbd0b84 183} while(0)
a51ea417 184
c62fbfe1
MD
185#define EXIT_NESTED_DATA(pstate) { --pstate->top; }
186
bb35f315 187SCM scm_print_state_vtable;
c4f37e80 188
bb35f315 189static SCM print_state_pool;
c4f37e80 190
f843a84c 191#ifdef GUILE_DEBUG /* Used for debugging purposes */
1cc91f1b 192
3b3b36dd 193SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0,
1bbd0b84 194 (),
b450f070
GB
195 "Return the current-pstate--the `cadr' of the print_state_pool.\n"
196 "`current-pstate' is only included in GUILE_DEBUG builds.")
1bbd0b84 197#define FUNC_NAME s_scm_current_pstate
c62fbfe1 198{
a0adfbf0
MD
199 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
200 return SCM_CADR (print_state_pool);
201 else
0a284a4e 202 return SCM_BOOL_F;
c62fbfe1 203}
1bbd0b84
GB
204#undef FUNC_NAME
205
c62fbfe1
MD
206#endif
207
208#define PSTATE_SIZE 50L
209
698c0295 210static SCM
1bbd0b84 211make_print_state (void)
698c0295
MD
212{
213 SCM print_state = scm_make_struct (SCM_CAR (print_state_pool), /* pstate type */
bf685b6d 214 SCM_INUM0,
698c0295 215 SCM_EOL);
bf685b6d 216 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
00ffa0e7 217 pstate->ref_vect = scm_c_make_vector (PSTATE_SIZE, SCM_UNDEFINED);
bf685b6d 218 pstate->ref_stack = SCM_VELTS (pstate->ref_vect);
b17004b8 219 pstate->ceiling = SCM_VECTOR_LENGTH (pstate->ref_vect);
698c0295
MD
220 return print_state;
221}
1cc91f1b 222
c62fbfe1
MD
223SCM
224scm_make_print_state ()
c62fbfe1 225{
230d095f 226 SCM answer = SCM_BOOL_F;
698c0295
MD
227
228 /* First try to allocate a print state from the pool */
229 SCM_DEFER_INTS;
a0adfbf0 230 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
698c0295
MD
231 {
232 answer = SCM_CADR (print_state_pool);
233 SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
234 }
235 SCM_ALLOW_INTS;
236
230d095f 237 return SCM_FALSEP (answer) ? make_print_state () : answer;
c62fbfe1 238}
a51ea417 239
698c0295 240void
6e8d25a6 241scm_free_print_state (SCM print_state)
698c0295
MD
242{
243 SCM handle;
244 scm_print_state *pstate = SCM_PRINT_STATE (print_state);
245 /* Cleanup before returning print state to pool.
246 * It is better to do it here. Doing it in scm_prin1
247 * would cost more since that function is called much more
248 * often.
249 */
250 pstate->fancyp = 0;
bb35f315 251 pstate->revealed = 0;
698c0295
MD
252 SCM_NEWCELL (handle);
253 SCM_DEFER_INTS;
254 SCM_SETCAR (handle, print_state);
255 SCM_SETCDR (handle, SCM_CDR (print_state_pool));
256 SCM_SETCDR (print_state_pool, handle);
257 SCM_ALLOW_INTS;
258}
1cc91f1b 259
a51ea417 260static void
1bbd0b84 261grow_ref_stack (scm_print_state *pstate)
a51ea417 262{
b17004b8
DH
263 unsigned long int old_size = SCM_VECTOR_LENGTH (pstate->ref_vect);
264 SCM *old_elts = SCM_VELTS (pstate->ref_vect);
265 unsigned long int new_size = 2 * pstate->ceiling;
00ffa0e7 266 SCM new_vect = scm_c_make_vector (new_size, SCM_UNDEFINED);
b17004b8
DH
267 SCM *new_elts = SCM_VELTS (new_vect);
268 unsigned long int i;
269
270 for (i = 0; i != old_size; ++i)
271 new_elts [i] = old_elts [i];
272
273 pstate->ref_vect = new_vect;
274 pstate->ref_stack = new_elts;
bf685b6d 275 pstate->ceiling = new_size;
a51ea417
MD
276}
277
1cc91f1b 278
a51ea417 279static void
1bbd0b84 280print_circref (SCM port,scm_print_state *pstate,SCM ref)
a51ea417 281{
c62fbfe1
MD
282 register int i;
283 int self = pstate->top - 1;
284 i = pstate->top - 1;
285 if (SCM_CONSP (pstate->ref_stack[i]))
286 {
287 while (i > 0)
288 {
289 if (SCM_NCONSP (pstate->ref_stack[i - 1])
230d095f
DH
290 || !SCM_EQ_P (SCM_CDR (pstate->ref_stack[i - 1]),
291 pstate->ref_stack[i]))
c62fbfe1
MD
292 break;
293 --i;
294 }
295 self = i;
296 }
297 for (i = pstate->top - 1; 1; --i)
230d095f 298 if (SCM_EQ_P (pstate->ref_stack[i], ref))
c62fbfe1 299 break;
b7f3516f 300 scm_putc ('#', port);
c62fbfe1 301 scm_intprint (i - self, 10, port);
b7f3516f 302 scm_putc ('#', port);
a51ea417
MD
303}
304
c62fbfe1 305/* Print generally. Handles both write and display according to PSTATE.
0f2d19dd 306 */
8b840115
MD
307SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write);
308SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display);
1cc91f1b 309
0f2d19dd 310void
1bbd0b84 311scm_iprin1 (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 312{
0f2d19dd 313taloop:
54778cd3 314 switch (SCM_ITAG3 (exp))
0f2d19dd 315 {
e34f941a
DH
316 case scm_tc3_closure:
317 case scm_tc3_tc7_1:
318 case scm_tc3_tc7_2:
319 /* These tc3 tags should never occur in an immediate value. They are
320 * only used in cell types of non-immediates, i. e. the value returned
321 * by SCM_CELL_TYPE (exp) can use these tags.
322 */
323 scm_ipruk ("immediate", exp, port);
324 break;
325 case scm_tc3_int_1:
326 case scm_tc3_int_2:
0f2d19dd
JB
327 scm_intprint (SCM_INUM (exp), 10, port);
328 break;
e34f941a 329 case scm_tc3_imm24:
7866a09b 330 if (SCM_CHARP (exp))
0f2d19dd 331 {
e34f941a 332 long i = SCM_CHAR (exp);
5ca6dc39 333
b7f3516f
TT
334 if (SCM_WRITINGP (pstate))
335 {
336 scm_puts ("#\\", port);
337 if ((i >= 0) && (i <= ' ') && scm_charnames[i])
338 scm_puts (scm_charnames[i], port);
57b74422
GH
339#ifndef EBCDIC
340 else if (i == '\177')
341 scm_puts (scm_charnames[scm_n_charnames - 1], port);
342#endif
b7f3516f
TT
343 else if (i < 0 || i > '\177')
344 scm_intprint (i, 8, port);
345 else
346 scm_putc (i, port);
347 }
348 else
349 scm_putc (i, port);
0f2d19dd 350 }
a51ea417 351 else if (SCM_IFLAGP (exp)
5ca6dc39 352 && ((size_t) SCM_ISYMNUM (exp) < (sizeof scm_isymnames / sizeof (char *))))
b7f3516f 353 scm_puts (SCM_ISYMCHARS (exp), port);
0f2d19dd
JB
354 else if (SCM_ILOCP (exp))
355 {
b7f3516f 356 scm_puts ("#@", port);
230d095f 357 scm_intprint (SCM_IFRAME (exp), 10, port);
b7f3516f 358 scm_putc (SCM_ICDRP (exp) ? '-' : '+', port);
230d095f 359 scm_intprint (SCM_IDIST (exp), 10, port);
0f2d19dd
JB
360 }
361 else
e34f941a
DH
362 {
363 /* unknown immediate value */
364 scm_ipruk ("immediate", exp, port);
365 }
0f2d19dd 366 break;
e34f941a 367 case scm_tc3_cons_gloc:
0f2d19dd 368 /* gloc */
b7f3516f 369 scm_puts ("#@", port);
998308d3 370 exp = SCM_GLOC_SYM (exp);
0f2d19dd 371 goto taloop;
e34f941a 372 case scm_tc3_cons:
0f2d19dd
JB
373 switch (SCM_TYP7 (exp))
374 {
375 case scm_tcs_cons_gloc:
376
fee7ef83 377 if (SCM_STRUCT_VTABLE_DATA (exp) [scm_vtable_index_vcell] == 0)
0f2d19dd 378 {
c4f37e80 379 ENTER_NESTED_DATA (pstate, exp, circref);
8b840115
MD
380 if (SCM_OBJ_CLASS_FLAGS (exp) & SCM_CLASSF_GOOPS)
381 {
382 SCM pwps, print = pstate->writingp ? g_write : g_display;
383 if (!print)
384 goto print_struct;
385 SCM_NEWSMOB (pwps,
386 scm_tc16_port_with_ps,
54778cd3 387 SCM_UNPACK (scm_cons (port, pstate->handle)));
8b840115
MD
388 scm_call_generic_2 (print, exp, pwps);
389 }
390 else
391 {
392 print_struct:
393 scm_print_struct (exp, port, pstate);
394 }
c4f37e80 395 EXIT_NESTED_DATA (pstate);
0f2d19dd
JB
396 break;
397 }
398
399 case scm_tcs_cons_imcar:
400 case scm_tcs_cons_nimcar:
c62fbfe1
MD
401 ENTER_NESTED_DATA (pstate, exp, circref);
402 scm_iprlist ("(", exp, ')', port, pstate);
403 EXIT_NESTED_DATA (pstate);
a51ea417
MD
404 break;
405 circref:
c62fbfe1 406 print_circref (port, pstate, exp);
0f2d19dd 407 break;
7332df66 408 macros:
80ea260c 409 if (!SCM_CLOSUREP (SCM_CDR (exp)))
7332df66 410 goto prinmacro;
0f2d19dd 411 case scm_tcs_closures:
7332df66
MD
412 /* The user supplied print closure procedure must handle
413 macro closures as well. */
bb35f315
MV
414 if (SCM_FALSEP (scm_procedure_p (SCM_PRINT_CLOSURE))
415 || SCM_FALSEP (scm_printer_apply (SCM_PRINT_CLOSURE,
77c25af7 416 exp, port, pstate)))
bb35f315 417 {
ba031394 418 SCM name, code, env;
bb35f315
MV
419 if (SCM_TYP16 (exp) == scm_tc16_macro)
420 {
421 /* Printing a macro. */
422 prinmacro:
423 name = scm_macro_name (exp);
424 if (!SCM_CLOSUREP (SCM_CDR (exp)))
425 {
9e882eec 426 code = env = SCM_UNDEFINED;
b7f3516f 427 scm_puts ("#<primitive-", port);
bb35f315
MV
428 }
429 else
430 {
431 code = SCM_CODE (SCM_CDR (exp));
ba031394 432 env = SCM_ENV (SCM_CDR (exp));
b7f3516f 433 scm_puts ("#<", port);
bb35f315 434 }
206d3de3 435 if (SCM_CELL_WORD_0 (exp) & (3L << 16))
b7f3516f 436 scm_puts ("macro", port);
bb35f315 437 else
b7f3516f 438 scm_puts ("syntax", port);
206d3de3 439 if (SCM_CELL_WORD_0 (exp) & (2L << 16))
b7f3516f 440 scm_putc ('!', port);
bb35f315
MV
441 }
442 else
443 {
444 /* Printing a closure. */
445 name = scm_procedure_name (exp);
446 code = SCM_CODE (exp);
ba031394 447 env = SCM_ENV (exp);
b7f3516f 448 scm_puts ("#<procedure", port);
bb35f315 449 }
b24b5e13 450 if (SCM_SYMBOLP (name))
bb35f315 451 {
b7f3516f 452 scm_putc (' ', port);
b24b5e13
DH
453 scm_lfwrite (SCM_SYMBOL_CHARS (name), SCM_SYMBOL_LENGTH (name), port);
454 }
455 else if (SCM_STRINGP (name))
456 {
457 scm_putc (' ', port);
34f0f2b8 458 scm_lfwrite (SCM_STRING_CHARS (name), SCM_STRING_LENGTH (name), port);
bb35f315 459 }
9e882eec 460 if (!SCM_UNBNDP (code))
bb35f315 461 {
ba031394
MD
462 if (SCM_PRINT_SOURCE_P)
463 {
464 code = scm_unmemocopy (code,
465 SCM_EXTEND_ENV (SCM_CAR (code),
466 SCM_EOL,
467 env));
468 ENTER_NESTED_DATA (pstate, exp, circref);
469 scm_iprlist (" ", code, '>', port, pstate);
470 EXIT_NESTED_DATA (pstate);
471 }
472 else
473 {
474 if (SCM_TYP16 (exp) != scm_tc16_macro)
475 {
b7f3516f 476 scm_putc (' ', port);
ba031394
MD
477 scm_iprin1 (SCM_CAR (code), port, pstate);
478 }
b7f3516f 479 scm_putc ('>', port);
ba031394 480 }
bb35f315
MV
481 }
482 else
b7f3516f 483 scm_putc ('>', port);
bb35f315 484 }
0f2d19dd 485 break;
0f2d19dd
JB
486 case scm_tc7_substring:
487 case scm_tc7_string:
c62fbfe1 488 if (SCM_WRITINGP (pstate))
0f2d19dd 489 {
5ca6dc39
JB
490 scm_sizet i;
491
b7f3516f 492 scm_putc ('"', port);
d1ca2c64 493 for (i = 0; i < SCM_STRING_LENGTH (exp); ++i)
34f0f2b8 494 switch (SCM_STRING_CHARS (exp)[i])
0f2d19dd 495 {
dbef8851 496 case '"':
0f2d19dd 497 case '\\':
b7f3516f 498 scm_putc ('\\', port);
0f2d19dd 499 default:
34f0f2b8 500 scm_putc (SCM_STRING_CHARS (exp)[i], port);
0f2d19dd 501 }
b7f3516f 502 scm_putc ('"', port);
0f2d19dd
JB
503 break;
504 }
505 else
34f0f2b8 506 scm_lfwrite (SCM_STRING_CHARS (exp), SCM_STRING_LENGTH (exp), port);
0f2d19dd 507 break;
28b06554 508 case scm_tc7_symbol:
0f2d19dd
JB
509 {
510 int pos;
511 int end;
512 int len;
513 char * str;
514 int weird;
515 int maybe_weird;
4dc2435a 516 int mw_pos = 0;
0f2d19dd 517
b17004b8 518 len = SCM_SYMBOL_LENGTH (exp);
86c991c2 519 str = SCM_SYMBOL_CHARS (exp);
0f2d19dd
JB
520 pos = 0;
521 weird = 0;
522 maybe_weird = 0;
523
524 if (len == 0)
b7f3516f 525 scm_lfwrite ("#{}#", 4, port);
0f2d19dd
JB
526
527 for (end = pos; end < len; ++end)
528 switch (str[end])
529 {
530#ifdef BRACKETS_AS_PARENS
531 case '[':
532 case ']':
533#endif
534 case '(':
535 case ')':
dbef8851 536 case '"':
0f2d19dd
JB
537 case ';':
538 case SCM_WHITE_SPACES:
539 case SCM_LINE_INCREMENTORS:
540 weird_handler:
541 if (maybe_weird)
542 {
543 end = mw_pos;
544 maybe_weird = 0;
545 }
546 if (!weird)
547 {
b7f3516f 548 scm_lfwrite ("#{", 2, port);
0f2d19dd
JB
549 weird = 1;
550 }
551 if (pos < end)
552 {
b7f3516f 553 scm_lfwrite (str + pos, end - pos, port);
0f2d19dd
JB
554 }
555 {
556 char buf[2];
557 buf[0] = '\\';
558 buf[1] = str[end];
b7f3516f 559 scm_lfwrite (buf, 2, port);
0f2d19dd
JB
560 }
561 pos = end + 1;
562 break;
563 case '\\':
564 if (weird)
565 goto weird_handler;
566 if (!maybe_weird)
567 {
568 maybe_weird = 1;
569 mw_pos = pos;
570 }
571 break;
572 case '}':
573 case '#':
574 if (weird)
575 goto weird_handler;
576 break;
577 default:
578 break;
579 }
580 if (pos < end)
b7f3516f 581 scm_lfwrite (str + pos, end - pos, port);
5d2b97cd 582 scm_remember_upto_here_1 (exp);
0f2d19dd 583 if (weird)
b7f3516f 584 scm_lfwrite ("}#", 2, port);
0f2d19dd
JB
585 break;
586 }
587 case scm_tc7_wvect:
c62fbfe1 588 ENTER_NESTED_DATA (pstate, exp, circref);
0f2d19dd 589 if (SCM_IS_WHVEC (exp))
b7f3516f 590 scm_puts ("#wh(", port);
0f2d19dd 591 else
b7f3516f 592 scm_puts ("#w(", port);
0f2d19dd
JB
593 goto common_vector_printer;
594
595 case scm_tc7_vector:
c62fbfe1 596 ENTER_NESTED_DATA (pstate, exp, circref);
b7f3516f 597 scm_puts ("#(", port);
0f2d19dd 598 common_vector_printer:
9fbaf27c 599 {
5ca6dc39 600 register long i;
b17004b8 601 int last = SCM_VECTOR_LENGTH (exp) - 1;
9fbaf27c 602 int cutp = 0;
b17004b8 603 if (pstate->fancyp && SCM_VECTOR_LENGTH (exp) > pstate->length)
9fbaf27c
MD
604 {
605 last = pstate->length - 1;
606 cutp = 1;
607 }
608 for (i = 0; i < last; ++i)
609 {
610 /* CHECK_INTS; */
611 scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
b7f3516f 612 scm_putc (' ', port);
9fbaf27c
MD
613 }
614 if (i == last)
615 {
616 /* CHECK_INTS; */
617 scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
618 }
619 if (cutp)
b7f3516f
TT
620 scm_puts (" ...", port);
621 scm_putc (')', port);
9fbaf27c 622 }
c62fbfe1 623 EXIT_NESTED_DATA (pstate);
0f2d19dd 624 break;
afe5177e 625#ifdef HAVE_ARRAYS
0f2d19dd
JB
626 case scm_tc7_bvect:
627 case scm_tc7_byvect:
628 case scm_tc7_svect:
629 case scm_tc7_ivect:
630 case scm_tc7_uvect:
631 case scm_tc7_fvect:
632 case scm_tc7_dvect:
633 case scm_tc7_cvect:
5c11cc9d 634#ifdef HAVE_LONG_LONGS
0f2d19dd
JB
635 case scm_tc7_llvect:
636#endif
c62fbfe1 637 scm_raprin1 (exp, port, pstate);
0f2d19dd 638 break;
afe5177e 639#endif
0f2d19dd 640 case scm_tcs_subrs:
9de33deb
MD
641 scm_puts (SCM_SUBR_GENERIC (exp) && *SCM_SUBR_GENERIC (exp)
642 ? "#<primitive-generic "
643 : "#<primitive-procedure ",
644 port);
a002f1a2 645 scm_puts (SCM_SYMBOL_CHARS (SCM_SNAME (exp)), port);
b7f3516f 646 scm_putc ('>', port);
0f2d19dd
JB
647 break;
648#ifdef CCLO
649 case scm_tc7_cclo:
56977059
MD
650 {
651 SCM proc = SCM_CCLO_SUBR (exp);
54778cd3 652 if (SCM_EQ_P (proc, scm_f_gsubr_apply))
56977059
MD
653 {
654 /* Print gsubrs as primitives */
c180dfd3 655 SCM name = scm_procedure_name (exp);
56977059
MD
656 scm_puts ("#<primitive-procedure", port);
657 if (SCM_NFALSEP (name))
658 {
659 scm_putc (' ', port);
a002f1a2 660 scm_puts (SCM_SYMBOL_CHARS (name), port);
56977059
MD
661 }
662 }
663 else
664 {
665 scm_puts ("#<compiled-closure ", port);
666 scm_iprin1 (proc, port, pstate);
667 }
668 scm_putc ('>', port);
669 }
0f2d19dd
JB
670 break;
671#endif
c180dfd3
MD
672 case scm_tc7_pws:
673 scm_puts ("#<procedure-with-setter", port);
674 {
675 SCM name = scm_procedure_name (exp);
676 if (SCM_NFALSEP (name))
677 {
678 scm_putc (' ', port);
b24b5e13 679 scm_display (name, port);
c180dfd3
MD
680 }
681 }
682 scm_putc ('>', port);
683 break;
0f2d19dd 684 case scm_tc7_port:
5ca6dc39
JB
685 {
686 register long i = SCM_PTOBNUM (exp);
687 if (i < scm_numptob
688 && scm_ptobs[i].print
689 && (scm_ptobs[i].print) (exp, port, pstate))
a51ea417 690 break;
5ca6dc39
JB
691 goto punk;
692 }
693 case scm_tc7_smob:
694 {
695 register long i;
696 ENTER_NESTED_DATA (pstate, exp, circref);
697 i = SCM_SMOBNUM (exp);
698 if (i < scm_numsmob && scm_smobs[i].print
699 && (scm_smobs[i].print) (exp, port, pstate))
700 {
701 EXIT_NESTED_DATA (pstate);
702 break;
703 }
704 EXIT_NESTED_DATA (pstate);
705 /* Macros have their print field set to NULL. They are
706 handled at the same place as closures in order to achieve
707 non-redundancy. Placing the condition here won't slow
708 down printing of other smobs. */
709 if (SCM_TYP16 (exp) == scm_tc16_macro)
710 goto macros;
711 }
0f2d19dd 712 default:
a51ea417
MD
713 punk:
714 scm_ipruk ("type", exp, port);
0f2d19dd
JB
715 }
716 }
717}
718
c62fbfe1
MD
719/* Print states are necessary for circular reference safe printing.
720 * They are also expensive to allocate. Therefore print states are
721 * kept in a pool so that they can be reused.
722 */
1cc91f1b 723
bb35f315
MV
724/* The PORT argument can also be a print-state/port pair, which will
725 * then be used instead of allocating a new print state. This is
726 * useful for continuing a chain of print calls from Scheme. */
727
a51ea417 728void
1bbd0b84 729scm_prin1 (SCM exp, SCM port, int writingp)
a51ea417 730{
c4f37e80
MV
731 SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
732 SCM pstate_scm;
c62fbfe1
MD
733 scm_print_state *pstate;
734
bb35f315
MV
735 /* If PORT is a print-state/port pair, use that. Else create a new
736 print-state. */
c4f37e80 737
0c95b57d 738 if (SCM_PORT_WITH_PS_P (port))
bb35f315 739 {
52235e71
MD
740 pstate_scm = SCM_PORT_WITH_PS_PS (port);
741 port = SCM_PORT_WITH_PS_PORT (port);
bb35f315
MV
742 }
743 else
c62fbfe1 744 {
c4f37e80
MV
745 /* First try to allocate a print state from the pool */
746 SCM_DEFER_INTS;
747 if (SCM_NNULLP (SCM_CDR (print_state_pool)))
748 {
749 handle = SCM_CDR (print_state_pool);
750 SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
751 }
752 SCM_ALLOW_INTS;
54778cd3 753 if (SCM_FALSEP (handle))
c4f37e80
MV
754 handle = scm_cons (make_print_state (), SCM_EOL);
755 pstate_scm = SCM_CAR (handle);
c62fbfe1 756 }
c62fbfe1 757
c4f37e80 758 pstate = SCM_PRINT_STATE (pstate_scm);
c62fbfe1
MD
759 pstate->writingp = writingp;
760 scm_iprin1 (exp, port, pstate);
761
bb35f315
MV
762 /* Return print state to pool if it has been created above and
763 hasn't escaped to Scheme. */
764
54778cd3 765 if (!SCM_FALSEP (handle) && !pstate->revealed)
c4f37e80
MV
766 {
767 SCM_DEFER_INTS;
768 SCM_SETCDR (handle, SCM_CDR (print_state_pool));
769 SCM_SETCDR (print_state_pool, handle);
770 SCM_ALLOW_INTS;
771 }
a51ea417
MD
772}
773
0f2d19dd
JB
774
775/* Print an integer.
776 */
1cc91f1b 777
0f2d19dd 778void
1bbd0b84 779scm_intprint (long n, int radix, SCM port)
0f2d19dd
JB
780{
781 char num_buf[SCM_INTBUFLEN];
b7f3516f 782 scm_lfwrite (num_buf, scm_iint2str (n, radix, num_buf), port);
0f2d19dd
JB
783}
784
785/* Print an object of unrecognized type.
786 */
1cc91f1b 787
0f2d19dd 788void
1bbd0b84 789scm_ipruk (char *hdr, SCM ptr, SCM port)
0f2d19dd 790{
b7f3516f
TT
791 scm_puts ("#<unknown-", port);
792 scm_puts (hdr, port);
0f2d19dd
JB
793 if (SCM_CELLP (ptr))
794 {
b7f3516f 795 scm_puts (" (0x", port);
54778cd3 796 scm_intprint (SCM_CELL_WORD_0 (ptr), 16, port);
b7f3516f 797 scm_puts (" . 0x", port);
54778cd3 798 scm_intprint (SCM_CELL_WORD_1 (ptr), 16, port);
b7f3516f 799 scm_puts (") @", port);
0f2d19dd 800 }
b7f3516f 801 scm_puts (" 0x", port);
54778cd3 802 scm_intprint (SCM_UNPACK (ptr), 16, port);
b7f3516f 803 scm_putc ('>', port);
0f2d19dd
JB
804}
805
806/* Print a list.
807 */
a51ea417 808
1cc91f1b 809
0f2d19dd 810void
1bbd0b84 811scm_iprlist (char *hdr,SCM exp,int tlr,SCM port,scm_print_state *pstate)
0f2d19dd 812{
c62fbfe1
MD
813 register SCM hare, tortoise;
814 int floor = pstate->top - 2;
b7f3516f 815 scm_puts (hdr, port);
0f2d19dd 816 /* CHECK_INTS; */
c62fbfe1
MD
817 if (pstate->fancyp)
818 goto fancy_printing;
819
820 /* Run a hare and tortoise so that total time complexity will be
821 O(depth * N) instead of O(N^2). */
822 hare = SCM_CDR (exp);
823 tortoise = exp;
0c95b57d 824 while (SCM_ECONSP (hare))
c62fbfe1 825 {
54778cd3 826 if (SCM_EQ_P (hare, tortoise))
c62fbfe1
MD
827 goto fancy_printing;
828 hare = SCM_CDR (hare);
2fab3faa 829 if (SCM_IMP (hare) || SCM_NECONSP (hare))
c62fbfe1
MD
830 break;
831 hare = SCM_CDR (hare);
832 tortoise = SCM_CDR (tortoise);
833 }
834
835 /* No cdr cycles intrinsic to this list */
836 scm_iprin1 (SCM_CAR (exp), port, pstate);
0f2d19dd
JB
837 exp = SCM_CDR (exp);
838 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
839 {
5ca6dc39
JB
840 register int i;
841
0f2d19dd
JB
842 if (SCM_NECONSP (exp))
843 break;
c62fbfe1 844 for (i = floor; i >= 0; --i)
230d095f 845 if (SCM_EQ_P (pstate->ref_stack[i], exp))
c62fbfe1
MD
846 goto circref;
847 PUSH_REF (pstate, exp);
b7f3516f 848 scm_putc (' ', port);
0f2d19dd 849 /* CHECK_INTS; */
c62fbfe1 850 scm_iprin1 (SCM_CAR (exp), port, pstate);
0f2d19dd
JB
851 }
852 if (SCM_NNULLP (exp))
853 {
b7f3516f 854 scm_puts (" . ", port);
c62fbfe1 855 scm_iprin1 (exp, port, pstate);
0f2d19dd 856 }
c62fbfe1 857
a51ea417 858end:
b7f3516f 859 scm_putc (tlr, port);
c62fbfe1 860 pstate->top = floor + 2;
a51ea417 861 return;
c62fbfe1
MD
862
863fancy_printing:
864 {
865 int n = pstate->length;
866
867 scm_iprin1 (SCM_CAR (exp), port, pstate);
868 exp = SCM_CDR (exp); --n;
869 for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
870 {
5ca6dc39
JB
871 register unsigned long i;
872
c62fbfe1
MD
873 if (SCM_NECONSP (exp))
874 break;
875 for (i = 0; i < pstate->top; ++i)
230d095f 876 if (SCM_EQ_P (pstate->ref_stack[i], exp))
c62fbfe1
MD
877 goto fancy_circref;
878 if (pstate->fancyp)
879 {
880 if (n == 0)
881 {
b7f3516f 882 scm_puts (" ...", port);
c62fbfe1
MD
883 goto skip_tail;
884 }
885 else
886 --n;
887 }
888 PUSH_REF(pstate, exp);
889 ++pstate->list_offset;
b7f3516f 890 scm_putc (' ', port);
c62fbfe1
MD
891 /* CHECK_INTS; */
892 scm_iprin1 (SCM_CAR (exp), port, pstate);
893 }
894 }
895 if (SCM_NNULLP (exp))
896 {
b7f3516f 897 scm_puts (" . ", port);
c62fbfe1
MD
898 scm_iprin1 (exp, port, pstate);
899 }
900skip_tail:
901 pstate->list_offset -= pstate->top - floor - 2;
a51ea417 902 goto end;
a51ea417 903
c62fbfe1
MD
904fancy_circref:
905 pstate->list_offset -= pstate->top - floor - 2;
906
907circref:
b7f3516f 908 scm_puts (" . ", port);
c62fbfe1
MD
909 print_circref (port, pstate, exp);
910 goto end;
0f2d19dd
JB
911}
912
913\f
914
bb35f315
MV
915int
916scm_valid_oport_value_p (SCM val)
917{
368cf54d
GB
918 return (SCM_OPOUTPORTP (val)
919 || (SCM_PORT_WITH_PS_P (val)
920 && SCM_OPOUTPORTP (SCM_PORT_WITH_PS_PORT (val))));
bb35f315
MV
921}
922
8b840115 923/* SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write); */
1cc91f1b 924
0f2d19dd 925SCM
1bbd0b84 926scm_write (SCM obj, SCM port)
0f2d19dd
JB
927{
928 if (SCM_UNBNDP (port))
929 port = scm_cur_outp;
3eb7e6ee
JB
930
931 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
bb35f315 932
a51ea417 933 scm_prin1 (obj, port, 1);
0f2d19dd
JB
934#ifdef HAVE_PIPE
935# ifdef EPIPE
936 if (EPIPE == errno)
937 scm_close_port (port);
938# endif
939#endif
940 return SCM_UNSPECIFIED;
941}
942
943
8b840115 944/* SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display); */
1cc91f1b 945
0f2d19dd 946SCM
1bbd0b84 947scm_display (SCM obj, SCM port)
0f2d19dd
JB
948{
949 if (SCM_UNBNDP (port))
950 port = scm_cur_outp;
3eb7e6ee
JB
951
952 SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
bb35f315 953
a51ea417 954 scm_prin1 (obj, port, 0);
0f2d19dd
JB
955#ifdef HAVE_PIPE
956# ifdef EPIPE
957 if (EPIPE == errno)
958 scm_close_port (port);
959# endif
960#endif
961 return SCM_UNSPECIFIED;
962}
963
70d63753
GB
964
965SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
966 (SCM destination, SCM message, SCM args),
eca65e90
MG
967 "Write @var{message} to @var{destination}, defaulting to\n"
968 "the current output port.\n"
969 "@var{message} can contain @code{~A} (was @code{%s}) and\n"
970 "@code{~S} (was @code{%S}) escapes. When printed,\n"
971 "the escapes are replaced with corresponding members of\n"
972 "@var{ARGS}:\n"
973 "@code{~A} formats using @code{display} and @code{~S} formats\n"
974 "using @code{write}.\n"
975 "If @var{destination} is @code{#t}, then use the current output\n"
976 "port, if @var{destination} is @code{#f}, then return a string\n"
977 "containing the formatted text. Does not add a trailing newline.")
70d63753
GB
978#define FUNC_NAME s_scm_simple_format
979{
980 SCM answer = SCM_UNSPECIFIED;
981 int fReturnString = 0;
982 int writingp;
983 char *start;
b24b5e13 984 char *end;
70d63753
GB
985 char *p;
986
daba1a71
MD
987 if (SCM_EQ_P (destination, SCM_BOOL_T))
988 {
989 destination = scm_cur_outp;
990 }
991 else if (SCM_FALSEP (destination))
992 {
993 fReturnString = 1;
994 destination = scm_mkstrport (SCM_INUM0,
995 scm_make_string (SCM_INUM0, SCM_UNDEFINED),
996 SCM_OPN | SCM_WRTNG,
997 FUNC_NAME);
998 }
999 else
1000 {
1001 SCM_VALIDATE_OPORT_VALUE (1, destination);
1002 destination = SCM_COERCE_OUTPORT (destination);
1003 }
1004 SCM_VALIDATE_STRING (2, message);
af45e3b0 1005 SCM_VALIDATE_REST_ARGUMENT (args);
70d63753 1006
34f0f2b8 1007 start = SCM_STRING_CHARS (message);
b24b5e13
DH
1008 end = start + SCM_STRING_LENGTH (message);
1009 for (p = start; p != end; ++p)
70d63753
GB
1010 if (*p == '~')
1011 {
b24b5e13
DH
1012 if (!SCM_CONSP (args))
1013 continue;
1014
1015 if (++p == end)
70d63753
GB
1016 continue;
1017
cc6f0237 1018 if (*p == 'A' || *p == 'a')
70d63753 1019 writingp = 0;
cc6f0237 1020 else if (*p == 'S' || *p == 's')
70d63753
GB
1021 writingp = 1;
1022 else
1023 continue;
1024
1025 scm_lfwrite (start, p - start - 1, destination);
1026 scm_prin1 (SCM_CAR (args), destination, writingp);
1027 args = SCM_CDR (args);
1028 start = p + 1;
1029 }
1030 scm_lfwrite (start, p - start, destination);
1031
1032 if (fReturnString)
1033 answer = scm_strport_to_string (destination);
1034
daba1a71 1035 return scm_return_first (answer, message);
70d63753
GB
1036}
1037#undef FUNC_NAME
1038
1039
3b3b36dd 1040SCM_DEFINE (scm_newline, "newline", 0, 1, 0,
b450f070 1041 (SCM port),
eca65e90 1042 "Send a newline to @var{port}.")
1bbd0b84 1043#define FUNC_NAME s_scm_newline
0f2d19dd
JB
1044{
1045 if (SCM_UNBNDP (port))
bb35f315 1046 port = scm_cur_outp;
3eb7e6ee 1047
3b3b36dd 1048 SCM_VALIDATE_OPORT_VALUE (1,port);
bb35f315 1049
0ef4ae82 1050 scm_putc ('\n', SCM_COERCE_OUTPORT (port));
0f2d19dd
JB
1051 return SCM_UNSPECIFIED;
1052}
1bbd0b84 1053#undef FUNC_NAME
0f2d19dd 1054
3b3b36dd 1055SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
b450f070 1056 (SCM chr, SCM port),
eca65e90 1057 "Send character @var{chr} to @var{port}.")
1bbd0b84 1058#define FUNC_NAME s_scm_write_char
0f2d19dd
JB
1059{
1060 if (SCM_UNBNDP (port))
bb35f315 1061 port = scm_cur_outp;
3eb7e6ee 1062
7866a09b 1063 SCM_VALIDATE_CHAR (1,chr);
3b3b36dd 1064 SCM_VALIDATE_OPORT_VALUE (2,port);
bb35f315 1065
7866a09b 1066 scm_putc ((int) SCM_CHAR (chr), SCM_COERCE_OUTPORT (port));
0f2d19dd
JB
1067#ifdef HAVE_PIPE
1068# ifdef EPIPE
1069 if (EPIPE == errno)
1070 scm_close_port (port);
1071# endif
1072#endif
1073 return SCM_UNSPECIFIED;
1074}
1bbd0b84 1075#undef FUNC_NAME
0f2d19dd 1076
0f2d19dd
JB
1077\f
1078
bb35f315 1079/* Call back to Scheme code to do the printing of special objects
c19bc088
MD
1080 * (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a smob
1081 * containing PORT and PSTATE. This object can be used as the port for
1082 * display/write etc to continue the current print chain. The REVEALED
1083 * field of PSTATE is set to true to indicate that the print state has
1084 * escaped to Scheme and thus has to be freed by the GC.
1085 */
1086
e841c3e0 1087scm_bits_t scm_tc16_port_with_ps;
c19bc088
MD
1088
1089/* Print exactly as the port itself would */
1090
1091static int
e841c3e0 1092port_with_ps_print (SCM obj, SCM port, scm_print_state *pstate)
c19bc088
MD
1093{
1094 obj = SCM_PORT_WITH_PS_PORT (obj);
1095 return scm_ptobs[SCM_PTOBNUM (obj)].print (obj, port, pstate);
1096}
c4f37e80
MV
1097
1098SCM
1bbd0b84 1099scm_printer_apply (SCM proc, SCM exp, SCM port, scm_print_state *pstate)
c4f37e80 1100{
c19bc088 1101 SCM pwps;
bb35f315 1102 SCM pair = scm_cons (port, pstate->handle);
54778cd3 1103 SCM_NEWSMOB (pwps, scm_tc16_port_with_ps, SCM_UNPACK (pair));
bb35f315 1104 pstate->revealed = 1;
c19bc088
MD
1105 return scm_apply (proc, exp, scm_cons (pwps, scm_listofnull));
1106}
1107
a1ec6916 1108SCM_DEFINE (scm_port_with_print_state, "port-with-print-state", 2, 0, 0,
1bbd0b84 1109 (SCM port, SCM pstate),
71331188
MG
1110 "Create a new port which behaves like @var{port}, but with an\n"
1111 "included print state @var{pstate}.")
1bbd0b84 1112#define FUNC_NAME s_scm_port_with_print_state
c19bc088
MD
1113{
1114 SCM pwps;
3b3b36dd
GB
1115 SCM_VALIDATE_OPORT_VALUE (1,port);
1116 SCM_VALIDATE_PRINTSTATE (2,pstate);
c19bc088 1117 port = SCM_COERCE_OUTPORT (port);
54778cd3 1118 SCM_NEWSMOB (pwps, scm_tc16_port_with_ps, SCM_UNPACK (scm_cons (port, pstate)));
c19bc088
MD
1119 return pwps;
1120}
1bbd0b84 1121#undef FUNC_NAME
c19bc088 1122
a1ec6916 1123SCM_DEFINE (scm_get_print_state, "get-print-state", 1, 0, 0,
1bbd0b84 1124 (SCM port),
71331188
MG
1125 "Return the print state of the port @var{port}. If @var{port}\n"
1126 "has no associated print state, @code{#f} is returned.")
1bbd0b84 1127#define FUNC_NAME s_scm_get_print_state
c19bc088 1128{
368cf54d
GB
1129 if (SCM_PORT_WITH_PS_P (port))
1130 return SCM_PORT_WITH_PS_PS (port);
f5f2dcff 1131 if (SCM_OUTPUT_PORT_P (port))
368cf54d 1132 return SCM_BOOL_F;
276dd677 1133 SCM_WRONG_TYPE_ARG (1, port);
c4f37e80 1134}
1bbd0b84 1135#undef FUNC_NAME
bb35f315 1136
c4f37e80 1137\f
1cc91f1b 1138
0f2d19dd
JB
1139void
1140scm_init_print ()
0f2d19dd 1141{
c19bc088 1142 SCM vtable, layout, type;
4bfdf158 1143
b7ff98dd 1144 scm_init_opts (scm_print_options, scm_print_opts, SCM_N_PRINT_OPTIONS);
3ce4544c 1145 vtable = scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
4bfdf158 1146 layout = scm_make_struct_layout (scm_makfrom0str (SCM_PRINT_STATE_LAYOUT));
c19bc088 1147 type = scm_make_struct (vtable, SCM_INUM0, SCM_LIST1 (layout));
38ae064c 1148 scm_set_struct_vtable_name_x (type, scm_str2symbol ("print-state"));
c62fbfe1 1149 print_state_pool = scm_permanent_object (scm_cons (type, SCM_EOL));
c4f37e80 1150
bb35f315 1151 scm_print_state_vtable = type;
c4f37e80 1152
c19bc088
MD
1153 /* Don't want to bind a wrapper class in GOOPS, so pass 0 as arg1. */
1154 scm_tc16_port_with_ps = scm_make_smob_type (0, 0);
1155 scm_set_smob_mark (scm_tc16_port_with_ps, scm_markcdr);
e841c3e0 1156 scm_set_smob_print (scm_tc16_port_with_ps, port_with_ps_print);
c19bc088 1157
8dc9439f 1158#ifndef SCM_MAGIC_SNARFER
a0599745 1159#include "libguile/print.x"
8dc9439f 1160#endif
0f2d19dd 1161}
89e00824
ML
1162
1163/*
1164 Local Variables:
1165 c-file-style: "gnu"
1166 End:
1167*/