diff --git a/libguile/fports.c b/libguile/fports.c index 3e4756204..11aa1707b 100644 --- a/libguile/fports.c +++ b/libguile/fports.c @@ -578,29 +578,29 @@ fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED) /* fill a port's read-buffer with a single read. returns the first char or EOF if end of file. */ -static void -fport_read (SCM port, scm_t_port_buffer *dst) +static size_t +fport_read (SCM port, SCM dst, size_t start, size_t count) { - long count; + long res; scm_t_fport *fp = SCM_FSTREAM (port); - scm_t_uint8 *ptr = dst->buf + dst->end; - size_t size = dst->size - dst->end; + signed char *ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start; - SCM_SYSCALL (count = read (fp->fdes, ptr, size)); - if (count == -1) + SCM_SYSCALL (res = read (fp->fdes, ptr, count)); + if (res == -1) scm_syserror ("fport_read"); - dst->end += count; + return res; } -static void -fport_write (SCM port, scm_t_port_buffer *src) +static size_t +fport_write (SCM port, SCM src, size_t start, size_t count) { int fd = SCM_FPORT_FDES (port); - scm_t_uint8 *ptr = src->buf + src->cur; - size_t size = src->end - src->cur; + signed char *ptr = SCM_BYTEVECTOR_CONTENTS (src) + start; - if (full_write (fd, ptr, size) < size) + if (full_write (fd, ptr, count) < count) scm_syserror ("fport_write"); + + return count; } static scm_t_off diff --git a/libguile/ports.c b/libguile/ports.c index 8f07425e3..144daef3f 100644 --- a/libguile/ports.c +++ b/libguile/ports.c @@ -229,8 +229,10 @@ static const size_t default_buffer_size = 1024; scm_t_bits scm_make_port_type (char *name, - void (*read) (SCM port, scm_t_port_buffer *buf), - void (*write) (SCM port, scm_t_port_buffer *buf)) + size_t (*read) (SCM port, SCM dst, size_t start, + size_t count), + size_t (*write) (SCM port, SCM src, size_t start, + size_t count)) { scm_t_ptob_descriptor *desc; long ptobnum; @@ -527,7 +529,8 @@ scm_c_make_port_buffer (size_t size) scm_t_port_buffer *ret = scm_gc_typed_calloc (scm_t_port_buffer); ret->size = size; - ret->buf = scm_gc_malloc_pointerless (ret->size, "port buffer"); + ret->bytevector = scm_c_make_bytevector (size); + ret->buf = (scm_t_uint8 *) SCM_BYTEVECTOR_CONTENTS (ret->bytevector); return ret; } @@ -1432,33 +1435,51 @@ scm_peek_byte_or_eof (SCM port) return ret; } +static size_t +scm_i_read_bytes_unlocked (SCM port, SCM dst, size_t start, size_t count) +{ + size_t filled; + scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port); + + assert (count <= SCM_BYTEVECTOR_LENGTH (dst)); + assert (start + count <= SCM_BYTEVECTOR_LENGTH (dst)); + + filled = ptob->read (port, dst, start, count); + + assert (filled <= count); + + return filled; +} + /* scm_i_read_unlocked is used internally to add bytes to the given port buffer. If the number of available bytes in the buffer does not increase after a call to scm_i_read_unlocked, that indicates EOF. */ static void scm_i_read_unlocked (SCM port, scm_t_port_buffer *buf) { - size_t prev_end = buf->end; + size_t count; + assert (buf->end < buf->size); - SCM_PORT_DESCRIPTOR (port)->read (port, buf); - buf->has_eof = buf->end == prev_end; + count = scm_i_read_bytes_unlocked (port, buf->bytevector, buf->end, + buf->size - buf->end); + buf->end += count; + buf->has_eof = count == 0; } -/* scm_c_read - * - * Used by an application to read arbitrary number of bytes from an SCM - * port. Same semantics as libc read, except that scm_c_read only - * returns less than SIZE bytes if at end-of-file. - * - * Warning: Doesn't update port line and column counts! */ -size_t -scm_c_read_unlocked (SCM port, void *buffer, size_t size) -#define FUNC_NAME "scm_c_read" +/* Used by an application to read arbitrary number of bytes from an SCM + port. Same semantics as libc read, except that scm_c_read_bytes only + returns less than SIZE bytes if at end-of-file. + + Warning: Doesn't update port line and column counts! */ +static size_t +scm_c_read_bytes_unlocked (SCM port, SCM dst, size_t start, size_t count) +#define FUNC_NAME "scm_c_read_bytes" { + size_t to_read = count; scm_t_port *pt; scm_t_port_buffer *read_buf; - scm_t_port_buffer dst_buf = { buffer, 0, 0, size, 0, NULL }; + signed char *dst_ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start; SCM_VALIDATE_OPINPORT (1, port); @@ -1475,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 diff --git a/libguile/ports.h b/libguile/ports.h index 80e3a6774..e7277e3ab 100644 --- a/libguile/ports.h +++ b/libguile/ports.h @@ -87,8 +87,8 @@ typedef struct peek-u8 should still return EOF. */ int has_eof; - /* Heap object that keeps `buf' alive. */ - void *holder; + /* Bytevector whose contents are [BUF, BUF + SIZE). */ + SCM bytevector; } scm_t_port_buffer; @@ -204,8 +204,8 @@ typedef struct scm_t_ptob_descriptor char *name; int (*print) (SCM exp, SCM port, scm_print_state *pstate); - void (*read) (SCM port, scm_t_port_buffer *dst); - void (*write) (SCM port, scm_t_port_buffer *src); + size_t (*read) (SCM port, SCM dst, size_t start, size_t count); + size_t (*write) (SCM port, SCM src, size_t start, size_t count); scm_t_off (*seek) (SCM port, scm_t_off OFFSET, int WHENCE); void (*close) (SCM port); @@ -230,8 +230,8 @@ SCM_API scm_t_ptob_descriptor* scm_c_port_type_ref (long ptobnum); SCM_API long scm_c_port_type_add_x (scm_t_ptob_descriptor *desc); SCM_API scm_t_bits scm_make_port_type (char *name, - void (*read) (SCM port, scm_t_port_buffer *dst), - void (*write) (SCM port, scm_t_port_buffer *src)); + size_t (*read) (SCM port, SCM dst, size_t start, size_t count), + size_t (*write) (SCM port, SCM src, size_t start, size_t count)); SCM_API void scm_set_port_print (scm_t_bits tc, int (*print) (SCM exp, SCM port, @@ -323,6 +323,7 @@ SCM_INLINE int scm_peek_byte_or_eof_unlocked (SCM port); SCM_API int scm_slow_peek_byte_or_eof_unlocked (SCM port); SCM_API size_t scm_c_read (SCM port, void *buffer, size_t size); SCM_API size_t scm_c_read_unlocked (SCM port, void *buffer, size_t size); +SCM_API size_t scm_c_read_bytes (SCM port, SCM dst, size_t start, size_t count); SCM_API scm_t_wchar scm_getc (SCM port); SCM_API scm_t_wchar scm_getc_unlocked (SCM port); SCM_API SCM scm_read_char (SCM port); @@ -359,6 +360,7 @@ SCM_API void scm_puts (const char *str_data, SCM port); SCM_INLINE void scm_puts_unlocked (const char *str_data, SCM port); SCM_API void scm_c_write (SCM port, const void *buffer, size_t size); SCM_API void scm_c_write_unlocked (SCM port, const void *buffer, size_t size); +SCM_API void scm_c_write_bytes (SCM port, SCM src, size_t start, size_t count); SCM_API void scm_lfwrite (const char *ptr, size_t size, SCM port); SCM_API void scm_lfwrite_unlocked (const char *ptr, size_t size, SCM port); SCM_INTERNAL void scm_lfwrite_substr (SCM str, size_t start, size_t end, diff --git a/libguile/r6rs-ports.c b/libguile/r6rs-ports.c index aa54a0e67..fb821bb18 100644 --- a/libguile/r6rs-ports.c +++ b/libguile/r6rs-ports.c @@ -99,25 +99,26 @@ make_bytevector_input_port (SCM bv) (scm_t_bits) stream); } -static void -bytevector_input_port_read (SCM port, scm_t_port_buffer *buf) +static size_t +bytevector_input_port_read (SCM port, SCM dst, size_t start, size_t count) { - size_t count; + size_t remaining; struct bytevector_input_port *stream = (void *) SCM_STREAM (port); if (stream->pos >= SCM_BYTEVECTOR_LENGTH (stream->bytevector)) - return; + return 0; - count = SCM_BYTEVECTOR_LENGTH (stream->bytevector) - stream->pos; - if (count > buf->size - buf->end) - count = buf->size - buf->end; + remaining = SCM_BYTEVECTOR_LENGTH (stream->bytevector) - stream->pos; + if (remaining < count) + count = remaining; - memcpy (buf->buf + buf->end, + memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start, SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos, count); - buf->end += count; stream->pos += count; + + return count; } static scm_t_off @@ -277,32 +278,21 @@ make_custom_binary_input_port (SCM read_proc, SCM get_position_proc, (scm_t_bits) stream); } -static void -custom_binary_input_port_read (SCM port, scm_t_port_buffer *buf) +static size_t +custom_binary_input_port_read (SCM port, SCM dst, size_t start, size_t count) #define FUNC_NAME "custom_binary_input_port_read" { struct custom_binary_port *stream = (void *) SCM_STREAM (port); - SCM bv, octets; + SCM octets; size_t c_octets; - /* FIXME: We need to make sure buf->buf is kept alive. If read_buf is - referenced from PORT, passing PORT as the parent will do it. But, - pushback could re-set PORT->read_buf, which would be a fail. But, - probably buf->buf is itself GC-allocated, so we can pack it - directly. But, perhaps it's not, as in scm_c_read(). In that - latter case we're kinda screwed and probably need to prevent - rewinding. But shouldn't we always prevent rewinding? And how can - we avoid allocating the bytevector at all? */ - bv = scm_c_take_gc_bytevector ((signed char *) (buf->buf + buf->end), - buf->size - buf->end, - PTR2SCM (buf->buf)); - - octets = scm_call_3 (stream->read, bv, SCM_INUM0, scm_bytevector_length (bv)); + octets = scm_call_3 (stream->read, dst, scm_from_size_t (start), + scm_from_size_t (count)); c_octets = scm_to_size_t (octets); - if (c_octets > scm_c_bytevector_length (bv)) + if (c_octets > count) scm_out_of_range (FUNC_NAME, octets); - buf->end += c_octets; + return c_octets; } #undef FUNC_NAME @@ -405,7 +395,6 @@ SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 0, 0, #define FUNC_NAME s_scm_get_bytevector_n { SCM result; - char *c_bv; unsigned c_count; size_t c_read; @@ -413,11 +402,10 @@ SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 0, 0, c_count = scm_to_uint (count); result = scm_c_make_bytevector (c_count); - c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (result); if (SCM_LIKELY (c_count > 0)) /* XXX: `scm_c_read ()' does not update the port position. */ - c_read = scm_c_read_unlocked (port, c_bv, c_count); + c_read = scm_c_read_bytes (port, result, 0, c_count); else /* Don't invoke `scm_c_read ()' since it may block. */ c_read = 0; @@ -443,7 +431,6 @@ SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0, #define FUNC_NAME s_scm_get_bytevector_n_x { SCM result; - char *c_bv; unsigned c_start, c_count, c_len; size_t c_read; @@ -452,14 +439,13 @@ SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0, c_start = scm_to_uint (start); c_count = scm_to_uint (count); - c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv); c_len = SCM_BYTEVECTOR_LENGTH (bv); if (SCM_UNLIKELY (c_start + c_count > c_len)) scm_out_of_range (FUNC_NAME, count); if (SCM_LIKELY (c_count > 0)) - c_read = scm_c_read_unlocked (port, c_bv + c_start, c_count); + c_read = scm_c_read_bytes (port, bv, c_start, c_count); else /* Don't invoke `scm_c_read ()' since it may block. */ c_read = 0; @@ -513,14 +499,13 @@ SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0, #define FUNC_NAME s_scm_get_bytevector_all { SCM result; - char *c_bv; unsigned c_len, c_count; size_t c_read, c_total; SCM_VALIDATE_BINARY_INPUT_PORT (1, port); c_len = c_count = 4096; - c_bv = (char *) scm_gc_malloc_pointerless (c_len, SCM_GC_BYTEVECTOR); + result = scm_c_make_bytevector (c_count); c_total = c_read = 0; do @@ -528,37 +513,27 @@ SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0, if (c_total + c_read > c_len) { /* Grow the bytevector. */ - c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2, - SCM_GC_BYTEVECTOR); + SCM prev = result; + result = scm_c_make_bytevector (c_len * 2); + memcpy (SCM_BYTEVECTOR_CONTENTS (result), + SCM_BYTEVECTOR_CONTENTS (prev), + c_total); c_count = c_len; c_len *= 2; } /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is reached. */ - c_read = scm_c_read_unlocked (port, c_bv + c_total, c_count); + c_read = scm_c_read_bytes (port, result, c_total, c_count); c_total += c_read, c_count -= c_read; } while (c_count == 0); if (c_total == 0) - { - result = SCM_EOF_VAL; - scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR); - } - else - { - if (c_len > c_total) - { - /* Shrink the bytevector. */ - c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_total, - SCM_GC_BYTEVECTOR); - c_len = (unsigned) c_total; - } + return SCM_EOF_VAL; - result = scm_c_take_gc_bytevector ((signed char *) c_bv, c_len, - SCM_BOOL_F); - } + if (c_len > c_total) + return scm_c_shrink_bytevector (result, c_total); return result; } @@ -596,14 +571,12 @@ SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0, "octets.") #define FUNC_NAME s_scm_put_bytevector { - char *c_bv; unsigned c_start, c_count, c_len; SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port); SCM_VALIDATE_BYTEVECTOR (2, bv); c_len = SCM_BYTEVECTOR_LENGTH (bv); - c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv); if (!scm_is_eq (start, SCM_UNDEFINED)) { @@ -626,7 +599,7 @@ SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0, else c_start = 0, c_count = c_len; - scm_c_write_unlocked (port, c_bv + c_start, c_count); + scm_c_write_bytes (port, bv, c_start, c_count); return SCM_UNSPECIFIED; } @@ -777,21 +750,22 @@ make_bytevector_output_port (void) } /* Write octets from WRITE_BUF to the backing store. */ -static void -bytevector_output_port_write (SCM port, scm_t_port_buffer *write_buf) +static size_t +bytevector_output_port_write (SCM port, SCM src, size_t start, size_t count) { - size_t count; scm_t_bytevector_output_port_buffer *buf; buf = SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER (port); - count = write_buf->end - write_buf->cur; if (buf->pos + count > buf->total_len) bytevector_output_port_buffer_grow (buf, buf->pos + count); - memcpy (buf->buffer + buf->pos, write_buf->buf + write_buf->cur, count); + memcpy (buf->buffer + buf->pos, SCM_BYTEVECTOR_CONTENTS (src) + start, count); + buf->pos += count; buf->len = (buf->len > buf->pos) ? buf->len : buf->pos; + + return count; } static scm_t_off @@ -909,41 +883,35 @@ make_custom_binary_output_port (SCM write_proc, SCM get_position_proc, } /* Flush octets from BUF to the backing store. */ -static void -custom_binary_output_port_write (SCM port, scm_t_port_buffer *buf) +static size_t +custom_binary_output_port_write (SCM port, SCM src, size_t start, size_t count) #define FUNC_NAME "custom_binary_output_port_write" { - size_t size, written; + size_t written; struct custom_binary_port *stream = (void *) SCM_STREAM (port); - SCM bv; - - /* FIXME: If BUF is the same as PORT->write_buf, then the data is - GC-managed and we could avoid allocating a new bytevector backing - store. Otherwise we have to copy, as we do here. */ - size = buf->end - buf->cur; - bv = scm_c_make_bytevector (size); - memcpy (SCM_BYTEVECTOR_CONTENTS (bv), buf->buf + buf->cur, size); /* Since the `write' procedure of Guile's ports has type `void', it must try hard to write exactly SIZE bytes, regardless of how many bytes the sink can handle. */ written = 0; - while (written < size) + while (written < count) { long int c_result; SCM result; - result = scm_call_3 (stream->write, bv, - scm_from_size_t (written), - scm_from_size_t (size - written)); + result = scm_call_3 (stream->write, src, + scm_from_size_t (start + written), + scm_from_size_t (count - written)); c_result = scm_to_long (result); - if (c_result < 0 || (size_t) c_result > (size - written)) + if (c_result < 0 || (size_t) c_result > (count - written)) scm_wrong_type_arg_msg (FUNC_NAME, 0, result, "R6RS custom binary output port `write!' " "returned a incorrect integer"); written += c_result; } + + return written; } #undef FUNC_NAME @@ -1008,32 +976,19 @@ make_transcoded_port (SCM binary_port, unsigned long mode) return port; } -static void -transcoded_port_write (SCM port, scm_t_port_buffer *buf) +static size_t +transcoded_port_write (SCM port, SCM src, size_t start, size_t count) { SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port); - scm_c_write_unlocked (bport, buf->buf + buf->cur, buf->end - buf->cur); + scm_c_write_bytes (bport, src, start, count); + return count; } -static void -transcoded_port_read (SCM port, scm_t_port_buffer *buf) +static size_t +transcoded_port_read (SCM port, SCM dst, size_t start, size_t count) { - size_t count; - scm_t_port_buffer *bport_buf; - - /* We can't use `scm_c_read' here, since it blocks until the whole - block has been read or EOF. */ - - bport_buf = scm_fill_input (SCM_TRANSCODED_PORT_BINARY_PORT (port)); - /* Consume EOF from bport. */ - bport_buf->has_eof = 0; - count = bport_buf->end - bport_buf->cur; - if (count > buf->size - buf->end) - count = buf->size - buf->end; - - memcpy (buf->buf + buf->end, bport_buf->buf + bport_buf->cur, count); - bport_buf->cur += count; - buf->end += count; + SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port); + return scm_c_read_bytes (bport, dst, start, count); } static void diff --git a/libguile/strports.c b/libguile/strports.c index 6ad7d18f2..e8ce67a8f 100644 --- a/libguile/strports.c +++ b/libguile/strports.c @@ -60,31 +60,29 @@ struct string_port { size_t len; }; -static void -string_port_read (SCM port, scm_t_port_buffer *dst) +static size_t +string_port_read (SCM port, SCM dst, size_t start, size_t count) { - size_t count; struct string_port *stream = (void *) SCM_STREAM (port); if (stream->pos >= stream->len) - return; + return 0; - count = stream->len - stream->pos; - if (count > dst->size - dst->end) - count = dst->size - dst->end; + if (count > stream->len - stream->pos) + count = stream->len - stream->pos; - memcpy (dst->buf + dst->end, + memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start, SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos, count); - dst->end += count; + stream->pos += count; + return count; } -static void -string_port_write (SCM port, scm_t_port_buffer *src) +static size_t +string_port_write (SCM port, SCM src, size_t start, size_t count) { struct string_port *stream = (void *) SCM_STREAM (port); - size_t count = src->end - src->cur; if (SCM_BYTEVECTOR_LENGTH (stream->bytevector) < stream->pos + count) { @@ -101,12 +99,13 @@ string_port_write (SCM port, scm_t_port_buffer *src) } memcpy (SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos, - src->buf + src->cur, + SCM_BYTEVECTOR_CONTENTS (src) + start, count); - src->cur += count; stream->pos += count; if (stream->pos > stream->len) stream->len = stream->pos; + + return count; } static scm_t_off diff --git a/libguile/vports.c b/libguile/vports.c index 82fef1e0b..e52057065 100644 --- a/libguile/vports.c +++ b/libguile/vports.c @@ -72,27 +72,30 @@ soft_port_get_natural_buffer_sizes (SCM port, size_t *read_size, *write_size = 1; } -static void -soft_port_write (SCM port, scm_t_port_buffer *buf) +static size_t +soft_port_write (SCM port, SCM src, size_t start, size_t count) { struct soft_port *stream = (void *) SCM_STREAM (port); - scm_t_uint8 * ptr = buf->buf + buf->cur; - SCM str = scm_from_port_stringn ((char *) ptr, buf->end - buf->cur, port); - buf->end = buf->cur = 0; + signed char * ptr = SCM_BYTEVECTOR_CONTENTS (src) + start; - scm_call_1 (stream->write_string, str); + scm_call_1 (stream->write_string, + scm_from_port_stringn ((char *) ptr, count, port)); /* Backwards compatibility. */ if (scm_is_true (stream->flush)) scm_call_0 (stream->flush); + + return count; } /* places a single char in the input buffer. */ -static void -soft_port_read (SCM port, scm_t_port_buffer *dst) +static size_t +soft_port_read (SCM port, SCM dst, size_t start, size_t count) { + size_t written; struct soft_port *stream = (void *) SCM_STREAM (port); scm_t_port_buffer *encode_buf = stream->encode_buf; + signed char *dst_ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start; /* A character can be more than one byte, but we don't have a guarantee that there is more than one byte in the read buffer. So, @@ -106,7 +109,7 @@ soft_port_read (SCM port, scm_t_port_buffer *dst) ans = scm_call_0 (stream->read_char); if (scm_is_false (ans) || SCM_EOF_OBJECT_P (ans)) - return; + return 0; SCM_ASSERT (SCM_CHARP (ans), ans, SCM_ARG1, "soft_port_read"); /* It's possible to make a fast path here, but it would be fastest @@ -119,8 +122,12 @@ soft_port_read (SCM port, scm_t_port_buffer *dst) free (str); } - while (dst->end < dst->size && encode_buf->cur < encode_buf->end) - dst->buf[dst->end++] = encode_buf->buf[encode_buf->cur++]; + for (written = 0; + written < count && encode_buf->cur < encode_buf->end; + written++, encode_buf->cur++) + dst_ptr[written] = encode_buf->buf[encode_buf->cur]; + + return written; } diff --git a/test-suite/standalone/test-scm-c-read.c b/test-suite/standalone/test-scm-c-read.c index 86bca48ed..7850f3447 100644 --- a/test-suite/standalone/test-scm-c-read.c +++ b/test-suite/standalone/test-scm-c-read.c @@ -54,18 +54,20 @@ make_port (scm_t_bits port_type) return scm_c_make_port (port_type, SCM_RDNG, (scm_t_bits) stream); } -static void -custom_port_read (SCM port, scm_t_port_buffer *dst) +static size_t +custom_port_read (SCM port, SCM dst, size_t start, size_t count) { - size_t to_copy = dst->size - dst->end; + size_t to_copy = count; struct custom_port *stream = (void *) SCM_STREAM (port); if (stream->pos + to_copy > stream->len) to_copy = stream->len - stream->pos; - memcpy (dst->buf + dst->end, stream->buf + stream->pos, to_copy); + memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start, + stream->buf + stream->pos, to_copy); stream->pos += to_copy; - dst->end += to_copy; + + return to_copy; } /* Return true (non-zero) if BUF contains only zeros. */