r6rs-ports.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269
  1. /* Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public License
  5. * as published by the Free Software Foundation; either version 3 of
  6. * the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. * 02110-1301 USA
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. # include <config.h>
  20. #endif
  21. #ifdef HAVE_UNISTD_H
  22. # include <unistd.h>
  23. #endif
  24. #include <string.h>
  25. #include <stdio.h>
  26. #include <assert.h>
  27. #include "libguile/_scm.h"
  28. #include "libguile/bytevectors.h"
  29. #include "libguile/chars.h"
  30. #include "libguile/eval.h"
  31. #include "libguile/r6rs-ports.h"
  32. #include "libguile/strings.h"
  33. #include "libguile/validate.h"
  34. #include "libguile/values.h"
  35. #include "libguile/vectors.h"
  36. /* Unimplemented features. */
  37. /* Transoders are currently not implemented since Guile 1.8 is not
  38. Unicode-capable. Thus, most of the code here assumes the use of the
  39. binary transcoder. */
  40. static inline void
  41. transcoders_not_implemented (void)
  42. {
  43. fprintf (stderr, "%s: warning: transcoders not implemented\n",
  44. PACKAGE_NAME);
  45. }
  46. /* End-of-file object. */
  47. SCM_DEFINE (scm_eof_object, "eof-object", 0, 0, 0,
  48. (void),
  49. "Return the end-of-file object.")
  50. #define FUNC_NAME s_scm_eof_object
  51. {
  52. return (SCM_EOF_VAL);
  53. }
  54. #undef FUNC_NAME
  55. /* Input ports. */
  56. #ifndef MIN
  57. # define MIN(a,b) ((a) < (b) ? (a) : (b))
  58. #endif
  59. /* Bytevector input ports or "bip" for short. */
  60. static scm_t_bits bytevector_input_port_type = 0;
  61. static inline SCM
  62. make_bip (SCM bv)
  63. {
  64. SCM port;
  65. char *c_bv;
  66. unsigned c_len;
  67. scm_t_port *c_port;
  68. const unsigned long mode_bits = SCM_OPN | SCM_RDNG;
  69. port = scm_c_make_port_with_encoding (bytevector_input_port_type,
  70. mode_bits,
  71. NULL, /* encoding */
  72. SCM_FAILED_CONVERSION_ERROR,
  73. SCM_UNPACK (bv));
  74. c_port = SCM_PTAB_ENTRY (port);
  75. /* Have the port directly access the bytevector. */
  76. c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
  77. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  78. c_port->read_pos = c_port->read_buf = (unsigned char *) c_bv;
  79. c_port->read_end = (unsigned char *) c_bv + c_len;
  80. c_port->read_buf_size = c_len;
  81. return port;
  82. }
  83. static int
  84. bip_fill_input (SCM port)
  85. {
  86. int result;
  87. scm_t_port *c_port = SCM_PTAB_ENTRY (port);
  88. if (c_port->read_pos >= c_port->read_end)
  89. result = EOF;
  90. else
  91. result = (int) *c_port->read_pos;
  92. return result;
  93. }
  94. static scm_t_off
  95. bip_seek (SCM port, scm_t_off offset, int whence)
  96. #define FUNC_NAME "bip_seek"
  97. {
  98. scm_t_off c_result = 0;
  99. scm_t_port *c_port = SCM_PTAB_ENTRY (port);
  100. switch (whence)
  101. {
  102. case SEEK_CUR:
  103. offset += c_port->read_pos - c_port->read_buf;
  104. /* Fall through. */
  105. case SEEK_SET:
  106. if (c_port->read_buf + offset <= c_port->read_end)
  107. {
  108. c_port->read_pos = c_port->read_buf + offset;
  109. c_result = offset;
  110. }
  111. else
  112. scm_out_of_range (FUNC_NAME, scm_from_int (offset));
  113. break;
  114. case SEEK_END:
  115. if (c_port->read_end - offset >= c_port->read_buf)
  116. {
  117. c_port->read_pos = c_port->read_end - offset;
  118. c_result = c_port->read_pos - c_port->read_buf;
  119. }
  120. else
  121. scm_out_of_range (FUNC_NAME, scm_from_int (offset));
  122. break;
  123. default:
  124. scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
  125. "invalid `seek' parameter");
  126. }
  127. return c_result;
  128. }
  129. #undef FUNC_NAME
  130. /* Instantiate the bytevector input port type. */
  131. static inline void
  132. initialize_bytevector_input_ports (void)
  133. {
  134. bytevector_input_port_type =
  135. scm_make_port_type ("r6rs-bytevector-input-port", bip_fill_input,
  136. NULL);
  137. scm_set_port_seek (bytevector_input_port_type, bip_seek);
  138. }
  139. SCM_DEFINE (scm_open_bytevector_input_port,
  140. "open-bytevector-input-port", 1, 1, 0,
  141. (SCM bv, SCM transcoder),
  142. "Return an input port whose contents are drawn from "
  143. "bytevector @var{bv}.")
  144. #define FUNC_NAME s_scm_open_bytevector_input_port
  145. {
  146. SCM_VALIDATE_BYTEVECTOR (1, bv);
  147. if (!SCM_UNBNDP (transcoder) && !scm_is_false (transcoder))
  148. transcoders_not_implemented ();
  149. return (make_bip (bv));
  150. }
  151. #undef FUNC_NAME
  152. /* Custom binary ports. The following routines are shared by input and
  153. output custom binary ports. */
  154. #define SCM_CBP_GET_POSITION_PROC(_port) \
  155. SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 1)
  156. #define SCM_CBP_SET_POSITION_PROC(_port) \
  157. SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 2)
  158. #define SCM_CBP_CLOSE_PROC(_port) \
  159. SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 3)
  160. static scm_t_off
  161. cbp_seek (SCM port, scm_t_off offset, int whence)
  162. #define FUNC_NAME "cbp_seek"
  163. {
  164. SCM result;
  165. scm_t_off c_result = 0;
  166. switch (whence)
  167. {
  168. case SEEK_CUR:
  169. {
  170. SCM get_position_proc;
  171. get_position_proc = SCM_CBP_GET_POSITION_PROC (port);
  172. if (SCM_LIKELY (scm_is_true (get_position_proc)))
  173. result = scm_call_0 (get_position_proc);
  174. else
  175. scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
  176. "R6RS custom binary port does not "
  177. "support `port-position'");
  178. offset += scm_to_int (result);
  179. /* Fall through. */
  180. }
  181. case SEEK_SET:
  182. {
  183. SCM set_position_proc;
  184. set_position_proc = SCM_CBP_SET_POSITION_PROC (port);
  185. if (SCM_LIKELY (scm_is_true (set_position_proc)))
  186. result = scm_call_1 (set_position_proc, scm_from_int (offset));
  187. else
  188. scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
  189. "R6RS custom binary port does not "
  190. "support `set-port-position!'");
  191. /* Assuming setting the position succeeded. */
  192. c_result = offset;
  193. break;
  194. }
  195. default:
  196. /* `SEEK_END' cannot be supported. */
  197. scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
  198. "R6RS custom binary ports do not "
  199. "support `SEEK_END'");
  200. }
  201. return c_result;
  202. }
  203. #undef FUNC_NAME
  204. static int
  205. cbp_close (SCM port)
  206. {
  207. SCM close_proc;
  208. close_proc = SCM_CBP_CLOSE_PROC (port);
  209. if (scm_is_true (close_proc))
  210. /* Invoke the `close' thunk. */
  211. scm_call_0 (close_proc);
  212. return 1;
  213. }
  214. /* Custom binary input port ("cbip" for short). */
  215. static scm_t_bits custom_binary_input_port_type = 0;
  216. /* Size of the buffer embedded in custom binary input ports. */
  217. #define CBIP_BUFFER_SIZE 4096
  218. /* Return the bytevector associated with PORT. */
  219. #define SCM_CBIP_BYTEVECTOR(_port) \
  220. SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 4)
  221. /* Return the various procedures of PORT. */
  222. #define SCM_CBIP_READ_PROC(_port) \
  223. SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
  224. static inline SCM
  225. make_cbip (SCM read_proc, SCM get_position_proc,
  226. SCM set_position_proc, SCM close_proc)
  227. {
  228. SCM port, bv, method_vector;
  229. char *c_bv;
  230. unsigned c_len;
  231. scm_t_port *c_port;
  232. const unsigned long mode_bits = SCM_OPN | SCM_RDNG;
  233. /* Use a bytevector as the underlying buffer. */
  234. c_len = CBIP_BUFFER_SIZE;
  235. bv = scm_c_make_bytevector (c_len);
  236. c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
  237. /* Store the various methods and bytevector in a vector. */
  238. method_vector = scm_c_make_vector (5, SCM_BOOL_F);
  239. SCM_SIMPLE_VECTOR_SET (method_vector, 4, bv);
  240. SCM_SIMPLE_VECTOR_SET (method_vector, 0, read_proc);
  241. SCM_SIMPLE_VECTOR_SET (method_vector, 1, get_position_proc);
  242. SCM_SIMPLE_VECTOR_SET (method_vector, 2, set_position_proc);
  243. SCM_SIMPLE_VECTOR_SET (method_vector, 3, close_proc);
  244. port = scm_c_make_port_with_encoding (custom_binary_input_port_type,
  245. mode_bits,
  246. NULL, /* encoding */
  247. SCM_FAILED_CONVERSION_ERROR,
  248. SCM_UNPACK (method_vector));
  249. c_port = SCM_PTAB_ENTRY (port);
  250. /* Have the port directly access the buffer (bytevector). */
  251. c_port->read_pos = c_port->read_buf = (unsigned char *) c_bv;
  252. c_port->read_end = (unsigned char *) c_bv;
  253. c_port->read_buf_size = c_len;
  254. return port;
  255. }
  256. static int
  257. cbip_fill_input (SCM port)
  258. #define FUNC_NAME "cbip_fill_input"
  259. {
  260. int result;
  261. scm_t_port *c_port = SCM_PTAB_ENTRY (port);
  262. again:
  263. if (c_port->read_pos >= c_port->read_end)
  264. {
  265. /* Invoke the user's `read!' procedure. */
  266. unsigned c_octets;
  267. SCM bv, read_proc, octets;
  268. /* Use the bytevector associated with PORT as the buffer passed to the
  269. `read!' procedure, thereby avoiding additional allocations. */
  270. bv = SCM_CBIP_BYTEVECTOR (port);
  271. read_proc = SCM_CBIP_READ_PROC (port);
  272. /* The assumption here is that C_PORT's internal buffer wasn't changed
  273. behind our back. */
  274. assert (c_port->read_buf ==
  275. (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv));
  276. assert ((unsigned) c_port->read_buf_size
  277. == SCM_BYTEVECTOR_LENGTH (bv));
  278. octets = scm_call_3 (read_proc, bv, SCM_INUM0,
  279. SCM_I_MAKINUM (CBIP_BUFFER_SIZE));
  280. c_octets = scm_to_uint (octets);
  281. c_port->read_pos = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
  282. c_port->read_end = (unsigned char *) c_port->read_pos + c_octets;
  283. if (c_octets > 0)
  284. goto again;
  285. else
  286. result = EOF;
  287. }
  288. else
  289. result = (int) *c_port->read_pos;
  290. return result;
  291. }
  292. #undef FUNC_NAME
  293. SCM_DEFINE (scm_make_custom_binary_input_port,
  294. "make-custom-binary-input-port", 5, 0, 0,
  295. (SCM id, SCM read_proc, SCM get_position_proc,
  296. SCM set_position_proc, SCM close_proc),
  297. "Return a new custom binary input port whose input is drained "
  298. "by invoking @var{read_proc} and passing it a bytevector, an "
  299. "index where octets should be written, and an octet count.")
  300. #define FUNC_NAME s_scm_make_custom_binary_input_port
  301. {
  302. SCM_VALIDATE_STRING (1, id);
  303. SCM_VALIDATE_PROC (2, read_proc);
  304. if (!scm_is_false (get_position_proc))
  305. SCM_VALIDATE_PROC (3, get_position_proc);
  306. if (!scm_is_false (set_position_proc))
  307. SCM_VALIDATE_PROC (4, set_position_proc);
  308. if (!scm_is_false (close_proc))
  309. SCM_VALIDATE_PROC (5, close_proc);
  310. return (make_cbip (read_proc, get_position_proc, set_position_proc,
  311. close_proc));
  312. }
  313. #undef FUNC_NAME
  314. /* Instantiate the custom binary input port type. */
  315. static inline void
  316. initialize_custom_binary_input_ports (void)
  317. {
  318. custom_binary_input_port_type =
  319. scm_make_port_type ("r6rs-custom-binary-input-port",
  320. cbip_fill_input, NULL);
  321. scm_set_port_seek (custom_binary_input_port_type, cbp_seek);
  322. scm_set_port_close (custom_binary_input_port_type, cbp_close);
  323. }
  324. /* Binary input. */
  325. /* We currently don't support specific binary input ports. */
  326. #define SCM_VALIDATE_BINARY_INPUT_PORT SCM_VALIDATE_OPINPORT
  327. SCM_DEFINE (scm_get_u8, "get-u8", 1, 0, 0,
  328. (SCM port),
  329. "Read an octet from @var{port}, a binary input port, "
  330. "blocking as necessary.")
  331. #define FUNC_NAME s_scm_get_u8
  332. {
  333. SCM result;
  334. int c_result;
  335. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  336. c_result = scm_get_byte_or_eof (port);
  337. if (c_result == EOF)
  338. result = SCM_EOF_VAL;
  339. else
  340. result = SCM_I_MAKINUM ((unsigned char) c_result);
  341. return result;
  342. }
  343. #undef FUNC_NAME
  344. SCM_DEFINE (scm_lookahead_u8, "lookahead-u8", 1, 0, 0,
  345. (SCM port),
  346. "Like @code{get-u8} but does not update @var{port} to "
  347. "point past the octet.")
  348. #define FUNC_NAME s_scm_lookahead_u8
  349. {
  350. int u8;
  351. SCM result;
  352. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  353. u8 = scm_peek_byte_or_eof (port);
  354. if (u8 == EOF)
  355. result = SCM_EOF_VAL;
  356. else
  357. result = SCM_I_MAKINUM ((scm_t_uint8) u8);
  358. return result;
  359. }
  360. #undef FUNC_NAME
  361. SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 0, 0,
  362. (SCM port, SCM count),
  363. "Read @var{count} octets from @var{port}, blocking as "
  364. "necessary and return a bytevector containing the octets "
  365. "read. If fewer bytes are available, a bytevector smaller "
  366. "than @var{count} is returned.")
  367. #define FUNC_NAME s_scm_get_bytevector_n
  368. {
  369. SCM result;
  370. char *c_bv;
  371. unsigned c_count;
  372. size_t c_read;
  373. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  374. c_count = scm_to_uint (count);
  375. result = scm_c_make_bytevector (c_count);
  376. c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (result);
  377. if (SCM_LIKELY (c_count > 0))
  378. /* XXX: `scm_c_read ()' does not update the port position. */
  379. c_read = scm_c_read_unlocked (port, c_bv, c_count);
  380. else
  381. /* Don't invoke `scm_c_read ()' since it may block. */
  382. c_read = 0;
  383. if ((c_read == 0) && (c_count > 0))
  384. {
  385. if (SCM_EOF_OBJECT_P (scm_peek_char (port)))
  386. result = SCM_EOF_VAL;
  387. else
  388. result = scm_null_bytevector;
  389. }
  390. else
  391. {
  392. if (c_read < c_count)
  393. result = scm_c_shrink_bytevector (result, c_read);
  394. }
  395. return result;
  396. }
  397. #undef FUNC_NAME
  398. SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0,
  399. (SCM port, SCM bv, SCM start, SCM count),
  400. "Read @var{count} bytes from @var{port} and store them "
  401. "in @var{bv} starting at index @var{start}. Return either "
  402. "the number of bytes actually read or the end-of-file "
  403. "object.")
  404. #define FUNC_NAME s_scm_get_bytevector_n_x
  405. {
  406. SCM result;
  407. char *c_bv;
  408. unsigned c_start, c_count, c_len;
  409. size_t c_read;
  410. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  411. SCM_VALIDATE_BYTEVECTOR (2, bv);
  412. c_start = scm_to_uint (start);
  413. c_count = scm_to_uint (count);
  414. c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
  415. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  416. if (SCM_UNLIKELY (c_start + c_count > c_len))
  417. scm_out_of_range (FUNC_NAME, count);
  418. if (SCM_LIKELY (c_count > 0))
  419. c_read = scm_c_read_unlocked (port, c_bv + c_start, c_count);
  420. else
  421. /* Don't invoke `scm_c_read ()' since it may block. */
  422. c_read = 0;
  423. if ((c_read == 0) && (c_count > 0))
  424. {
  425. if (SCM_EOF_OBJECT_P (scm_peek_char (port)))
  426. result = SCM_EOF_VAL;
  427. else
  428. result = SCM_I_MAKINUM (0);
  429. }
  430. else
  431. result = scm_from_size_t (c_read);
  432. return result;
  433. }
  434. #undef FUNC_NAME
  435. SCM_DEFINE (scm_get_bytevector_some, "get-bytevector-some", 1, 0, 0,
  436. (SCM port),
  437. "Read from @var{port}, blocking as necessary, until data "
  438. "are available or and end-of-file is reached. Return either "
  439. "a new bytevector containing the data read or the "
  440. "end-of-file object.")
  441. #define FUNC_NAME s_scm_get_bytevector_some
  442. {
  443. /* Read at least one byte, unless the end-of-file is already reached, and
  444. read while characters are available (buffered). */
  445. SCM result;
  446. char *c_bv;
  447. unsigned c_len;
  448. size_t c_total;
  449. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  450. c_len = 4096;
  451. c_bv = (char *) scm_gc_malloc_pointerless (c_len, SCM_GC_BYTEVECTOR);
  452. c_total = 0;
  453. do
  454. {
  455. int c_chr;
  456. if (c_total + 1 > c_len)
  457. {
  458. /* Grow the bytevector. */
  459. c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2,
  460. SCM_GC_BYTEVECTOR);
  461. c_len *= 2;
  462. }
  463. /* We can't use `scm_c_read ()' since it blocks. */
  464. c_chr = scm_getc_unlocked (port);
  465. if (c_chr != EOF)
  466. {
  467. c_bv[c_total] = (char) c_chr;
  468. c_total++;
  469. }
  470. }
  471. while ((scm_is_true (scm_char_ready_p (port)))
  472. && (!SCM_EOF_OBJECT_P (scm_peek_char (port))));
  473. if (c_total == 0)
  474. {
  475. result = SCM_EOF_VAL;
  476. scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
  477. }
  478. else
  479. {
  480. if (c_len > c_total)
  481. {
  482. /* Shrink the bytevector. */
  483. c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_total,
  484. SCM_GC_BYTEVECTOR);
  485. c_len = (unsigned) c_total;
  486. }
  487. result = scm_c_take_gc_bytevector ((signed char *) c_bv, c_len,
  488. SCM_BOOL_F);
  489. }
  490. return result;
  491. }
  492. #undef FUNC_NAME
  493. SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0,
  494. (SCM port),
  495. "Read from @var{port}, blocking as necessary, until "
  496. "the end-of-file is reached. Return either "
  497. "a new bytevector containing the data read or the "
  498. "end-of-file object (if no data were available).")
  499. #define FUNC_NAME s_scm_get_bytevector_all
  500. {
  501. SCM result;
  502. char *c_bv;
  503. unsigned c_len, c_count;
  504. size_t c_read, c_total;
  505. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  506. c_len = c_count = 4096;
  507. c_bv = (char *) scm_gc_malloc_pointerless (c_len, SCM_GC_BYTEVECTOR);
  508. c_total = c_read = 0;
  509. do
  510. {
  511. if (c_total + c_read > c_len)
  512. {
  513. /* Grow the bytevector. */
  514. c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2,
  515. SCM_GC_BYTEVECTOR);
  516. c_count = c_len;
  517. c_len *= 2;
  518. }
  519. /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
  520. reached. */
  521. c_read = scm_c_read_unlocked (port, c_bv + c_total, c_count);
  522. c_total += c_read, c_count -= c_read;
  523. }
  524. while (!SCM_EOF_OBJECT_P (scm_peek_char (port)));
  525. if (c_total == 0)
  526. {
  527. result = SCM_EOF_VAL;
  528. scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
  529. }
  530. else
  531. {
  532. if (c_len > c_total)
  533. {
  534. /* Shrink the bytevector. */
  535. c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_total,
  536. SCM_GC_BYTEVECTOR);
  537. c_len = (unsigned) c_total;
  538. }
  539. result = scm_c_take_gc_bytevector ((signed char *) c_bv, c_len,
  540. SCM_BOOL_F);
  541. }
  542. return result;
  543. }
  544. #undef FUNC_NAME
  545. /* Binary output. */
  546. /* We currently don't support specific binary input ports. */
  547. #define SCM_VALIDATE_BINARY_OUTPUT_PORT SCM_VALIDATE_OPOUTPORT
  548. SCM_DEFINE (scm_put_u8, "put-u8", 2, 0, 0,
  549. (SCM port, SCM octet),
  550. "Write @var{octet} to binary port @var{port}.")
  551. #define FUNC_NAME s_scm_put_u8
  552. {
  553. scm_t_uint8 c_octet;
  554. SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
  555. c_octet = scm_to_uint8 (octet);
  556. scm_putc_unlocked ((char) c_octet, port);
  557. return SCM_UNSPECIFIED;
  558. }
  559. #undef FUNC_NAME
  560. SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
  561. (SCM port, SCM bv, SCM start, SCM count),
  562. "Write the contents of @var{bv} to @var{port}, optionally "
  563. "starting at index @var{start} and limiting to @var{count} "
  564. "octets.")
  565. #define FUNC_NAME s_scm_put_bytevector
  566. {
  567. char *c_bv;
  568. unsigned c_start, c_count, c_len;
  569. SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
  570. SCM_VALIDATE_BYTEVECTOR (2, bv);
  571. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  572. c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
  573. if (!scm_is_eq (start, SCM_UNDEFINED))
  574. {
  575. c_start = scm_to_uint (start);
  576. if (!scm_is_eq (count, SCM_UNDEFINED))
  577. {
  578. c_count = scm_to_uint (count);
  579. if (SCM_UNLIKELY (c_start + c_count > c_len))
  580. scm_out_of_range (FUNC_NAME, count);
  581. }
  582. else
  583. {
  584. if (SCM_UNLIKELY (c_start >= c_len))
  585. scm_out_of_range (FUNC_NAME, start);
  586. else
  587. c_count = c_len - c_start;
  588. }
  589. }
  590. else
  591. c_start = 0, c_count = c_len;
  592. scm_c_write_unlocked (port, c_bv + c_start, c_count);
  593. return SCM_UNSPECIFIED;
  594. }
  595. #undef FUNC_NAME
  596. /* Bytevector output port ("bop" for short). */
  597. /* Implementation of "bops".
  598. Each bop has an internal buffer, of type `scm_t_bop_buffer', attached to
  599. it. The procedure returned along with the output port is actually an
  600. applicable SMOB. The SMOB holds a reference to the port. When applied,
  601. the SMOB swallows the port's internal buffer, turning it into a
  602. bytevector, and resets it.
  603. XXX: Access to a bop's internal buffer is not thread-safe. */
  604. static scm_t_bits bytevector_output_port_type = 0;
  605. SCM_SMOB (bytevector_output_port_procedure,
  606. "r6rs-bytevector-output-port-procedure",
  607. 0);
  608. #define SCM_GC_BOP "r6rs-bytevector-output-port"
  609. #define SCM_BOP_BUFFER_INITIAL_SIZE 4096
  610. /* Representation of a bop's internal buffer. */
  611. typedef struct
  612. {
  613. size_t total_len;
  614. size_t len;
  615. size_t pos;
  616. char *buffer;
  617. } scm_t_bop_buffer;
  618. /* Accessing a bop's buffer. */
  619. #define SCM_BOP_BUFFER(_port) \
  620. ((scm_t_bop_buffer *) SCM_STREAM (_port))
  621. #define SCM_SET_BOP_BUFFER(_port, _buf) \
  622. (SCM_SETSTREAM ((_port), (scm_t_bits) (_buf)))
  623. static inline void
  624. bop_buffer_init (scm_t_bop_buffer *buf)
  625. {
  626. buf->total_len = buf->len = buf->pos = 0;
  627. buf->buffer = NULL;
  628. }
  629. static inline void
  630. bop_buffer_grow (scm_t_bop_buffer *buf, size_t min_size)
  631. {
  632. char *new_buf;
  633. size_t new_size;
  634. for (new_size = buf->total_len
  635. ? buf->total_len : SCM_BOP_BUFFER_INITIAL_SIZE;
  636. new_size < min_size;
  637. new_size *= 2);
  638. if (buf->buffer)
  639. new_buf = scm_gc_realloc ((void *) buf->buffer, buf->total_len,
  640. new_size, SCM_GC_BOP);
  641. else
  642. new_buf = scm_gc_malloc_pointerless (new_size, SCM_GC_BOP);
  643. buf->buffer = new_buf;
  644. buf->total_len = new_size;
  645. }
  646. static inline SCM
  647. make_bop (void)
  648. {
  649. SCM port, bop_proc;
  650. scm_t_port *c_port;
  651. scm_t_bop_buffer *buf;
  652. const unsigned long mode_bits = SCM_OPN | SCM_WRTNG;
  653. buf = (scm_t_bop_buffer *) scm_gc_malloc (sizeof (* buf), SCM_GC_BOP);
  654. bop_buffer_init (buf);
  655. port = scm_c_make_port_with_encoding (bytevector_output_port_type,
  656. mode_bits,
  657. NULL, /* encoding */
  658. SCM_FAILED_CONVERSION_ERROR,
  659. (scm_t_bits)buf);
  660. c_port = SCM_PTAB_ENTRY (port);
  661. c_port->write_buf = c_port->write_pos = c_port->write_end = NULL;
  662. c_port->write_buf_size = 0;
  663. /* Make the bop procedure. */
  664. SCM_NEWSMOB (bop_proc, bytevector_output_port_procedure, buf);
  665. return (scm_values (scm_list_2 (port, bop_proc)));
  666. }
  667. /* Write SIZE octets from DATA to PORT. */
  668. static void
  669. bop_write (SCM port, const void *data, size_t size)
  670. {
  671. scm_t_bop_buffer *buf;
  672. buf = SCM_BOP_BUFFER (port);
  673. if (buf->pos + size > buf->total_len)
  674. bop_buffer_grow (buf, buf->pos + size);
  675. memcpy (buf->buffer + buf->pos, data, size);
  676. buf->pos += size;
  677. buf->len = (buf->len > buf->pos) ? buf->len : buf->pos;
  678. }
  679. static scm_t_off
  680. bop_seek (SCM port, scm_t_off offset, int whence)
  681. #define FUNC_NAME "bop_seek"
  682. {
  683. scm_t_bop_buffer *buf;
  684. buf = SCM_BOP_BUFFER (port);
  685. switch (whence)
  686. {
  687. case SEEK_CUR:
  688. offset += (scm_t_off) buf->pos;
  689. /* Fall through. */
  690. case SEEK_SET:
  691. if (offset < 0 || (unsigned) offset > buf->len)
  692. scm_out_of_range (FUNC_NAME, scm_from_int (offset));
  693. else
  694. buf->pos = offset;
  695. break;
  696. case SEEK_END:
  697. if (offset < 0 || (unsigned) offset >= buf->len)
  698. scm_out_of_range (FUNC_NAME, scm_from_int (offset));
  699. else
  700. buf->pos = buf->len - (offset + 1);
  701. break;
  702. default:
  703. scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
  704. "invalid `seek' parameter");
  705. }
  706. return buf->pos;
  707. }
  708. #undef FUNC_NAME
  709. /* Fetch data from a bop. */
  710. SCM_SMOB_APPLY (bytevector_output_port_procedure,
  711. bop_proc_apply, 0, 0, 0, (SCM bop_proc))
  712. {
  713. SCM bv;
  714. scm_t_bop_buffer *buf, result_buf;
  715. buf = (scm_t_bop_buffer *) SCM_SMOB_DATA (bop_proc);
  716. result_buf = *buf;
  717. bop_buffer_init (buf);
  718. if (result_buf.len == 0)
  719. bv = scm_c_take_gc_bytevector (NULL, 0, SCM_BOOL_F);
  720. else
  721. {
  722. if (result_buf.total_len > result_buf.len)
  723. /* Shrink the buffer. */
  724. result_buf.buffer = scm_gc_realloc ((void *) result_buf.buffer,
  725. result_buf.total_len,
  726. result_buf.len,
  727. SCM_GC_BOP);
  728. bv = scm_c_take_gc_bytevector ((signed char *) result_buf.buffer,
  729. result_buf.len, SCM_BOOL_F);
  730. }
  731. return bv;
  732. }
  733. SCM_DEFINE (scm_open_bytevector_output_port,
  734. "open-bytevector-output-port", 0, 1, 0,
  735. (SCM transcoder),
  736. "Return two values: an output port and a procedure. The latter "
  737. "should be called with zero arguments to obtain a bytevector "
  738. "containing the data accumulated by the port.")
  739. #define FUNC_NAME s_scm_open_bytevector_output_port
  740. {
  741. if (!SCM_UNBNDP (transcoder) && !scm_is_false (transcoder))
  742. transcoders_not_implemented ();
  743. return (make_bop ());
  744. }
  745. #undef FUNC_NAME
  746. static inline void
  747. initialize_bytevector_output_ports (void)
  748. {
  749. bytevector_output_port_type =
  750. scm_make_port_type ("r6rs-bytevector-output-port",
  751. NULL, bop_write);
  752. scm_set_port_seek (bytevector_output_port_type, bop_seek);
  753. }
  754. /* Custom binary output port ("cbop" for short). */
  755. static scm_t_bits custom_binary_output_port_type;
  756. /* Return the various procedures of PORT. */
  757. #define SCM_CBOP_WRITE_PROC(_port) \
  758. SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
  759. static inline SCM
  760. make_cbop (SCM write_proc, SCM get_position_proc,
  761. SCM set_position_proc, SCM close_proc)
  762. {
  763. SCM port, method_vector;
  764. scm_t_port *c_port;
  765. const unsigned long mode_bits = SCM_OPN | SCM_WRTNG;
  766. /* Store the various methods and bytevector in a vector. */
  767. method_vector = scm_c_make_vector (4, SCM_BOOL_F);
  768. SCM_SIMPLE_VECTOR_SET (method_vector, 0, write_proc);
  769. SCM_SIMPLE_VECTOR_SET (method_vector, 1, get_position_proc);
  770. SCM_SIMPLE_VECTOR_SET (method_vector, 2, set_position_proc);
  771. SCM_SIMPLE_VECTOR_SET (method_vector, 3, close_proc);
  772. port = scm_c_make_port_with_encoding (custom_binary_output_port_type,
  773. mode_bits,
  774. NULL, /* encoding */
  775. SCM_FAILED_CONVERSION_ERROR,
  776. SCM_UNPACK (method_vector));
  777. c_port = SCM_PTAB_ENTRY (port);
  778. /* Have the port directly access the buffer (bytevector). */
  779. c_port->write_buf = c_port->write_pos = c_port->write_end = NULL;
  780. c_port->write_buf_size = c_port->read_buf_size = 0;
  781. return port;
  782. }
  783. /* Write SIZE octets from DATA to PORT. */
  784. static void
  785. cbop_write (SCM port, const void *data, size_t size)
  786. #define FUNC_NAME "cbop_write"
  787. {
  788. long int c_result;
  789. size_t c_written;
  790. SCM bv, write_proc, result;
  791. /* XXX: Allocating a new bytevector at each `write' call is inefficient,
  792. but necessary since (1) we don't control the lifetime of the buffer
  793. pointed to by DATA, and (2) the `write!' procedure could capture the
  794. bytevector it is passed. */
  795. bv = scm_c_make_bytevector (size);
  796. memcpy (SCM_BYTEVECTOR_CONTENTS (bv), data, size);
  797. write_proc = SCM_CBOP_WRITE_PROC (port);
  798. /* Since the `write' procedure of Guile's ports has type `void', it must
  799. try hard to write exactly SIZE bytes, regardless of how many bytes the
  800. sink can handle. */
  801. for (c_written = 0;
  802. c_written < size;
  803. c_written += c_result)
  804. {
  805. result = scm_call_3 (write_proc, bv,
  806. scm_from_size_t (c_written),
  807. scm_from_size_t (size - c_written));
  808. c_result = scm_to_long (result);
  809. if (SCM_UNLIKELY (c_result < 0
  810. || (size_t) c_result > (size - c_written)))
  811. scm_wrong_type_arg_msg (FUNC_NAME, 0, result,
  812. "R6RS custom binary output port `write!' "
  813. "returned a incorrect integer");
  814. }
  815. }
  816. #undef FUNC_NAME
  817. SCM_DEFINE (scm_make_custom_binary_output_port,
  818. "make-custom-binary-output-port", 5, 0, 0,
  819. (SCM id, SCM write_proc, SCM get_position_proc,
  820. SCM set_position_proc, SCM close_proc),
  821. "Return a new custom binary output port whose output is drained "
  822. "by invoking @var{write_proc} and passing it a bytevector, an "
  823. "index where octets should be written, and an octet count.")
  824. #define FUNC_NAME s_scm_make_custom_binary_output_port
  825. {
  826. SCM_VALIDATE_STRING (1, id);
  827. SCM_VALIDATE_PROC (2, write_proc);
  828. if (!scm_is_false (get_position_proc))
  829. SCM_VALIDATE_PROC (3, get_position_proc);
  830. if (!scm_is_false (set_position_proc))
  831. SCM_VALIDATE_PROC (4, set_position_proc);
  832. if (!scm_is_false (close_proc))
  833. SCM_VALIDATE_PROC (5, close_proc);
  834. return (make_cbop (write_proc, get_position_proc, set_position_proc,
  835. close_proc));
  836. }
  837. #undef FUNC_NAME
  838. /* Instantiate the custom binary output port type. */
  839. static inline void
  840. initialize_custom_binary_output_ports (void)
  841. {
  842. custom_binary_output_port_type =
  843. scm_make_port_type ("r6rs-custom-binary-output-port",
  844. NULL, cbop_write);
  845. scm_set_port_seek (custom_binary_output_port_type, cbp_seek);
  846. scm_set_port_close (custom_binary_output_port_type, cbp_close);
  847. }
  848. /* Transcoded ports ("tp" for short). */
  849. static scm_t_bits transcoded_port_type = 0;
  850. #define TP_INPUT_BUFFER_SIZE 4096
  851. #define SCM_TP_BINARY_PORT(_port) SCM_PACK (SCM_STREAM (_port))
  852. static inline SCM
  853. make_tp (SCM binary_port, unsigned long mode)
  854. {
  855. SCM port;
  856. scm_t_port *c_port;
  857. const unsigned long mode_bits = SCM_OPN | mode;
  858. port = scm_c_make_port (transcoded_port_type, mode_bits,
  859. SCM_UNPACK (binary_port));
  860. if (SCM_INPUT_PORT_P (port))
  861. {
  862. c_port = SCM_PTAB_ENTRY (port);
  863. c_port->read_buf = scm_gc_malloc_pointerless (TP_INPUT_BUFFER_SIZE,
  864. "port buffer");
  865. c_port->read_pos = c_port->read_end = c_port->read_buf;
  866. c_port->read_buf_size = TP_INPUT_BUFFER_SIZE;
  867. SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
  868. }
  869. return port;
  870. }
  871. static void
  872. tp_write (SCM port, const void *data, size_t size)
  873. {
  874. scm_c_write_unlocked (SCM_TP_BINARY_PORT (port), data, size);
  875. }
  876. static int
  877. tp_fill_input (SCM port)
  878. {
  879. size_t count;
  880. scm_t_port *c_port = SCM_PTAB_ENTRY (port);
  881. SCM bport = SCM_TP_BINARY_PORT (port);
  882. scm_t_port *c_bport = SCM_PTAB_ENTRY (bport);
  883. /* We can't use `scm_c_read' here, since it blocks until the whole
  884. block has been read or EOF. */
  885. if (c_bport->rw_active == SCM_PORT_WRITE)
  886. scm_force_output (bport);
  887. if (c_bport->read_pos >= c_bport->read_end)
  888. scm_fill_input_unlocked (bport);
  889. count = c_bport->read_end - c_bport->read_pos;
  890. if (count > c_port->read_buf_size)
  891. count = c_port->read_buf_size;
  892. memcpy (c_port->read_buf, c_bport->read_pos, count);
  893. c_bport->read_pos += count;
  894. if (c_bport->rw_random)
  895. c_bport->rw_active = SCM_PORT_READ;
  896. if (count == 0)
  897. return EOF;
  898. else
  899. {
  900. c_port->read_pos = c_port->read_buf;
  901. c_port->read_end = c_port->read_buf + count;
  902. return *c_port->read_buf;
  903. }
  904. }
  905. static void
  906. tp_flush (SCM port)
  907. {
  908. SCM binary_port = SCM_TP_BINARY_PORT (port);
  909. scm_t_port *c_port = SCM_PTAB_ENTRY (port);
  910. size_t count = c_port->write_pos - c_port->write_buf;
  911. /* As the runtime will try to flush all ports upon exit, we test for
  912. the underlying port still being open here. Otherwise, when you
  913. would explicitly close the underlying port and the transcoded port
  914. still had data outstanding, you'd get an exception on Guile exit.
  915. We just throw away the data when the underlying port is closed. */
  916. if (SCM_OPOUTPORTP (binary_port))
  917. scm_c_write_unlocked (binary_port, c_port->write_buf, count);
  918. c_port->write_pos = c_port->write_buf;
  919. c_port->rw_active = SCM_PORT_NEITHER;
  920. if (SCM_OPOUTPORTP (binary_port))
  921. scm_force_output (binary_port);
  922. }
  923. static int
  924. tp_close (SCM port)
  925. {
  926. if (SCM_OUTPUT_PORT_P (port))
  927. tp_flush (port);
  928. return scm_is_true (scm_close_port (SCM_TP_BINARY_PORT (port))) ? 0 : -1;
  929. }
  930. static inline void
  931. initialize_transcoded_ports (void)
  932. {
  933. transcoded_port_type =
  934. scm_make_port_type ("r6rs-transcoded-port", tp_fill_input, tp_write);
  935. scm_set_port_flush (transcoded_port_type, tp_flush);
  936. scm_set_port_close (transcoded_port_type, tp_close);
  937. }
  938. SCM_DEFINE (scm_i_make_transcoded_port,
  939. "%make-transcoded-port", 1, 0, 0,
  940. (SCM port),
  941. "Return a new port which reads and writes to @var{port}")
  942. #define FUNC_NAME s_scm_i_make_transcoded_port
  943. {
  944. SCM result;
  945. unsigned long mode = 0;
  946. SCM_VALIDATE_PORT (SCM_ARG1, port);
  947. if (scm_is_true (scm_output_port_p (port)))
  948. mode |= SCM_WRTNG;
  949. else if (scm_is_true (scm_input_port_p (port)))
  950. mode |= SCM_RDNG;
  951. result = make_tp (port, mode);
  952. /* FIXME: We should actually close `port' "in a special way" here,
  953. according to R6RS. As there is no way to do that in Guile without
  954. rendering the underlying port unusable for our purposes as well, we
  955. just leave it open. */
  956. return result;
  957. }
  958. #undef FUNC_NAME
  959. /* Textual I/O */
  960. SCM_DEFINE (scm_get_string_n_x,
  961. "get-string-n!", 4, 0, 0,
  962. (SCM port, SCM str, SCM start, SCM count),
  963. "Read up to @var{count} characters from @var{port} into "
  964. "@var{str}, starting at @var{start}. If no characters "
  965. "can be read before the end of file is encountered, the end "
  966. "of file object is returned. Otherwise, the number of "
  967. "characters read is returned.")
  968. #define FUNC_NAME s_scm_get_string_n_x
  969. {
  970. size_t c_start, c_count, c_len, c_end, j;
  971. scm_t_wchar c;
  972. SCM_VALIDATE_OPINPORT (1, port);
  973. SCM_VALIDATE_STRING (2, str);
  974. c_len = scm_c_string_length (str);
  975. c_start = scm_to_size_t (start);
  976. c_count = scm_to_size_t (count);
  977. c_end = c_start + c_count;
  978. if (SCM_UNLIKELY (c_end > c_len))
  979. scm_out_of_range (FUNC_NAME, count);
  980. for (j = c_start; j < c_end; j++)
  981. {
  982. c = scm_getc_unlocked (port);
  983. if (c == EOF)
  984. {
  985. size_t chars_read = j - c_start;
  986. return chars_read == 0 ? SCM_EOF_VAL : scm_from_size_t (chars_read);
  987. }
  988. scm_c_string_set_x (str, j, SCM_MAKE_CHAR (c));
  989. }
  990. return count;
  991. }
  992. #undef FUNC_NAME
  993. /* Initialization. */
  994. void
  995. scm_register_r6rs_ports (void)
  996. {
  997. scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
  998. "scm_init_r6rs_ports",
  999. (scm_t_extension_init_func) scm_init_r6rs_ports,
  1000. NULL);
  1001. }
  1002. void
  1003. scm_init_r6rs_ports (void)
  1004. {
  1005. #include "libguile/r6rs-ports.x"
  1006. initialize_bytevector_input_ports ();
  1007. initialize_custom_binary_input_ports ();
  1008. initialize_bytevector_output_ports ();
  1009. initialize_custom_binary_output_ports ();
  1010. initialize_transcoded_ports ();
  1011. }