mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
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.
This commit is contained in:
parent
55fb8f4e7e
commit
f7027a8b88
7 changed files with 372 additions and 240 deletions
|
@ -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
|
||||
|
|
351
libguile/ports.c
351
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,46 +1496,115 @@ 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;
|
||||
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 (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;
|
||||
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)
|
||||
break;
|
||||
}
|
||||
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;
|
||||
|
||||
return dst_buf.end;
|
||||
filled = scm_i_read_bytes_unlocked (port, dst,
|
||||
start + count - to_read,
|
||||
to_read);
|
||||
if (filled == 0)
|
||||
break;
|
||||
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 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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
ptob->write (port, &ad_hoc_buf);
|
||||
written = SCM_PORT_DESCRIPTOR (port)->write (port, src, start, count);
|
||||
assert (written == count);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue