mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-01 04:10:18 +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
|
/* fill a port's read-buffer with a single read. returns the first
|
||||||
char or EOF if end of file. */
|
char or EOF if end of file. */
|
||||||
static void
|
static size_t
|
||||||
fport_read (SCM port, scm_t_port_buffer *dst)
|
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_fport *fp = SCM_FSTREAM (port);
|
||||||
scm_t_uint8 *ptr = dst->buf + dst->end;
|
signed char *ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start;
|
||||||
size_t size = dst->size - dst->end;
|
|
||||||
|
|
||||||
SCM_SYSCALL (count = read (fp->fdes, ptr, size));
|
SCM_SYSCALL (res = read (fp->fdes, ptr, count));
|
||||||
if (count == -1)
|
if (res == -1)
|
||||||
scm_syserror ("fport_read");
|
scm_syserror ("fport_read");
|
||||||
dst->end += count;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
fport_write (SCM port, scm_t_port_buffer *src)
|
fport_write (SCM port, SCM src, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
int fd = SCM_FPORT_FDES (port);
|
int fd = SCM_FPORT_FDES (port);
|
||||||
scm_t_uint8 *ptr = src->buf + src->cur;
|
signed char *ptr = SCM_BYTEVECTOR_CONTENTS (src) + start;
|
||||||
size_t size = src->end - src->cur;
|
|
||||||
|
|
||||||
if (full_write (fd, ptr, size) < size)
|
if (full_write (fd, ptr, count) < count)
|
||||||
scm_syserror ("fport_write");
|
scm_syserror ("fport_write");
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static scm_t_off
|
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_t_bits
|
||||||
scm_make_port_type (char *name,
|
scm_make_port_type (char *name,
|
||||||
void (*read) (SCM port, scm_t_port_buffer *buf),
|
size_t (*read) (SCM port, SCM dst, size_t start,
|
||||||
void (*write) (SCM port, scm_t_port_buffer *buf))
|
size_t count),
|
||||||
|
size_t (*write) (SCM port, SCM src, size_t start,
|
||||||
|
size_t count))
|
||||||
{
|
{
|
||||||
scm_t_ptob_descriptor *desc;
|
scm_t_ptob_descriptor *desc;
|
||||||
long ptobnum;
|
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);
|
scm_t_port_buffer *ret = scm_gc_typed_calloc (scm_t_port_buffer);
|
||||||
|
|
||||||
ret->size = size;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1432,33 +1435,51 @@ scm_peek_byte_or_eof (SCM port)
|
||||||
return ret;
|
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
|
/* 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
|
buffer. If the number of available bytes in the buffer does not
|
||||||
increase after a call to scm_i_read_unlocked, that indicates EOF. */
|
increase after a call to scm_i_read_unlocked, that indicates EOF. */
|
||||||
static void
|
static void
|
||||||
scm_i_read_unlocked (SCM port, scm_t_port_buffer *buf)
|
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);
|
assert (buf->end < buf->size);
|
||||||
|
|
||||||
SCM_PORT_DESCRIPTOR (port)->read (port, buf);
|
count = scm_i_read_bytes_unlocked (port, buf->bytevector, buf->end,
|
||||||
buf->has_eof = buf->end == prev_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_bytes only
|
||||||
* Used by an application to read arbitrary number of bytes from an SCM
|
returns less than SIZE bytes if at end-of-file.
|
||||||
* 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! */
|
||||||
*
|
static size_t
|
||||||
* Warning: Doesn't update port line and column counts! */
|
scm_c_read_bytes_unlocked (SCM port, SCM dst, size_t start, size_t count)
|
||||||
size_t
|
#define FUNC_NAME "scm_c_read_bytes"
|
||||||
scm_c_read_unlocked (SCM port, void *buffer, size_t size)
|
|
||||||
#define FUNC_NAME "scm_c_read"
|
|
||||||
{
|
{
|
||||||
|
size_t to_read = count;
|
||||||
scm_t_port *pt;
|
scm_t_port *pt;
|
||||||
scm_t_port_buffer *read_buf;
|
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);
|
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. */
|
/* Take bytes first from the port's read buffer. */
|
||||||
if (read_buf->cur < read_buf->end)
|
if (read_buf->cur < read_buf->end)
|
||||||
{
|
{
|
||||||
size_t to_read = dst_buf.size - dst_buf.end;
|
size_t to_copy = count;
|
||||||
to_read = min (to_read, read_buf->end - read_buf->cur);
|
to_copy = min (to_copy, read_buf->end - read_buf->cur);
|
||||||
memcpy (dst_buf.buf + dst_buf.end, read_buf->buf + read_buf->cur,
|
memcpy (dst_ptr, read_buf->buf + read_buf->cur, to_copy);
|
||||||
to_read);
|
dst_ptr += to_copy;
|
||||||
dst_buf.end += to_read;
|
to_read -= to_copy;
|
||||||
read_buf->cur += to_read;
|
read_buf->cur += to_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (dst_buf.end < dst_buf.size)
|
while (to_read)
|
||||||
/* If the read buffering is larger than our read size, buffer the
|
{
|
||||||
read. Otherwise read into our buffer directly. */
|
/* If the read is smaller than the buffering on the read side of
|
||||||
if (dst_buf.size - dst_buf.end < pt->read_buffering)
|
this port, then go through the buffer. Otherwise fill our
|
||||||
{
|
buffer directly. */
|
||||||
size_t to_read = dst_buf.size - dst_buf.end;
|
if (to_read < pt->read_buffering)
|
||||||
read_buf = scm_fill_input_unlocked (port);
|
{
|
||||||
if (to_read > read_buf->end - read_buf->cur)
|
size_t to_copy = to_read;
|
||||||
to_read = read_buf->end - read_buf->cur;
|
read_buf = scm_fill_input_unlocked (port);
|
||||||
if (to_read == 0)
|
to_copy = min (to_copy, read_buf->end - read_buf->cur);
|
||||||
{
|
memcpy (dst_ptr, read_buf->buf + read_buf->cur, to_copy);
|
||||||
/* Consider that we've read off this EOF. */
|
if (to_copy == 0)
|
||||||
read_buf->has_eof = 0;
|
{
|
||||||
break;
|
/* Consider that we've read off this EOF. */
|
||||||
}
|
read_buf->has_eof = 0;
|
||||||
memcpy (dst_buf.buf + dst_buf.end,
|
break;
|
||||||
read_buf->buf + read_buf->cur,
|
}
|
||||||
to_read);
|
dst_ptr += to_copy;
|
||||||
read_buf->cur += to_read;
|
to_read -= to_copy;
|
||||||
dst_buf.end += to_read;
|
read_buf->cur += to_copy;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
scm_i_read_unlocked (port, &dst_buf);
|
size_t filled;
|
||||||
if (dst_buf.has_eof)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
#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
|
size_t
|
||||||
scm_c_read (SCM port, void *buffer, size_t size)
|
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
|
#undef FUNC_NAME
|
||||||
|
|
||||||
|
static void scm_i_write_unlocked (SCM port, scm_t_port_buffer *src);
|
||||||
|
|
||||||
void
|
void
|
||||||
scm_flush_unlocked (SCM port)
|
scm_flush_unlocked (SCM port)
|
||||||
{
|
{
|
||||||
scm_t_port_buffer *buf = SCM_PTAB_ENTRY (port)->write_buf;
|
scm_t_port_buffer *buf = SCM_PTAB_ENTRY (port)->write_buf;
|
||||||
if (buf->cur < buf->end)
|
if (buf->cur < buf->end)
|
||||||
SCM_PORT_DESCRIPTOR (port)->write (port, buf);
|
scm_i_write_unlocked (port, buf);
|
||||||
buf->cur = buf->end = 0;
|
|
||||||
SCM_PTAB_ENTRY (port)->rw_active = SCM_PORT_NEITHER;
|
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_i_pthread_mutex_unlock (lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scm_c_write
|
static void
|
||||||
*
|
scm_i_write_bytes_unlocked (SCM port, SCM src, size_t start, size_t count)
|
||||||
* Used by an application to write arbitrary number of bytes to an SCM
|
{
|
||||||
* port. Similar semantics as libc write. However, unlike libc
|
size_t written;
|
||||||
* write, scm_c_write writes the requested number of bytes and has no
|
scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port);
|
||||||
* return value.
|
|
||||||
*
|
assert (count <= SCM_BYTEVECTOR_LENGTH (src));
|
||||||
* Warning: Doesn't update port line and column counts!
|
assert (start + count <= SCM_BYTEVECTOR_LENGTH (src));
|
||||||
*/
|
|
||||||
void
|
written = ptob->write (port, src, start, count);
|
||||||
scm_c_write_unlocked (SCM port, const void *ptr, size_t size)
|
|
||||||
#define FUNC_NAME "scm_c_write"
|
/* 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 *pt;
|
||||||
scm_t_port_buffer *write_buf;
|
scm_t_port_buffer *write_buf;
|
||||||
scm_t_ptob_descriptor *ptob;
|
|
||||||
|
|
||||||
SCM_VALIDATE_OPOUTPORT (1, port);
|
SCM_VALIDATE_OPOUTPORT (1, port);
|
||||||
|
|
||||||
pt = SCM_PTAB_ENTRY (port);
|
pt = SCM_PTAB_ENTRY (port);
|
||||||
ptob = SCM_PORT_DESCRIPTOR (port);
|
|
||||||
write_buf = pt->write_buf;
|
write_buf = pt->write_buf;
|
||||||
|
|
||||||
if (pt->rw_random)
|
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;
|
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
|
/* Make it so that write_buf->end is only nonzero if there are
|
||||||
buffered bytes already. */
|
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
|
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
|
full after filling it with the new data; if that's the case, we
|
||||||
flush then instead. */
|
flush then instead. */
|
||||||
if (write_buf->end + size > write_buf->size)
|
if (write_buf->end + count > write_buf->size)
|
||||||
{
|
scm_i_write_unlocked (port, write_buf);
|
||||||
ptob->write (port, write_buf);
|
|
||||||
write_buf->cur = write_buf->end = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy (write_buf->buf + write_buf->end, ptr, size);
|
memcpy (write_buf->buf + write_buf->end,
|
||||||
write_buf->end += size;
|
SCM_BYTEVECTOR_CONTENTS (src) + start,
|
||||||
|
count);
|
||||||
|
write_buf->end += count;
|
||||||
|
|
||||||
if (write_buf->end == write_buf->size)
|
if (write_buf->end == write_buf->size)
|
||||||
{
|
scm_i_write_unlocked (port, write_buf);
|
||||||
ptob->write (port, write_buf);
|
|
||||||
write_buf->cur = write_buf->end = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Our write would overflow the buffer. Flush buffered bytes (if
|
/* Our write would overflow the buffer. Flush buffered bytes (if
|
||||||
needed), then write our bytes with just one syscall. */
|
needed), then write our bytes with just one syscall. */
|
||||||
|
size_t written;
|
||||||
scm_t_port_buffer ad_hoc_buf =
|
|
||||||
{ (scm_t_uint8 *) ptr, 0, size, size, 0, NULL };
|
|
||||||
|
|
||||||
if (write_buf->cur < write_buf->end)
|
if (write_buf->cur < write_buf->end)
|
||||||
{
|
scm_i_write_unlocked (port, write_buf);
|
||||||
ptob->write (port, write_buf);
|
|
||||||
write_buf->cur = write_buf->end = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
#undef FUNC_NAME
|
||||||
|
@ -2606,6 +2762,16 @@ scm_c_write (SCM port, const void *ptr, size_t size)
|
||||||
scm_i_pthread_mutex_unlock (lock);
|
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
|
/* scm_lfwrite
|
||||||
*
|
*
|
||||||
* This function differs from scm_c_write; it updates port line and
|
* 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))
|
else if (SCM_OPOUTPORTP (object))
|
||||||
{
|
{
|
||||||
off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
|
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);
|
scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (object);
|
||||||
|
|
||||||
if (!ptob->truncate)
|
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;
|
scm_t_bits scm_tc16_void_port = 0;
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
void_port_read (SCM port, scm_t_port_buffer *buf)
|
void_port_read (SCM port, SCM dst, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
void_port_write (SCM port, scm_t_port_buffer *buf)
|
void_port_write (SCM port, SCM src, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SCM
|
static SCM
|
||||||
|
|
|
@ -87,8 +87,8 @@ typedef struct
|
||||||
peek-u8 should still return EOF. */
|
peek-u8 should still return EOF. */
|
||||||
int has_eof;
|
int has_eof;
|
||||||
|
|
||||||
/* Heap object that keeps `buf' alive. */
|
/* Bytevector whose contents are [BUF, BUF + SIZE). */
|
||||||
void *holder;
|
SCM bytevector;
|
||||||
} scm_t_port_buffer;
|
} scm_t_port_buffer;
|
||||||
|
|
||||||
|
|
||||||
|
@ -204,8 +204,8 @@ typedef struct scm_t_ptob_descriptor
|
||||||
char *name;
|
char *name;
|
||||||
int (*print) (SCM exp, SCM port, scm_print_state *pstate);
|
int (*print) (SCM exp, SCM port, scm_print_state *pstate);
|
||||||
|
|
||||||
void (*read) (SCM port, scm_t_port_buffer *dst);
|
size_t (*read) (SCM port, SCM dst, size_t start, size_t count);
|
||||||
void (*write) (SCM port, scm_t_port_buffer *src);
|
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);
|
scm_t_off (*seek) (SCM port, scm_t_off OFFSET, int WHENCE);
|
||||||
void (*close) (SCM port);
|
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 long scm_c_port_type_add_x (scm_t_ptob_descriptor *desc);
|
||||||
SCM_API scm_t_bits scm_make_port_type
|
SCM_API scm_t_bits scm_make_port_type
|
||||||
(char *name,
|
(char *name,
|
||||||
void (*read) (SCM port, scm_t_port_buffer *dst),
|
size_t (*read) (SCM port, SCM dst, size_t start, size_t count),
|
||||||
void (*write) (SCM port, scm_t_port_buffer *src));
|
size_t (*write) (SCM port, SCM src, size_t start, size_t count));
|
||||||
SCM_API void scm_set_port_print (scm_t_bits tc,
|
SCM_API void scm_set_port_print (scm_t_bits tc,
|
||||||
int (*print) (SCM exp,
|
int (*print) (SCM exp,
|
||||||
SCM port,
|
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 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 (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_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 (SCM port);
|
||||||
SCM_API scm_t_wchar scm_getc_unlocked (SCM port);
|
SCM_API scm_t_wchar scm_getc_unlocked (SCM port);
|
||||||
SCM_API SCM scm_read_char (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_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 (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_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 (const char *ptr, size_t size, SCM port);
|
||||||
SCM_API void scm_lfwrite_unlocked (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,
|
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);
|
(scm_t_bits) stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
bytevector_input_port_read (SCM port, scm_t_port_buffer *buf)
|
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);
|
struct bytevector_input_port *stream = (void *) SCM_STREAM (port);
|
||||||
|
|
||||||
if (stream->pos >= SCM_BYTEVECTOR_LENGTH (stream->bytevector))
|
if (stream->pos >= SCM_BYTEVECTOR_LENGTH (stream->bytevector))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
count = SCM_BYTEVECTOR_LENGTH (stream->bytevector) - stream->pos;
|
remaining = SCM_BYTEVECTOR_LENGTH (stream->bytevector) - stream->pos;
|
||||||
if (count > buf->size - buf->end)
|
if (remaining < count)
|
||||||
count = buf->size - buf->end;
|
count = remaining;
|
||||||
|
|
||||||
memcpy (buf->buf + buf->end,
|
memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
|
||||||
SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
|
SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
|
||||||
count);
|
count);
|
||||||
|
|
||||||
buf->end += count;
|
|
||||||
stream->pos += count;
|
stream->pos += count;
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static scm_t_off
|
static scm_t_off
|
||||||
|
@ -277,32 +278,21 @@ make_custom_binary_input_port (SCM read_proc, SCM get_position_proc,
|
||||||
(scm_t_bits) stream);
|
(scm_t_bits) stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
custom_binary_input_port_read (SCM port, scm_t_port_buffer *buf)
|
custom_binary_input_port_read (SCM port, SCM dst, size_t start, size_t count)
|
||||||
#define FUNC_NAME "custom_binary_input_port_read"
|
#define FUNC_NAME "custom_binary_input_port_read"
|
||||||
{
|
{
|
||||||
struct custom_binary_port *stream = (void *) SCM_STREAM (port);
|
struct custom_binary_port *stream = (void *) SCM_STREAM (port);
|
||||||
SCM bv, octets;
|
SCM octets;
|
||||||
size_t c_octets;
|
size_t c_octets;
|
||||||
|
|
||||||
/* FIXME: We need to make sure buf->buf is kept alive. If read_buf is
|
octets = scm_call_3 (stream->read, dst, scm_from_size_t (start),
|
||||||
referenced from PORT, passing PORT as the parent will do it. But,
|
scm_from_size_t (count));
|
||||||
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));
|
|
||||||
c_octets = scm_to_size_t (octets);
|
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);
|
scm_out_of_range (FUNC_NAME, octets);
|
||||||
|
|
||||||
buf->end += c_octets;
|
return c_octets;
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#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
|
#define FUNC_NAME s_scm_get_bytevector_n
|
||||||
{
|
{
|
||||||
SCM result;
|
SCM result;
|
||||||
char *c_bv;
|
|
||||||
unsigned c_count;
|
unsigned c_count;
|
||||||
size_t c_read;
|
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);
|
c_count = scm_to_uint (count);
|
||||||
|
|
||||||
result = scm_c_make_bytevector (c_count);
|
result = scm_c_make_bytevector (c_count);
|
||||||
c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (result);
|
|
||||||
|
|
||||||
if (SCM_LIKELY (c_count > 0))
|
if (SCM_LIKELY (c_count > 0))
|
||||||
/* XXX: `scm_c_read ()' does not update the port position. */
|
/* 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
|
else
|
||||||
/* Don't invoke `scm_c_read ()' since it may block. */
|
/* Don't invoke `scm_c_read ()' since it may block. */
|
||||||
c_read = 0;
|
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
|
#define FUNC_NAME s_scm_get_bytevector_n_x
|
||||||
{
|
{
|
||||||
SCM result;
|
SCM result;
|
||||||
char *c_bv;
|
|
||||||
unsigned c_start, c_count, c_len;
|
unsigned c_start, c_count, c_len;
|
||||||
size_t c_read;
|
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_start = scm_to_uint (start);
|
||||||
c_count = scm_to_uint (count);
|
c_count = scm_to_uint (count);
|
||||||
|
|
||||||
c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
|
|
||||||
c_len = SCM_BYTEVECTOR_LENGTH (bv);
|
c_len = SCM_BYTEVECTOR_LENGTH (bv);
|
||||||
|
|
||||||
if (SCM_UNLIKELY (c_start + c_count > c_len))
|
if (SCM_UNLIKELY (c_start + c_count > c_len))
|
||||||
scm_out_of_range (FUNC_NAME, count);
|
scm_out_of_range (FUNC_NAME, count);
|
||||||
|
|
||||||
if (SCM_LIKELY (c_count > 0))
|
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
|
else
|
||||||
/* Don't invoke `scm_c_read ()' since it may block. */
|
/* Don't invoke `scm_c_read ()' since it may block. */
|
||||||
c_read = 0;
|
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
|
#define FUNC_NAME s_scm_get_bytevector_all
|
||||||
{
|
{
|
||||||
SCM result;
|
SCM result;
|
||||||
char *c_bv;
|
|
||||||
unsigned c_len, c_count;
|
unsigned c_len, c_count;
|
||||||
size_t c_read, c_total;
|
size_t c_read, c_total;
|
||||||
|
|
||||||
SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
|
SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
|
||||||
|
|
||||||
c_len = c_count = 4096;
|
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;
|
c_total = c_read = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -528,37 +513,27 @@ SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0,
|
||||||
if (c_total + c_read > c_len)
|
if (c_total + c_read > c_len)
|
||||||
{
|
{
|
||||||
/* Grow the bytevector. */
|
/* Grow the bytevector. */
|
||||||
c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2,
|
SCM prev = result;
|
||||||
SCM_GC_BYTEVECTOR);
|
result = scm_c_make_bytevector (c_len * 2);
|
||||||
|
memcpy (SCM_BYTEVECTOR_CONTENTS (result),
|
||||||
|
SCM_BYTEVECTOR_CONTENTS (prev),
|
||||||
|
c_total);
|
||||||
c_count = c_len;
|
c_count = c_len;
|
||||||
c_len *= 2;
|
c_len *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
|
/* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
|
||||||
reached. */
|
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;
|
c_total += c_read, c_count -= c_read;
|
||||||
}
|
}
|
||||||
while (c_count == 0);
|
while (c_count == 0);
|
||||||
|
|
||||||
if (c_total == 0)
|
if (c_total == 0)
|
||||||
{
|
return SCM_EOF_VAL;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = scm_c_take_gc_bytevector ((signed char *) c_bv, c_len,
|
if (c_len > c_total)
|
||||||
SCM_BOOL_F);
|
return scm_c_shrink_bytevector (result, c_total);
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -596,14 +571,12 @@ SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
|
||||||
"octets.")
|
"octets.")
|
||||||
#define FUNC_NAME s_scm_put_bytevector
|
#define FUNC_NAME s_scm_put_bytevector
|
||||||
{
|
{
|
||||||
char *c_bv;
|
|
||||||
unsigned c_start, c_count, c_len;
|
unsigned c_start, c_count, c_len;
|
||||||
|
|
||||||
SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
|
SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
|
||||||
SCM_VALIDATE_BYTEVECTOR (2, bv);
|
SCM_VALIDATE_BYTEVECTOR (2, bv);
|
||||||
|
|
||||||
c_len = SCM_BYTEVECTOR_LENGTH (bv);
|
c_len = SCM_BYTEVECTOR_LENGTH (bv);
|
||||||
c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
|
|
||||||
|
|
||||||
if (!scm_is_eq (start, SCM_UNDEFINED))
|
if (!scm_is_eq (start, SCM_UNDEFINED))
|
||||||
{
|
{
|
||||||
|
@ -626,7 +599,7 @@ SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
|
||||||
else
|
else
|
||||||
c_start = 0, c_count = c_len;
|
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;
|
return SCM_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
@ -777,21 +750,22 @@ make_bytevector_output_port (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write octets from WRITE_BUF to the backing store. */
|
/* Write octets from WRITE_BUF to the backing store. */
|
||||||
static void
|
static size_t
|
||||||
bytevector_output_port_write (SCM port, scm_t_port_buffer *write_buf)
|
bytevector_output_port_write (SCM port, SCM src, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
size_t count;
|
|
||||||
scm_t_bytevector_output_port_buffer *buf;
|
scm_t_bytevector_output_port_buffer *buf;
|
||||||
|
|
||||||
buf = SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER (port);
|
buf = SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER (port);
|
||||||
count = write_buf->end - write_buf->cur;
|
|
||||||
|
|
||||||
if (buf->pos + count > buf->total_len)
|
if (buf->pos + count > buf->total_len)
|
||||||
bytevector_output_port_buffer_grow (buf, buf->pos + count);
|
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->pos += count;
|
||||||
buf->len = (buf->len > buf->pos) ? buf->len : buf->pos;
|
buf->len = (buf->len > buf->pos) ? buf->len : buf->pos;
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static scm_t_off
|
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. */
|
/* Flush octets from BUF to the backing store. */
|
||||||
static void
|
static size_t
|
||||||
custom_binary_output_port_write (SCM port, scm_t_port_buffer *buf)
|
custom_binary_output_port_write (SCM port, SCM src, size_t start, size_t count)
|
||||||
#define FUNC_NAME "custom_binary_output_port_write"
|
#define FUNC_NAME "custom_binary_output_port_write"
|
||||||
{
|
{
|
||||||
size_t size, written;
|
size_t written;
|
||||||
struct custom_binary_port *stream = (void *) SCM_STREAM (port);
|
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
|
/* 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
|
try hard to write exactly SIZE bytes, regardless of how many bytes the
|
||||||
sink can handle. */
|
sink can handle. */
|
||||||
written = 0;
|
written = 0;
|
||||||
while (written < size)
|
while (written < count)
|
||||||
{
|
{
|
||||||
long int c_result;
|
long int c_result;
|
||||||
SCM result;
|
SCM result;
|
||||||
|
|
||||||
result = scm_call_3 (stream->write, bv,
|
result = scm_call_3 (stream->write, src,
|
||||||
scm_from_size_t (written),
|
scm_from_size_t (start + written),
|
||||||
scm_from_size_t (size - written));
|
scm_from_size_t (count - written));
|
||||||
|
|
||||||
c_result = scm_to_long (result);
|
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,
|
scm_wrong_type_arg_msg (FUNC_NAME, 0, result,
|
||||||
"R6RS custom binary output port `write!' "
|
"R6RS custom binary output port `write!' "
|
||||||
"returned a incorrect integer");
|
"returned a incorrect integer");
|
||||||
written += c_result;
|
written += c_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return written;
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
||||||
|
@ -1008,32 +976,19 @@ make_transcoded_port (SCM binary_port, unsigned long mode)
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
transcoded_port_write (SCM port, scm_t_port_buffer *buf)
|
transcoded_port_write (SCM port, SCM src, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port);
|
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
|
static size_t
|
||||||
transcoded_port_read (SCM port, scm_t_port_buffer *buf)
|
transcoded_port_read (SCM port, SCM dst, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
size_t count;
|
SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port);
|
||||||
scm_t_port_buffer *bport_buf;
|
return scm_c_read_bytes (bport, dst, start, count);
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -60,31 +60,29 @@ struct string_port {
|
||||||
size_t len;
|
size_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
string_port_read (SCM port, scm_t_port_buffer *dst)
|
string_port_read (SCM port, SCM dst, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
size_t count;
|
|
||||||
struct string_port *stream = (void *) SCM_STREAM (port);
|
struct string_port *stream = (void *) SCM_STREAM (port);
|
||||||
|
|
||||||
if (stream->pos >= stream->len)
|
if (stream->pos >= stream->len)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
count = stream->len - stream->pos;
|
if (count > stream->len - stream->pos)
|
||||||
if (count > dst->size - dst->end)
|
count = stream->len - stream->pos;
|
||||||
count = dst->size - dst->end;
|
|
||||||
|
|
||||||
memcpy (dst->buf + dst->end,
|
memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
|
||||||
SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
|
SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
|
||||||
count);
|
count);
|
||||||
dst->end += count;
|
|
||||||
stream->pos += count;
|
stream->pos += count;
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
string_port_write (SCM port, scm_t_port_buffer *src)
|
string_port_write (SCM port, SCM src, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
struct string_port *stream = (void *) SCM_STREAM (port);
|
struct string_port *stream = (void *) SCM_STREAM (port);
|
||||||
size_t count = src->end - src->cur;
|
|
||||||
|
|
||||||
if (SCM_BYTEVECTOR_LENGTH (stream->bytevector) < stream->pos + count)
|
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,
|
memcpy (SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
|
||||||
src->buf + src->cur,
|
SCM_BYTEVECTOR_CONTENTS (src) + start,
|
||||||
count);
|
count);
|
||||||
src->cur += count;
|
|
||||||
stream->pos += count;
|
stream->pos += count;
|
||||||
if (stream->pos > stream->len)
|
if (stream->pos > stream->len)
|
||||||
stream->len = stream->pos;
|
stream->len = stream->pos;
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static scm_t_off
|
static scm_t_off
|
||||||
|
|
|
@ -72,27 +72,30 @@ soft_port_get_natural_buffer_sizes (SCM port, size_t *read_size,
|
||||||
*write_size = 1;
|
*write_size = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
soft_port_write (SCM port, scm_t_port_buffer *buf)
|
soft_port_write (SCM port, SCM src, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
struct soft_port *stream = (void *) SCM_STREAM (port);
|
struct soft_port *stream = (void *) SCM_STREAM (port);
|
||||||
scm_t_uint8 * ptr = buf->buf + buf->cur;
|
signed char * ptr = SCM_BYTEVECTOR_CONTENTS (src) + start;
|
||||||
SCM str = scm_from_port_stringn ((char *) ptr, buf->end - buf->cur, port);
|
|
||||||
buf->end = buf->cur = 0;
|
|
||||||
|
|
||||||
scm_call_1 (stream->write_string, str);
|
scm_call_1 (stream->write_string,
|
||||||
|
scm_from_port_stringn ((char *) ptr, count, port));
|
||||||
|
|
||||||
/* Backwards compatibility. */
|
/* Backwards compatibility. */
|
||||||
if (scm_is_true (stream->flush))
|
if (scm_is_true (stream->flush))
|
||||||
scm_call_0 (stream->flush);
|
scm_call_0 (stream->flush);
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* places a single char in the input buffer. */
|
/* places a single char in the input buffer. */
|
||||||
static void
|
static size_t
|
||||||
soft_port_read (SCM port, scm_t_port_buffer *dst)
|
soft_port_read (SCM port, SCM dst, size_t start, size_t count)
|
||||||
{
|
{
|
||||||
|
size_t written;
|
||||||
struct soft_port *stream = (void *) SCM_STREAM (port);
|
struct soft_port *stream = (void *) SCM_STREAM (port);
|
||||||
scm_t_port_buffer *encode_buf = stream->encode_buf;
|
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
|
/* 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,
|
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);
|
ans = scm_call_0 (stream->read_char);
|
||||||
if (scm_is_false (ans) || SCM_EOF_OBJECT_P (ans))
|
if (scm_is_false (ans) || SCM_EOF_OBJECT_P (ans))
|
||||||
return;
|
return 0;
|
||||||
SCM_ASSERT (SCM_CHARP (ans), ans, SCM_ARG1, "soft_port_read");
|
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
|
/* 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);
|
free (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (dst->end < dst->size && encode_buf->cur < encode_buf->end)
|
for (written = 0;
|
||||||
dst->buf[dst->end++] = encode_buf->buf[encode_buf->cur++];
|
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);
|
return scm_c_make_port (port_type, SCM_RDNG, (scm_t_bits) stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static size_t
|
||||||
custom_port_read (SCM port, scm_t_port_buffer *dst)
|
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);
|
struct custom_port *stream = (void *) SCM_STREAM (port);
|
||||||
|
|
||||||
if (stream->pos + to_copy > stream->len)
|
if (stream->pos + to_copy > stream->len)
|
||||||
to_copy = stream->len - stream->pos;
|
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;
|
stream->pos += to_copy;
|
||||||
dst->end += to_copy;
|
|
||||||
|
return to_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true (non-zero) if BUF contains only zeros. */
|
/* Return true (non-zero) if BUF contains only zeros. */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue