print.c 48 KB

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