summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2016-04-11 18:40:03 +0200
committerAndy Wingo <wingo@pobox.com>2016-04-11 22:23:47 +0200
commitf7027a8b88452948cd6bf0fe2605ef3d9ef4dded (patch)
tree28c1addea333d1b8ae56db070fbc64eaa9ec97d4
parent55fb8f4e7e8181ef09e49ea9d917ca25f9fe8159 (diff)
downloadguile-f7027a8b88452948cd6bf0fe2605ef3d9ef4dded.tar.gz
Port read/write functions take bytevectors
This will allow better Scheme integration for ports. * libguile/ports.h (scm_t_port_buffer): Change "holder" member to be a bytevector defined to have "buf" as its starting point. (scm_t_ptob_descriptor): Change read and write functions to take bytevectors as arguments and to return the number of octets read or written. (scm_make_port_type): Adapt accordingly. (scm_c_read_bytes, scm_c_write_bytes): New functions that take bytevectors. * libguile/ports.c (scm_make_port_type): Adapt to read/write function prototype change. (scm_c_make_port_buffer): Arrange to populate the "bytevector" field. (scm_i_read_bytes_unlocked): New function. (scm_i_read_unlocked): Use scm_i_read_bytes_unlocked. (scm_c_read_bytes_unlocked): New function. (scm_c_read_unlocked): Update comment, and always go through the buffer. (scm_c_read_bytes): New function. (scm_flush_unlocked): Use scm_i_write_unlocked instead of the port's write function. (scm_i_write_bytes_unlocked): New function. (scm_i_write_unlocked): Use scm_i_write_bytes_unlocked. (scm_c_write_bytes_unlocked): New function. (scm_c_write_unlocked): Always write through the buffer. (scm_c_write_bytes): New function. (scm_truncate_file): Remove unused variable. (void_port_read, void_port_write): Adapt to read/write prototype change. * libguile/fports.c (fport_read, fport_write): * libguile/r6rs-ports.c (bytevector_input_port_read) (custom_binary_input_port_read, bytevector_output_port_write) (custom_binary_output_port_write, transcoded_port_write) (transcoded_port_read): Adapt to read/write prototype change. (scm_get_bytevector_n, scm_get_bytevector_n_x) (scm_get_bytevector_all): Use scm_c_read_bytes. (scm_put_bytevector): Use scm_c_write_bytes. * libguile/strports.c (string_port_read, string_port_write): * libguile/vports.c (soft_port_write, soft_port_read): Adapt to read/write prototype change. * test-suite/standalone/test-scm-c-read.c (custom_port_read): Fix for read API change.
-rw-r--r--libguile/fports.c26
-rw-r--r--libguile/ports.c351
-rw-r--r--libguile/ports.h14
-rw-r--r--libguile/r6rs-ports.c153
-rw-r--r--libguile/strports.c27
-rw-r--r--libguile/vports.c29
-rw-r--r--test-suite/standalone/test-scm-c-read.c12
7 files changed, 372 insertions, 240 deletions
diff --git a/libguile/fports.c b/libguile/fports.c
index 3e4756204..11aa1707b 100644
--- a/libguile/fports.c
+++ b/libguile/fports.c
@@ -578,29 +578,29 @@ fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
/* fill a port's read-buffer with a single read. returns the first
char or EOF if end of file. */
-static void
-fport_read (SCM port, scm_t_port_buffer *dst)
+static size_t
+fport_read (SCM port, SCM dst, size_t start, size_t count)
{
- long count;
+ long res;
scm_t_fport *fp = SCM_FSTREAM (port);
- scm_t_uint8 *ptr = dst->buf + dst->end;
- size_t size = dst->size - dst->end;
+ signed char *ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start;
- SCM_SYSCALL (count = read (fp->fdes, ptr, size));
- if (count == -1)
+ SCM_SYSCALL (res = read (fp->fdes, ptr, count));
+ if (res == -1)
scm_syserror ("fport_read");
- dst->end += count;
+ return res;
}
-static void
-fport_write (SCM port, scm_t_port_buffer *src)
+static size_t
+fport_write (SCM port, SCM src, size_t start, size_t count)
{
int fd = SCM_FPORT_FDES (port);
- scm_t_uint8 *ptr = src->buf + src->cur;
- size_t size = src->end - src->cur;
+ signed char *ptr = SCM_BYTEVECTOR_CONTENTS (src) + start;
- if (full_write (fd, ptr, size) < size)
+ if (full_write (fd, ptr, count) < count)
scm_syserror ("fport_write");
+
+ return count;
}
static scm_t_off
diff --git a/libguile/ports.c b/libguile/ports.c
index 8f07425e3..144daef3f 100644
--- a/libguile/ports.c
+++ b/libguile/ports.c
@@ -229,8 +229,10 @@ static const size_t default_buffer_size = 1024;
scm_t_bits
scm_make_port_type (char *name,
- void (*read) (SCM port, scm_t_port_buffer *buf),
- void (*write) (SCM port, scm_t_port_buffer *buf))
+ size_t (*read) (SCM port, SCM dst, size_t start,
+ size_t count),
+ size_t (*write) (SCM port, SCM src, size_t start,
+ size_t count))
{
scm_t_ptob_descriptor *desc;
long ptobnum;
@@ -527,7 +529,8 @@ scm_c_make_port_buffer (size_t size)
scm_t_port_buffer *ret = scm_gc_typed_calloc (scm_t_port_buffer);
ret->size = size;
- ret->buf = scm_gc_malloc_pointerless (ret->size, "port buffer");
+ ret->bytevector = scm_c_make_bytevector (size);
+ ret->buf = (scm_t_uint8 *) SCM_BYTEVECTOR_CONTENTS (ret->bytevector);
return ret;
}
@@ -1432,33 +1435,51 @@ scm_peek_byte_or_eof (SCM port)
return ret;
}
+static size_t
+scm_i_read_bytes_unlocked (SCM port, SCM dst, size_t start, size_t count)
+{
+ size_t filled;
+ scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port);
+
+ assert (count <= SCM_BYTEVECTOR_LENGTH (dst));
+ assert (start + count <= SCM_BYTEVECTOR_LENGTH (dst));
+
+ filled = ptob->read (port, dst, start, count);
+
+ assert (filled <= count);
+
+ return filled;
+}
+
/* scm_i_read_unlocked is used internally to add bytes to the given port
buffer. If the number of available bytes in the buffer does not
increase after a call to scm_i_read_unlocked, that indicates EOF. */
static void
scm_i_read_unlocked (SCM port, scm_t_port_buffer *buf)
{
- size_t prev_end = buf->end;
+ size_t count;
+
assert (buf->end < buf->size);
- SCM_PORT_DESCRIPTOR (port)->read (port, buf);
- buf->has_eof = buf->end == prev_end;
+ count = scm_i_read_bytes_unlocked (port, buf->bytevector, buf->end,
+ buf->size - buf->end);
+ buf->end += count;
+ buf->has_eof = count == 0;
}
-/* scm_c_read
- *
- * Used by an application to read arbitrary number of bytes from an SCM
- * port. Same semantics as libc read, except that scm_c_read only
- * returns less than SIZE bytes if at end-of-file.
- *
- * Warning: Doesn't update port line and column counts! */
-size_t
-scm_c_read_unlocked (SCM port, void *buffer, size_t size)
-#define FUNC_NAME "scm_c_read"
+/* Used by an application to read arbitrary number of bytes from an SCM
+ port. Same semantics as libc read, except that scm_c_read_bytes only
+ returns less than SIZE bytes if at end-of-file.
+
+ Warning: Doesn't update port line and column counts! */
+static size_t
+scm_c_read_bytes_unlocked (SCM port, SCM dst, size_t start, size_t count)
+#define FUNC_NAME "scm_c_read_bytes"
{
+ size_t to_read = count;
scm_t_port *pt;
scm_t_port_buffer *read_buf;
- scm_t_port_buffer dst_buf = { buffer, 0, 0, size, 0, NULL };
+ signed char *dst_ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start;
SCM_VALIDATE_OPINPORT (1, port);
@@ -1475,47 +1496,116 @@ scm_c_read_unlocked (SCM port, void *buffer, size_t size)
/* Take bytes first from the port's read buffer. */
if (read_buf->cur < read_buf->end)
{
- size_t to_read = dst_buf.size - dst_buf.end;
- to_read = min (to_read, read_buf->end - read_buf->cur);
- memcpy (dst_buf.buf + dst_buf.end, read_buf->buf + read_buf->cur,
- to_read);
- dst_buf.end += to_read;
- read_buf->cur += to_read;
- }
-
- while (dst_buf.end < dst_buf.size)
- /* If the read buffering is larger than our read size, buffer the
- read. Otherwise read into our buffer directly. */
- if (dst_buf.size - dst_buf.end < pt->read_buffering)
- {
- size_t to_read = dst_buf.size - dst_buf.end;
- read_buf = scm_fill_input_unlocked (port);
- if (to_read > read_buf->end - read_buf->cur)
- to_read = read_buf->end - read_buf->cur;
- if (to_read == 0)
- {
- /* Consider that we've read off this EOF. */
- read_buf->has_eof = 0;
+ size_t to_copy = count;
+ to_copy = min (to_copy, read_buf->end - read_buf->cur);
+ memcpy (dst_ptr, read_buf->buf + read_buf->cur, to_copy);
+ dst_ptr += to_copy;
+ to_read -= to_copy;
+ read_buf->cur += to_copy;
+ }
+
+ while (to_read)
+ {
+ /* If the read is smaller than the buffering on the read side of
+ this port, then go through the buffer. Otherwise fill our
+ buffer directly. */
+ if (to_read < pt->read_buffering)
+ {
+ size_t to_copy = to_read;
+ read_buf = scm_fill_input_unlocked (port);
+ to_copy = min (to_copy, read_buf->end - read_buf->cur);
+ memcpy (dst_ptr, read_buf->buf + read_buf->cur, to_copy);
+ if (to_copy == 0)
+ {
+ /* Consider that we've read off this EOF. */
+ read_buf->has_eof = 0;
+ break;
+ }
+ dst_ptr += to_copy;
+ to_read -= to_copy;
+ read_buf->cur += to_copy;
+ }
+ else
+ {
+ size_t filled;
+
+ filled = scm_i_read_bytes_unlocked (port, dst,
+ start + count - to_read,
+ to_read);
+ if (filled == 0)
break;
- }
- memcpy (dst_buf.buf + dst_buf.end,
- read_buf->buf + read_buf->cur,
- to_read);
- read_buf->cur += to_read;
- dst_buf.end += to_read;
- }
- else
- {
- scm_i_read_unlocked (port, &dst_buf);
- if (dst_buf.has_eof)
+ to_read -= filled;
+ dst_ptr += filled;
+ }
+ }
+
+ return count - to_read;
+}
+#undef FUNC_NAME
+
+/* Like scm_c_read_bytes, but always proxies reads through the port's
+ read buffer. Used by an application when it wants to read into a
+ memory chunk that's not owned by Guile's GC. */
+size_t
+scm_c_read_unlocked (SCM port, void *buffer, size_t size)
+#define FUNC_NAME "scm_c_read"
+{
+ size_t copied = 0;
+ scm_t_port *pt;
+ scm_t_port_buffer *read_buf;
+ scm_t_uint8 *dst = buffer;
+
+ SCM_VALIDATE_OPINPORT (1, port);
+
+ pt = SCM_PTAB_ENTRY (port);
+ read_buf = pt->read_buf;
+
+ if (pt->rw_random)
+ {
+ if (pt->rw_active == SCM_PORT_WRITE)
+ scm_flush_unlocked (port);
+ pt->rw_active = SCM_PORT_READ;
+ }
+
+ while (copied < size)
+ {
+ read_buf = scm_fill_input_unlocked (port);
+ /* Take bytes first from the port's read buffer. */
+ if (read_buf->cur < read_buf->end)
+ {
+ size_t to_copy = size - copied;
+ to_copy = min (to_copy, read_buf->end - read_buf->cur);
+ memcpy (dst + copied, read_buf->buf + read_buf->cur, to_copy);
+ copied += to_copy;
+ read_buf->cur += to_copy;
+ }
+ else
+ {
+ /* Consider that we've read off this EOF. */
+ read_buf->has_eof = 0;
break;
- }
+ }
+ }
- return dst_buf.end;
+ return copied;
}
#undef FUNC_NAME
size_t
+scm_c_read_bytes (SCM port, SCM dst, size_t start, size_t count)
+{
+ scm_i_pthread_mutex_t *lock;
+ size_t ret;
+
+ scm_c_lock_port (port, &lock);
+ ret = scm_c_read_bytes_unlocked (port, dst, start, count);
+ if (lock)
+ scm_i_pthread_mutex_unlock (lock);
+
+ return ret;
+}
+
+size_t
scm_c_read (SCM port, void *buffer, size_t size)
{
scm_i_pthread_mutex_t *lock;
@@ -2447,13 +2537,14 @@ SCM_DEFINE (scm_force_output, "force-output", 0, 1, 0,
}
#undef FUNC_NAME
+static void scm_i_write_unlocked (SCM port, scm_t_port_buffer *src);
+
void
scm_flush_unlocked (SCM port)
{
scm_t_port_buffer *buf = SCM_PTAB_ENTRY (port)->write_buf;
if (buf->cur < buf->end)
- SCM_PORT_DESCRIPTOR (port)->write (port, buf);
- buf->cur = buf->end = 0;
+ scm_i_write_unlocked (port, buf);
SCM_PTAB_ENTRY (port)->rw_active = SCM_PORT_NEITHER;
}
@@ -2520,27 +2611,56 @@ scm_puts (const char *s, SCM port)
scm_i_pthread_mutex_unlock (lock);
}
-/* scm_c_write
- *
- * Used by an application to write arbitrary number of bytes to an SCM
- * port. Similar semantics as libc write. However, unlike libc
- * write, scm_c_write writes the requested number of bytes and has no
- * return value.
- *
- * Warning: Doesn't update port line and column counts!
- */
-void
-scm_c_write_unlocked (SCM port, const void *ptr, size_t size)
-#define FUNC_NAME "scm_c_write"
+static void
+scm_i_write_bytes_unlocked (SCM port, SCM src, size_t start, size_t count)
+{
+ size_t written;
+ scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port);
+
+ assert (count <= SCM_BYTEVECTOR_LENGTH (src));
+ assert (start + count <= SCM_BYTEVECTOR_LENGTH (src));
+
+ written = ptob->write (port, src, start, count);
+
+ /* FIXME: Allow short writes? */
+ assert (written == count);
+}
+
+static void
+scm_i_write_unlocked (SCM port, scm_t_port_buffer *src)
+{
+ size_t start, count;
+
+ assert (src->cur < src->end);
+ assert (src->end <= src->size);
+
+ /* Update cursors before attempting to write, assuming that I/O errors
+ are sticky. That way if the write throws an error, causing the
+ computation to abort, and possibly causing the port to be collected
+ by GC when it's open, any subsequent close-port / force-output
+ won't signal *another* error. */
+
+ start = src->cur;
+ count = src->end - src->cur;
+ src->cur = src->end = 0;
+ scm_i_write_bytes_unlocked (port, src->bytevector, start, count);
+}
+
+/* Used by an application to write arbitrary number of bytes to an SCM
+ port. Similar semantics as libc write. However, unlike libc write,
+ scm_c_write writes the requested number of bytes.
+
+ Warning: Doesn't update port line and column counts! */
+static size_t
+scm_c_write_bytes_unlocked (SCM port, SCM src, size_t start, size_t count)
+#define FUNC_NAME "scm_c_write_bytes"
{
scm_t_port *pt;
scm_t_port_buffer *write_buf;
- scm_t_ptob_descriptor *ptob;
SCM_VALIDATE_OPOUTPORT (1, port);
pt = SCM_PTAB_ENTRY (port);
- ptob = SCM_PORT_DESCRIPTOR (port);
write_buf = pt->write_buf;
if (pt->rw_random)
@@ -2550,7 +2670,7 @@ scm_c_write_unlocked (SCM port, const void *ptr, size_t size)
pt->rw_active = SCM_PORT_WRITE;
}
- if (size < write_buf->size)
+ if (count < write_buf->size)
{
/* Make it so that write_buf->end is only nonzero if there are
buffered bytes already. */
@@ -2562,36 +2682,72 @@ scm_c_write_unlocked (SCM port, const void *ptr, size_t size)
flush it beforehand. Otherwise it could be that the buffer is
full after filling it with the new data; if that's the case, we
flush then instead. */
- if (write_buf->end + size > write_buf->size)
- {
- ptob->write (port, write_buf);
- write_buf->cur = write_buf->end = 0;
- }
+ if (write_buf->end + count > write_buf->size)
+ scm_i_write_unlocked (port, write_buf);
- memcpy (write_buf->buf + write_buf->end, ptr, size);
- write_buf->end += size;
+ memcpy (write_buf->buf + write_buf->end,
+ SCM_BYTEVECTOR_CONTENTS (src) + start,
+ count);
+ write_buf->end += count;
if (write_buf->end == write_buf->size)
- {
- ptob->write (port, write_buf);
- write_buf->cur = write_buf->end = 0;
- }
+ scm_i_write_unlocked (port, write_buf);
}
else
{
/* Our write would overflow the buffer. Flush buffered bytes (if
needed), then write our bytes with just one syscall. */
-
- scm_t_port_buffer ad_hoc_buf =
- { (scm_t_uint8 *) ptr, 0, size, size, 0, NULL };
+ size_t written;
if (write_buf->cur < write_buf->end)
- {
- ptob->write (port, write_buf);
- write_buf->cur = write_buf->end = 0;
- }
+ scm_i_write_unlocked (port, write_buf);
+
+ written = SCM_PORT_DESCRIPTOR (port)->write (port, src, start, count);
+ assert (written == count);
+ }
+
+ return count;
+}
+#undef FUNC_NAME
- ptob->write (port, &ad_hoc_buf);
+/* Like scm_c_write_bytes, but always writes through the write buffer.
+ Used when an application wants to write bytes stored in an area not
+ managed by GC. */
+void
+scm_c_write_unlocked (SCM port, const void *ptr, size_t size)
+#define FUNC_NAME "scm_c_write"
+{
+ scm_t_port *pt;
+ scm_t_port_buffer *write_buf;
+ size_t written = 0;
+ const scm_t_uint8 *src = ptr;
+
+ SCM_VALIDATE_OPOUTPORT (1, port);
+
+ pt = SCM_PTAB_ENTRY (port);
+ write_buf = pt->write_buf;
+
+ if (pt->rw_random)
+ {
+ if (pt->rw_active == SCM_PORT_READ)
+ scm_end_input_unlocked (port);
+ pt->rw_active = SCM_PORT_WRITE;
+ }
+
+ while (written < size)
+ {
+ size_t to_write = write_buf->size - write_buf->end;
+
+ if (to_write > size - written)
+ to_write = size - written;
+
+ memcpy (write_buf->buf + write_buf->end, src, to_write);
+ write_buf->end += to_write;
+ written += to_write;
+ src += to_write;
+
+ if (write_buf->end == write_buf->size)
+ scm_i_write_unlocked (port, write_buf);
}
}
#undef FUNC_NAME
@@ -2606,6 +2762,16 @@ scm_c_write (SCM port, const void *ptr, size_t size)
scm_i_pthread_mutex_unlock (lock);
}
+void
+scm_c_write_bytes (SCM port, SCM src, size_t start, size_t count)
+{
+ scm_i_pthread_mutex_t *lock;
+ scm_c_lock_port (port, &lock);
+ scm_c_write_bytes_unlocked (port, src, start, count);
+ if (lock)
+ scm_i_pthread_mutex_unlock (lock);
+}
+
/* scm_lfwrite
*
* This function differs from scm_c_write; it updates port line and
@@ -2846,7 +3012,6 @@ SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0,
else if (SCM_OPOUTPORTP (object))
{
off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
- scm_t_port *pt = SCM_PTAB_ENTRY (object);
scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (object);
if (!ptob->truncate)
@@ -3082,14 +3247,16 @@ SCM_DEFINE (scm_flush_all_ports, "flush-all-ports", 0, 0, 0,
scm_t_bits scm_tc16_void_port = 0;
-static void
-void_port_read (SCM port, scm_t_port_buffer *buf)
+static size_t
+void_port_read (SCM port, SCM dst, size_t start, size_t count)
{
+ return 0;
}
-static void
-void_port_write (SCM port, scm_t_port_buffer *buf)
+static size_t
+void_port_write (SCM port, SCM src, size_t start, size_t count)
{
+ return count;
}
static SCM
diff --git a/libguile/ports.h b/libguile/ports.h
index 80e3a6774..e7277e3ab 100644
--- a/libguile/ports.h
+++ b/libguile/ports.h
@@ -87,8 +87,8 @@ typedef struct
peek-u8 should still return EOF. */
int has_eof;
- /* Heap object that keeps `buf' alive. */
- void *holder;
+ /* Bytevector whose contents are [BUF, BUF + SIZE). */
+ SCM bytevector;
} scm_t_port_buffer;
@@ -204,8 +204,8 @@ typedef struct scm_t_ptob_descriptor
char *name;
int (*print) (SCM exp, SCM port, scm_print_state *pstate);
- void (*read) (SCM port, scm_t_port_buffer *dst);
- void (*write) (SCM port, scm_t_port_buffer *src);
+ size_t (*read) (SCM port, SCM dst, size_t start, size_t count);
+ size_t (*write) (SCM port, SCM src, size_t start, size_t count);
scm_t_off (*seek) (SCM port, scm_t_off OFFSET, int WHENCE);
void (*close) (SCM port);
@@ -230,8 +230,8 @@ SCM_API scm_t_ptob_descriptor* scm_c_port_type_ref (long ptobnum);
SCM_API long scm_c_port_type_add_x (scm_t_ptob_descriptor *desc);
SCM_API scm_t_bits scm_make_port_type
(char *name,
- void (*read) (SCM port, scm_t_port_buffer *dst),
- void (*write) (SCM port, scm_t_port_buffer *src));
+ size_t (*read) (SCM port, SCM dst, size_t start, size_t count),
+ size_t (*write) (SCM port, SCM src, size_t start, size_t count));
SCM_API void scm_set_port_print (scm_t_bits tc,
int (*print) (SCM exp,
SCM port,
@@ -323,6 +323,7 @@ SCM_INLINE int scm_peek_byte_or_eof_unlocked (SCM port);
SCM_API int scm_slow_peek_byte_or_eof_unlocked (SCM port);
SCM_API size_t scm_c_read (SCM port, void *buffer, size_t size);
SCM_API size_t scm_c_read_unlocked (SCM port, void *buffer, size_t size);
+SCM_API size_t scm_c_read_bytes (SCM port, SCM dst, size_t start, size_t count);
SCM_API scm_t_wchar scm_getc (SCM port);
SCM_API scm_t_wchar scm_getc_unlocked (SCM port);
SCM_API SCM scm_read_char (SCM port);
@@ -359,6 +360,7 @@ SCM_API void scm_puts (const char *str_data, SCM port);
SCM_INLINE void scm_puts_unlocked (const char *str_data, SCM port);
SCM_API void scm_c_write (SCM port, const void *buffer, size_t size);
SCM_API void scm_c_write_unlocked (SCM port, const void *buffer, size_t size);
+SCM_API void scm_c_write_bytes (SCM port, SCM src, size_t start, size_t count);
SCM_API void scm_lfwrite (const char *ptr, size_t size, SCM port);
SCM_API void scm_lfwrite_unlocked (const char *ptr, size_t size, SCM port);
SCM_INTERNAL void scm_lfwrite_substr (SCM str, size_t start, size_t end,
diff --git a/libguile/r6rs-ports.c b/libguile/r6rs-ports.c
index aa54a0e67..fb821bb18 100644
--- a/libguile/r6rs-ports.c
+++ b/libguile/r6rs-ports.c
@@ -99,25 +99,26 @@ make_bytevector_input_port (SCM bv)
(scm_t_bits) stream);
}
-static void
-bytevector_input_port_read (SCM port, scm_t_port_buffer *buf)
+static size_t
+bytevector_input_port_read (SCM port, SCM dst, size_t start, size_t count)
{
- size_t count;
+ size_t remaining;
struct bytevector_input_port *stream = (void *) SCM_STREAM (port);
if (stream->pos >= SCM_BYTEVECTOR_LENGTH (stream->bytevector))
- return;
+ return 0;
- count = SCM_BYTEVECTOR_LENGTH (stream->bytevector) - stream->pos;
- if (count > buf->size - buf->end)
- count = buf->size - buf->end;
+ remaining = SCM_BYTEVECTOR_LENGTH (stream->bytevector) - stream->pos;
+ if (remaining < count)
+ count = remaining;
- memcpy (buf->buf + buf->end,
+ memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
count);
- buf->end += count;
stream->pos += count;
+
+ return count;
}
static scm_t_off
@@ -277,32 +278,21 @@ make_custom_binary_input_port (SCM read_proc, SCM get_position_proc,
(scm_t_bits) stream);
}
-static void
-custom_binary_input_port_read (SCM port, scm_t_port_buffer *buf)
+static size_t
+custom_binary_input_port_read (SCM port, SCM dst, size_t start, size_t count)
#define FUNC_NAME "custom_binary_input_port_read"
{
struct custom_binary_port *stream = (void *) SCM_STREAM (port);
- SCM bv, octets;
+ SCM octets;
size_t c_octets;
- /* FIXME: We need to make sure buf->buf is kept alive. If read_buf is
- referenced from PORT, passing PORT as the parent will do it. But,
- pushback could re-set PORT->read_buf, which would be a fail. But,
- probably buf->buf is itself GC-allocated, so we can pack it
- directly. But, perhaps it's not, as in scm_c_read(). In that
- latter case we're kinda screwed and probably need to prevent
- rewinding. But shouldn't we always prevent rewinding? And how can
- we avoid allocating the bytevector at all? */
- bv = scm_c_take_gc_bytevector ((signed char *) (buf->buf + buf->end),
- buf->size - buf->end,
- PTR2SCM (buf->buf));
-
- octets = scm_call_3 (stream->read, bv, SCM_INUM0, scm_bytevector_length (bv));
+ octets = scm_call_3 (stream->read, dst, scm_from_size_t (start),
+ scm_from_size_t (count));
c_octets = scm_to_size_t (octets);
- if (c_octets > scm_c_bytevector_length (bv))
+ if (c_octets > count)
scm_out_of_range (FUNC_NAME, octets);
- buf->end += c_octets;
+ return c_octets;
}
#undef FUNC_NAME
@@ -405,7 +395,6 @@ SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 0, 0,
#define FUNC_NAME s_scm_get_bytevector_n
{
SCM result;
- char *c_bv;
unsigned c_count;
size_t c_read;
@@ -413,11 +402,10 @@ SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 0, 0,
c_count = scm_to_uint (count);
result = scm_c_make_bytevector (c_count);
- c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (result);
if (SCM_LIKELY (c_count > 0))
/* XXX: `scm_c_read ()' does not update the port position. */
- c_read = scm_c_read_unlocked (port, c_bv, c_count);
+ c_read = scm_c_read_bytes (port, result, 0, c_count);
else
/* Don't invoke `scm_c_read ()' since it may block. */
c_read = 0;
@@ -443,7 +431,6 @@ SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0,
#define FUNC_NAME s_scm_get_bytevector_n_x
{
SCM result;
- char *c_bv;
unsigned c_start, c_count, c_len;
size_t c_read;
@@ -452,14 +439,13 @@ SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0,
c_start = scm_to_uint (start);
c_count = scm_to_uint (count);
- c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
c_len = SCM_BYTEVECTOR_LENGTH (bv);
if (SCM_UNLIKELY (c_start + c_count > c_len))
scm_out_of_range (FUNC_NAME, count);
if (SCM_LIKELY (c_count > 0))
- c_read = scm_c_read_unlocked (port, c_bv + c_start, c_count);
+ c_read = scm_c_read_bytes (port, bv, c_start, c_count);
else
/* Don't invoke `scm_c_read ()' since it may block. */
c_read = 0;
@@ -513,14 +499,13 @@ SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0,
#define FUNC_NAME s_scm_get_bytevector_all
{
SCM result;
- char *c_bv;
unsigned c_len, c_count;
size_t c_read, c_total;
SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
c_len = c_count = 4096;
- c_bv = (char *) scm_gc_malloc_pointerless (c_len, SCM_GC_BYTEVECTOR);
+ result = scm_c_make_bytevector (c_count);
c_total = c_read = 0;
do
@@ -528,37 +513,27 @@ SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0,
if (c_total + c_read > c_len)
{
/* Grow the bytevector. */
- c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2,
- SCM_GC_BYTEVECTOR);
+ SCM prev = result;
+ result = scm_c_make_bytevector (c_len * 2);
+ memcpy (SCM_BYTEVECTOR_CONTENTS (result),
+ SCM_BYTEVECTOR_CONTENTS (prev),
+ c_total);
c_count = c_len;
c_len *= 2;
}
/* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
reached. */
- c_read = scm_c_read_unlocked (port, c_bv + c_total, c_count);
+ c_read = scm_c_read_bytes (port, result, c_total, c_count);
c_total += c_read, c_count -= c_read;
}
while (c_count == 0);
if (c_total == 0)
- {
- result = SCM_EOF_VAL;
- scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
- }
- else
- {
- if (c_len > c_total)
- {
- /* Shrink the bytevector. */
- c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_total,
- SCM_GC_BYTEVECTOR);
- c_len = (unsigned) c_total;
- }
+ return SCM_EOF_VAL;
- result = scm_c_take_gc_bytevector ((signed char *) c_bv, c_len,
- SCM_BOOL_F);
- }
+ if (c_len > c_total)
+ return scm_c_shrink_bytevector (result, c_total);
return result;
}
@@ -596,14 +571,12 @@ SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
"octets.")
#define FUNC_NAME s_scm_put_bytevector
{
- char *c_bv;
unsigned c_start, c_count, c_len;
SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
SCM_VALIDATE_BYTEVECTOR (2, bv);
c_len = SCM_BYTEVECTOR_LENGTH (bv);
- c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
if (!scm_is_eq (start, SCM_UNDEFINED))
{
@@ -626,7 +599,7 @@ SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
else
c_start = 0, c_count = c_len;
- scm_c_write_unlocked (port, c_bv + c_start, c_count);
+ scm_c_write_bytes (port, bv, c_start, c_count);
return SCM_UNSPECIFIED;
}
@@ -777,21 +750,22 @@ make_bytevector_output_port (void)
}
/* Write octets from WRITE_BUF to the backing store. */
-static void
-bytevector_output_port_write (SCM port, scm_t_port_buffer *write_buf)
+static size_t
+bytevector_output_port_write (SCM port, SCM src, size_t start, size_t count)
{
- size_t count;
scm_t_bytevector_output_port_buffer *buf;
buf = SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER (port);
- count = write_buf->end - write_buf->cur;
if (buf->pos + count > buf->total_len)
bytevector_output_port_buffer_grow (buf, buf->pos + count);
- memcpy (buf->buffer + buf->pos, write_buf->buf + write_buf->cur, count);
+ memcpy (buf->buffer + buf->pos, SCM_BYTEVECTOR_CONTENTS (src) + start, count);
+
buf->pos += count;
buf->len = (buf->len > buf->pos) ? buf->len : buf->pos;
+
+ return count;
}
static scm_t_off
@@ -909,41 +883,35 @@ make_custom_binary_output_port (SCM write_proc, SCM get_position_proc,
}
/* Flush octets from BUF to the backing store. */
-static void
-custom_binary_output_port_write (SCM port, scm_t_port_buffer *buf)
+static size_t
+custom_binary_output_port_write (SCM port, SCM src, size_t start, size_t count)
#define FUNC_NAME "custom_binary_output_port_write"
{
- size_t size, written;
+ size_t written;
struct custom_binary_port *stream = (void *) SCM_STREAM (port);
- SCM bv;
-
- /* FIXME: If BUF is the same as PORT->write_buf, then the data is
- GC-managed and we could avoid allocating a new bytevector backing
- store. Otherwise we have to copy, as we do here. */
- size = buf->end - buf->cur;
- bv = scm_c_make_bytevector (size);
- memcpy (SCM_BYTEVECTOR_CONTENTS (bv), buf->buf + buf->cur, size);
/* Since the `write' procedure of Guile's ports has type `void', it must
try hard to write exactly SIZE bytes, regardless of how many bytes the
sink can handle. */
written = 0;
- while (written < size)
+ while (written < count)
{
long int c_result;
SCM result;
- result = scm_call_3 (stream->write, bv,
- scm_from_size_t (written),
- scm_from_size_t (size - written));
+ result = scm_call_3 (stream->write, src,
+ scm_from_size_t (start + written),
+ scm_from_size_t (count - written));
c_result = scm_to_long (result);
- if (c_result < 0 || (size_t) c_result > (size - written))
+ if (c_result < 0 || (size_t) c_result > (count - written))
scm_wrong_type_arg_msg (FUNC_NAME, 0, result,
"R6RS custom binary output port `write!' "
"returned a incorrect integer");
written += c_result;
}
+
+ return written;
}
#undef FUNC_NAME
@@ -1008,32 +976,19 @@ make_transcoded_port (SCM binary_port, unsigned long mode)
return port;
}
-static void
-transcoded_port_write (SCM port, scm_t_port_buffer *buf)
+static size_t
+transcoded_port_write (SCM port, SCM src, size_t start, size_t count)
{
SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port);
- scm_c_write_unlocked (bport, buf->buf + buf->cur, buf->end - buf->cur);
+ scm_c_write_bytes (bport, src, start, count);
+ return count;
}
-static void
-transcoded_port_read (SCM port, scm_t_port_buffer *buf)
+static size_t
+transcoded_port_read (SCM port, SCM dst, size_t start, size_t count)
{
- size_t count;
- scm_t_port_buffer *bport_buf;
-
- /* We can't use `scm_c_read' here, since it blocks until the whole
- block has been read or EOF. */
-
- bport_buf = scm_fill_input (SCM_TRANSCODED_PORT_BINARY_PORT (port));
- /* Consume EOF from bport. */
- bport_buf->has_eof = 0;
- count = bport_buf->end - bport_buf->cur;
- if (count > buf->size - buf->end)
- count = buf->size - buf->end;
-
- memcpy (buf->buf + buf->end, bport_buf->buf + bport_buf->cur, count);
- bport_buf->cur += count;
- buf->end += count;
+ SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port);
+ return scm_c_read_bytes (bport, dst, start, count);
}
static void
diff --git a/libguile/strports.c b/libguile/strports.c
index 6ad7d18f2..e8ce67a8f 100644
--- a/libguile/strports.c
+++ b/libguile/strports.c
@@ -60,31 +60,29 @@ struct string_port {
size_t len;
};
-static void
-string_port_read (SCM port, scm_t_port_buffer *dst)
+static size_t
+string_port_read (SCM port, SCM dst, size_t start, size_t count)
{
- size_t count;
struct string_port *stream = (void *) SCM_STREAM (port);
if (stream->pos >= stream->len)
- return;
+ return 0;
- count = stream->len - stream->pos;
- if (count > dst->size - dst->end)
- count = dst->size - dst->end;
+ if (count > stream->len - stream->pos)
+ count = stream->len - stream->pos;
- memcpy (dst->buf + dst->end,
+ memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
count);
- dst->end += count;
+
stream->pos += count;
+ return count;
}
-static void
-string_port_write (SCM port, scm_t_port_buffer *src)
+static size_t
+string_port_write (SCM port, SCM src, size_t start, size_t count)
{
struct string_port *stream = (void *) SCM_STREAM (port);
- size_t count = src->end - src->cur;
if (SCM_BYTEVECTOR_LENGTH (stream->bytevector) < stream->pos + count)
{
@@ -101,12 +99,13 @@ string_port_write (SCM port, scm_t_port_buffer *src)
}
memcpy (SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
- src->buf + src->cur,
+ SCM_BYTEVECTOR_CONTENTS (src) + start,
count);
- src->cur += count;
stream->pos += count;
if (stream->pos > stream->len)
stream->len = stream->pos;
+
+ return count;
}
static scm_t_off
diff --git a/libguile/vports.c b/libguile/vports.c
index 82fef1e0b..e52057065 100644
--- a/libguile/vports.c
+++ b/libguile/vports.c
@@ -72,27 +72,30 @@ soft_port_get_natural_buffer_sizes (SCM port, size_t *read_size,
*write_size = 1;
}
-static void
-soft_port_write (SCM port, scm_t_port_buffer *buf)
+static size_t
+soft_port_write (SCM port, SCM src, size_t start, size_t count)
{
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;
+ signed char * ptr = SCM_BYTEVECTOR_CONTENTS (src) + start;
- scm_call_1 (stream->write_string, str);
+ scm_call_1 (stream->write_string,
+ scm_from_port_stringn ((char *) ptr, count, port));
/* Backwards compatibility. */
if (scm_is_true (stream->flush))
scm_call_0 (stream->flush);
+
+ return count;
}
/* places a single char in the input buffer. */
-static void
-soft_port_read (SCM port, scm_t_port_buffer *dst)
+static size_t
+soft_port_read (SCM port, SCM dst, size_t start, size_t count)
{
+ size_t written;
struct soft_port *stream = (void *) SCM_STREAM (port);
scm_t_port_buffer *encode_buf = stream->encode_buf;
+ signed char *dst_ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start;
/* 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,
@@ -106,7 +109,7 @@ soft_port_read (SCM port, scm_t_port_buffer *dst)
ans = scm_call_0 (stream->read_char);
if (scm_is_false (ans) || SCM_EOF_OBJECT_P (ans))
- return;
+ return 0;
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
@@ -119,8 +122,12 @@ soft_port_read (SCM port, scm_t_port_buffer *dst)
free (str);
}
- while (dst->end < dst->size && encode_buf->cur < encode_buf->end)
- dst->buf[dst->end++] = encode_buf->buf[encode_buf->cur++];
+ for (written = 0;
+ written < count && encode_buf->cur < encode_buf->end;
+ written++, encode_buf->cur++)
+ dst_ptr[written] = encode_buf->buf[encode_buf->cur];
+
+ return written;
}
diff --git a/test-suite/standalone/test-scm-c-read.c b/test-suite/standalone/test-scm-c-read.c
index 86bca48ed..7850f3447 100644
--- a/test-suite/standalone/test-scm-c-read.c
+++ b/test-suite/standalone/test-scm-c-read.c
@@ -54,18 +54,20 @@ make_port (scm_t_bits port_type)
return scm_c_make_port (port_type, SCM_RDNG, (scm_t_bits) stream);
}
-static void
-custom_port_read (SCM port, scm_t_port_buffer *dst)
+static size_t
+custom_port_read (SCM port, SCM dst, size_t start, size_t count)
{
- size_t to_copy = dst->size - dst->end;
+ size_t to_copy = count;
struct custom_port *stream = (void *) SCM_STREAM (port);
if (stream->pos + to_copy > stream->len)
to_copy = stream->len - stream->pos;
- memcpy (dst->buf + dst->end, stream->buf + stream->pos, to_copy);
+ memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
+ stream->buf + stream->pos, to_copy);
stream->pos += to_copy;
- dst->end += to_copy;
+
+ return to_copy;
}
/* Return true (non-zero) if BUF contains only zeros. */