r6rs-ports.c 29 KB

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