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