print.c 45 KB

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