print.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558
  1. /* Copyright (C) 1995-1999, 2000, 2001, 2002, 2003, 2004, 2006, 2008,
  2. * 2009, 2010, 2011, 2012 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 <iconv.h>
  24. #include <stdio.h>
  25. #include <assert.h>
  26. #include <uniconv.h>
  27. #include <unictype.h>
  28. #include "libguile/_scm.h"
  29. #include "libguile/chars.h"
  30. #include "libguile/continuations.h"
  31. #include "libguile/smob.h"
  32. #include "libguile/control.h"
  33. #include "libguile/eval.h"
  34. #include "libguile/macros.h"
  35. #include "libguile/procprop.h"
  36. #include "libguile/read.h"
  37. #include "libguile/programs.h"
  38. #include "libguile/alist.h"
  39. #include "libguile/struct.h"
  40. #include "libguile/ports.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 size_t display_string (const void *, int, size_t, SCM,
  52. scm_t_string_failed_conversion_handler);
  53. static int display_character (scm_t_wchar, SCM,
  54. scm_t_string_failed_conversion_handler);
  55. static void write_character (scm_t_wchar, SCM, int);
  56. static void write_character_escaped (scm_t_wchar, int, SCM);
  57. /* {Names of immediate symbols}
  58. *
  59. * This table must agree with the declarations in scm.h: {Immediate Symbols}.
  60. */
  61. /* This table must agree with the list of flags in tags.h. */
  62. static const char *iflagnames[] =
  63. {
  64. "#f",
  65. "#nil", /* Elisp nil value. Should print from elisp as symbol `nil'. */
  66. "#<XXX UNUSED LISP FALSE -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
  67. "()",
  68. "#t",
  69. "#<XXX UNUSED BOOLEAN 0 -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
  70. "#<XXX UNUSED BOOLEAN 1 -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
  71. "#<XXX UNUSED BOOLEAN 2 -- DO NOT USE -- SHOULD NEVER BE SEEN XXX>",
  72. "#<unspecified>",
  73. "#<undefined>",
  74. "#<eof>",
  75. /* Unbound slot marker for GOOPS. For internal use in GOOPS only. */
  76. "#<unbound>",
  77. };
  78. SCM_SYMBOL (sym_reader, "reader");
  79. scm_t_option scm_print_opts[] = {
  80. { SCM_OPTION_SCM, "highlight-prefix", (scm_t_bits)SCM_BOOL_F_BITS,
  81. "The string to print before highlighted values." },
  82. { SCM_OPTION_SCM, "highlight-suffix", (scm_t_bits)SCM_BOOL_F_BITS,
  83. "The string to print after highlighted values." },
  84. { SCM_OPTION_SCM, "quote-keywordish-symbols", (scm_t_bits)SCM_BOOL_F_BITS,
  85. "How to print symbols that have a colon as their first or last character. "
  86. "The value '#f' does not quote the colons; '#t' quotes them; "
  87. "'reader' quotes them when the reader option 'keywords' is not '#f'." },
  88. { SCM_OPTION_BOOLEAN, "escape-newlines", 1,
  89. "Render newlines as \\n when printing using `write'." },
  90. { 0 },
  91. };
  92. SCM_DEFINE (scm_print_options, "print-options-interface", 0, 1, 0,
  93. (SCM setting),
  94. "Option interface for the print options. Instead of using\n"
  95. "this procedure directly, use the procedures\n"
  96. "@code{print-enable}, @code{print-disable}, @code{print-set!}\n"
  97. "and @code{print-options}.")
  98. #define FUNC_NAME s_scm_print_options
  99. {
  100. SCM ans = scm_options (setting,
  101. scm_print_opts,
  102. FUNC_NAME);
  103. return ans;
  104. }
  105. #undef FUNC_NAME
  106. /* {Printing of Scheme Objects}
  107. */
  108. /* Detection of circular references.
  109. *
  110. * Due to other constraints in the implementation, this code has bad
  111. * time complexity (O (depth * N)), The printer code can be
  112. * rewritten to be O(N).
  113. */
  114. #define PUSH_REF(pstate, obj) \
  115. do \
  116. { \
  117. PSTATE_STACK_SET (pstate, pstate->top, obj); \
  118. pstate->top++; \
  119. if (pstate->top == pstate->ceiling) \
  120. grow_ref_stack (pstate); \
  121. } while(0)
  122. #define ENTER_NESTED_DATA(pstate, obj, label) \
  123. do \
  124. { \
  125. register unsigned long i; \
  126. for (i = 0; i < pstate->top; ++i) \
  127. if (scm_is_eq (PSTATE_STACK_REF (pstate, i), (obj))) \
  128. goto label; \
  129. if (pstate->fancyp) \
  130. { \
  131. if (pstate->top - pstate->list_offset >= pstate->level) \
  132. { \
  133. scm_putc_unlocked ('#', port); \
  134. return; \
  135. } \
  136. } \
  137. PUSH_REF(pstate, obj); \
  138. } while(0)
  139. #define EXIT_NESTED_DATA(pstate) \
  140. do \
  141. { \
  142. --pstate->top; \
  143. PSTATE_STACK_SET (pstate, pstate->top, SCM_UNDEFINED); \
  144. } \
  145. while (0)
  146. SCM scm_print_state_vtable = SCM_BOOL_F;
  147. static SCM print_state_pool = SCM_EOL;
  148. scm_i_pthread_mutex_t print_state_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
  149. #ifdef GUILE_DEBUG /* Used for debugging purposes */
  150. SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0,
  151. (),
  152. "Return the current-pstate -- the car of the\n"
  153. "@code{print_state_pool}. @code{current-pstate} is only\n"
  154. "included in @code{--enable-guile-debug} builds.")
  155. #define FUNC_NAME s_scm_current_pstate
  156. {
  157. if (!scm_is_null (print_state_pool))
  158. return SCM_CAR (print_state_pool);
  159. else
  160. return SCM_BOOL_F;
  161. }
  162. #undef FUNC_NAME
  163. #endif
  164. #define PSTATE_SIZE 50L
  165. static SCM
  166. make_print_state (void)
  167. {
  168. SCM print_state
  169. = scm_make_struct (scm_print_state_vtable, SCM_INUM0, SCM_EOL);
  170. scm_print_state *pstate = SCM_PRINT_STATE (print_state);
  171. pstate->ref_vect = scm_c_make_vector (PSTATE_SIZE, SCM_UNDEFINED);
  172. pstate->ceiling = SCM_SIMPLE_VECTOR_LENGTH (pstate->ref_vect);
  173. pstate->highlight_objects = SCM_EOL;
  174. return print_state;
  175. }
  176. SCM
  177. scm_make_print_state ()
  178. {
  179. SCM answer = SCM_BOOL_F;
  180. /* First try to allocate a print state from the pool */
  181. scm_i_pthread_mutex_lock (&print_state_mutex);
  182. if (!scm_is_null (print_state_pool))
  183. {
  184. answer = SCM_CAR (print_state_pool);
  185. print_state_pool = SCM_CDR (print_state_pool);
  186. }
  187. scm_i_pthread_mutex_unlock (&print_state_mutex);
  188. return scm_is_false (answer) ? make_print_state () : answer;
  189. }
  190. void
  191. scm_free_print_state (SCM print_state)
  192. {
  193. SCM handle;
  194. scm_print_state *pstate = SCM_PRINT_STATE (print_state);
  195. /* Cleanup before returning print state to pool.
  196. * It is better to do it here. Doing it in scm_prin1
  197. * would cost more since that function is called much more
  198. * often.
  199. */
  200. pstate->fancyp = 0;
  201. pstate->revealed = 0;
  202. pstate->highlight_objects = SCM_EOL;
  203. scm_i_pthread_mutex_lock (&print_state_mutex);
  204. handle = scm_cons (print_state, print_state_pool);
  205. print_state_pool = handle;
  206. scm_i_pthread_mutex_unlock (&print_state_mutex);
  207. }
  208. SCM
  209. scm_i_port_with_print_state (SCM port, SCM print_state)
  210. {
  211. if (SCM_UNBNDP (print_state))
  212. {
  213. if (SCM_PORT_WITH_PS_P (port))
  214. return port;
  215. else
  216. print_state = scm_make_print_state ();
  217. /* port does not need to be coerced since it doesn't have ps */
  218. }
  219. else
  220. port = SCM_COERCE_OUTPORT (port);
  221. SCM_RETURN_NEWSMOB (scm_tc16_port_with_ps,
  222. SCM_UNPACK (scm_cons (port, print_state)));
  223. }
  224. static void
  225. grow_ref_stack (scm_print_state *pstate)
  226. {
  227. SCM old_vect = pstate->ref_vect;
  228. size_t old_size = SCM_SIMPLE_VECTOR_LENGTH (old_vect);
  229. size_t new_size = 2 * pstate->ceiling;
  230. SCM new_vect = scm_c_make_vector (new_size, SCM_UNDEFINED);
  231. unsigned long int i;
  232. for (i = 0; i != old_size; ++i)
  233. SCM_SIMPLE_VECTOR_SET (new_vect, i, SCM_SIMPLE_VECTOR_REF (old_vect, i));
  234. pstate->ref_vect = new_vect;
  235. pstate->ceiling = new_size;
  236. }
  237. #define PSTATE_STACK_REF(p,i) SCM_SIMPLE_VECTOR_REF((p)->ref_vect, (i))
  238. #define PSTATE_STACK_SET(p,i,v) SCM_SIMPLE_VECTOR_SET((p)->ref_vect, (i), (v))
  239. static void
  240. print_circref (SCM port, scm_print_state *pstate, SCM ref)
  241. {
  242. register long i;
  243. long self = pstate->top - 1;
  244. i = pstate->top - 1;
  245. if (scm_is_pair (PSTATE_STACK_REF (pstate, i)))
  246. {
  247. while (i > 0)
  248. {
  249. if (!scm_is_pair (PSTATE_STACK_REF (pstate, i-1))
  250. || !scm_is_eq (SCM_CDR (PSTATE_STACK_REF (pstate, i-1)),
  251. SCM_CDR (PSTATE_STACK_REF (pstate, i))))
  252. break;
  253. --i;
  254. }
  255. self = i;
  256. }
  257. for (i = pstate->top - 1; 1; --i)
  258. if (scm_is_eq (PSTATE_STACK_REF(pstate, i), ref))
  259. break;
  260. scm_putc_unlocked ('#', port);
  261. scm_intprint (i - self, 10, port);
  262. scm_putc_unlocked ('#', port);
  263. }
  264. /* Print the name of a symbol. */
  265. static int
  266. quote_keywordish_symbols (void)
  267. {
  268. SCM option = SCM_PRINT_KEYWORD_STYLE;
  269. if (scm_is_false (option))
  270. return 0;
  271. if (scm_is_eq (option, sym_reader))
  272. return scm_is_true (SCM_PACK (SCM_KEYWORD_STYLE));
  273. return 1;
  274. }
  275. #define INITIAL_IDENTIFIER_MASK \
  276. (UC_CATEGORY_MASK_Lu | UC_CATEGORY_MASK_Ll | UC_CATEGORY_MASK_Lt \
  277. | UC_CATEGORY_MASK_Lm | UC_CATEGORY_MASK_Lo | UC_CATEGORY_MASK_Mn \
  278. | UC_CATEGORY_MASK_Nl | UC_CATEGORY_MASK_No | UC_CATEGORY_MASK_Pd \
  279. | UC_CATEGORY_MASK_Pc | UC_CATEGORY_MASK_Po | UC_CATEGORY_MASK_Sc \
  280. | UC_CATEGORY_MASK_Sm | UC_CATEGORY_MASK_Sk | UC_CATEGORY_MASK_So \
  281. | UC_CATEGORY_MASK_Co)
  282. #define SUBSEQUENT_IDENTIFIER_MASK \
  283. (INITIAL_IDENTIFIER_MASK \
  284. | UC_CATEGORY_MASK_Nd | UC_CATEGORY_MASK_Mc | UC_CATEGORY_MASK_Me)
  285. static int
  286. symbol_has_extended_read_syntax (SCM sym)
  287. {
  288. size_t pos, len = scm_i_symbol_length (sym);
  289. scm_t_wchar c;
  290. /* The empty symbol. */
  291. if (len == 0)
  292. return 1;
  293. c = scm_i_symbol_ref (sym, 0);
  294. /* Single dot; conflicts with dotted-pair notation. */
  295. if (len == 1 && c == '.')
  296. return 1;
  297. /* Other initial-character constraints. */
  298. if (c == '\'' || c == '`' || c == ',' || c == '"' || c == ';' || c == '#')
  299. return 1;
  300. /* Keywords can be identified by trailing colons too. */
  301. if (c == ':' || scm_i_symbol_ref (sym, len - 1) == ':')
  302. return quote_keywordish_symbols ();
  303. /* Number-ish symbols. */
  304. if (scm_is_true (scm_i_string_to_number (scm_symbol_to_string (sym), 10)))
  305. return 1;
  306. /* Other disallowed first characters. */
  307. if (!uc_is_general_category_withtable (c, INITIAL_IDENTIFIER_MASK))
  308. return 1;
  309. /* Otherwise, any character that's in the identifier category mask is
  310. fine to pass through as-is, provided it's not one of the ASCII
  311. delimiters like `;'. */
  312. for (pos = 1; pos < len; pos++)
  313. {
  314. c = scm_i_symbol_ref (sym, pos);
  315. if (!uc_is_general_category_withtable (c, SUBSEQUENT_IDENTIFIER_MASK))
  316. return 1;
  317. else if (c == '"' || c == ';' || c == '#')
  318. return 1;
  319. }
  320. return 0;
  321. }
  322. static void
  323. print_normal_symbol (SCM sym, SCM port)
  324. {
  325. scm_display (scm_symbol_to_string (sym), port);
  326. }
  327. static void
  328. print_extended_symbol (SCM sym, SCM port)
  329. {
  330. size_t pos, len;
  331. scm_t_string_failed_conversion_handler strategy;
  332. len = scm_i_symbol_length (sym);
  333. strategy = scm_i_get_conversion_strategy (port);
  334. scm_lfwrite_unlocked ("#{", 2, port);
  335. for (pos = 0; pos < len; pos++)
  336. {
  337. scm_t_wchar c = scm_i_symbol_ref (sym, pos);
  338. if (uc_is_general_category_withtable (c,
  339. SUBSEQUENT_IDENTIFIER_MASK
  340. | UC_CATEGORY_MASK_Zs))
  341. {
  342. if (!display_character (c, port, strategy))
  343. scm_encoding_error ("print_extended_symbol", errno,
  344. "cannot convert to output locale",
  345. port, SCM_MAKE_CHAR (c));
  346. }
  347. else
  348. {
  349. display_string ("\\x", 1, 2, port, iconveh_question_mark);
  350. scm_intprint (c, 16, port);
  351. display_character (';', port, iconveh_question_mark);
  352. }
  353. }
  354. scm_lfwrite_unlocked ("}#", 2, port);
  355. }
  356. /* FIXME: allow R6RS hex escapes instead of #{...}#. */
  357. void
  358. scm_i_print_symbol_name (SCM sym, SCM port)
  359. {
  360. if (symbol_has_extended_read_syntax (sym))
  361. print_extended_symbol (sym, port);
  362. else
  363. print_normal_symbol (sym, port);
  364. }
  365. void
  366. scm_print_symbol_name (const char *str, size_t len, SCM port)
  367. {
  368. SCM symbol = scm_from_utf8_symboln (str, len);
  369. scm_i_print_symbol_name (symbol, port);
  370. }
  371. /* Print generally. Handles both write and display according to PSTATE.
  372. */
  373. SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write);
  374. SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display);
  375. static void iprin1 (SCM exp, SCM port, scm_print_state *pstate);
  376. /* Print a character as an octal or hex escape. */
  377. #define PRINT_CHAR_ESCAPE(i, port) \
  378. do \
  379. { \
  380. if (!SCM_R6RS_ESCAPES_P) \
  381. scm_intprint (i, 8, port); \
  382. else \
  383. { \
  384. scm_puts_unlocked ("x", port); \
  385. scm_intprint (i, 16, port); \
  386. } \
  387. } \
  388. while (0)
  389. void
  390. scm_iprin1 (SCM exp, SCM port, scm_print_state *pstate)
  391. {
  392. if (pstate->fancyp
  393. && scm_is_true (scm_memq (exp, pstate->highlight_objects)))
  394. {
  395. scm_display (SCM_PRINT_HIGHLIGHT_PREFIX, port);
  396. iprin1 (exp, port, pstate);
  397. scm_display (SCM_PRINT_HIGHLIGHT_SUFFIX, port);
  398. }
  399. else
  400. iprin1 (exp, port, pstate);
  401. }
  402. static void
  403. iprin1 (SCM exp, SCM port, scm_print_state *pstate)
  404. {
  405. switch (SCM_ITAG3 (exp))
  406. {
  407. case scm_tc3_tc7_1:
  408. case scm_tc3_tc7_2:
  409. /* These tc3 tags should never occur in an immediate value. They are
  410. * only used in cell types of non-immediates, i. e. the value returned
  411. * by SCM_CELL_TYPE (exp) can use these tags.
  412. */
  413. scm_ipruk ("immediate", exp, port);
  414. break;
  415. case scm_tc3_int_1:
  416. case scm_tc3_int_2:
  417. scm_intprint (SCM_I_INUM (exp), 10, port);
  418. break;
  419. case scm_tc3_imm24:
  420. if (SCM_CHARP (exp))
  421. {
  422. if (SCM_WRITINGP (pstate))
  423. write_character (SCM_CHAR (exp), port, 0);
  424. else
  425. {
  426. if (!display_character (SCM_CHAR (exp), port,
  427. scm_i_get_conversion_strategy (port)))
  428. scm_encoding_error (__func__, errno,
  429. "cannot convert to output locale",
  430. port, exp);
  431. }
  432. }
  433. else if (SCM_IFLAGP (exp)
  434. && ((size_t) SCM_IFLAGNUM (exp) < (sizeof iflagnames / sizeof (char *))))
  435. {
  436. scm_puts_unlocked (iflagnames [SCM_IFLAGNUM (exp)], port);
  437. }
  438. else
  439. {
  440. /* unknown immediate value */
  441. scm_ipruk ("immediate", exp, port);
  442. }
  443. break;
  444. case scm_tc3_cons:
  445. switch (SCM_TYP7 (exp))
  446. {
  447. case scm_tcs_struct:
  448. {
  449. ENTER_NESTED_DATA (pstate, exp, circref);
  450. if (SCM_OBJ_CLASS_FLAGS (exp) & SCM_CLASSF_GOOPS)
  451. {
  452. SCM pwps, print = pstate->writingp ? g_write : g_display;
  453. if (SCM_UNPACK (print) == 0)
  454. goto print_struct;
  455. pwps = scm_i_port_with_print_state (port, pstate->handle);
  456. pstate->revealed = 1;
  457. scm_call_2 (print, exp, pwps);
  458. }
  459. else
  460. {
  461. print_struct:
  462. scm_print_struct (exp, port, pstate);
  463. }
  464. EXIT_NESTED_DATA (pstate);
  465. }
  466. break;
  467. case scm_tcs_cons_imcar:
  468. case scm_tcs_cons_nimcar:
  469. ENTER_NESTED_DATA (pstate, exp, circref);
  470. scm_iprlist ("(", exp, ')', port, pstate);
  471. EXIT_NESTED_DATA (pstate);
  472. break;
  473. circref:
  474. print_circref (port, pstate, exp);
  475. break;
  476. case scm_tc7_number:
  477. switch SCM_TYP16 (exp) {
  478. case scm_tc16_big:
  479. scm_bigprint (exp, port, pstate);
  480. break;
  481. case scm_tc16_real:
  482. scm_print_real (exp, port, pstate);
  483. break;
  484. case scm_tc16_complex:
  485. scm_print_complex (exp, port, pstate);
  486. break;
  487. case scm_tc16_fraction:
  488. scm_i_print_fraction (exp, port, pstate);
  489. break;
  490. }
  491. break;
  492. case scm_tc7_string:
  493. if (SCM_WRITINGP (pstate))
  494. {
  495. size_t len, i;
  496. display_character ('"', port, iconveh_question_mark);
  497. len = scm_i_string_length (exp);
  498. for (i = 0; i < len; ++i)
  499. write_character (scm_i_string_ref (exp, i), port, 1);
  500. display_character ('"', port, iconveh_question_mark);
  501. scm_remember_upto_here_1 (exp);
  502. }
  503. else
  504. {
  505. size_t len, printed;
  506. len = scm_i_string_length (exp);
  507. printed = display_string (scm_i_string_data (exp),
  508. scm_i_is_narrow_string (exp),
  509. len, port,
  510. scm_i_get_conversion_strategy (port));
  511. if (SCM_UNLIKELY (printed < len))
  512. scm_encoding_error (__func__, errno,
  513. "cannot convert to output locale",
  514. port, scm_c_string_ref (exp, printed));
  515. }
  516. scm_remember_upto_here_1 (exp);
  517. break;
  518. case scm_tc7_symbol:
  519. if (scm_i_symbol_is_interned (exp))
  520. {
  521. scm_i_print_symbol_name (exp, port);
  522. scm_remember_upto_here_1 (exp);
  523. }
  524. else
  525. {
  526. scm_puts_unlocked ("#<uninterned-symbol ", port);
  527. scm_i_print_symbol_name (exp, port);
  528. scm_putc_unlocked (' ', port);
  529. scm_uintprint (SCM_UNPACK (exp), 16, port);
  530. scm_putc_unlocked ('>', port);
  531. }
  532. break;
  533. case scm_tc7_variable:
  534. scm_i_variable_print (exp, port, pstate);
  535. break;
  536. case scm_tc7_program:
  537. scm_i_program_print (exp, port, pstate);
  538. break;
  539. case scm_tc7_pointer:
  540. scm_i_pointer_print (exp, port, pstate);
  541. break;
  542. case scm_tc7_hashtable:
  543. scm_i_hashtable_print (exp, port, pstate);
  544. break;
  545. case scm_tc7_weak_set:
  546. scm_i_weak_set_print (exp, port, pstate);
  547. break;
  548. case scm_tc7_weak_table:
  549. scm_i_weak_table_print (exp, port, pstate);
  550. break;
  551. case scm_tc7_fluid:
  552. scm_i_fluid_print (exp, port, pstate);
  553. break;
  554. case scm_tc7_dynamic_state:
  555. scm_i_dynamic_state_print (exp, port, pstate);
  556. break;
  557. case scm_tc7_frame:
  558. scm_i_frame_print (exp, port, pstate);
  559. break;
  560. case scm_tc7_objcode:
  561. scm_i_objcode_print (exp, port, pstate);
  562. break;
  563. case scm_tc7_vm:
  564. scm_i_vm_print (exp, port, pstate);
  565. break;
  566. case scm_tc7_vm_cont:
  567. scm_i_vm_cont_print (exp, port, pstate);
  568. break;
  569. case scm_tc7_prompt:
  570. scm_i_prompt_print (exp, port, pstate);
  571. break;
  572. case scm_tc7_with_fluids:
  573. scm_i_with_fluids_print (exp, port, pstate);
  574. break;
  575. case scm_tc7_array:
  576. ENTER_NESTED_DATA (pstate, exp, circref);
  577. scm_i_print_array (exp, port, pstate);
  578. EXIT_NESTED_DATA (pstate);
  579. break;
  580. case scm_tc7_bytevector:
  581. scm_i_print_bytevector (exp, port, pstate);
  582. break;
  583. case scm_tc7_bitvector:
  584. scm_i_print_bitvector (exp, port, pstate);
  585. break;
  586. case scm_tc7_wvect:
  587. ENTER_NESTED_DATA (pstate, exp, circref);
  588. scm_puts_unlocked ("#w(", port);
  589. goto common_vector_printer;
  590. case scm_tc7_vector:
  591. ENTER_NESTED_DATA (pstate, exp, circref);
  592. scm_puts_unlocked ("#(", port);
  593. common_vector_printer:
  594. {
  595. register long i;
  596. long last = SCM_SIMPLE_VECTOR_LENGTH (exp) - 1;
  597. int cutp = 0;
  598. if (pstate->fancyp
  599. && SCM_SIMPLE_VECTOR_LENGTH (exp) > pstate->length)
  600. {
  601. last = pstate->length - 1;
  602. cutp = 1;
  603. }
  604. for (i = 0; i < last; ++i)
  605. {
  606. scm_iprin1 (scm_c_vector_ref (exp, i), port, pstate);
  607. scm_putc_unlocked (' ', port);
  608. }
  609. if (i == last)
  610. {
  611. /* CHECK_INTS; */
  612. scm_iprin1 (scm_c_vector_ref (exp, i), port, pstate);
  613. }
  614. if (cutp)
  615. scm_puts_unlocked (" ...", port);
  616. scm_putc_unlocked (')', port);
  617. }
  618. EXIT_NESTED_DATA (pstate);
  619. break;
  620. case scm_tc7_port:
  621. {
  622. scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (exp);
  623. if (ptob->print && ptob->print (exp, port, pstate))
  624. break;
  625. goto punk;
  626. }
  627. case scm_tc7_smob:
  628. ENTER_NESTED_DATA (pstate, exp, circref);
  629. SCM_SMOB_DESCRIPTOR (exp).print (exp, port, pstate);
  630. EXIT_NESTED_DATA (pstate);
  631. break;
  632. default:
  633. /* case scm_tcs_closures: */
  634. punk:
  635. scm_ipruk ("type", exp, port);
  636. }
  637. }
  638. }
  639. /* Print states are necessary for circular reference safe printing.
  640. * They are also expensive to allocate. Therefore print states are
  641. * kept in a pool so that they can be reused.
  642. */
  643. /* The PORT argument can also be a print-state/port pair, which will
  644. * then be used instead of allocating a new print state. This is
  645. * useful for continuing a chain of print calls from Scheme. */
  646. void
  647. scm_prin1 (SCM exp, SCM port, int writingp)
  648. {
  649. SCM handle = SCM_BOOL_F; /* Will GC protect the handle whilst unlinked */
  650. SCM pstate_scm;
  651. scm_print_state *pstate;
  652. int old_writingp;
  653. /* If PORT is a print-state/port pair, use that. Else create a new
  654. print-state. */
  655. if (SCM_PORT_WITH_PS_P (port))
  656. {
  657. pstate_scm = SCM_PORT_WITH_PS_PS (port);
  658. port = SCM_PORT_WITH_PS_PORT (port);
  659. }
  660. else
  661. {
  662. /* First try to allocate a print state from the pool */
  663. scm_i_pthread_mutex_lock (&print_state_mutex);
  664. if (!scm_is_null (print_state_pool))
  665. {
  666. handle = print_state_pool;
  667. print_state_pool = SCM_CDR (print_state_pool);
  668. }
  669. scm_i_pthread_mutex_unlock (&print_state_mutex);
  670. if (scm_is_false (handle))
  671. handle = scm_list_1 (make_print_state ());
  672. pstate_scm = SCM_CAR (handle);
  673. }
  674. pstate = SCM_PRINT_STATE (pstate_scm);
  675. old_writingp = pstate->writingp;
  676. pstate->writingp = writingp;
  677. scm_iprin1 (exp, port, pstate);
  678. pstate->writingp = old_writingp;
  679. /* Return print state to pool if it has been created above and
  680. hasn't escaped to Scheme. */
  681. if (scm_is_true (handle) && !pstate->revealed)
  682. {
  683. scm_i_pthread_mutex_lock (&print_state_mutex);
  684. SCM_SETCDR (handle, print_state_pool);
  685. print_state_pool = handle;
  686. scm_i_pthread_mutex_unlock (&print_state_mutex);
  687. }
  688. }
  689. /* Convert codepoint CH to UTF-8 and store the result in UTF8. Return
  690. the number of bytes of the UTF-8-encoded string. */
  691. static size_t
  692. codepoint_to_utf8 (scm_t_wchar ch, scm_t_uint8 utf8[4])
  693. {
  694. size_t len;
  695. scm_t_uint32 codepoint;
  696. codepoint = (scm_t_uint32) ch;
  697. if (codepoint <= 0x7f)
  698. {
  699. len = 1;
  700. utf8[0] = (scm_t_uint8) codepoint;
  701. }
  702. else if (codepoint <= 0x7ffUL)
  703. {
  704. len = 2;
  705. utf8[0] = 0xc0 | (codepoint >> 6);
  706. utf8[1] = 0x80 | (codepoint & 0x3f);
  707. }
  708. else if (codepoint <= 0xffffUL)
  709. {
  710. len = 3;
  711. utf8[0] = 0xe0 | (codepoint >> 12);
  712. utf8[1] = 0x80 | ((codepoint >> 6) & 0x3f);
  713. utf8[2] = 0x80 | (codepoint & 0x3f);
  714. }
  715. else
  716. {
  717. len = 4;
  718. utf8[0] = 0xf0 | (codepoint >> 18);
  719. utf8[1] = 0x80 | ((codepoint >> 12) & 0x3f);
  720. utf8[2] = 0x80 | ((codepoint >> 6) & 0x3f);
  721. utf8[3] = 0x80 | (codepoint & 0x3f);
  722. }
  723. return len;
  724. }
  725. #define STR_REF(s, x) \
  726. (narrow_p \
  727. ? (scm_t_wchar) ((unsigned char *) (s))[x] \
  728. : ((scm_t_wchar *) (s))[x])
  729. /* Write STR to PORT as UTF-8. STR is a LEN-codepoint string; it is
  730. narrow if NARROW_P is true, wide otherwise. Return LEN. */
  731. static size_t
  732. display_string_as_utf8 (const void *str, int narrow_p, size_t len,
  733. SCM port)
  734. {
  735. size_t printed = 0;
  736. while (len > printed)
  737. {
  738. size_t utf8_len, i;
  739. char *input, utf8_buf[256];
  740. /* Convert STR to UTF-8. */
  741. for (i = printed, utf8_len = 0, input = utf8_buf;
  742. i < len && utf8_len + 4 < sizeof (utf8_buf);
  743. i++)
  744. {
  745. utf8_len += codepoint_to_utf8 (STR_REF (str, i),
  746. (scm_t_uint8 *) input);
  747. input = utf8_buf + utf8_len;
  748. }
  749. /* INPUT was successfully converted, entirely; print the
  750. result. */
  751. scm_lfwrite_unlocked (utf8_buf, utf8_len, port);
  752. printed += i - printed;
  753. }
  754. assert (printed == len);
  755. return len;
  756. }
  757. /* Convert STR through PORT's output conversion descriptor and write the
  758. output to PORT. Return the number of codepoints written. */
  759. static size_t
  760. display_string_using_iconv (const void *str, int narrow_p, size_t len,
  761. SCM port,
  762. scm_t_string_failed_conversion_handler strategy)
  763. {
  764. size_t printed;
  765. scm_t_iconv_descriptors *id;
  766. id = scm_i_port_iconv_descriptors (port);
  767. printed = 0;
  768. while (len > printed)
  769. {
  770. size_t done, utf8_len, input_left, output_left, i;
  771. size_t codepoints_read, output_len;
  772. char *input, *output;
  773. char utf8_buf[256], encoded_output[256];
  774. size_t offsets[256];
  775. /* Convert STR to UTF-8. */
  776. for (i = printed, utf8_len = 0, input = utf8_buf;
  777. i < len && utf8_len + 4 < sizeof (utf8_buf);
  778. i++)
  779. {
  780. offsets[utf8_len] = i;
  781. utf8_len += codepoint_to_utf8 (STR_REF (str, i),
  782. (scm_t_uint8 *) input);
  783. input = utf8_buf + utf8_len;
  784. }
  785. input = utf8_buf;
  786. input_left = utf8_len;
  787. output = encoded_output;
  788. output_left = sizeof (encoded_output);
  789. done = iconv (id->output_cd, &input, &input_left,
  790. &output, &output_left);
  791. output_len = sizeof (encoded_output) - output_left;
  792. if (SCM_UNLIKELY (done == (size_t) -1))
  793. {
  794. int errno_save = errno;
  795. /* Reset the `iconv' state. */
  796. iconv (id->output_cd, NULL, NULL, NULL, NULL);
  797. /* Print the OUTPUT_LEN bytes successfully converted. */
  798. scm_lfwrite_unlocked (encoded_output, output_len, port);
  799. /* See how many input codepoints these OUTPUT_LEN bytes
  800. corresponds to. */
  801. codepoints_read = offsets[input - utf8_buf] - printed;
  802. printed += codepoints_read;
  803. if (errno_save == EILSEQ &&
  804. strategy != SCM_FAILED_CONVERSION_ERROR)
  805. {
  806. /* Conversion failed somewhere in INPUT and we want to
  807. escape or substitute the offending input character. */
  808. if (strategy == SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE)
  809. {
  810. scm_t_wchar ch;
  811. /* Find CH, the offending codepoint, and escape it. */
  812. ch = STR_REF (str, offsets[input - utf8_buf]);
  813. write_character_escaped (ch, 1, port);
  814. }
  815. else
  816. /* STRATEGY is `SCM_FAILED_CONVERSION_QUESTION_MARK'. */
  817. display_string ("?", 1, 1, port, strategy);
  818. printed++;
  819. }
  820. else
  821. /* Something bad happened that we can't handle: bail out. */
  822. break;
  823. }
  824. else
  825. {
  826. /* INPUT was successfully converted, entirely; print the
  827. result. */
  828. scm_lfwrite_unlocked (encoded_output, output_len, port);
  829. codepoints_read = i - printed;
  830. printed += codepoints_read;
  831. }
  832. }
  833. return printed;
  834. }
  835. #undef STR_REF
  836. /* Display the LEN codepoints in STR to PORT according to STRATEGY;
  837. return the number of codepoints successfully displayed. If NARROW_P,
  838. then STR is interpreted as a sequence of `char', denoting a Latin-1
  839. string; otherwise it's interpreted as a sequence of
  840. `scm_t_wchar'. */
  841. static size_t
  842. display_string (const void *str, int narrow_p,
  843. size_t len, SCM port,
  844. scm_t_string_failed_conversion_handler strategy)
  845. {
  846. scm_t_port *pt;
  847. pt = SCM_PTAB_ENTRY (port);
  848. if (pt->encoding_mode == SCM_PORT_ENCODING_MODE_UTF8)
  849. return display_string_as_utf8 (str, narrow_p, len, port);
  850. else
  851. return display_string_using_iconv (str, narrow_p, len,
  852. port, strategy);
  853. }
  854. /* Attempt to display CH to PORT according to STRATEGY. Return non-zero
  855. if CH was successfully displayed, zero otherwise (e.g., if it was not
  856. representable in PORT's encoding.) */
  857. static int
  858. display_character (scm_t_wchar ch, SCM port,
  859. scm_t_string_failed_conversion_handler strategy)
  860. {
  861. return display_string (&ch, 0, 1, port, strategy) == 1;
  862. }
  863. /* Attempt to pretty-print CH, a combining character, to PORT. Return
  864. zero upon failure, non-zero otherwise. The idea is to print CH above
  865. a dotted circle to make it more visible. */
  866. static int
  867. write_combining_character (scm_t_wchar ch, SCM port)
  868. {
  869. scm_t_wchar str[2];
  870. str[0] = SCM_CODEPOINT_DOTTED_CIRCLE;
  871. str[1] = ch;
  872. return display_string (str, 0, 2, port, iconveh_error) == 2;
  873. }
  874. /* Write CH to PORT in its escaped form, using the string escape syntax
  875. if STRING_ESCAPES_P is non-zero. */
  876. static void
  877. write_character_escaped (scm_t_wchar ch, int string_escapes_p, SCM port)
  878. {
  879. if (string_escapes_p)
  880. {
  881. /* Represent CH using the in-string escape syntax. */
  882. static const char hex[] = "0123456789abcdef";
  883. static const char escapes[7] = "abtnvfr";
  884. char buf[9];
  885. if (ch >= 0x07 && ch <= 0x0D && ch != 0x0A)
  886. {
  887. /* Use special escapes for some C0 controls. */
  888. buf[0] = '\\';
  889. buf[1] = escapes[ch - 0x07];
  890. scm_lfwrite_unlocked (buf, 2, port);
  891. }
  892. else if (!SCM_R6RS_ESCAPES_P)
  893. {
  894. if (ch <= 0xFF)
  895. {
  896. buf[0] = '\\';
  897. buf[1] = 'x';
  898. buf[2] = hex[ch / 16];
  899. buf[3] = hex[ch % 16];
  900. scm_lfwrite_unlocked (buf, 4, port);
  901. }
  902. else if (ch <= 0xFFFF)
  903. {
  904. buf[0] = '\\';
  905. buf[1] = 'u';
  906. buf[2] = hex[(ch & 0xF000) >> 12];
  907. buf[3] = hex[(ch & 0xF00) >> 8];
  908. buf[4] = hex[(ch & 0xF0) >> 4];
  909. buf[5] = hex[(ch & 0xF)];
  910. scm_lfwrite_unlocked (buf, 6, port);
  911. }
  912. else if (ch > 0xFFFF)
  913. {
  914. buf[0] = '\\';
  915. buf[1] = 'U';
  916. buf[2] = hex[(ch & 0xF00000) >> 20];
  917. buf[3] = hex[(ch & 0xF0000) >> 16];
  918. buf[4] = hex[(ch & 0xF000) >> 12];
  919. buf[5] = hex[(ch & 0xF00) >> 8];
  920. buf[6] = hex[(ch & 0xF0) >> 4];
  921. buf[7] = hex[(ch & 0xF)];
  922. scm_lfwrite_unlocked (buf, 8, port);
  923. }
  924. }
  925. else
  926. {
  927. /* Print an R6RS variable-length hex escape: "\xNNNN;". */
  928. scm_t_wchar ch2 = ch;
  929. int i = 8;
  930. buf[i] = ';';
  931. i --;
  932. if (ch == 0)
  933. buf[i--] = '0';
  934. else
  935. while (ch2 > 0)
  936. {
  937. buf[i] = hex[ch2 & 0xF];
  938. ch2 >>= 4;
  939. i --;
  940. }
  941. buf[i] = 'x';
  942. i --;
  943. buf[i] = '\\';
  944. scm_lfwrite_unlocked (buf + i, 9 - i, port);
  945. }
  946. }
  947. else
  948. {
  949. /* Represent CH using the character escape syntax. */
  950. const char *name;
  951. name = scm_i_charname (SCM_MAKE_CHAR (ch));
  952. if (name != NULL)
  953. scm_puts_unlocked (name, port);
  954. else
  955. PRINT_CHAR_ESCAPE (ch, port);
  956. }
  957. }
  958. /* Write CH to PORT, escaping it if it's non-graphic or not
  959. representable in PORT's encoding. If STRING_ESCAPES_P is true and CH
  960. needs to be escaped, it is escaped using the in-string escape syntax;
  961. otherwise the character escape syntax is used. */
  962. static void
  963. write_character (scm_t_wchar ch, SCM port, int string_escapes_p)
  964. {
  965. int printed = 0;
  966. scm_t_string_failed_conversion_handler strategy;
  967. strategy = scm_i_get_conversion_strategy (port);
  968. if (string_escapes_p)
  969. {
  970. /* Check if CH deserves special treatment. */
  971. if (ch == '"' || ch == '\\')
  972. {
  973. display_character ('\\', port, iconveh_question_mark);
  974. display_character (ch, port, strategy);
  975. printed = 1;
  976. }
  977. else if (ch == '\n' && SCM_PRINT_ESCAPE_NEWLINES_P)
  978. {
  979. display_character ('\\', port, iconveh_question_mark);
  980. display_character ('n', port, strategy);
  981. printed = 1;
  982. }
  983. else if (ch == ' ' || ch == '\n')
  984. {
  985. display_character (ch, port, strategy);
  986. printed = 1;
  987. }
  988. }
  989. else
  990. {
  991. display_string ("#\\", 1, 2, port, iconveh_question_mark);
  992. if (uc_combining_class (ch) != UC_CCC_NR)
  993. /* Character is a combining character, so attempt to
  994. pretty-print it. */
  995. printed = write_combining_character (ch, port);
  996. }
  997. if (!printed
  998. && uc_is_general_category_withtable (ch,
  999. UC_CATEGORY_MASK_L |
  1000. UC_CATEGORY_MASK_M |
  1001. UC_CATEGORY_MASK_N |
  1002. UC_CATEGORY_MASK_P |
  1003. UC_CATEGORY_MASK_S))
  1004. /* CH is graphic; attempt to display it. */
  1005. printed = display_character (ch, port, iconveh_error);
  1006. if (!printed)
  1007. /* CH isn't graphic or cannot be represented in PORT's encoding. */
  1008. write_character_escaped (ch, string_escapes_p, port);
  1009. }
  1010. /* Print an integer.
  1011. */
  1012. void
  1013. scm_intprint (scm_t_intmax n, int radix, SCM port)
  1014. {
  1015. char num_buf[SCM_INTBUFLEN];
  1016. scm_lfwrite_unlocked (num_buf, scm_iint2str (n, radix, num_buf), port);
  1017. }
  1018. void
  1019. scm_uintprint (scm_t_uintmax n, int radix, SCM port)
  1020. {
  1021. char num_buf[SCM_INTBUFLEN];
  1022. scm_lfwrite_unlocked (num_buf, scm_iuint2str (n, radix, num_buf), port);
  1023. }
  1024. /* Print an object of unrecognized type.
  1025. */
  1026. void
  1027. scm_ipruk (char *hdr, SCM ptr, SCM port)
  1028. {
  1029. scm_puts_unlocked ("#<unknown-", port);
  1030. scm_puts_unlocked (hdr, port);
  1031. if (1) /* (scm_in_heap_p (ptr)) */ /* FIXME */
  1032. {
  1033. scm_puts_unlocked (" (0x", port);
  1034. scm_uintprint (SCM_CELL_WORD_0 (ptr), 16, port);
  1035. scm_puts_unlocked (" . 0x", port);
  1036. scm_uintprint (SCM_CELL_WORD_1 (ptr), 16, port);
  1037. scm_puts_unlocked (") @", port);
  1038. }
  1039. scm_puts_unlocked (" 0x", port);
  1040. scm_uintprint (SCM_UNPACK (ptr), 16, port);
  1041. scm_putc_unlocked ('>', port);
  1042. }
  1043. /* Print a list.
  1044. */
  1045. void
  1046. scm_iprlist (char *hdr, SCM exp, int tlr, SCM port, scm_print_state *pstate)
  1047. {
  1048. register SCM hare, tortoise;
  1049. long floor = pstate->top - 2;
  1050. scm_puts_unlocked (hdr, port);
  1051. /* CHECK_INTS; */
  1052. if (pstate->fancyp)
  1053. goto fancy_printing;
  1054. /* Run a hare and tortoise so that total time complexity will be
  1055. O(depth * N) instead of O(N^2). */
  1056. hare = SCM_CDR (exp);
  1057. tortoise = exp;
  1058. while (scm_is_pair (hare))
  1059. {
  1060. if (scm_is_eq (hare, tortoise))
  1061. goto fancy_printing;
  1062. hare = SCM_CDR (hare);
  1063. if (!scm_is_pair (hare))
  1064. break;
  1065. hare = SCM_CDR (hare);
  1066. tortoise = SCM_CDR (tortoise);
  1067. }
  1068. /* No cdr cycles intrinsic to this list */
  1069. scm_iprin1 (SCM_CAR (exp), port, pstate);
  1070. for (exp = SCM_CDR (exp); scm_is_pair (exp); exp = SCM_CDR (exp))
  1071. {
  1072. register long i;
  1073. for (i = floor; i >= 0; --i)
  1074. if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
  1075. goto circref;
  1076. PUSH_REF (pstate, exp);
  1077. scm_putc_unlocked (' ', port);
  1078. /* CHECK_INTS; */
  1079. scm_iprin1 (SCM_CAR (exp), port, pstate);
  1080. }
  1081. if (!SCM_NULL_OR_NIL_P (exp))
  1082. {
  1083. scm_puts_unlocked (" . ", port);
  1084. scm_iprin1 (exp, port, pstate);
  1085. }
  1086. end:
  1087. scm_putc_unlocked (tlr, port);
  1088. pstate->top = floor + 2;
  1089. return;
  1090. fancy_printing:
  1091. {
  1092. long n = pstate->length;
  1093. scm_iprin1 (SCM_CAR (exp), port, pstate);
  1094. exp = SCM_CDR (exp); --n;
  1095. for (; scm_is_pair (exp); exp = SCM_CDR (exp))
  1096. {
  1097. register unsigned long i;
  1098. for (i = 0; i < pstate->top; ++i)
  1099. if (scm_is_eq (PSTATE_STACK_REF(pstate, i), exp))
  1100. goto fancy_circref;
  1101. if (pstate->fancyp)
  1102. {
  1103. if (n == 0)
  1104. {
  1105. scm_puts_unlocked (" ...", port);
  1106. goto skip_tail;
  1107. }
  1108. else
  1109. --n;
  1110. }
  1111. PUSH_REF(pstate, exp);
  1112. ++pstate->list_offset;
  1113. scm_putc_unlocked (' ', port);
  1114. /* CHECK_INTS; */
  1115. scm_iprin1 (SCM_CAR (exp), port, pstate);
  1116. }
  1117. }
  1118. if (!SCM_NULL_OR_NIL_P (exp))
  1119. {
  1120. scm_puts_unlocked (" . ", port);
  1121. scm_iprin1 (exp, port, pstate);
  1122. }
  1123. skip_tail:
  1124. pstate->list_offset -= pstate->top - floor - 2;
  1125. goto end;
  1126. fancy_circref:
  1127. pstate->list_offset -= pstate->top - floor - 2;
  1128. circref:
  1129. scm_puts_unlocked (" . ", port);
  1130. print_circref (port, pstate, exp);
  1131. goto end;
  1132. }
  1133. int
  1134. scm_valid_oport_value_p (SCM val)
  1135. {
  1136. return (SCM_OPOUTPORTP (val)
  1137. || (SCM_PORT_WITH_PS_P (val)
  1138. && SCM_OPOUTPORTP (SCM_PORT_WITH_PS_PORT (val))));
  1139. }
  1140. /* SCM_GPROC(s_write, "write", 1, 1, 0, scm_write, g_write); */
  1141. SCM
  1142. scm_write (SCM obj, SCM port)
  1143. {
  1144. if (SCM_UNBNDP (port))
  1145. port = scm_current_output_port ();
  1146. SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_write);
  1147. scm_dynwind_begin (0);
  1148. scm_dynwind_lock_port (SCM_COERCE_OUTPORT (port));
  1149. scm_prin1 (obj, port, 1);
  1150. scm_dynwind_end ();
  1151. return SCM_UNSPECIFIED;
  1152. }
  1153. /* SCM_GPROC(s_display, "display", 1, 1, 0, scm_display, g_display); */
  1154. SCM
  1155. scm_display (SCM obj, SCM port)
  1156. {
  1157. if (SCM_UNBNDP (port))
  1158. port = scm_current_output_port ();
  1159. SCM_ASSERT (scm_valid_oport_value_p (port), port, SCM_ARG2, s_display);
  1160. scm_dynwind_begin (0);
  1161. scm_dynwind_lock_port (SCM_COERCE_OUTPORT (port));
  1162. scm_prin1 (obj, port, 0);
  1163. scm_dynwind_end ();
  1164. return SCM_UNSPECIFIED;
  1165. }
  1166. SCM_DEFINE (scm_simple_format, "simple-format", 2, 0, 1,
  1167. (SCM destination, SCM message, SCM args),
  1168. "Write @var{message} to @var{destination}, defaulting to\n"
  1169. "the current output port.\n"
  1170. "@var{message} can contain @code{~A} (was @code{%s}) and\n"
  1171. "@code{~S} (was @code{%S}) escapes. When printed,\n"
  1172. "the escapes are replaced with corresponding members of\n"
  1173. "@var{args}:\n"
  1174. "@code{~A} formats using @code{display} and @code{~S} formats\n"
  1175. "using @code{write}.\n"
  1176. "If @var{destination} is @code{#t}, then use the current output\n"
  1177. "port, if @var{destination} is @code{#f}, then return a string\n"
  1178. "containing the formatted text. Does not add a trailing newline.")
  1179. #define FUNC_NAME s_scm_simple_format
  1180. {
  1181. SCM port, answer = SCM_UNSPECIFIED;
  1182. int fReturnString = 0;
  1183. int writingp;
  1184. size_t start, p, end;
  1185. if (scm_is_eq (destination, SCM_BOOL_T))
  1186. {
  1187. destination = port = scm_current_output_port ();
  1188. }
  1189. else if (scm_is_false (destination))
  1190. {
  1191. fReturnString = 1;
  1192. port = scm_mkstrport (SCM_INUM0, SCM_BOOL_F,
  1193. SCM_OPN | SCM_WRTNG,
  1194. FUNC_NAME);
  1195. destination = port;
  1196. }
  1197. else
  1198. {
  1199. SCM_VALIDATE_OPORT_VALUE (1, destination);
  1200. port = SCM_COERCE_OUTPORT (destination);
  1201. }
  1202. SCM_VALIDATE_STRING (2, message);
  1203. SCM_VALIDATE_REST_ARGUMENT (args);
  1204. p = 0;
  1205. start = 0;
  1206. end = scm_i_string_length (message);
  1207. for (p = start; p != end; ++p)
  1208. if (scm_i_string_ref (message, p) == '~')
  1209. {
  1210. if (++p == end)
  1211. break;
  1212. switch (scm_i_string_ref (message, p))
  1213. {
  1214. case 'A': case 'a':
  1215. writingp = 0;
  1216. break;
  1217. case 'S': case 's':
  1218. writingp = 1;
  1219. break;
  1220. case '~':
  1221. scm_lfwrite_substr (message, start, p, port);
  1222. start = p + 1;
  1223. continue;
  1224. case '%':
  1225. scm_lfwrite_substr (message, start, p - 1, port);
  1226. scm_newline (port);
  1227. start = p + 1;
  1228. continue;
  1229. default:
  1230. SCM_MISC_ERROR ("FORMAT: Unsupported format option ~~~A - use (ice-9 format) instead",
  1231. scm_list_1 (SCM_MAKE_CHAR (scm_i_string_ref (message, p))));
  1232. }
  1233. if (!scm_is_pair (args))
  1234. SCM_MISC_ERROR ("FORMAT: Missing argument for ~~~A",
  1235. scm_list_1 (SCM_MAKE_CHAR (scm_i_string_ref (message, p))));
  1236. scm_lfwrite_substr (message, start, p - 1, port);
  1237. /* we pass destination here */
  1238. scm_prin1 (SCM_CAR (args), destination, writingp);
  1239. args = SCM_CDR (args);
  1240. start = p + 1;
  1241. }
  1242. scm_lfwrite_substr (message, start, p, port);
  1243. if (!scm_is_eq (args, SCM_EOL))
  1244. SCM_MISC_ERROR ("FORMAT: ~A superfluous arguments",
  1245. scm_list_1 (scm_length (args)));
  1246. if (fReturnString)
  1247. answer = scm_strport_to_string (destination);
  1248. return scm_return_first (answer, message);
  1249. }
  1250. #undef FUNC_NAME
  1251. SCM_DEFINE (scm_newline, "newline", 0, 1, 0,
  1252. (SCM port),
  1253. "Send a newline to @var{port}.\n"
  1254. "If @var{port} is omitted, send to the current output port.")
  1255. #define FUNC_NAME s_scm_newline
  1256. {
  1257. if (SCM_UNBNDP (port))
  1258. port = scm_current_output_port ();
  1259. SCM_VALIDATE_OPORT_VALUE (1, port);
  1260. scm_putc_unlocked ('\n', SCM_COERCE_OUTPORT (port));
  1261. return SCM_UNSPECIFIED;
  1262. }
  1263. #undef FUNC_NAME
  1264. SCM_DEFINE (scm_write_char, "write-char", 1, 1, 0,
  1265. (SCM chr, SCM port),
  1266. "Send character @var{chr} to @var{port}.")
  1267. #define FUNC_NAME s_scm_write_char
  1268. {
  1269. if (SCM_UNBNDP (port))
  1270. port = scm_current_output_port ();
  1271. SCM_VALIDATE_CHAR (1, chr);
  1272. SCM_VALIDATE_OPORT_VALUE (2, port);
  1273. port = SCM_COERCE_OUTPORT (port);
  1274. if (!display_character (SCM_CHAR (chr), port,
  1275. scm_i_get_conversion_strategy (port)))
  1276. scm_encoding_error (__func__, errno,
  1277. "cannot convert to output locale",
  1278. port, chr);
  1279. return SCM_UNSPECIFIED;
  1280. }
  1281. #undef FUNC_NAME
  1282. /* Call back to Scheme code to do the printing of special objects
  1283. * (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a smob
  1284. * containing PORT and PSTATE. This object can be used as the port for
  1285. * display/write etc to continue the current print chain. The REVEALED
  1286. * field of PSTATE is set to true to indicate that the print state has
  1287. * escaped to Scheme and thus has to be freed by the GC.
  1288. */
  1289. scm_t_bits scm_tc16_port_with_ps;
  1290. /* Print exactly as the port itself would */
  1291. static int
  1292. port_with_ps_print (SCM obj, SCM port, scm_print_state *pstate)
  1293. {
  1294. obj = SCM_PORT_WITH_PS_PORT (obj);
  1295. return SCM_PORT_DESCRIPTOR (obj)->print (obj, port, pstate);
  1296. }
  1297. SCM
  1298. scm_printer_apply (SCM proc, SCM exp, SCM port, scm_print_state *pstate)
  1299. {
  1300. pstate->revealed = 1;
  1301. return scm_call_2 (proc, exp,
  1302. scm_i_port_with_print_state (port, pstate->handle));
  1303. }
  1304. SCM_DEFINE (scm_port_with_print_state, "port-with-print-state", 1, 1, 0,
  1305. (SCM port, SCM pstate),
  1306. "Create a new port which behaves like @var{port}, but with an\n"
  1307. "included print state @var{pstate}. @var{pstate} is optional.\n"
  1308. "If @var{pstate} isn't supplied and @var{port} already has\n"
  1309. "a print state, the old print state is reused.")
  1310. #define FUNC_NAME s_scm_port_with_print_state
  1311. {
  1312. SCM_VALIDATE_OPORT_VALUE (1, port);
  1313. if (!SCM_UNBNDP (pstate))
  1314. SCM_VALIDATE_PRINTSTATE (2, pstate);
  1315. return scm_i_port_with_print_state (port, pstate);
  1316. }
  1317. #undef FUNC_NAME
  1318. SCM_DEFINE (scm_get_print_state, "get-print-state", 1, 0, 0,
  1319. (SCM port),
  1320. "Return the print state of the port @var{port}. If @var{port}\n"
  1321. "has no associated print state, @code{#f} is returned.")
  1322. #define FUNC_NAME s_scm_get_print_state
  1323. {
  1324. if (SCM_PORT_WITH_PS_P (port))
  1325. return SCM_PORT_WITH_PS_PS (port);
  1326. if (SCM_OUTPUT_PORT_P (port))
  1327. return SCM_BOOL_F;
  1328. SCM_WRONG_TYPE_ARG (1, port);
  1329. }
  1330. #undef FUNC_NAME
  1331. void
  1332. scm_init_print ()
  1333. {
  1334. SCM type;
  1335. type = scm_make_vtable (scm_from_locale_string (SCM_PRINT_STATE_LAYOUT),
  1336. SCM_BOOL_F);
  1337. scm_set_struct_vtable_name_x (type, scm_from_latin1_symbol ("print-state"));
  1338. scm_print_state_vtable = type;
  1339. /* Don't want to bind a wrapper class in GOOPS, so pass 0 as arg1. */
  1340. scm_tc16_port_with_ps = scm_make_smob_type (0, 0);
  1341. scm_set_smob_print (scm_tc16_port_with_ps, port_with_ps_print);
  1342. #include "libguile/print.x"
  1343. scm_init_opts (scm_print_options, scm_print_opts);
  1344. scm_print_opts[SCM_PRINT_HIGHLIGHT_PREFIX_I].val =
  1345. SCM_UNPACK (scm_from_locale_string ("{"));
  1346. scm_print_opts[SCM_PRINT_HIGHLIGHT_SUFFIX_I].val =
  1347. SCM_UNPACK (scm_from_locale_string ("}"));
  1348. scm_print_opts[SCM_PRINT_KEYWORD_STYLE_I].val = SCM_UNPACK (sym_reader);
  1349. }
  1350. /*
  1351. Local Variables:
  1352. c-file-style: "gnu"
  1353. End:
  1354. */