summaryrefslogtreecommitdiff
path: root/libguile/vports.c
diff options
context:
space:
mode:
Diffstat (limited to 'libguile/vports.c')
-rw-r--r--libguile/vports.c103
1 files changed, 49 insertions, 54 deletions
diff --git a/libguile/vports.c b/libguile/vports.c
index 65041283d..82fef1e0b 100644
--- a/libguile/vports.c
+++ b/libguile/vports.c
@@ -22,6 +22,7 @@
# include <config.h>
#endif
+#include <assert.h>
#include <stdio.h>
#include <errno.h>
@@ -58,73 +59,68 @@ struct soft_port {
SCM read_char;
SCM close;
SCM input_waiting;
+ scm_t_port_buffer *encode_buf;
};
+/* Sadly it seems that most code expects there to be no write buffering
+ at all. */
static void
-soft_port_flush (SCM port)
+soft_port_get_natural_buffer_sizes (SCM port, size_t *read_size,
+ size_t *write_size)
{
- struct soft_port *stream = (void *) SCM_STREAM (port);
-
- if (scm_is_true (stream->flush))
- scm_call_0 (stream->flush);
+ *write_size = 1;
}
static void
-soft_port_write (SCM port, const void *data, size_t size)
+soft_port_write (SCM port, scm_t_port_buffer *buf)
{
struct soft_port *stream = (void *) SCM_STREAM (port);
+ scm_t_uint8 * ptr = buf->buf + buf->cur;
+ SCM str = scm_from_port_stringn ((char *) ptr, buf->end - buf->cur, port);
+ buf->end = buf->cur = 0;
- /* DATA is assumed to be a locale-encoded C string, which makes it
- hard to reliably pass binary data to a soft port. It can be
- achieved by choosing a Latin-1 locale, though, but the recommended
- approach is to use an R6RS "custom binary output port" instead. */
- scm_call_1 (stream->write_string,
- scm_from_locale_stringn ((char *) data, size));
-}
+ scm_call_1 (stream->write_string, str);
-/* calling the flush proc (element 2) is in case old code needs it,
- but perhaps softports could the use port buffer in the same way as
- fports. */
+ /* Backwards compatibility. */
+ if (scm_is_true (stream->flush))
+ scm_call_0 (stream->flush);
+}
/* places a single char in the input buffer. */
-static int
-soft_port_fill_input (SCM port)
+static void
+soft_port_read (SCM port, scm_t_port_buffer *dst)
{
struct soft_port *stream = (void *) SCM_STREAM (port);
- SCM ans;
- scm_t_wchar c;
- scm_t_port_internal *pti;
-
- ans = scm_call_0 (stream->read_char);
- if (scm_is_false (ans) || SCM_EOF_OBJECT_P (ans))
- return EOF;
- SCM_ASSERT (SCM_CHARP (ans), ans, SCM_ARG1, "soft_port_fill_input");
- pti = SCM_PORT_GET_INTERNAL (port);
-
- c = SCM_CHAR (ans);
+ scm_t_port_buffer *encode_buf = stream->encode_buf;
- if (pti->encoding_mode == SCM_PORT_ENCODING_MODE_LATIN1
- || (pti->encoding_mode == SCM_PORT_ENCODING_MODE_UTF8 && c < 0xff))
+ /* A character can be more than one byte, but we don't have a
+ guarantee that there is more than one byte in the read buffer. So,
+ use an intermediate buffer. Terrible. This whole facility should
+ be (re)designed. */
+ if (encode_buf->cur == encode_buf->end)
{
- scm_t_port *pt = SCM_PTAB_ENTRY (port);
-
- *pt->read_buf = c;
- pt->read_pos = pt->read_buf;
- pt->read_end = pt->read_buf + 1;
- }
- else
- {
- long line = SCM_LINUM (port);
- int column = SCM_COL (port);
-
- scm_ungetc_unlocked (c, port);
-
- SCM_LINUM (port) = line;
- SCM_COL (port) = column;
+ SCM ans;
+ char *str;
+ size_t len;
+
+ ans = scm_call_0 (stream->read_char);
+ if (scm_is_false (ans) || SCM_EOF_OBJECT_P (ans))
+ return;
+ SCM_ASSERT (SCM_CHARP (ans), ans, SCM_ARG1, "soft_port_read");
+
+ /* It's possible to make a fast path here, but it would be fastest
+ if the read procedure could fill its buffer directly. */
+ str = scm_to_port_stringn (scm_string (scm_list_1 (ans)), &len, port);
+ assert (len > 0 && len <= encode_buf->size);
+ encode_buf->cur = 0;
+ encode_buf->end = len;
+ memcpy (encode_buf->buf, str, len);
+ free (str);
}
- return c;
+ while (dst->end < dst->size && encode_buf->cur < encode_buf->end)
+ dst->buf[dst->end++] = encode_buf->buf[encode_buf->cur++];
}
@@ -199,7 +195,6 @@ SCM_DEFINE (scm_make_soft_port, "make-soft-port", 2, 0, 0,
#define FUNC_NAME s_scm_make_soft_port
{
int vlen;
- SCM z;
struct soft_port *stream;
SCM_VALIDATE_VECTOR (1, pv);
@@ -216,11 +211,10 @@ SCM_DEFINE (scm_make_soft_port, "make-soft-port", 2, 0, 0,
stream->input_waiting =
vlen == 6 ? SCM_SIMPLE_VECTOR_REF (pv, 5) : SCM_BOOL_F;
- z = scm_c_make_port (scm_tc16_soft_port, scm_i_mode_bits (modes),
- (scm_t_bits) stream);
- scm_port_non_buffer (SCM_PTAB_ENTRY (z));
+ stream->encode_buf = scm_c_make_port_buffer (10);
- return z;
+ return scm_c_make_port (scm_tc16_soft_port, scm_i_mode_bits (modes),
+ (scm_t_bits) stream);
}
#undef FUNC_NAME
@@ -228,12 +222,13 @@ SCM_DEFINE (scm_make_soft_port, "make-soft-port", 2, 0, 0,
static scm_t_bits
scm_make_sfptob ()
{
- scm_t_bits tc = scm_make_port_type ("soft", soft_port_fill_input,
+ scm_t_bits tc = scm_make_port_type ("soft", soft_port_read,
soft_port_write);
- scm_set_port_flush (tc, soft_port_flush);
scm_set_port_close (tc, soft_port_close);
scm_set_port_needs_close_on_gc (tc, 1);
+ scm_set_port_get_natural_buffer_sizes (tc,
+ soft_port_get_natural_buffer_sizes);
scm_set_port_input_waiting (tc, soft_port_input_waiting);
return tc;