print.c 31 KB

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