print.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311
  1. /* Copyright (C) 1995-1999, 2000, 2001, 2002, 2003, 2004, 2006, 2008,
  2. * 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public License
  6. * as published by the Free Software Foundation; either version 3 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301 USA
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. # include <config.h>
  21. #endif
  22. #include <errno.h>
  23. #include <stdio.h>
  24. #include <assert.h>
  25. #include <uniconv.h>
  26. #include <unictype.h>
  27. #include "libguile/_scm.h"
  28. #include "libguile/chars.h"
  29. #include "libguile/continuations.h"
  30. #include "libguile/smob.h"
  31. #include "libguile/control.h"
  32. #include "libguile/eval.h"
  33. #include "libguile/macros.h"
  34. #include "libguile/procprop.h"
  35. #include "libguile/read.h"
  36. #include "libguile/programs.h"
  37. #include "libguile/alist.h"
  38. #include "libguile/struct.h"
  39. #include "libguile/ports.h"
  40. #include "libguile/ports-internal.h"
  41. #include "libguile/root.h"
  42. #include "libguile/strings.h"
  43. #include "libguile/strports.h"
  44. #include "libguile/vectors.h"
  45. #include "libguile/numbers.h"
  46. #include "libguile/vm.h"
  47. #include "libguile/validate.h"
  48. #include "libguile/print.h"
  49. #include "libguile/private-options.h"
  50. /* Character printers. */
  51. static void write_string (const void *, int, size_t, SCM);
  52. static void write_character (scm_t_wchar, SCM);
  53. /* {Names of immediate symbols}
  54. *
  55. * This table must agree with the declarations in scm.h: {Immediate Symbols}.
  56. */
  57. /* This table must agree with the list of flags in tags.h. */
  58. static const char *iflagnames[] =
  59. {
  60. "#f",
  61. "#nil", /* Elisp nil value. Should print from elisp as symbol `nil'. */
  62. "#<XXX UNUSED LISP FALSE -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
  63. "()",
  64. "#t",
  65. "#<XXX UNUSED BOOLEAN 0 -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
  66. "#<XXX UNUSED BOOLEAN 1 -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
  67. "#<XXX UNUSED BOOLEAN 2 -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
  68. "#<unspecified>",
  69. "#<undefined>",
  70. "#<eof>",
  71. /* Unbound slot marker for GOOPS. For internal use in GOOPS only. */
  72. "#<unbound>",
  73. };
  74. SCM_SYMBOL (sym_reader, "reader");
  75. scm_t_option scm_print_opts[] = {
  76. { SCM_OPTION_SCM, "highlight-prefix", (scm_t_bits)SCM_BOOL_F_BITS,
  77. "The string to print before highlighted values." },
  78. { SCM_OPTION_SCM, "highlight-suffix", (scm_t_bits)SCM_BOOL_F_BITS,
  79. "The string to print after highlighted values." },
  80. { SCM_OPTION_SCM, "quote-keywordish-symbols", (scm_t_bits)SCM_BOOL_F_BITS,
  81. "How to print symbols that have a colon as their first or last character. "
  82. "The value '#f' does not quote the colons; '#t' quotes them; "
  83. "'reader' quotes them when the reader option 'keywords' is not '#f'." },
  84. { SCM_OPTION_BOOLEAN, "escape-newlines", 1,
  85. "Render newlines as \\n when printing using `write'." },
  86. { SCM_OPTION_BOOLEAN, "r7rs-symbols", 0,
  87. "Escape symbols using R7RS |...| symbol notation." },
  88. { 0 },
  89. };
  90. SCM_DEFINE (scm_print_options, "print-options-interface", 0, 1, 0,
  91. (SCM setting),
  92. "Option interface for the print options. Instead of using\n"
  93. "this procedure directly, use the procedures\n"
  94. "@code{print-enable}, @code{print-disable}, @code{print-set!}\n"
  95. "and @code{print-options}.")
  96. #define FUNC_NAME s_scm_print_options
  97. {
  98. SCM ans = scm_options (setting,
  99. scm_print_opts,
  100. FUNC_NAME);
  101. return ans;
  102. }
  103. #undef FUNC_NAME
  104. /* {Printing of Scheme Objects}
  105. */
  106. /* Detection of circular references.
  107. *
  108. * Due to other constraints in the implementation, this code has bad
  109. * time complexity (O (depth * N)), The printer code can be
  110. * rewritten to be O(N).
  111. */
  112. #define PUSH_REF(pstate, obj) \
  113. do \
  114. { \
  115. PSTATE_STACK_SET (pstate, pstate->top, obj); \
  116. pstate->top++; \
  117. if (pstate->top == pstate->ceiling) \
  118. grow_ref_stack (pstate); \
  119. } while(0)
  120. #define ENTER_NESTED_DATA(pstate, obj, label) \
  121. do \
  122. { \
  123. register unsigned long i; \
  124. for (i = 0; i < pstate->top; ++i) \
  125. if (scm_is_eq (PSTATE_STACK_REF (pstate, i), (obj))) \
  126. goto label; \
  127. if (pstate->fancyp) \
  128. { \
  129. if (pstate->top - pstate->list_offset >= pstate->level) \
  130. { \
  131. scm_putc ('#', port); \
  132. return; \
  133. } \
  134. } \
  135. PUSH_REF(pstate, obj); \
  136. } while(0)
  137. #define EXIT_NESTED_DATA(pstate) \
  138. do \
  139. { \
  140. --pstate->top; \
  141. PSTATE_STACK_SET (pstate, pstate->top, SCM_UNDEFINED); \
  142. } \
  143. while (0)
  144. SCM scm_print_state_vtable = SCM_BOOL_F;
  145. static SCM print_state_pool = SCM_EOL;
  146. scm_i_pthread_mutex_t print_state_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
  147. #ifdef GUILE_DEBUG /* Used for debugging purposes */
  148. SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0,
  149. (),
  150. "Return the current-pstate -- the car of the\n"
  151. "@code{print_state_pool}. @code{current-pstate} is only\n"
  152. "included in @code{--enable-guile-debug} builds.")
  153. #define FUNC_NAME s_scm_current_pstate
  154. {
  155. if (!scm_is_null (print_state_pool))
  156. return SCM_CAR (print_state_pool);
  157. else
  158. return SCM_BOOL_F;
  159. }
  160. #undef FUNC_NAME
  161. #endif
  162. #define PSTATE_SIZE 50L
  163. static SCM
  164. make_print_state (void)
  165. {
  166. SCM print_state
  167. = scm_make_struct (scm_print_state_vtable, SCM_INUM0, SCM_EOL);
  168. scm_print_state *pstate = SCM_PRINT_STATE (print_state);
  169. pstate->ref_vect = scm_c_make_vector (PSTATE_SIZE, SCM_UNDEFINED);
  170. pstate->ceiling = SCM_SIMPLE_VECTOR_LENGTH (pstate->ref_vect);
  171. pstate->highlight_objects = SCM_EOL;
  172. return print_state;
  173. }
  174. SCM
  175. scm_make_print_state ()
  176. {
  177. SCM answer = SCM_BOOL_F;
  178. /* First try to allocate a print state from the pool */
  179. scm_i_pthread_mutex_lock (&print_state_mutex);
  180. if (!scm_is_null (print_state_pool))
  181. {
  182. answer = SCM_CAR (print_state_pool);
  183. print_state_pool = SCM_CDR (print_state_pool);
  184. }
  185. scm_i_pthread_mutex_unlock (&print_state_mutex);
  186. return scm_is_false (answer) ? make_print_state () : answer;
  187. }
  188. void
  189. scm_free_print_state (SCM print_state)
  190. {
  191. SCM handle;
  192. scm_print_state *pstate = SCM_PRINT_STATE (print_state);
  193. /* Cleanup before returning print state to pool.
  194. * It is better to do it here. Doing it in scm_prin1
  195. * would cost more since that function is called much more
  196. * often.
  197. */
  198. pstate->fancyp = 0;
  199. pstate->revealed = 0;
  200. pstate->highlight_objects = SCM_EOL;
  201. scm_i_pthread_mutex_lock (&print_state_mutex);
  202. handle = scm_cons (print_state, print_state_pool);
  203. print_state_pool = handle;
  204. scm_i_pthread_mutex_unlock (&print_state_mutex);
  205. }
  206. SCM
  207. scm_i_port_with_print_state (SCM port, SCM print_state)
  208. {
  209. if (SCM_UNBNDP (print_state))
  210. {
  211. if (SCM_PORT_WITH_PS_P (port))
  212. return port;
  213. else
  214. print_state = scm_make_print_state ();
  215. /* port does not need to be coerced since it doesn't have ps */
  216. }
  217. else
  218. port = SCM_COERCE_OUTPORT (port);
  219. SCM_RETURN_NEWSMOB (scm_tc16_port_with_ps,
  220. SCM_UNPACK (scm_cons (port, print_state)));
  221. }
  222. static void
  223. grow_ref_stack (scm_print_state *pstate)
  224. {
  225. SCM old_vect = pstate->ref_vect;
  226. size_t old_size = SCM_SIMPLE_VECTOR_LENGTH (old_vect);
  227. size_t new_size = 2 * pstate->ceiling;
  228. SCM new_vect = scm_c_make_vector (new_size, SCM_UNDEFINED);
  229. unsigned long int i;
  230. for (i = 0; i != old_size; ++i)
  231. SCM_SIMPLE_VECTOR_SET (new_vect, i, SCM_SIMPLE_VECTOR_REF (old_vect, i));
  232. pstate->ref_vect = new_vect;
  233. pstate->ceiling = new_size;
  234. }
  235. #define PSTATE_STACK_REF(p,i) SCM_SIMPLE_VECTOR_REF((p)->ref_vect, (i))
  236. #define PSTATE_STACK_SET(p,i,v) SCM_SIMPLE_VECTOR_SET((p)->ref_vect, (i), (v))
  237. static void
  238. print_circref (SCM port, scm_print_state *pstate, SCM ref)
  239. {
  240. register long i;
  241. long self = pstate->top - 1;
  242. i = pstate->top - 1;
  243. if (scm_is_pair (PSTATE_STACK_REF (pstate, i)))
  244. {
  245. while (i > 0)
  246. {
  247. if (!scm_is_pair (PSTATE_STACK_REF (pstate, i-1))
  248. || !scm_is_eq (SCM_CDR (PSTATE_STACK_REF (pstate, i-1)),
  249. SCM_CDR (PSTATE_STACK_REF (pstate, i))))
  250. break;
  251. --i;
  252. }
  253. self = i;
  254. }
  255. for (i = pstate->top - 1; 1; --i)
  256. if (scm_is_eq (PSTATE_STACK_REF(pstate, i), ref))
  257. break;
  258. scm_putc ('#', port);
  259. scm_intprint (i - self, 10, port);
  260. scm_putc ('#', port);
  261. }
  262. /* Print the name of a symbol. */
  263. static int
  264. quote_keywordish_symbols (void)
  265. {
  266. SCM option = SCM_PRINT_KEYWORD_STYLE;
  267. if (scm_is_false (option))
  268. return 0;
  269. if (scm_is_eq (option, sym_reader))
  270. return scm_is_true (SCM_PACK (SCM_KEYWORD_STYLE));
  271. return 1;
  272. }
  273. #define INITIAL_IDENTIFIER_MASK \
  274. (UC_CATEGORY_MASK_Lu | UC_CATEGORY_MASK_Ll | UC_CATEGORY_MASK_Lt \
  275. | UC_CATEGORY_MASK_Lm | UC_CATEGORY_MASK_Lo | UC_CATEGORY_MASK_Mn \
  276. | UC_CATEGORY_MASK_Nl | UC_CATEGORY_MASK_No | UC_CATEGORY_MASK_Pd \
  277. | UC_CATEGORY_MASK_Pc | UC_CATEGORY_MASK_Po | UC_CATEGORY_MASK_Sc \
  278. | UC_CATEGORY_MASK_Sm | UC_CATEGORY_MASK_Sk | UC_CATEGORY_MASK_So \
  279. | UC_CATEGORY_MASK_Co)
  280. #define SUBSEQUENT_IDENTIFIER_MASK \
  281. (INITIAL_IDENTIFIER_MASK \
  282. | UC_CATEGORY_MASK_Nd | UC_CATEGORY_MASK_Mc | UC_CATEGORY_MASK_Me)
  283. /* FIXME: Cache this information on the symbol, somehow. */
  284. static int
  285. symbol_has_extended_read_syntax (SCM sym)
  286. {
  287. size_t pos, len = scm_i_symbol_length (sym);
  288. scm_t_wchar c;
  289. /* The empty symbol. */
  290. if (len == 0)
  291. return 1;
  292. c = scm_i_symbol_ref (sym, 0);
  293. switch (c)
  294. {
  295. case '\'':
  296. case '`':
  297. case ',':
  298. case '"':
  299. case ';':
  300. case '#':
  301. /* Some initial-character constraints. */
  302. return 1;
  303. case '|':
  304. case '\\':
  305. /* R7RS allows neither '|' nor '\' in bare symbols. */
  306. if (SCM_PRINT_R7RS_SYMBOLS_P)
  307. return 1;
  308. break;
  309. case ':':
  310. /* Symbols that look like keywords. */
  311. return quote_keywordish_symbols ();
  312. case '.':
  313. /* Single dot conflicts with dotted-pair notation. */
  314. if (len == 1)
  315. return 1;
  316. /* Fall through to check numbers. */
  317. case '+':
  318. case '-':
  319. case '0':
  320. case '1':
  321. case '2':
  322. case '3':
  323. case '4':
  324. case '5':
  325. case '6':
  326. case '7':
  327. case '8':
  328. case '9':
  329. /* Number-ish symbols. Numbers with radixes already caught be #
  330. above. */
  331. if (scm_is_true (scm_i_string_to_number (scm_symbol_to_string (sym), 10)))
  332. return 1;
  333. break;
  334. default:
  335. break;
  336. }
  337. /* Other disallowed first characters. */
  338. if (!uc_is_general_category_withtable (c, INITIAL_IDENTIFIER_MASK))
  339. return 1;
  340. /* Keywords can be identified by trailing colons too. */
  341. if (scm_i_symbol_ref (sym, len - 1) == ':')
  342. return quote_keywordish_symbols ();
  343. /* Otherwise, any character that's in the identifier category mask is
  344. fine to pass through as-is, provided it's not one of the ASCII
  345. delimiters like `;'. */
  346. for (pos = 1; pos < len; pos++)
  347. {
  348. c = scm_i_symbol_ref (sym, pos);
  349. if (!uc_is_general_category_withtable (c, SUBSEQUENT_IDENTIFIER_MASK))
  350. return 1;
  351. else if (c == '"' || c == ';' || c == '#')
  352. return 1;
  353. else if ((c == '|' || c == '\\') && SCM_PRINT_R7RS_SYMBOLS_P)
  354. /* R7RS allows neither '|' nor '\' in bare symbols. */
  355. return 1;
  356. }
  357. return 0;
  358. }
  359. static void
  360. print_normal_symbol (SCM sym, SCM port)
  361. {
  362. size_t len = scm_i_symbol_length (sym);
  363. if (scm_i_is_narrow_symbol (sym))
  364. {
  365. const char *ptr = scm_i_symbol_chars (sym);
  366. scm_c_put_latin1_chars (port, (const scm_t_uint8 *) ptr, len);
  367. }
  368. else
  369. {
  370. const scm_t_wchar *ptr = scm_i_symbol_wide_chars (sym);
  371. scm_c_put_utf32_chars (port, (const scm_t_uint32 *) ptr, len);
  372. }
  373. }
  374. static void
  375. print_extended_symbol (SCM sym, SCM port)
  376. {
  377. size_t pos, len;
  378. len = scm_i_symbol_length (sym);
  379. scm_lfwrite ("#{", 2, port);
  380. for (pos = 0; pos < len; pos++)
  381. {
  382. scm_t_wchar c = scm_i_symbol_ref (sym, pos);
  383. if (uc_is_general_category_withtable (c,
  384. SUBSEQUENT_IDENTIFIER_MASK
  385. | UC_CATEGORY_MASK_Zs))
  386. scm_c_put_char (port, c);
  387. else
  388. {
  389. scm_lfwrite ("\\x", 2, port);
  390. scm_intprint (c, 16, port);
  391. scm_putc (';', port);
  392. }
  393. }
  394. scm_lfwrite ("}#", 2, port);
  395. }
  396. static void
  397. print_r7rs_extended_symbol (SCM sym, SCM port)
  398. {
  399. size_t pos, len;
  400. len = scm_i_symbol_length (sym);
  401. scm_putc ('|', port);
  402. for (pos = 0; pos < len; pos++)
  403. {
  404. scm_t_wchar c = scm_i_symbol_ref (sym, pos);
  405. switch (c)
  406. {
  407. case '\a': scm_lfwrite ("\\a", 2, port); break;
  408. case '\b': scm_lfwrite ("\\b", 2, port); break;
  409. case '\t': scm_lfwrite ("\\t", 2, port); break;
  410. case '\n': scm_lfwrite ("\\n", 2, port); break;
  411. case '\r': scm_lfwrite ("\\r", 2, port); break;
  412. case '|': scm_lfwrite ("\\|", 2, port); break;
  413. case '\\': scm_lfwrite ("\\x5c;", 5, port); break;
  414. default:
  415. if (uc_is_general_category_withtable (c,
  416. UC_CATEGORY_MASK_L
  417. | UC_CATEGORY_MASK_M
  418. | UC_CATEGORY_MASK_N
  419. | UC_CATEGORY_MASK_P
  420. | UC_CATEGORY_MASK_S)
  421. || (c == ' '))
  422. scm_c_put_char (port, c);
  423. else
  424. {
  425. scm_lfwrite ("\\x", 2, port);
  426. scm_intprint (c, 16, port);
  427. scm_putc (';', port);
  428. }
  429. break;
  430. }
  431. }
  432. scm_putc ('|', port);
  433. }
  434. /* FIXME: allow R6RS hex escapes instead of #{...}# or |...|. */
  435. static void
  436. print_symbol (SCM sym, SCM port)
  437. {
  438. if (!symbol_has_extended_read_syntax (sym))
  439. print_normal_symbol (sym, port);
  440. else if (SCM_PRINT_R7RS_SYMBOLS_P)
  441. print_r7rs_extended_symbol (sym, port);
  442. else
  443. print_extended_symbol (sym, port);
  444. }
  445. void
  446. scm_print_symbol_name (const char *str, size_t len, SCM port)
  447. {
  448. SCM symbol = scm_from_utf8_symboln (str, len);
  449. print_symbol (symbol, port);
  450. }
  451. /* Print generally. Handles both write and display according to PSTATE.
  452. */
  453. SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write);
  454. SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display);
  455. static void iprin1 (SCM exp, SCM port, scm_print_state *pstate);
  456. void
  457. scm_iprin1 (SCM exp, SCM port, scm_print_state *pstate)
  458. {
  459. if (pstate->fancyp
  460. && scm_is_true (scm_memq (exp, pstate->highlight_objects)))
  461. {
  462. scm_display (SCM_PRINT_HIGHLIGHT_PREFIX, port);
  463. iprin1 (exp, port, pstate);
  464. scm_display (SCM_PRINT_HIGHLIGHT_SUFFIX, port);
  465. }
  466. else
  467. iprin1 (exp, port, pstate);
  468. }
  469. static void
  470. print_vector_or_weak_vector (SCM v, size_t len, SCM (*ref) (SCM, size_t),
  471. SCM port, scm_print_state *pstate)
  472. {
  473. long i;
  474. long last = len - 1;
  475. int cutp = 0;
  476. if (pstate->fancyp && len > pstate->length)
  477. {
  478. last = pstate->length - 1;
  479. cutp = 1;
  480. }
  481. for (i = 0; i < last; ++i)
  482. {
  483. scm_iprin1 (ref (v, i), port, pstate);
  484. scm_putc (' ', port);
  485. }
  486. if (i == last)
  487. {
  488. /* CHECK_INTS; */
  489. scm_iprin1 (ref (v, i), port, pstate);
  490. }
  491. if (cutp)
  492. scm_puts (" ...", port);
  493. scm_putc (')', port);
  494. }
  495. static void
  496. iprin1 (SCM exp, SCM port, scm_print_state *pstate)
  497. {
  498. switch (SCM_ITAG3 (exp))
  499. {
  500. case scm_tc3_tc7_1:
  501. case scm_tc3_tc7_2:
  502. /* These tc3 tags should never occur in an immediate value. They are
  503. * only used in cell types of non-immediates, i. e. the value returned
  504. * by SCM_CELL_TYPE (exp) can use these tags.
  505. */
  506. scm_ipruk ("immediate", exp, port);
  507. break;
  508. case scm_tc3_int_1:
  509. case scm_tc3_int_2:
  510. scm_intprint (SCM_I_INUM (exp), 10, port);
  511. break;
  512. case scm_tc3_imm24:
  513. if (SCM_CHARP (exp))
  514. {
  515. if (SCM_WRITINGP (pstate))
  516. write_character (SCM_CHAR (exp), port);
  517. else
  518. scm_c_put_char (port, SCM_CHAR (exp));
  519. }
  520. else if (SCM_IFLAGP (exp)
  521. && ((size_t) SCM_IFLAGNUM (exp) < (sizeof iflagnames / sizeof (char *))))
  522. {
  523. scm_puts (iflagnames [SCM_IFLAGNUM (exp)], port);
  524. }
  525. else
  526. {
  527. /* unknown immediate value */
  528. scm_ipruk ("immediate", exp, port);
  529. }
  530. break;
  531. case scm_tc3_cons:
  532. switch (SCM_TYP7 (exp))
  533. {
  534. case scm_tcs_struct:
  535. {
  536. ENTER_NESTED_DATA (pstate, exp, circref);
  537. if (SCM_OBJ_CLASS_FLAGS (exp) & SCM_CLASSF_GOOPS)
  538. {
  539. SCM pwps, print = pstate->writingp ? g_write : g_display;
  540. if (SCM_UNPACK (print) == 0)
  541. goto print_struct;
  542. pwps = scm_i_port_with_print_state (port, pstate->handle);
  543. pstate->revealed = 1;
  544. scm_call_2 (print, exp, pwps);
  545. }
  546. else
  547. {
  548. print_struct:
  549. scm_print_struct (exp, port, pstate);
  550. }
  551. EXIT_NESTED_DATA (pstate);
  552. }
  553. break;
  554. case scm_tcs_cons_imcar:
  555. case scm_tcs_cons_nimcar:
  556. ENTER_NESTED_DATA (pstate, exp, circref);
  557. scm_iprlist ("(", exp, ')', port, pstate);
  558. EXIT_NESTED_DATA (pstate);
  559. break;
  560. circref:
  561. print_circref (port, pstate, exp);
  562. break;
  563. case scm_tc7_number:
  564. switch SCM_TYP16 (exp) {
  565. case scm_tc16_big:
  566. scm_bigprint (exp, port, pstate);
  567. break;
  568. case scm_tc16_real:
  569. scm_print_real (exp, port, pstate);
  570. break;
  571. case scm_tc16_complex:
  572. scm_print_complex (exp, port, pstate);
  573. break;
  574. case scm_tc16_fraction:
  575. scm_i_print_fraction (exp, port, pstate);
  576. break;
  577. }
  578. break;
  579. case scm_tc7_stringbuf:
  580. scm_i_print_stringbuf (exp, port, pstate);
  581. break;
  582. case scm_tc7_string:
  583. {
  584. size_t len = scm_i_string_length (exp);
  585. if (SCM_WRITINGP (pstate))
  586. write_string (scm_i_string_data (exp),
  587. scm_i_is_narrow_string (exp),
  588. len, port);
  589. else
  590. scm_c_put_string (port, exp, 0, len);
  591. }
  592. scm_remember_upto_here_1 (exp);
  593. break;
  594. case scm_tc7_symbol:
  595. if (scm_i_symbol_is_interned (exp))
  596. {
  597. print_symbol (exp, port);
  598. scm_remember_upto_here_1 (exp);
  599. }
  600. else
  601. {
  602. scm_puts ("#<uninterned-symbol ", port);
  603. print_symbol (exp, port);
  604. scm_putc (' ', port);
  605. scm_uintprint (SCM_UNPACK (exp), 16, port);
  606. scm_putc ('>', port);
  607. }
  608. break;
  609. case scm_tc7_variable:
  610. scm_i_variable_print (exp, port, pstate);
  611. break;
  612. case scm_tc7_program:
  613. scm_i_program_print (exp, port, pstate);
  614. break;
  615. case scm_tc7_pointer:
  616. scm_i_pointer_print (exp, port, pstate);
  617. break;
  618. case scm_tc7_hashtable:
  619. scm_i_hashtable_print (exp, port, pstate);
  620. break;
  621. case scm_tc7_weak_set:
  622. scm_i_weak_set_print (exp, port, pstate);
  623. break;
  624. case scm_tc7_weak_table:
  625. scm_i_weak_table_print (exp, port, pstate);
  626. break;
  627. case scm_tc7_fluid:
  628. scm_i_fluid_print (exp, port, pstate);
  629. break;
  630. case scm_tc7_dynamic_state:
  631. scm_i_dynamic_state_print (exp, port, pstate);
  632. break;
  633. case scm_tc7_frame:
  634. scm_i_frame_print (exp, port, pstate);
  635. break;
  636. case scm_tc7_keyword:
  637. scm_puts ("#:", port);
  638. scm_iprin1 (scm_keyword_to_symbol (exp), port, pstate);
  639. break;
  640. case scm_tc7_vm_cont:
  641. scm_i_vm_cont_print (exp, port, pstate);
  642. break;
  643. case scm_tc7_array:
  644. ENTER_NESTED_DATA (pstate, exp, circref);
  645. scm_i_print_array (exp, port, pstate);
  646. EXIT_NESTED_DATA (pstate);
  647. break;
  648. case scm_tc7_bytevector:
  649. scm_i_print_bytevector (exp, port, pstate);
  650. break;
  651. case scm_tc7_bitvector:
  652. scm_i_print_bitvector (exp, port, pstate);
  653. break;
  654. case scm_tc7_wvect:
  655. ENTER_NESTED_DATA (pstate, exp, circref);
  656. scm_puts ("#w(", port);
  657. print_vector_or_weak_vector (exp, scm_c_weak_vector_length (exp),
  658. scm_c_weak_vector_ref, port, pstate);
  659. EXIT_NESTED_DATA (pstate);
  660. break;
  661. case scm_tc7_vector:
  662. ENTER_NESTED_DATA (pstate, exp, circref);
  663. scm_puts ("#(", port);
  664. print_vector_or_weak_vector (exp, SCM_SIMPLE_VECTOR_LENGTH (exp),
  665. scm_c_vector_ref, port, pstate);
  666. EXIT_NESTED_DATA (pstate);
  667. break;
  668. case scm_tc7_port:
  669. {
  670. scm_t_port_type *ptob = SCM_PORT_TYPE (exp);
  671. if (ptob->print && ptob->print (exp, port, pstate))
  672. break;
  673. goto punk;
  674. }
  675. case scm_tc7_smob:
  676. ENTER_NESTED_DATA (pstate, exp, circref);
  677. SCM_SMOB_DESCRIPTOR (exp).print (exp, port, pstate);
  678. EXIT_NESTED_DATA (pstate);
  679. break;
  680. default:
  681. /* case scm_tcs_closures: */
  682. punk:
  683. scm_ipruk ("type", exp, port);
  684. }
  685. }
  686. }
  687. /* Print states are necessary for circular reference safe printing.
  688. * They are also expensive to allocate. Therefore print states are
  689. * kept in a pool so that they can be reused.
  690. */
  691. /* The PORT argument can also be a print-state/port pair, which will
  692. * then be used instead of allocating a new print state. This is
  693. * useful for continuing a chain of print calls from Scheme. */
  694. void
  695. scm_prin1 (SCM exp, SCM port, int writingp)
  696. {
  697. SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
  698. SCM pstate_scm;
  699. scm_print_state *pstate;
  700. int old_writingp;
  701. /* If PORT is a print-state/port pair, use that. Else create a new
  702. print-state. */
  703. if (SCM_PORT_WITH_PS_P (port))
  704. {
  705. pstate_scm = SCM_PORT_WITH_PS_PS (port);
  706. port = SCM_PORT_WITH_PS_PORT (port);
  707. }
  708. else
  709. {
  710. /* First try to allocate a print state from the pool */
  711. scm_i_pthread_mutex_lock (&print_state_mutex);
  712. if (!scm_is_null (print_state_pool))
  713. {
  714. handle = print_state_pool;
  715. print_state_pool = SCM_CDR (print_state_pool);
  716. }
  717. scm_i_pthread_mutex_unlock (&print_state_mutex);
  718. if (scm_is_false (handle))
  719. handle = scm_list_1 (make_print_state ());
  720. pstate_scm = SCM_CAR (handle);
  721. }
  722. pstate = SCM_PRINT_STATE (pstate_scm);
  723. old_writingp = pstate->writingp;
  724. pstate->writingp = writingp;
  725. scm_iprin1 (exp, port, pstate);
  726. pstate->writingp = old_writingp;
  727. /* Return print state to pool if it has been created above and
  728. hasn't escaped to Scheme. */
  729. if (scm_is_true (handle) && !pstate->revealed)
  730. {
  731. scm_i_pthread_mutex_lock (&print_state_mutex);
  732. SCM_SETCDR (handle, print_state_pool);
  733. print_state_pool = handle;
  734. scm_i_pthread_mutex_unlock (&print_state_mutex);
  735. }
  736. }
  737. static void
  738. write_string (const void *str, int narrow_p, size_t len, SCM port)
  739. {
  740. size_t i;
  741. scm_c_put_char (port, (scm_t_uint8) '"');
  742. for (i = 0; i < len; ++i)
  743. {
  744. scm_t_wchar ch;
  745. if (narrow_p)
  746. ch = (scm_t_wchar) ((unsigned char *) (str))[i];
  747. else
  748. ch = ((scm_t_wchar *) (str))[i];
  749. /* Write CH to PORT, escaping it if it's non-graphic or not
  750. representable in PORT's encoding. If CH needs to be escaped,
  751. it is escaped using the in-string escape syntax. */
  752. if (ch == '"')
  753. scm_c_put_latin1_chars (port, (const scm_t_uint8 *) "\\\"", 2);
  754. else if (ch == '\\')
  755. scm_c_put_latin1_chars (port, (const scm_t_uint8 *) "\\\\", 2);
  756. else if (ch == '\n' && SCM_PRINT_ESCAPE_NEWLINES_P)
  757. scm_c_put_latin1_chars (port, (const scm_t_uint8 *) "\\n", 2);
  758. else if (ch == ' ' || ch == '\n'
  759. || (uc_is_general_category_withtable (ch,
  760. UC_CATEGORY_MASK_L |
  761. UC_CATEGORY_MASK_M |
  762. UC_CATEGORY_MASK_N |
  763. UC_CATEGORY_MASK_P |
  764. UC_CATEGORY_MASK_S)
  765. && scm_c_can_put_char (port, ch)))
  766. scm_c_put_char (port, ch);
  767. else
  768. scm_c_put_escaped_char (port, ch);
  769. }
  770. scm_c_put_char (port, (scm_t_uint8) '"');
  771. }
  772. /* Write CH to PORT, escaping it if it's non-graphic or not
  773. representable in PORT's encoding. The character escape syntax is
  774. used. */
  775. static void
  776. write_character (scm_t_wchar ch, SCM port)
  777. {
  778. scm_puts ("#\\", port);
  779. /* Pretty-print a combining characters over dotted circles, if
  780. possible, to make them more visible. */
  781. if (uc_combining_class (ch) != UC_CCC_NR
  782. && scm_c_can_put_char (port, SCM_CODEPOINT_DOTTED_CIRCLE)
  783. && scm_c_can_put_char (port, ch))
  784. {
  785. scm_c_put_char (port, SCM_CODEPOINT_DOTTED_CIRCLE);
  786. scm_c_put_char (port, ch);
  787. }
  788. else if (uc_is_general_category_withtable (ch,
  789. UC_CATEGORY_MASK_L |
  790. UC_CATEGORY_MASK_M |
  791. UC_CATEGORY_MASK_N |
  792. UC_CATEGORY_MASK_P |
  793. UC_CATEGORY_MASK_S)
  794. && scm_c_can_put_char (port, ch))
  795. /* CH is graphic and encodeable; display it. */
  796. scm_c_put_char (port, ch);
  797. else
  798. /* CH isn't graphic or cannot be represented in PORT's encoding. */
  799. {
  800. /* Represent CH using the character escape syntax. */
  801. const char *name;
  802. name = scm_i_charname (SCM_MAKE_CHAR (ch));
  803. if (name != NULL)
  804. scm_puts (name, port);
  805. else if (!SCM_R6RS_ESCAPES_P)
  806. scm_intprint (ch, 8, port);
  807. else
  808. {
  809. scm_puts ("x", port);
  810. scm_intprint (ch, 16, port);
  811. }
  812. }
  813. }
  814. /* Print an integer.
  815. */
  816. void
  817. scm_intprint (scm_t_intmax n, int radix, SCM port)
  818. {
  819. char num_buf[SCM_INTBUFLEN];
  820. scm_lfwrite (num_buf, scm_iint2str (n, radix, num_buf), port);
  821. }
  822. void
  823. scm_uintprint (scm_t_uintmax n, int radix, SCM port)
  824. {
  825. char num_buf[SCM_INTBUFLEN];
  826. scm_lfwrite (num_buf, scm_iuint2str (n, radix, num_buf), port);
  827. }
  828. /* Print an object of unrecognized type.
  829. */
  830. void
  831. scm_ipruk (char *hdr, SCM ptr, SCM port)
  832. {
  833. scm_puts ("#<unknown-", port);
  834. scm_puts (hdr, port);
  835. if (1) /* (scm_in_heap_p (ptr)) */ /* FIXME */
  836. {
  837. scm_puts (" (0x", port);
  838. scm_uintprint (SCM_CELL_WORD_0 (ptr), 16, port);
  839. scm_puts (" . 0x", port);
  840. scm_uintprint (SCM_CELL_WORD_1 (ptr), 16, port);
  841. scm_puts (") @", port);
  842. }
  843. scm_puts (" 0x", port);
  844. scm_uintprint (SCM_UNPACK (ptr), 16, port);
  845. scm_putc ('>', port);
  846. }
  847. /* Print a list.
  848. */
  849. void
  850. scm_iprlist (char *hdr, SCM exp, int tlr, SCM port, scm_print_state *pstate)
  851. {
  852. register SCM hare, tortoise;
  853. long floor = pstate->top - 2;
  854. scm_puts (hdr, port);
  855. /* CHECK_INTS; */
  856. if (pstate->fancyp)
  857. goto fancy_printing;
  858. /* Run a hare and tortoise so that total time complexity will be
  859. O(depth * N) instead of O(N^2). */
  860. hare = SCM_CDR (exp);
  861. tortoise = exp;
  862. while (scm_is_pair (hare))
  863. {
  864. if (scm_is_eq (hare, tortoise))
  865. goto fancy_printing;
  866. hare = SCM_CDR (hare);
  867. if (!scm_is_pair (hare))
  868. break;
  869. hare = SCM_CDR (hare);
  870. tortoise = SCM_CDR (tortoise);
  871. }
  872. /* No cdr cycles intrinsic to this list */
  873. scm_iprin1 (SCM_CAR (exp), port, pstate);
  874. for (exp = SCM_CDR (exp); scm_is_pair (exp); exp = SCM_CDR (exp))
  875. {
  876. register long i;
  877. for (i = floor; i >= 0; --i)
  878. if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
  879. goto circref;
  880. PUSH_REF (pstate, exp);
  881. scm_putc (' ', port);
  882. /* CHECK_INTS; */
  883. scm_iprin1 (SCM_CAR (exp), port, pstate);
  884. }
  885. if (!SCM_NULL_OR_NIL_P (exp))
  886. {
  887. scm_puts (" . ", port);
  888. scm_iprin1 (exp, port, pstate);
  889. }
  890. end:
  891. scm_putc (tlr, port);
  892. pstate->top = floor + 2;
  893. return;
  894. fancy_printing:
  895. {
  896. long n = pstate->length;
  897. scm_iprin1 (SCM_CAR (exp), port, pstate);
  898. exp = SCM_CDR (exp); --n;
  899. for (; scm_is_pair (exp); exp = SCM_CDR (exp))
  900. {
  901. register unsigned long i;
  902. for (i = 0; i < pstate->top; ++i)
  903. if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
  904. goto fancy_circref;
  905. if (pstate->fancyp)
  906. {
  907. if (n == 0)
  908. {
  909. scm_puts (" ...", port);
  910. goto skip_tail;
  911. }
  912. else
  913. --n;
  914. }
  915. PUSH_REF(pstate, exp);
  916. ++pstate->list_offset;
  917. scm_putc (' ', port);
  918. /* CHECK_INTS; */
  919. scm_iprin1 (SCM_CAR (exp), port, pstate);
  920. }
  921. }
  922. if (!SCM_NULL_OR_NIL_P (exp))
  923. {
  924. scm_puts (" . ", port);
  925. scm_iprin1 (exp, port, pstate);
  926. }
  927. skip_tail:
  928. pstate->list_offset -= pstate->top - floor - 2;
  929. goto end;
  930. fancy_circref:
  931. pstate->list_offset -= pstate->top - floor - 2;
  932. circref:
  933. scm_puts (" . ", port);
  934. print_circref (port, pstate, exp);
  935. goto end;
  936. }
  937. int
  938. scm_valid_oport_value_p (SCM val)
  939. {
  940. return (SCM_OPOUTPORTP (val)
  941. || (SCM_PORT_WITH_PS_P (val)
  942. && SCM_OPOUTPORTP (SCM_PORT_WITH_PS_PORT (val))));
  943. }
  944. /* SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write); */
  945. SCM
  946. scm_write (SCM obj, SCM port)
  947. {
  948. if (SCM_UNBNDP (port))
  949. port = scm_current_output_port ();
  950. SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
  951. scm_prin1 (obj, port, 1);
  952. return SCM_UNSPECIFIED;
  953. }
  954. /* SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display); */
  955. SCM
  956. scm_display (SCM obj, SCM port)
  957. {
  958. if (SCM_UNBNDP (port))
  959. port = scm_current_output_port ();
  960. SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
  961. scm_prin1 (obj, port, 0);
  962. return SCM_UNSPECIFIED;
  963. }
  964. SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
  965. (SCM destination, SCM message, SCM args),
  966. "Write @var{message} to @var{destination}, defaulting to\n"
  967. "the current output port.\n"
  968. "@var{message} can contain @code{~A} (was @code{%s}) and\n"
  969. "@code{~S} (was @code{%S}) escapes. When printed,\n"
  970. "the escapes are replaced with corresponding members of\n"
  971. "@var{args}:\n"
  972. "@code{~A} formats using @code{display} and @code{~S} formats\n"
  973. "using @code{write}.\n"
  974. "If @var{destination} is @code{#t}, then use the current output\n"
  975. "port, if @var{destination} is @code{#f}, then return a string\n"
  976. "containing the formatted text. Does not add a trailing newline.")
  977. #define FUNC_NAME s_scm_simple_format
  978. {
  979. SCM port, answer = SCM_UNSPECIFIED;
  980. int fReturnString = 0;
  981. int writingp;
  982. size_t start, p, end;
  983. if (scm_is_eq (destination, SCM_BOOL_T))
  984. {
  985. destination = port = scm_current_output_port ();
  986. SCM_VALIDATE_OPORT_VALUE (1, destination);
  987. }
  988. else if (scm_is_false (destination))
  989. {
  990. fReturnString = 1;
  991. port = scm_mkstrport (SCM_INUM0, SCM_BOOL_F, SCM_WRTNG, FUNC_NAME);
  992. destination = port;
  993. }
  994. else
  995. {
  996. SCM_VALIDATE_OPORT_VALUE (1, destination);
  997. port = SCM_COERCE_OUTPORT (destination);
  998. }
  999. SCM_VALIDATE_STRING (2, message);
  1000. SCM_VALIDATE_REST_ARGUMENT (args);
  1001. p = 0;
  1002. start = 0;
  1003. end = scm_i_string_length (message);
  1004. for (p = start; p != end; ++p)
  1005. if (scm_i_string_ref (message, p) == '~')
  1006. {
  1007. if (++p == end)
  1008. break;
  1009. switch (scm_i_string_ref (message, p))
  1010. {
  1011. case 'A': case 'a':
  1012. writingp = 0;
  1013. break;
  1014. case 'S': case 's':
  1015. writingp = 1;
  1016. break;
  1017. case '~':
  1018. scm_lfwrite_substr (message, start, p, port);
  1019. start = p + 1;
  1020. continue;
  1021. case '%':
  1022. scm_lfwrite_substr (message, start, p - 1, port);
  1023. scm_newline (port);
  1024. start = p + 1;
  1025. continue;
  1026. default:
  1027. SCM_MISC_ERROR ("FORMAT: Unsupported format option ~~~A - use (ice-9 format) instead",
  1028. scm_list_1 (SCM_MAKE_CHAR (scm_i_string_ref (message, p))));
  1029. }
  1030. if (!scm_is_pair (args))
  1031. SCM_MISC_ERROR ("FORMAT: Missing argument for ~~~A",
  1032. scm_list_1 (SCM_MAKE_CHAR (scm_i_string_ref (message, p))));
  1033. scm_lfwrite_substr (message, start, p - 1, port);
  1034. /* we pass destination here */
  1035. scm_prin1 (SCM_CAR (args), destination, writingp);
  1036. args = SCM_CDR (args);
  1037. start = p + 1;
  1038. }
  1039. scm_lfwrite_substr (message, start, p, port);
  1040. if (!scm_is_eq (args, SCM_EOL))
  1041. SCM_MISC_ERROR ("FORMAT: ~A superfluous arguments",
  1042. scm_list_1 (scm_length (args)));
  1043. if (fReturnString)
  1044. answer = scm_strport_to_string (destination);
  1045. return scm_return_first (answer, message);
  1046. }
  1047. #undef FUNC_NAME
  1048. SCM_DEFINE (scm_newline, "newline", 0, 1, 0,
  1049. (SCM port),
  1050. "Send a newline to @var{port}.\n"
  1051. "If @var{port} is omitted, send to the current output port.")
  1052. #define FUNC_NAME s_scm_newline
  1053. {
  1054. if (SCM_UNBNDP (port))
  1055. port = scm_current_output_port ();
  1056. SCM_VALIDATE_OPORT_VALUE (1, port);
  1057. scm_putc ('\n', SCM_COERCE_OUTPORT (port));
  1058. return SCM_UNSPECIFIED;
  1059. }
  1060. #undef FUNC_NAME
  1061. SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
  1062. (SCM chr, SCM port),
  1063. "Send character @var{chr} to @var{port}.")
  1064. #define FUNC_NAME s_scm_write_char
  1065. {
  1066. if (SCM_UNBNDP (port))
  1067. port = scm_current_output_port ();
  1068. else
  1069. port = SCM_COERCE_OUTPORT (port);
  1070. SCM_VALIDATE_CHAR (1, chr);
  1071. SCM_VALIDATE_OPOUTPORT (2, port);
  1072. scm_c_put_char (port, SCM_CHAR (chr));
  1073. return SCM_UNSPECIFIED;
  1074. }
  1075. #undef FUNC_NAME
  1076. /* Call back to Scheme code to do the printing of special objects
  1077. * (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a smob
  1078. * containing PORT and PSTATE. This object can be used as the port for
  1079. * display/write etc to continue the current print chain. The REVEALED
  1080. * field of PSTATE is set to true to indicate that the print state has
  1081. * escaped to Scheme and thus has to be freed by the GC.
  1082. */
  1083. scm_t_bits scm_tc16_port_with_ps;
  1084. /* Print exactly as the port itself would */
  1085. static int
  1086. port_with_ps_print (SCM obj, SCM port, scm_print_state *pstate)
  1087. {
  1088. obj = SCM_PORT_WITH_PS_PORT (obj);
  1089. return SCM_PORT_TYPE (obj)->print (obj, port, pstate);
  1090. }
  1091. SCM
  1092. scm_printer_apply (SCM proc, SCM exp, SCM port, scm_print_state *pstate)
  1093. {
  1094. pstate->revealed = 1;
  1095. return scm_call_2 (proc, exp,
  1096. scm_i_port_with_print_state (port, pstate->handle));
  1097. }
  1098. SCM_DEFINE (scm_port_with_print_state, "port-with-print-state", 1, 1, 0,
  1099. (SCM port, SCM pstate),
  1100. "Create a new port which behaves like @var{port}, but with an\n"
  1101. "included print state @var{pstate}. @var{pstate} is optional.\n"
  1102. "If @var{pstate} isn't supplied and @var{port} already has\n"
  1103. "a print state, the old print state is reused.")
  1104. #define FUNC_NAME s_scm_port_with_print_state
  1105. {
  1106. SCM_VALIDATE_OPORT_VALUE (1, port);
  1107. if (!SCM_UNBNDP (pstate))
  1108. SCM_VALIDATE_PRINTSTATE (2, pstate);
  1109. return scm_i_port_with_print_state (port, pstate);
  1110. }
  1111. #undef FUNC_NAME
  1112. SCM_DEFINE (scm_get_print_state, "get-print-state", 1, 0, 0,
  1113. (SCM port),
  1114. "Return the print state of the port @var{port}. If @var{port}\n"
  1115. "has no associated print state, @code{#f} is returned.")
  1116. #define FUNC_NAME s_scm_get_print_state
  1117. {
  1118. if (SCM_PORT_WITH_PS_P (port))
  1119. return SCM_PORT_WITH_PS_PS (port);
  1120. if (SCM_OUTPUT_PORT_P (port))
  1121. return SCM_BOOL_F;
  1122. SCM_WRONG_TYPE_ARG (1, port);
  1123. }
  1124. #undef FUNC_NAME
  1125. void
  1126. scm_init_print ()
  1127. {
  1128. SCM type;
  1129. type = scm_make_vtable (scm_from_locale_string (SCM_PRINT_STATE_LAYOUT),
  1130. SCM_BOOL_F);
  1131. scm_set_struct_vtable_name_x (type, scm_from_latin1_symbol ("print-state"));
  1132. scm_print_state_vtable = type;
  1133. /* Don't want to bind a wrapper class in GOOPS, so pass 0 as arg1. */
  1134. scm_tc16_port_with_ps = scm_make_smob_type (0, 0);
  1135. scm_set_smob_print (scm_tc16_port_with_ps, port_with_ps_print);
  1136. #include "libguile/print.x"
  1137. scm_init_opts (scm_print_options, scm_print_opts);
  1138. scm_print_opts[SCM_PRINT_HIGHLIGHT_PREFIX_I].val =
  1139. SCM_UNPACK (scm_from_locale_string ("{"));
  1140. scm_print_opts[SCM_PRINT_HIGHLIGHT_SUFFIX_I].val =
  1141. SCM_UNPACK (scm_from_locale_string ("}"));
  1142. scm_print_opts[SCM_PRINT_KEYWORD_STYLE_I].val = SCM_UNPACK (sym_reader);
  1143. }
  1144. /*
  1145. Local Variables:
  1146. c-file-style: "gnu"
  1147. End:
  1148. */