print.c 28 KB

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