r6rs-ports.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. /* Copyright 2009-2011,2013-2015,2018-2019,2023
  2. Free Software Foundation, Inc.
  3. This file is part of Guile.
  4. Guile is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Lesser General Public License as published
  6. by the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Guile is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with Guile. If not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #ifdef HAVE_CONFIG_H
  16. # include <config.h>
  17. #endif
  18. #include <assert.h>
  19. #include <intprops.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include "boolean.h"
  24. #include "bytevectors.h"
  25. #include "chars.h"
  26. #include "eval.h"
  27. #include "extensions.h"
  28. #include "gsubr.h"
  29. #include "modules.h"
  30. #include "numbers.h"
  31. #include "ports-internal.h"
  32. #include "procs.h"
  33. #include "smob.h"
  34. #include "strings.h"
  35. #include "symbols.h"
  36. #include "syscalls.h"
  37. #include "threads.h"
  38. #include "values.h"
  39. #include "variable.h"
  40. #include "vectors.h"
  41. #include "version.h"
  42. #include "r6rs-ports.h"
  43. SCM_SYMBOL (sym_ISO_8859_1, "ISO-8859-1");
  44. SCM_SYMBOL (sym_error, "error");
  45. /* Unimplemented features. */
  46. /* Transoders are currently not implemented since Guile 1.8 is not
  47. Unicode-capable. Thus, most of the code here assumes the use of the
  48. binary transcoder. */
  49. static inline void
  50. transcoders_not_implemented (void)
  51. {
  52. fprintf (stderr, "%s: warning: transcoders not implemented\n",
  53. PACKAGE_NAME);
  54. }
  55. /* End-of-file object. */
  56. SCM_DEFINE (scm_eof_object, "eof-object", 0, 0, 0,
  57. (void),
  58. "Return the end-of-file object.")
  59. #define FUNC_NAME s_scm_eof_object
  60. {
  61. return SCM_EOF_VAL;
  62. }
  63. #undef FUNC_NAME
  64. /* Input ports. */
  65. #define MAX(A, B) ((A) >= (B) ? (A) : (B))
  66. #define MIN(A, B) ((A) < (B) ? (A) : (B))
  67. /* Bytevector input ports. */
  68. static scm_t_port_type *bytevector_input_port_type = 0;
  69. struct bytevector_input_port {
  70. SCM bytevector;
  71. size_t pos;
  72. };
  73. static inline SCM
  74. make_bytevector_input_port (SCM bv)
  75. {
  76. const unsigned long mode_bits = SCM_RDNG;
  77. struct bytevector_input_port *stream;
  78. stream = scm_gc_typed_calloc (struct bytevector_input_port);
  79. stream->bytevector = bv;
  80. stream->pos = 0;
  81. return scm_c_make_port_with_encoding (bytevector_input_port_type, mode_bits,
  82. sym_ISO_8859_1, sym_error,
  83. (scm_t_bits) stream);
  84. }
  85. static size_t
  86. bytevector_input_port_read (SCM port, SCM dst, size_t start, size_t count)
  87. {
  88. size_t remaining;
  89. struct bytevector_input_port *stream = (void *) SCM_STREAM (port);
  90. if (stream->pos >= SCM_BYTEVECTOR_LENGTH (stream->bytevector))
  91. return 0;
  92. remaining = SCM_BYTEVECTOR_LENGTH (stream->bytevector) - stream->pos;
  93. if (remaining < count)
  94. count = remaining;
  95. memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
  96. SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
  97. count);
  98. stream->pos += count;
  99. return count;
  100. }
  101. static scm_t_off
  102. bytevector_input_port_seek (SCM port, scm_t_off offset, int whence)
  103. #define FUNC_NAME "bytevector_input_port_seek"
  104. {
  105. struct bytevector_input_port *stream = (void *) SCM_STREAM (port);
  106. size_t base;
  107. scm_t_off target;
  108. if (whence == SEEK_CUR)
  109. base = stream->pos;
  110. else if (whence == SEEK_SET)
  111. base = 0;
  112. else if (whence == SEEK_END)
  113. base = SCM_BYTEVECTOR_LENGTH (stream->bytevector);
  114. else
  115. scm_wrong_type_arg_msg (FUNC_NAME, 0, port, "invalid `seek' parameter");
  116. if (base > SCM_T_OFF_MAX
  117. || INT_ADD_OVERFLOW ((scm_t_off) base, offset))
  118. scm_num_overflow (FUNC_NAME);
  119. target = (scm_t_off) base + offset;
  120. if (target >= 0 && target <= SCM_BYTEVECTOR_LENGTH (stream->bytevector))
  121. stream->pos = target;
  122. else
  123. scm_out_of_range (FUNC_NAME, scm_from_off_t (offset));
  124. return target;
  125. }
  126. #undef FUNC_NAME
  127. /* Instantiate the bytevector input port type. */
  128. static inline void
  129. initialize_bytevector_input_ports (void)
  130. {
  131. bytevector_input_port_type =
  132. scm_make_port_type ("r6rs-bytevector-input-port",
  133. bytevector_input_port_read,
  134. NULL);
  135. scm_set_port_seek (bytevector_input_port_type, bytevector_input_port_seek);
  136. }
  137. SCM_DEFINE (scm_open_bytevector_input_port,
  138. "open-bytevector-input-port", 1, 1, 0,
  139. (SCM bv, SCM transcoder),
  140. "Return an input port whose contents are drawn from "
  141. "bytevector @var{bv}.")
  142. #define FUNC_NAME s_scm_open_bytevector_input_port
  143. {
  144. SCM_VALIDATE_BYTEVECTOR (1, bv);
  145. if (!SCM_UNBNDP (transcoder) && !scm_is_false (transcoder))
  146. transcoders_not_implemented ();
  147. return make_bytevector_input_port (bv);
  148. }
  149. #undef FUNC_NAME
  150. /* Binary input. */
  151. /* We currently don't support specific binary input ports. */
  152. #define SCM_VALIDATE_BINARY_INPUT_PORT SCM_VALIDATE_OPINPORT
  153. SCM_DEFINE (scm_get_u8, "get-u8", 1, 0, 0,
  154. (SCM port),
  155. "Read an octet from @var{port}, a binary input port, "
  156. "blocking as necessary.")
  157. #define FUNC_NAME s_scm_get_u8
  158. {
  159. SCM result;
  160. int c_result;
  161. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  162. c_result = scm_get_byte_or_eof (port);
  163. if (c_result == EOF)
  164. result = SCM_EOF_VAL;
  165. else
  166. result = SCM_I_MAKINUM ((unsigned char) c_result);
  167. return result;
  168. }
  169. #undef FUNC_NAME
  170. SCM_DEFINE (scm_lookahead_u8, "lookahead-u8", 1, 0, 0,
  171. (SCM port),
  172. "Like @code{get-u8} but does not update @var{port} to "
  173. "point past the octet.")
  174. #define FUNC_NAME s_scm_lookahead_u8
  175. {
  176. int u8;
  177. SCM result;
  178. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  179. u8 = scm_peek_byte_or_eof (port);
  180. if (u8 == EOF)
  181. result = SCM_EOF_VAL;
  182. else
  183. result = SCM_I_MAKINUM ((uint8_t) u8);
  184. return result;
  185. }
  186. #undef FUNC_NAME
  187. SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 0, 0,
  188. (SCM port, SCM count),
  189. "Read @var{count} octets from @var{port}, blocking as "
  190. "necessary and return a bytevector containing the octets "
  191. "read. If fewer bytes are available, a bytevector smaller "
  192. "than @var{count} is returned.")
  193. #define FUNC_NAME s_scm_get_bytevector_n
  194. {
  195. SCM result;
  196. size_t c_count;
  197. size_t c_read;
  198. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  199. c_count = scm_to_size_t (count);
  200. result = scm_c_make_bytevector (c_count);
  201. if (SCM_LIKELY (c_count > 0))
  202. /* XXX: `scm_c_read ()' does not update the port position. */
  203. c_read = scm_c_read_bytes (port, result, 0, c_count);
  204. else
  205. /* Don't invoke `scm_c_read ()' since it may block. */
  206. c_read = 0;
  207. if (c_read < c_count)
  208. {
  209. if (c_read == 0)
  210. result = SCM_EOF_VAL;
  211. else
  212. result = scm_c_shrink_bytevector (result, c_read);
  213. }
  214. return result;
  215. }
  216. #undef FUNC_NAME
  217. SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0,
  218. (SCM port, SCM bv, SCM start, SCM count),
  219. "Read @var{count} bytes from @var{port} and store them "
  220. "in @var{bv} starting at index @var{start}. Return either "
  221. "the number of bytes actually read or the end-of-file "
  222. "object.")
  223. #define FUNC_NAME s_scm_get_bytevector_n_x
  224. {
  225. SCM result;
  226. size_t c_start, c_count, c_len;
  227. size_t c_read;
  228. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  229. SCM_VALIDATE_BYTEVECTOR (2, bv);
  230. c_start = scm_to_size_t (start);
  231. c_count = scm_to_size_t (count);
  232. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  233. if (SCM_UNLIKELY (c_len < c_start
  234. || (c_len - c_start < c_count)))
  235. scm_out_of_range (FUNC_NAME, count);
  236. if (SCM_LIKELY (c_count > 0))
  237. c_read = scm_c_read_bytes (port, bv, c_start, c_count);
  238. else
  239. /* Don't invoke `scm_c_read ()' since it may block. */
  240. c_read = 0;
  241. if (c_read == 0 && c_count > 0)
  242. result = SCM_EOF_VAL;
  243. else
  244. result = scm_from_size_t (c_read);
  245. return result;
  246. }
  247. #undef FUNC_NAME
  248. SCM_DEFINE (scm_get_bytevector_some, "get-bytevector-some", 1, 0, 0,
  249. (SCM port),
  250. "Read from @var{port}, blocking as necessary, until bytes "
  251. "are available or an end-of-file is reached. Return either "
  252. "the end-of-file object or a new bytevector containing some "
  253. "of the available bytes (at least one), and update the port "
  254. "position to point just past these bytes.")
  255. #define FUNC_NAME s_scm_get_bytevector_some
  256. {
  257. SCM buf;
  258. size_t cur, avail;
  259. SCM bv;
  260. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  261. buf = scm_fill_input (port, 0, &cur, &avail);
  262. if (avail == 0)
  263. {
  264. scm_port_buffer_set_has_eof_p (buf, SCM_BOOL_F);
  265. return SCM_EOF_VAL;
  266. }
  267. bv = scm_c_make_bytevector (avail);
  268. scm_port_buffer_take (buf, (uint8_t *) SCM_BYTEVECTOR_CONTENTS (bv),
  269. avail, cur, avail);
  270. return bv;
  271. }
  272. #undef FUNC_NAME
  273. SCM_DEFINE (scm_get_bytevector_some_x, "get-bytevector-some!", 4, 0, 0,
  274. (SCM port, SCM bv, SCM start, SCM count),
  275. "Read up to @var{count} bytes from @var{port}, blocking "
  276. "as necessary until at least one byte is available or an "
  277. "end-of-file is reached. Store them in @var{bv} starting "
  278. "at index @var{start}. Return the number of bytes actually "
  279. "read, or an end-of-file object.")
  280. #define FUNC_NAME s_scm_get_bytevector_some_x
  281. {
  282. SCM buf;
  283. size_t c_start, c_count, c_len;
  284. size_t cur, avail, transfer_size;
  285. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  286. SCM_VALIDATE_BYTEVECTOR (2, bv);
  287. c_start = scm_to_size_t (start);
  288. c_count = scm_to_size_t (count);
  289. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  290. if (SCM_UNLIKELY (c_len < c_start
  291. || c_len - c_start < c_count))
  292. scm_out_of_range (FUNC_NAME, count);
  293. if (c_count == 0)
  294. return SCM_INUM0;
  295. buf = scm_fill_input (port, 0, &cur, &avail);
  296. if (avail == 0)
  297. {
  298. scm_port_buffer_set_has_eof_p (buf, SCM_BOOL_F);
  299. return SCM_EOF_VAL;
  300. }
  301. transfer_size = MIN (avail, c_count);
  302. scm_port_buffer_take (buf,
  303. (uint8_t *) SCM_BYTEVECTOR_CONTENTS (bv) + c_start,
  304. transfer_size, cur, avail);
  305. return scm_from_size_t (transfer_size);
  306. }
  307. #undef FUNC_NAME
  308. SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0,
  309. (SCM port),
  310. "Read from @var{port}, blocking as necessary, until "
  311. "the end-of-file is reached. Return either "
  312. "a new bytevector containing the data read or the "
  313. "end-of-file object (if no data were available).")
  314. #define FUNC_NAME s_scm_get_bytevector_all
  315. {
  316. SCM result;
  317. size_t c_len, c_count;
  318. size_t c_read, c_total;
  319. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  320. c_len = c_count = 4096;
  321. result = scm_c_make_bytevector (c_count);
  322. c_total = c_read = 0;
  323. do
  324. {
  325. if (c_read > c_len - c_total)
  326. {
  327. /* Grow the bytevector. */
  328. SCM prev = result;
  329. if (INT_ADD_OVERFLOW (c_len, c_len))
  330. scm_num_overflow (FUNC_NAME);
  331. result = scm_c_make_bytevector (c_len * 2);
  332. memcpy (SCM_BYTEVECTOR_CONTENTS (result),
  333. SCM_BYTEVECTOR_CONTENTS (prev),
  334. c_total);
  335. c_count = c_len;
  336. c_len *= 2;
  337. }
  338. /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
  339. reached. */
  340. c_read = scm_c_read_bytes (port, result, c_total, c_count);
  341. c_total += c_read, c_count -= c_read;
  342. }
  343. while (c_count == 0);
  344. if (c_total == 0)
  345. return SCM_EOF_VAL;
  346. if (c_len > c_total)
  347. return scm_c_shrink_bytevector (result, c_total);
  348. return result;
  349. }
  350. #undef FUNC_NAME
  351. /* Binary output. */
  352. /* We currently don't support specific binary input ports. */
  353. #define SCM_VALIDATE_BINARY_OUTPUT_PORT SCM_VALIDATE_OPOUTPORT
  354. SCM_DEFINE (scm_put_u8, "put-u8", 2, 0, 0,
  355. (SCM port, SCM octet),
  356. "Write @var{octet} to binary port @var{port}.")
  357. #define FUNC_NAME s_scm_put_u8
  358. {
  359. uint8_t c_octet;
  360. SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
  361. c_octet = scm_to_uint8 (octet);
  362. scm_c_write (port, &c_octet, 1);
  363. return SCM_UNSPECIFIED;
  364. }
  365. #undef FUNC_NAME
  366. SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
  367. (SCM port, SCM bv, SCM start, SCM count),
  368. "Write the contents of @var{bv} to @var{port}, optionally "
  369. "starting at index @var{start} and limiting to @var{count} "
  370. "octets.")
  371. #define FUNC_NAME s_scm_put_bytevector
  372. {
  373. size_t c_start, c_count, c_len;
  374. SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
  375. SCM_VALIDATE_BYTEVECTOR (2, bv);
  376. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  377. if (!scm_is_eq (start, SCM_UNDEFINED))
  378. {
  379. c_start = scm_to_size_t (start);
  380. if (SCM_UNLIKELY (c_start > c_len))
  381. scm_out_of_range (FUNC_NAME, start);
  382. if (!scm_is_eq (count, SCM_UNDEFINED))
  383. {
  384. c_count = scm_to_size_t (count);
  385. if (SCM_UNLIKELY (c_count > c_len - c_start))
  386. scm_out_of_range (FUNC_NAME, count);
  387. }
  388. else
  389. c_count = c_len - c_start;
  390. }
  391. else
  392. c_start = 0, c_count = c_len;
  393. scm_c_write_bytes (port, bv, c_start, c_count);
  394. return SCM_UNSPECIFIED;
  395. }
  396. #undef FUNC_NAME
  397. SCM_DEFINE (scm_unget_bytevector, "unget-bytevector", 2, 2, 0,
  398. (SCM port, SCM bv, SCM start, SCM count),
  399. "Unget the contents of @var{bv} to @var{port}, optionally "
  400. "starting at index @var{start} and limiting to @var{count} "
  401. "octets.")
  402. #define FUNC_NAME s_scm_unget_bytevector
  403. {
  404. unsigned char *c_bv;
  405. size_t c_start, c_count, c_len;
  406. SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
  407. SCM_VALIDATE_BYTEVECTOR (2, bv);
  408. c_len = SCM_BYTEVECTOR_LENGTH (bv);
  409. c_bv = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
  410. if (!scm_is_eq (start, SCM_UNDEFINED))
  411. {
  412. c_start = scm_to_size_t (start);
  413. if (SCM_UNLIKELY (c_start > c_len))
  414. scm_out_of_range (FUNC_NAME, start);
  415. if (!scm_is_eq (count, SCM_UNDEFINED))
  416. {
  417. c_count = scm_to_size_t (count);
  418. if (SCM_UNLIKELY (c_count > c_len - c_start))
  419. scm_out_of_range (FUNC_NAME, count);
  420. }
  421. else
  422. c_count = c_len - c_start;
  423. }
  424. else
  425. c_start = 0, c_count = c_len;
  426. scm_unget_bytes (c_bv + c_start, c_count, port);
  427. return SCM_UNSPECIFIED;
  428. }
  429. #undef FUNC_NAME
  430. /* Bytevector output port. */
  431. /* Implementation of "bytevector output ports".
  432. Each bytevector output port has an internal buffer, of type
  433. `scm_t_bytevector_output_port_buffer', attached to it. The procedure
  434. returned along with the output port is actually an applicable SMOB.
  435. The SMOB holds a reference to the port. When applied, the SMOB
  436. swallows the port's internal buffer, turning it into a bytevector,
  437. and resets it.
  438. XXX: Access to a bytevector output port's internal buffer is not
  439. thread-safe. */
  440. static scm_t_port_type *bytevector_output_port_type = 0;
  441. SCM_SMOB (bytevector_output_port_procedure,
  442. "r6rs-bytevector-output-port-procedure",
  443. 0);
  444. #define SCM_GC_BYTEVECTOR_OUTPUT_PORT "r6rs-bytevector-output-port"
  445. #define SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER_INITIAL_SIZE 4096
  446. /* Representation of a bytevector output port's internal buffer. */
  447. typedef struct
  448. {
  449. size_t total_len;
  450. size_t len;
  451. size_t pos;
  452. char *buffer;
  453. /* The get-bytevector procedure will flush this port, if it's
  454. open. */
  455. SCM port;
  456. } scm_t_bytevector_output_port_buffer;
  457. /* Accessing a bytevector output port's buffer. */
  458. #define SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER(_port) \
  459. ((scm_t_bytevector_output_port_buffer *) SCM_STREAM (_port))
  460. #define SCM_SET_BYTEVECTOR_OUTPUT_PORT_BUFFER(_port, _buf) \
  461. (SCM_SETSTREAM ((_port), (scm_t_bits) (_buf)))
  462. static inline void
  463. bytevector_output_port_buffer_init (scm_t_bytevector_output_port_buffer *buf)
  464. {
  465. buf->total_len = buf->len = buf->pos = 0;
  466. buf->buffer = NULL;
  467. /* Don't clear the port. */
  468. }
  469. static inline void
  470. bytevector_output_port_buffer_grow (scm_t_bytevector_output_port_buffer *buf,
  471. size_t min_size)
  472. {
  473. char *new_buf;
  474. size_t new_size;
  475. if (buf->buffer)
  476. {
  477. if (INT_ADD_OVERFLOW (buf->total_len, buf->total_len))
  478. scm_num_overflow ("bytevector_output_port_buffer_grow");
  479. new_size = MAX (min_size, buf->total_len * 2);
  480. new_buf = scm_gc_realloc ((void *) buf->buffer, buf->total_len,
  481. new_size, SCM_GC_BYTEVECTOR_OUTPUT_PORT);
  482. }
  483. else
  484. {
  485. new_size = MAX (min_size, SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER_INITIAL_SIZE);
  486. new_buf = scm_gc_malloc_pointerless (new_size,
  487. SCM_GC_BYTEVECTOR_OUTPUT_PORT);
  488. }
  489. buf->buffer = new_buf;
  490. buf->total_len = new_size;
  491. }
  492. static inline SCM
  493. make_bytevector_output_port (void)
  494. {
  495. SCM port, proc;
  496. scm_t_bytevector_output_port_buffer *buf;
  497. const unsigned long mode_bits = SCM_WRTNG;
  498. buf = (scm_t_bytevector_output_port_buffer *)
  499. scm_gc_malloc (sizeof (* buf), SCM_GC_BYTEVECTOR_OUTPUT_PORT);
  500. bytevector_output_port_buffer_init (buf);
  501. port = scm_c_make_port_with_encoding (bytevector_output_port_type,
  502. mode_bits,
  503. sym_ISO_8859_1, sym_error,
  504. (scm_t_bits)buf);
  505. buf->port = port;
  506. SCM_NEWSMOB (proc, bytevector_output_port_procedure, buf);
  507. return scm_values_2 (port, proc);
  508. }
  509. /* Write octets from WRITE_BUF to the backing store. */
  510. static size_t
  511. bytevector_output_port_write (SCM port, SCM src, size_t start, size_t count)
  512. #define FUNC_NAME "bytevector_output_port_write"
  513. {
  514. scm_t_bytevector_output_port_buffer *buf;
  515. buf = SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER (port);
  516. if (count > buf->total_len - buf->pos)
  517. {
  518. if (INT_ADD_OVERFLOW (buf->pos, count))
  519. scm_num_overflow (FUNC_NAME);
  520. bytevector_output_port_buffer_grow (buf, buf->pos + count);
  521. }
  522. memcpy (buf->buffer + buf->pos, SCM_BYTEVECTOR_CONTENTS (src) + start, count);
  523. buf->pos += count;
  524. buf->len = (buf->len > buf->pos) ? buf->len : buf->pos;
  525. return count;
  526. }
  527. #undef FUNC_NAME
  528. static scm_t_off
  529. bytevector_output_port_seek (SCM port, scm_t_off offset, int whence)
  530. #define FUNC_NAME "bytevector_output_port_seek"
  531. {
  532. scm_t_bytevector_output_port_buffer *buf;
  533. size_t base;
  534. scm_t_off target;
  535. buf = SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER (port);
  536. if (whence == SEEK_CUR)
  537. base = buf->pos;
  538. else if (whence == SEEK_SET)
  539. base = 0;
  540. else if (whence == SEEK_END)
  541. base = buf->len;
  542. else
  543. scm_wrong_type_arg_msg (FUNC_NAME, 0, port, "invalid `seek' parameter");
  544. if (base > SCM_T_OFF_MAX
  545. || INT_ADD_OVERFLOW ((scm_t_off) base, offset))
  546. scm_num_overflow (FUNC_NAME);
  547. target = (scm_t_off) base + offset;
  548. if (target >= 0 && target <= buf->len)
  549. buf->pos = target;
  550. else
  551. scm_out_of_range (FUNC_NAME, scm_from_off_t (offset));
  552. return target;
  553. }
  554. #undef FUNC_NAME
  555. /* Fetch data from a bytevector output port. */
  556. SCM_SMOB_APPLY (bytevector_output_port_procedure,
  557. bytevector_output_port_proc_apply, 0, 0, 0, (SCM proc))
  558. {
  559. SCM bv;
  560. scm_t_bytevector_output_port_buffer *buf, result_buf;
  561. buf = (scm_t_bytevector_output_port_buffer *) SCM_SMOB_DATA (proc);
  562. if (SCM_OPPORTP (buf->port))
  563. scm_flush (buf->port);
  564. result_buf = *buf;
  565. bytevector_output_port_buffer_init (buf);
  566. if (result_buf.len == 0)
  567. bv = scm_c_take_gc_bytevector (NULL, 0, SCM_BOOL_F);
  568. else
  569. {
  570. if (result_buf.total_len > result_buf.len)
  571. /* Shrink the buffer. */
  572. result_buf.buffer = scm_gc_realloc ((void *) result_buf.buffer,
  573. result_buf.total_len,
  574. result_buf.len,
  575. SCM_GC_BYTEVECTOR_OUTPUT_PORT);
  576. bv = scm_c_take_gc_bytevector ((signed char *) result_buf.buffer,
  577. result_buf.len, SCM_BOOL_F);
  578. }
  579. return bv;
  580. }
  581. SCM_DEFINE (scm_open_bytevector_output_port,
  582. "open-bytevector-output-port", 0, 1, 0,
  583. (SCM transcoder),
  584. "Return two values: an output port and a procedure. The latter "
  585. "should be called with zero arguments to obtain a bytevector "
  586. "containing the data accumulated by the port.")
  587. #define FUNC_NAME s_scm_open_bytevector_output_port
  588. {
  589. if (!SCM_UNBNDP (transcoder) && !scm_is_false (transcoder))
  590. transcoders_not_implemented ();
  591. return make_bytevector_output_port ();
  592. }
  593. #undef FUNC_NAME
  594. static inline void
  595. initialize_bytevector_output_ports (void)
  596. {
  597. bytevector_output_port_type =
  598. scm_make_port_type ("r6rs-bytevector-output-port",
  599. NULL, bytevector_output_port_write);
  600. scm_set_port_seek (bytevector_output_port_type, bytevector_output_port_seek);
  601. }
  602. /* Custom ports. */
  603. static SCM make_custom_binary_input_port_var;
  604. static SCM make_custom_binary_output_port_var;
  605. static SCM make_custom_binary_input_output_port_var;
  606. static scm_i_pthread_once_t make_custom_binary_port_vars =
  607. SCM_I_PTHREAD_ONCE_INIT;
  608. static void
  609. init_make_custom_binary_port_vars (void)
  610. {
  611. SCM mod = scm_c_resolve_module ("ice-9 binary-ports");
  612. SCM iface = scm_module_public_interface (mod);
  613. make_custom_binary_input_port_var =
  614. scm_c_module_lookup (iface, "make-custom-binary-input-port");
  615. make_custom_binary_output_port_var =
  616. scm_c_module_lookup (iface, "make-custom-binary-output-port");
  617. make_custom_binary_input_output_port_var =
  618. scm_c_module_lookup (iface, "make-custom-binary-input/output-port");
  619. }
  620. SCM scm_make_custom_binary_input_port (SCM id, SCM read_proc,
  621. SCM get_position_proc,
  622. SCM set_position_proc, SCM close_proc) {
  623. scm_i_pthread_once (&make_custom_binary_port_vars,
  624. init_make_custom_binary_port_vars);
  625. return scm_call_5 (scm_variable_ref (make_custom_binary_input_port_var),
  626. id, read_proc, get_position_proc, set_position_proc,
  627. close_proc);
  628. }
  629. SCM scm_make_custom_binary_output_port (SCM id, SCM write_proc,
  630. SCM get_position_proc,
  631. SCM set_position_proc, SCM close_proc) {
  632. scm_i_pthread_once (&make_custom_binary_port_vars,
  633. init_make_custom_binary_port_vars);
  634. return scm_call_5 (scm_variable_ref (make_custom_binary_output_port_var),
  635. id, write_proc, get_position_proc, set_position_proc,
  636. close_proc);
  637. }
  638. SCM scm_make_custom_binary_input_output_port (SCM id, SCM read_proc,
  639. SCM write_proc,
  640. SCM get_position_proc,
  641. SCM set_position_proc,
  642. SCM close_proc) {
  643. scm_i_pthread_once (&make_custom_binary_port_vars,
  644. init_make_custom_binary_port_vars);
  645. return scm_call_6 (scm_variable_ref (make_custom_binary_input_output_port_var),
  646. id, read_proc, write_proc, get_position_proc,
  647. set_position_proc, close_proc);
  648. }
  649. /* Transcoded ports. */
  650. static scm_t_port_type *transcoded_port_type = 0;
  651. #define SCM_TRANSCODED_PORT_BINARY_PORT(_port) SCM_PACK (SCM_STREAM (_port))
  652. static inline SCM
  653. make_transcoded_port (SCM binary_port, unsigned long mode)
  654. {
  655. return scm_c_make_port (transcoded_port_type, mode,
  656. SCM_UNPACK (binary_port));
  657. }
  658. static size_t
  659. transcoded_port_write (SCM port, SCM src, size_t start, size_t count)
  660. {
  661. SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port);
  662. scm_c_write_bytes (bport, src, start, count);
  663. return count;
  664. }
  665. static size_t
  666. transcoded_port_read (SCM port, SCM dst, size_t start, size_t count)
  667. {
  668. SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port);
  669. return scm_c_read_bytes (bport, dst, start, count);
  670. }
  671. static void
  672. transcoded_port_close (SCM port)
  673. {
  674. scm_close_port (SCM_TRANSCODED_PORT_BINARY_PORT (port));
  675. }
  676. static inline void
  677. initialize_transcoded_ports (void)
  678. {
  679. transcoded_port_type =
  680. scm_make_port_type ("r6rs-transcoded-port", transcoded_port_read,
  681. transcoded_port_write);
  682. scm_set_port_close (transcoded_port_type, transcoded_port_close);
  683. scm_set_port_needs_close_on_gc (transcoded_port_type, 1);
  684. }
  685. SCM_INTERNAL SCM scm_i_make_transcoded_port (SCM);
  686. SCM_DEFINE (scm_i_make_transcoded_port,
  687. "%make-transcoded-port", 1, 0, 0,
  688. (SCM port),
  689. "Return a new port which reads and writes to @var{port}")
  690. #define FUNC_NAME s_scm_i_make_transcoded_port
  691. {
  692. SCM result;
  693. unsigned long mode = 0;
  694. SCM_VALIDATE_PORT (SCM_ARG1, port);
  695. if (scm_is_true (scm_output_port_p (port)))
  696. mode |= SCM_WRTNG;
  697. if (scm_is_true (scm_input_port_p (port)))
  698. mode |= SCM_RDNG;
  699. result = make_transcoded_port (port, mode);
  700. /* FIXME: We should actually close `port' "in a special way" here,
  701. according to R6RS. As there is no way to do that in Guile without
  702. rendering the underlying port unusable for our purposes as well, we
  703. just leave it open. */
  704. return result;
  705. }
  706. #undef FUNC_NAME
  707. /* Textual I/O */
  708. SCM_DEFINE (scm_get_string_n_x,
  709. "get-string-n!", 4, 0, 0,
  710. (SCM port, SCM str, SCM start, SCM count),
  711. "Read up to @var{count} characters from @var{port} into "
  712. "@var{str}, starting at @var{start}. If no characters "
  713. "can be read before the end of file is encountered, the end "
  714. "of file object is returned. Otherwise, the number of "
  715. "characters read is returned.")
  716. #define FUNC_NAME s_scm_get_string_n_x
  717. {
  718. size_t c_start, c_count, c_len, c_end, j;
  719. scm_t_wchar c;
  720. SCM_VALIDATE_OPINPORT (1, port);
  721. SCM_VALIDATE_STRING (2, str);
  722. c_len = scm_c_string_length (str);
  723. c_start = scm_to_size_t (start);
  724. c_count = scm_to_size_t (count);
  725. c_end = c_start + c_count;
  726. if (SCM_UNLIKELY (c_end > c_len))
  727. scm_out_of_range (FUNC_NAME, count);
  728. for (j = c_start; j < c_end; j++)
  729. {
  730. c = scm_getc (port);
  731. if (c == EOF)
  732. {
  733. size_t chars_read = j - c_start;
  734. return chars_read == 0 ? SCM_EOF_VAL : scm_from_size_t (chars_read);
  735. }
  736. scm_c_string_set_x (str, j, SCM_MAKE_CHAR (c));
  737. }
  738. return count;
  739. }
  740. #undef FUNC_NAME
  741. /* Initialization. */
  742. void
  743. scm_register_r6rs_ports (void)
  744. {
  745. scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
  746. "scm_init_r6rs_ports",
  747. (scm_t_extension_init_func) scm_init_r6rs_ports,
  748. NULL);
  749. initialize_bytevector_input_ports ();
  750. initialize_bytevector_output_ports ();
  751. initialize_transcoded_ports ();
  752. }
  753. void
  754. scm_init_r6rs_ports (void)
  755. {
  756. #include "r6rs-ports.x"
  757. }