1
Fork 0
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:
Andy Wingo 2016-04-11 18:40:03 +02:00
parent 55fb8f4e7e
commit f7027a8b88
7 changed files with 372 additions and 240 deletions

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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. */