print.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131
  1. /* Copyright (C) 1995-1999, 2000, 2002 Free Software Foundation, Inc.
  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
  15. * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. * Boston, MA 02111-1307 USA
  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.
  40. * If you do not wish that, delete this exception notice. */
  41. #include <stdio.h>
  42. #include "libguile/_scm.h"
  43. #include "libguile/chars.h"
  44. #include "libguile/smob.h"
  45. #include "libguile/eval.h"
  46. #include "libguile/macros.h"
  47. #include "libguile/procprop.h"
  48. #include "libguile/read.h"
  49. #include "libguile/weaks.h"
  50. #include "libguile/unif.h"
  51. #include "libguile/alist.h"
  52. #include "libguile/struct.h"
  53. #include "libguile/objects.h"
  54. #include "libguile/ports.h"
  55. #include "libguile/root.h"
  56. #include "libguile/strings.h"
  57. #include "libguile/strports.h"
  58. #include "libguile/vectors.h"
  59. #include "libguile/validate.h"
  60. #include "libguile/print.h"
  61. /* {Names of immediate symbols}
  62. *
  63. * This table must agree with the declarations in scm.h: {Immediate Symbols}.
  64. */
  65. char *scm_isymnames[] =
  66. {
  67. /* This table must agree with the declarations */
  68. "#@and",
  69. "#@begin",
  70. "#@case",
  71. "#@cond",
  72. "#@do",
  73. "#@if",
  74. "#@lambda",
  75. "#@let",
  76. "#@let*",
  77. "#@letrec",
  78. "#@or",
  79. "#@quote",
  80. "#@set!",
  81. "#@define",
  82. #if 0
  83. "#@literal-variable-ref",
  84. "#@literal-variable-set!",
  85. #endif
  86. "#@apply",
  87. "#@call-with-current-continuation",
  88. /* user visible ISYMS */
  89. /* other keywords */
  90. /* Flags */
  91. "#f",
  92. "#t",
  93. "#<undefined>",
  94. "#<eof>",
  95. "()",
  96. "#<unspecified>",
  97. "#@dispatch",
  98. "#@slot-ref",
  99. "#@slot-set!",
  100. /* Multi-language support */
  101. "#@nil-cond",
  102. "#@nil-ify",
  103. "#@t-ify",
  104. "#@0-cond",
  105. "#@0-ify",
  106. "#@1-ify",
  107. "#@bind",
  108. "#@delay",
  109. "#<unbound>"
  110. };
  111. scm_option scm_print_opts[] = {
  112. { SCM_OPTION_SCM, "closure-hook", SCM_UNPACK(SCM_BOOL_F),
  113. "Hook for printing closures." },
  114. { SCM_OPTION_BOOLEAN, "source", 0,
  115. "Print closures with source." }
  116. };
  117. SCM_DEFINE (scm_print_options, "print-options-interface", 0, 1, 0,
  118. (SCM setting),
  119. "")
  120. #define FUNC_NAME s_scm_print_options
  121. {
  122. SCM ans = scm_options (setting,
  123. scm_print_opts,
  124. SCM_N_PRINT_OPTIONS,
  125. FUNC_NAME);
  126. return ans;
  127. }
  128. #undef FUNC_NAME
  129. /* {Printing of Scheme Objects}
  130. */
  131. /* Detection of circular references.
  132. *
  133. * Due to other constraints in the implementation, this code has bad
  134. * time complexity (O (depth * N)), The printer code can be
  135. * rewritten to be O(N).
  136. */
  137. #define PUSH_REF(pstate, obj) \
  138. do { \
  139. pstate->ref_stack[pstate->top++] = (obj); \
  140. if (pstate->top == pstate->ceiling) \
  141. grow_ref_stack (pstate); \
  142. } while(0)
  143. #define ENTER_NESTED_DATA(pstate, obj, label) \
  144. do { \
  145. register unsigned long i; \
  146. for (i = 0; i < pstate->top; ++i) \
  147. if (SCM_EQ_P (pstate->ref_stack[i], (obj))) \
  148. goto label; \
  149. if (pstate->fancyp) \
  150. { \
  151. if (pstate->top - pstate->list_offset >= pstate->level) \
  152. { \
  153. scm_putc ('#', port); \
  154. return; \
  155. } \
  156. } \
  157. PUSH_REF(pstate, obj); \
  158. } while(0)
  159. #define EXIT_NESTED_DATA(pstate) { --pstate->top; }
  160. SCM scm_print_state_vtable;
  161. static SCM print_state_pool;
  162. #ifdef GUILE_DEBUG /* Used for debugging purposes */
  163. SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0,
  164. (),
  165. "Return the current-pstate--the `cadr' of the print_state_pool.\n"
  166. "`current-pstate' is only included in GUILE_DEBUG builds.")
  167. #define FUNC_NAME s_scm_current_pstate
  168. {
  169. if (SCM_NNULLP (SCM_CDR (print_state_pool)))
  170. return SCM_CADR (print_state_pool);
  171. else
  172. return SCM_BOOL_F;
  173. }
  174. #undef FUNC_NAME
  175. #endif
  176. #define PSTATE_SIZE 50L
  177. static SCM
  178. make_print_state (void)
  179. {
  180. SCM print_state = scm_make_struct (SCM_CAR (print_state_pool), /* pstate type */
  181. SCM_INUM0,
  182. SCM_EOL);
  183. scm_print_state *pstate = SCM_PRINT_STATE (print_state);
  184. pstate->ref_vect = scm_make_vector (SCM_MAKINUM (PSTATE_SIZE),
  185. SCM_UNDEFINED);
  186. pstate->ref_stack = SCM_VELTS (pstate->ref_vect);
  187. pstate->ceiling = SCM_LENGTH (pstate->ref_vect);
  188. return print_state;
  189. }
  190. SCM
  191. scm_make_print_state ()
  192. {
  193. SCM answer = SCM_BOOL_F;
  194. /* First try to allocate a print state from the pool */
  195. SCM_DEFER_INTS;
  196. if (SCM_NNULLP (SCM_CDR (print_state_pool)))
  197. {
  198. answer = SCM_CADR (print_state_pool);
  199. SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
  200. }
  201. SCM_ALLOW_INTS;
  202. return SCM_FALSEP (answer) ? make_print_state () : answer;
  203. }
  204. void
  205. scm_free_print_state (SCM print_state)
  206. {
  207. SCM handle;
  208. scm_print_state *pstate = SCM_PRINT_STATE (print_state);
  209. /* Cleanup before returning print state to pool.
  210. * It is better to do it here. Doing it in scm_prin1
  211. * would cost more since that function is called much more
  212. * often.
  213. */
  214. pstate->fancyp = 0;
  215. pstate->revealed = 0;
  216. SCM_NEWCELL (handle);
  217. SCM_DEFER_INTS;
  218. SCM_SETCAR (handle, print_state);
  219. SCM_SETCDR (handle, SCM_CDR (print_state_pool));
  220. SCM_SETCDR (print_state_pool, handle);
  221. SCM_ALLOW_INTS;
  222. }
  223. static void
  224. grow_ref_stack (scm_print_state *pstate)
  225. {
  226. int new_size = 2 * pstate->ceiling;
  227. scm_vector_set_length_x (pstate->ref_vect, SCM_MAKINUM (new_size));
  228. pstate->ref_stack = SCM_VELTS (pstate->ref_vect);
  229. pstate->ceiling = new_size;
  230. }
  231. static void
  232. print_circref (SCM port,scm_print_state *pstate,SCM ref)
  233. {
  234. register int i;
  235. int self = pstate->top - 1;
  236. i = pstate->top - 1;
  237. if (SCM_CONSP (pstate->ref_stack[i]))
  238. {
  239. while (i > 0)
  240. {
  241. if (SCM_NCONSP (pstate->ref_stack[i - 1])
  242. || !SCM_EQ_P (SCM_CDR (pstate->ref_stack[i - 1]),
  243. pstate->ref_stack[i]))
  244. break;
  245. --i;
  246. }
  247. self = i;
  248. }
  249. for (i = pstate->top - 1; 1; --i)
  250. if (SCM_EQ_P (pstate->ref_stack[i], ref))
  251. break;
  252. scm_putc ('#', port);
  253. scm_intprint (i - self, 10, port);
  254. scm_putc ('#', port);
  255. }
  256. /* Print generally. Handles both write and display according to PSTATE.
  257. */
  258. SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write);
  259. SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display);
  260. void
  261. scm_iprin1 (SCM exp, SCM port, scm_print_state *pstate)
  262. {
  263. taloop:
  264. switch (SCM_ITAG3 (exp))
  265. {
  266. case 2:
  267. case 6:
  268. scm_intprint (SCM_INUM (exp), 10, port);
  269. break;
  270. case 4:
  271. if (SCM_CHARP (exp))
  272. {
  273. register long i;
  274. i = SCM_CHAR (exp);
  275. if (SCM_WRITINGP (pstate))
  276. {
  277. scm_puts ("#\\", port);
  278. if ((i >= 0) && (i <= ' ') && scm_charnames[i])
  279. scm_puts (scm_charnames[i], port);
  280. else if (i < 0 || i > '\177')
  281. scm_intprint (i, 8, port);
  282. else
  283. scm_putc (i, port);
  284. }
  285. else
  286. scm_putc (i, port);
  287. }
  288. else if (SCM_IFLAGP (exp)
  289. && ((size_t) SCM_ISYMNUM (exp) < (sizeof scm_isymnames / sizeof (char *))))
  290. scm_puts (SCM_ISYMCHARS (exp), port);
  291. else if (SCM_ILOCP (exp))
  292. {
  293. scm_puts ("#@", port);
  294. scm_intprint (SCM_IFRAME (exp), 10, port);
  295. scm_putc (SCM_ICDRP (exp) ? '-' : '+', port);
  296. scm_intprint (SCM_IDIST (exp), 10, port);
  297. }
  298. else
  299. goto idef;
  300. break;
  301. case 1:
  302. /* gloc */
  303. scm_puts ("#@", port);
  304. exp = SCM_GLOC_SYM (exp);
  305. goto taloop;
  306. default:
  307. idef:
  308. scm_ipruk ("immediate", exp, port);
  309. break;
  310. case 0:
  311. switch (SCM_TYP7 (exp))
  312. {
  313. case scm_tcs_cons_gloc:
  314. if (SCM_STRUCT_VTABLE_DATA (exp) [scm_vtable_index_vcell] == 0)
  315. {
  316. ENTER_NESTED_DATA (pstate, exp, circref);
  317. if (SCM_OBJ_CLASS_FLAGS (exp) & SCM_CLASSF_GOOPS)
  318. {
  319. SCM pwps, print = pstate->writingp ? g_write : g_display;
  320. if (!print)
  321. goto print_struct;
  322. SCM_NEWSMOB (pwps,
  323. scm_tc16_port_with_ps,
  324. SCM_UNPACK (scm_cons (port, pstate->handle)));
  325. scm_call_generic_2 (print, exp, pwps);
  326. }
  327. else
  328. {
  329. print_struct:
  330. scm_print_struct (exp, port, pstate);
  331. }
  332. EXIT_NESTED_DATA (pstate);
  333. break;
  334. }
  335. case scm_tcs_cons_imcar:
  336. case scm_tcs_cons_nimcar:
  337. ENTER_NESTED_DATA (pstate, exp, circref);
  338. scm_iprlist ("(", exp, ')', port, pstate);
  339. EXIT_NESTED_DATA (pstate);
  340. break;
  341. circref:
  342. print_circref (port, pstate, exp);
  343. break;
  344. macros:
  345. if (!SCM_CLOSUREP (SCM_CDR (exp)))
  346. goto prinmacro;
  347. case scm_tcs_closures:
  348. /* The user supplied print closure procedure must handle
  349. macro closures as well. */
  350. if (SCM_FALSEP (scm_procedure_p (SCM_PRINT_CLOSURE))
  351. || SCM_FALSEP (scm_printer_apply (SCM_PRINT_CLOSURE,
  352. exp, port, pstate)))
  353. {
  354. SCM name, code, env;
  355. if (SCM_TYP16 (exp) == scm_tc16_macro)
  356. {
  357. /* Printing a macro. */
  358. prinmacro:
  359. name = scm_macro_name (exp);
  360. if (!SCM_CLOSUREP (SCM_CDR (exp)))
  361. {
  362. code = env = SCM_UNDEFINED;
  363. scm_puts ("#<primitive-", port);
  364. }
  365. else
  366. {
  367. code = SCM_CODE (SCM_CDR (exp));
  368. env = SCM_ENV (SCM_CDR (exp));
  369. scm_puts ("#<", port);
  370. }
  371. if (SCM_CELL_WORD_0 (exp) & (3L << 16))
  372. scm_puts ("macro", port);
  373. else
  374. scm_puts ("syntax", port);
  375. if (SCM_CELL_WORD_0 (exp) & (2L << 16))
  376. scm_putc ('!', port);
  377. }
  378. else
  379. {
  380. /* Printing a closure. */
  381. name = scm_procedure_name (exp);
  382. code = SCM_CODE (exp);
  383. env = SCM_ENV (exp);
  384. scm_puts ("#<procedure", port);
  385. }
  386. if (SCM_ROSTRINGP (name))
  387. {
  388. scm_putc (' ', port);
  389. scm_puts (SCM_ROCHARS (name), port);
  390. }
  391. if (!SCM_UNBNDP (code))
  392. {
  393. if (SCM_PRINT_SOURCE_P)
  394. {
  395. code = scm_unmemocopy (code,
  396. SCM_EXTEND_ENV (SCM_CAR (code),
  397. SCM_EOL,
  398. env));
  399. ENTER_NESTED_DATA (pstate, exp, circref);
  400. scm_iprlist (" ", code, '>', port, pstate);
  401. EXIT_NESTED_DATA (pstate);
  402. }
  403. else
  404. {
  405. if (SCM_TYP16 (exp) != scm_tc16_macro)
  406. {
  407. scm_putc (' ', port);
  408. scm_iprin1 (SCM_CAR (code), port, pstate);
  409. }
  410. scm_putc ('>', port);
  411. }
  412. }
  413. else
  414. scm_putc ('>', port);
  415. }
  416. break;
  417. case scm_tc7_substring:
  418. case scm_tc7_string:
  419. if (SCM_WRITINGP (pstate))
  420. {
  421. scm_sizet i;
  422. scm_putc ('"', port);
  423. for (i = 0; i < SCM_ROLENGTH (exp); ++i)
  424. switch (SCM_ROCHARS (exp)[i])
  425. {
  426. case '"':
  427. case '\\':
  428. scm_putc ('\\', port);
  429. default:
  430. scm_putc (SCM_ROCHARS (exp)[i], port);
  431. }
  432. scm_putc ('"', port);
  433. break;
  434. }
  435. else
  436. scm_lfwrite (SCM_ROCHARS (exp), (scm_sizet) SCM_ROLENGTH (exp),
  437. port);
  438. break;
  439. case scm_tcs_symbols:
  440. {
  441. int pos;
  442. int end;
  443. int len;
  444. char * str;
  445. int weird;
  446. int maybe_weird;
  447. int mw_pos = 0;
  448. len = SCM_LENGTH (exp);
  449. str = SCM_CHARS (exp);
  450. scm_remember (&exp);
  451. pos = 0;
  452. weird = 0;
  453. maybe_weird = 0;
  454. if (len == 0)
  455. scm_lfwrite ("#{}#", 4, port);
  456. for (end = pos; end < len; ++end)
  457. switch (str[end])
  458. {
  459. #ifdef BRACKETS_AS_PARENS
  460. case '[':
  461. case ']':
  462. #endif
  463. case '(':
  464. case ')':
  465. case '"':
  466. case ';':
  467. case SCM_WHITE_SPACES:
  468. case SCM_LINE_INCREMENTORS:
  469. weird_handler:
  470. if (maybe_weird)
  471. {
  472. end = mw_pos;
  473. maybe_weird = 0;
  474. }
  475. if (!weird)
  476. {
  477. scm_lfwrite ("#{", 2, port);
  478. weird = 1;
  479. }
  480. if (pos < end)
  481. {
  482. scm_lfwrite (str + pos, end - pos, port);
  483. }
  484. {
  485. char buf[2];
  486. buf[0] = '\\';
  487. buf[1] = str[end];
  488. scm_lfwrite (buf, 2, port);
  489. }
  490. pos = end + 1;
  491. break;
  492. case '\\':
  493. if (weird)
  494. goto weird_handler;
  495. if (!maybe_weird)
  496. {
  497. maybe_weird = 1;
  498. mw_pos = pos;
  499. }
  500. break;
  501. case '}':
  502. case '#':
  503. if (weird)
  504. goto weird_handler;
  505. break;
  506. default:
  507. break;
  508. }
  509. if (pos < end)
  510. scm_lfwrite (str + pos, end - pos, port);
  511. if (weird)
  512. scm_lfwrite ("}#", 2, port);
  513. break;
  514. }
  515. case scm_tc7_wvect:
  516. ENTER_NESTED_DATA (pstate, exp, circref);
  517. if (SCM_IS_WHVEC (exp))
  518. scm_puts ("#wh(", port);
  519. else
  520. scm_puts ("#w(", port);
  521. goto common_vector_printer;
  522. case scm_tc7_vector:
  523. ENTER_NESTED_DATA (pstate, exp, circref);
  524. scm_puts ("#(", port);
  525. common_vector_printer:
  526. {
  527. register long i;
  528. int last = SCM_LENGTH (exp) - 1;
  529. int cutp = 0;
  530. if (pstate->fancyp && SCM_LENGTH (exp) > pstate->length)
  531. {
  532. last = pstate->length - 1;
  533. cutp = 1;
  534. }
  535. for (i = 0; i < last; ++i)
  536. {
  537. /* CHECK_INTS; */
  538. scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
  539. scm_putc (' ', port);
  540. }
  541. if (i == last)
  542. {
  543. /* CHECK_INTS; */
  544. scm_iprin1 (SCM_VELTS (exp)[i], port, pstate);
  545. }
  546. if (cutp)
  547. scm_puts (" ...", port);
  548. scm_putc (')', port);
  549. }
  550. EXIT_NESTED_DATA (pstate);
  551. break;
  552. #ifdef HAVE_ARRAYS
  553. case scm_tc7_bvect:
  554. case scm_tc7_byvect:
  555. case scm_tc7_svect:
  556. case scm_tc7_ivect:
  557. case scm_tc7_uvect:
  558. case scm_tc7_fvect:
  559. case scm_tc7_dvect:
  560. case scm_tc7_cvect:
  561. #ifdef HAVE_LONG_LONGS
  562. case scm_tc7_llvect:
  563. #endif
  564. scm_raprin1 (exp, port, pstate);
  565. break;
  566. #endif
  567. case scm_tcs_subrs:
  568. scm_puts (SCM_SUBR_GENERIC (exp) && *SCM_SUBR_GENERIC (exp)
  569. ? "#<primitive-generic "
  570. : "#<primitive-procedure ",
  571. port);
  572. scm_puts (SCM_CHARS (SCM_SNAME (exp)), port);
  573. scm_putc ('>', port);
  574. break;
  575. #ifdef CCLO
  576. case scm_tc7_cclo:
  577. {
  578. SCM proc = SCM_CCLO_SUBR (exp);
  579. if (SCM_EQ_P (proc, scm_f_gsubr_apply))
  580. {
  581. /* Print gsubrs as primitives */
  582. SCM name = scm_procedure_name (exp);
  583. scm_puts ("#<primitive-procedure", port);
  584. if (SCM_NFALSEP (name))
  585. {
  586. scm_putc (' ', port);
  587. scm_puts (SCM_CHARS (name), port);
  588. }
  589. }
  590. else
  591. {
  592. scm_puts ("#<compiled-closure ", port);
  593. scm_iprin1 (proc, port, pstate);
  594. }
  595. scm_putc ('>', port);
  596. }
  597. break;
  598. #endif
  599. case scm_tc7_pws:
  600. scm_puts ("#<procedure-with-setter", port);
  601. {
  602. SCM name = scm_procedure_name (exp);
  603. if (SCM_NFALSEP (name))
  604. {
  605. scm_putc (' ', port);
  606. scm_puts (SCM_ROCHARS (name), port);
  607. }
  608. }
  609. scm_putc ('>', port);
  610. break;
  611. case scm_tc7_contin:
  612. scm_puts ("#<continuation ", port);
  613. scm_intprint (SCM_LENGTH (exp), 10, port);
  614. scm_puts (" @ ", port);
  615. scm_intprint ((long) SCM_CHARS (exp), 16, port);
  616. scm_putc ('>', port);
  617. break;
  618. case scm_tc7_port:
  619. {
  620. register long i = SCM_PTOBNUM (exp);
  621. if (i < scm_numptob
  622. && scm_ptobs[i].print
  623. && (scm_ptobs[i].print) (exp, port, pstate))
  624. break;
  625. goto punk;
  626. }
  627. case scm_tc7_smob:
  628. {
  629. register long i;
  630. ENTER_NESTED_DATA (pstate, exp, circref);
  631. i = SCM_SMOBNUM (exp);
  632. if (i < scm_numsmob && scm_smobs[i].print
  633. && (scm_smobs[i].print) (exp, port, pstate))
  634. {
  635. EXIT_NESTED_DATA (pstate);
  636. break;
  637. }
  638. EXIT_NESTED_DATA (pstate);
  639. /* Macros have their print field set to NULL. They are
  640. handled at the same place as closures in order to achieve
  641. non-redundancy. Placing the condition here won't slow
  642. down printing of other smobs. */
  643. if (SCM_TYP16 (exp) == scm_tc16_macro)
  644. goto macros;
  645. }
  646. default:
  647. punk:
  648. scm_ipruk ("type", exp, port);
  649. }
  650. }
  651. }
  652. /* Print states are necessary for circular reference safe printing.
  653. * They are also expensive to allocate. Therefore print states are
  654. * kept in a pool so that they can be reused.
  655. */
  656. /* The PORT argument can also be a print-state/port pair, which will
  657. * then be used instead of allocating a new print state. This is
  658. * useful for continuing a chain of print calls from Scheme. */
  659. void
  660. scm_prin1 (SCM exp, SCM port, int writingp)
  661. {
  662. SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
  663. SCM pstate_scm;
  664. scm_print_state *pstate;
  665. /* If PORT is a print-state/port pair, use that. Else create a new
  666. print-state. */
  667. if (SCM_PORT_WITH_PS_P (port))
  668. {
  669. pstate_scm = SCM_PORT_WITH_PS_PS (port);
  670. port = SCM_PORT_WITH_PS_PORT (port);
  671. }
  672. else
  673. {
  674. /* First try to allocate a print state from the pool */
  675. SCM_DEFER_INTS;
  676. if (SCM_NNULLP (SCM_CDR (print_state_pool)))
  677. {
  678. handle = SCM_CDR (print_state_pool);
  679. SCM_SETCDR (print_state_pool, SCM_CDDR (print_state_pool));
  680. }
  681. SCM_ALLOW_INTS;
  682. if (SCM_FALSEP (handle))
  683. handle = scm_cons (make_print_state (), SCM_EOL);
  684. pstate_scm = SCM_CAR (handle);
  685. }
  686. pstate = SCM_PRINT_STATE (pstate_scm);
  687. pstate->writingp = writingp;
  688. scm_iprin1 (exp, port, pstate);
  689. /* Return print state to pool if it has been created above and
  690. hasn't escaped to Scheme. */
  691. if (!SCM_FALSEP (handle) && !pstate->revealed)
  692. {
  693. SCM_DEFER_INTS;
  694. SCM_SETCDR (handle, SCM_CDR (print_state_pool));
  695. SCM_SETCDR (print_state_pool, handle);
  696. SCM_ALLOW_INTS;
  697. }
  698. }
  699. /* Print an integer.
  700. */
  701. void
  702. scm_intprint (long n, int radix, SCM port)
  703. {
  704. char num_buf[SCM_INTBUFLEN];
  705. scm_lfwrite (num_buf, scm_iint2str (n, radix, num_buf), port);
  706. }
  707. /* Print an object of unrecognized type.
  708. */
  709. void
  710. scm_ipruk (char *hdr, SCM ptr, SCM port)
  711. {
  712. scm_puts ("#<unknown-", port);
  713. scm_puts (hdr, port);
  714. if (SCM_CELLP (ptr))
  715. {
  716. scm_puts (" (0x", port);
  717. scm_intprint (SCM_CELL_WORD_0 (ptr), 16, port);
  718. scm_puts (" . 0x", port);
  719. scm_intprint (SCM_CELL_WORD_1 (ptr), 16, port);
  720. scm_puts (") @", port);
  721. }
  722. scm_puts (" 0x", port);
  723. scm_intprint (SCM_UNPACK (ptr), 16, port);
  724. scm_putc ('>', port);
  725. }
  726. /* Print a list.
  727. */
  728. void
  729. scm_iprlist (char *hdr,SCM exp,int tlr,SCM port,scm_print_state *pstate)
  730. {
  731. register SCM hare, tortoise;
  732. int floor = pstate->top - 2;
  733. scm_puts (hdr, port);
  734. /* CHECK_INTS; */
  735. if (pstate->fancyp)
  736. goto fancy_printing;
  737. /* Run a hare and tortoise so that total time complexity will be
  738. O(depth * N) instead of O(N^2). */
  739. hare = SCM_CDR (exp);
  740. tortoise = exp;
  741. while (SCM_ECONSP (hare))
  742. {
  743. if (SCM_EQ_P (hare, tortoise))
  744. goto fancy_printing;
  745. hare = SCM_CDR (hare);
  746. if (SCM_IMP (hare) || SCM_NECONSP (hare))
  747. break;
  748. hare = SCM_CDR (hare);
  749. tortoise = SCM_CDR (tortoise);
  750. }
  751. /* No cdr cycles intrinsic to this list */
  752. scm_iprin1 (SCM_CAR (exp), port, pstate);
  753. exp = SCM_CDR (exp);
  754. for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
  755. {
  756. register int i;
  757. if (SCM_NECONSP (exp))
  758. break;
  759. for (i = floor; i >= 0; --i)
  760. if (SCM_EQ_P (pstate->ref_stack[i], exp))
  761. goto circref;
  762. PUSH_REF (pstate, exp);
  763. scm_putc (' ', port);
  764. /* CHECK_INTS; */
  765. scm_iprin1 (SCM_CAR (exp), port, pstate);
  766. }
  767. if (SCM_NNULLP (exp))
  768. {
  769. scm_puts (" . ", port);
  770. scm_iprin1 (exp, port, pstate);
  771. }
  772. end:
  773. scm_putc (tlr, port);
  774. pstate->top = floor + 2;
  775. return;
  776. fancy_printing:
  777. {
  778. int n = pstate->length;
  779. scm_iprin1 (SCM_CAR (exp), port, pstate);
  780. exp = SCM_CDR (exp); --n;
  781. for (; SCM_NIMP (exp); exp = SCM_CDR (exp))
  782. {
  783. register unsigned long i;
  784. if (SCM_NECONSP (exp))
  785. break;
  786. for (i = 0; i < pstate->top; ++i)
  787. if (SCM_EQ_P (pstate->ref_stack[i], exp))
  788. goto fancy_circref;
  789. if (pstate->fancyp)
  790. {
  791. if (n == 0)
  792. {
  793. scm_puts (" ...", port);
  794. goto skip_tail;
  795. }
  796. else
  797. --n;
  798. }
  799. PUSH_REF(pstate, exp);
  800. ++pstate->list_offset;
  801. scm_putc (' ', port);
  802. /* CHECK_INTS; */
  803. scm_iprin1 (SCM_CAR (exp), port, pstate);
  804. }
  805. }
  806. if (SCM_NNULLP (exp))
  807. {
  808. scm_puts (" . ", port);
  809. scm_iprin1 (exp, port, pstate);
  810. }
  811. skip_tail:
  812. pstate->list_offset -= pstate->top - floor - 2;
  813. goto end;
  814. fancy_circref:
  815. pstate->list_offset -= pstate->top - floor - 2;
  816. circref:
  817. scm_puts (" . ", port);
  818. print_circref (port, pstate, exp);
  819. goto end;
  820. }
  821. int
  822. scm_valid_oport_value_p (SCM val)
  823. {
  824. return (SCM_OPOUTPORTP (val)
  825. || (SCM_PORT_WITH_PS_P (val)
  826. && SCM_OPOUTPORTP (SCM_PORT_WITH_PS_PORT (val))));
  827. }
  828. /* SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write); */
  829. SCM
  830. scm_write (SCM obj, SCM port)
  831. {
  832. if (SCM_UNBNDP (port))
  833. port = scm_cur_outp;
  834. SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
  835. scm_prin1 (obj, port, 1);
  836. #ifdef HAVE_PIPE
  837. # ifdef EPIPE
  838. if (EPIPE == errno)
  839. scm_close_port (port);
  840. # endif
  841. #endif
  842. return SCM_UNSPECIFIED;
  843. }
  844. /* SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display); */
  845. SCM
  846. scm_display (SCM obj, SCM port)
  847. {
  848. if (SCM_UNBNDP (port))
  849. port = scm_cur_outp;
  850. SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
  851. scm_prin1 (obj, port, 0);
  852. #ifdef HAVE_PIPE
  853. # ifdef EPIPE
  854. if (EPIPE == errno)
  855. scm_close_port (port);
  856. # endif
  857. #endif
  858. return SCM_UNSPECIFIED;
  859. }
  860. SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
  861. (SCM destination, SCM message, SCM args),
  862. "Write MESSAGE to DESTINATION, defaulting to `current-output-port'.\n"
  863. "MESSAGE can contain ~A (was %s) and ~S (was %S) escapes. When printed,\n"
  864. "the escapes are replaced with corresponding members of ARGS:\n"
  865. "~A formats using `display' and ~S formats using `write'.\n"
  866. "If DESTINATION is #t, then use the `current-output-port',\n"
  867. "if DESTINATION is #f, then return a string containing the formatted text.\n"
  868. "Does not add a trailing newline.")
  869. #define FUNC_NAME s_scm_simple_format
  870. {
  871. SCM answer = SCM_UNSPECIFIED;
  872. int fReturnString = 0;
  873. int writingp;
  874. char *start;
  875. char *p;
  876. if (SCM_EQ_P (destination, SCM_BOOL_T)) {
  877. destination = scm_cur_outp;
  878. } else if (SCM_FALSEP (destination)) {
  879. fReturnString = 1;
  880. destination = scm_mkstrport (SCM_INUM0,
  881. scm_make_string (SCM_INUM0, SCM_UNDEFINED),
  882. SCM_OPN | SCM_WRTNG,
  883. FUNC_NAME);
  884. } else {
  885. SCM_VALIDATE_OPORT_VALUE (1,destination);
  886. }
  887. SCM_VALIDATE_STRING(2,message);
  888. SCM_VALIDATE_REST_ARGUMENT (args);
  889. start = SCM_ROCHARS (message);
  890. for (p = start; *p != '\0'; ++p)
  891. if (*p == '~')
  892. {
  893. if (SCM_IMP (args) || SCM_NCONSP (args))
  894. continue;
  895. ++p;
  896. if (*p == 'A')
  897. writingp = 0;
  898. else if (*p == 'S')
  899. writingp = 1;
  900. else
  901. continue;
  902. scm_lfwrite (start, p - start - 1, destination);
  903. scm_prin1 (SCM_CAR (args), destination, writingp);
  904. args = SCM_CDR (args);
  905. start = p + 1;
  906. }
  907. scm_lfwrite (start, p - start, destination);
  908. if (fReturnString)
  909. answer = scm_strport_to_string (destination);
  910. return scm_return_first(answer,message);
  911. }
  912. #undef FUNC_NAME
  913. SCM_DEFINE (scm_newline, "newline", 0, 1, 0,
  914. (SCM port),
  915. "Send a newline to PORT.")
  916. #define FUNC_NAME s_scm_newline
  917. {
  918. if (SCM_UNBNDP (port))
  919. port = scm_cur_outp;
  920. SCM_VALIDATE_OPORT_VALUE (1,port);
  921. scm_putc ('\n', SCM_COERCE_OUTPORT (port));
  922. return SCM_UNSPECIFIED;
  923. }
  924. #undef FUNC_NAME
  925. SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
  926. (SCM chr, SCM port),
  927. "Send character CHR to PORT.")
  928. #define FUNC_NAME s_scm_write_char
  929. {
  930. if (SCM_UNBNDP (port))
  931. port = scm_cur_outp;
  932. SCM_VALIDATE_CHAR (1,chr);
  933. SCM_VALIDATE_OPORT_VALUE (2,port);
  934. scm_putc ((int) SCM_CHAR (chr), SCM_COERCE_OUTPORT (port));
  935. #ifdef HAVE_PIPE
  936. # ifdef EPIPE
  937. if (EPIPE == errno)
  938. scm_close_port (port);
  939. # endif
  940. #endif
  941. return SCM_UNSPECIFIED;
  942. }
  943. #undef FUNC_NAME
  944. /* Call back to Scheme code to do the printing of special objects
  945. * (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a smob
  946. * containing PORT and PSTATE. This object can be used as the port for
  947. * display/write etc to continue the current print chain. The REVEALED
  948. * field of PSTATE is set to true to indicate that the print state has
  949. * escaped to Scheme and thus has to be freed by the GC.
  950. */
  951. long scm_tc16_port_with_ps;
  952. /* Print exactly as the port itself would */
  953. static int
  954. print_port_with_ps (SCM obj, SCM port, scm_print_state *pstate)
  955. {
  956. obj = SCM_PORT_WITH_PS_PORT (obj);
  957. return scm_ptobs[SCM_PTOBNUM (obj)].print (obj, port, pstate);
  958. }
  959. SCM
  960. scm_printer_apply (SCM proc, SCM exp, SCM port, scm_print_state *pstate)
  961. {
  962. SCM pwps;
  963. SCM pair = scm_cons (port, pstate->handle);
  964. SCM_NEWSMOB (pwps, scm_tc16_port_with_ps, SCM_UNPACK (pair));
  965. pstate->revealed = 1;
  966. return scm_apply (proc, exp, scm_cons (pwps, scm_listofnull));
  967. }
  968. SCM_DEFINE (scm_port_with_print_state, "port-with-print-state", 2, 0, 0,
  969. (SCM port, SCM pstate),
  970. "")
  971. #define FUNC_NAME s_scm_port_with_print_state
  972. {
  973. SCM pwps;
  974. SCM_VALIDATE_OPORT_VALUE (1,port);
  975. SCM_VALIDATE_PRINTSTATE (2,pstate);
  976. port = SCM_COERCE_OUTPORT (port);
  977. SCM_NEWSMOB (pwps, scm_tc16_port_with_ps, SCM_UNPACK (scm_cons (port, pstate)));
  978. return pwps;
  979. }
  980. #undef FUNC_NAME
  981. SCM_DEFINE (scm_get_print_state, "get-print-state", 1, 0, 0,
  982. (SCM port),
  983. "")
  984. #define FUNC_NAME s_scm_get_print_state
  985. {
  986. if (SCM_PORT_WITH_PS_P (port))
  987. return SCM_PORT_WITH_PS_PS (port);
  988. if (SCM_OUTPUT_PORT_P (port))
  989. return SCM_BOOL_F;
  990. RETURN_SCM_WTA (1,port);
  991. }
  992. #undef FUNC_NAME
  993. void
  994. scm_init_print ()
  995. {
  996. SCM vtable, layout, type;
  997. scm_init_opts (scm_print_options, scm_print_opts, SCM_N_PRINT_OPTIONS);
  998. vtable = scm_make_vtable_vtable (scm_make_struct_layout (scm_nullstr),
  999. SCM_INUM0,
  1000. SCM_EOL);
  1001. layout = scm_make_struct_layout (scm_makfrom0str (SCM_PRINT_STATE_LAYOUT));
  1002. type = scm_make_struct (vtable, SCM_INUM0, SCM_LIST1 (layout));
  1003. scm_set_struct_vtable_name_x (type, SCM_CAR (scm_intern0 ("print-state")));
  1004. print_state_pool = scm_permanent_object (scm_cons (type, SCM_EOL));
  1005. scm_print_state_vtable = type;
  1006. /* Don't want to bind a wrapper class in GOOPS, so pass 0 as arg1. */
  1007. scm_tc16_port_with_ps = scm_make_smob_type (0, 0);
  1008. scm_set_smob_mark (scm_tc16_port_with_ps, scm_markcdr);
  1009. scm_set_smob_print (scm_tc16_port_with_ps, print_port_with_ps);
  1010. #include "libguile/print.x"
  1011. }
  1012. /*
  1013. Local Variables:
  1014. c-file-style: "gnu"
  1015. End:
  1016. */