From 1f03c5b2ddfcabec46a4488e4a96597c3d8e3cdf Mon Sep 17 00:00:00 2001 From: Whiteknight Date: Sat, 9 Jun 2012 09:04:11 -0400 Subject: [PATCH] Add new IO vtables to set, get and advance the current in-memory cursor position. Update file position on read and write operations. For read/write handles, make sure to sync buffers so position stays consistent. Several codestd fixes. Add comments. Several tests still failing --- include/parrot/io.h | 56 ++++++++++++++++++++------------- src/io/api.c | 73 +++++++++++++++++++++++++++++++++---------- src/io/buffer.c | 43 ++++++++++++++++++++++--- src/io/filehandle.c | 66 +++++++++++++++++++++++++++++++++++--- src/io/io_private.h | 69 +++++++++++++++++++++++++++++++--------- src/io/pipe.c | 56 ++++++++++++++++++++++++++++++++- src/io/socket.c | 55 +++++++++++++++++++++++++++++++- src/io/stringhandle.c | 55 +++++++++++++++++++++++++++++++- src/io/userhandle.c | 2 +- src/io/utilities.c | 59 +++++++++++++++++++++++++++++++--- 10 files changed, 465 insertions(+), 69 deletions(-) diff --git a/include/parrot/io.h b/include/parrot/io.h index 9ab668a2d1..52b00da945 100644 --- a/include/parrot/io.h +++ b/include/parrot/io.h @@ -130,36 +130,40 @@ typedef INTVAL (*io_vtable_write_b) (PARROT_INTERP, PMC *handle, ARGIN typedef INTVAL (*io_vtable_flush) (PARROT_INTERP, PMC *handle); typedef INTVAL (*io_vtable_is_eof) (PARROT_INTERP, PMC *handle); typedef PIOOFF_T (*io_vtable_tell) (PARROT_INTERP, PMC *handle); -typedef INTVAL (*io_vtable_seek) (PARROT_INTERP, PMC *handle, PIOOFF_T offset, INTVAL whence); +typedef PIOOFF_T (*io_vtable_seek) (PARROT_INTERP, PMC *handle, PIOOFF_T offset, INTVAL whence); +typedef void (*io_vtable_adv_position) (PARROT_INTERP, PMC *handle, size_t len); +typedef void (*io_vtable_set_position) (PARROT_INTERP, PMC *handle, PIOOFF_T pos); +typedef PIOOFF_T (*io_vtable_get_position) (PARROT_INTERP, PMC *handle); typedef INTVAL (*io_vtable_open) (PARROT_INTERP, PMC *handle, ARGIN(STRING *path), INTVAL flags, ARGIN(STRING *mode)); typedef INTVAL (*io_vtable_is_open) (PARROT_INTERP, PMC *handle); typedef INTVAL (*io_vtable_close) (PARROT_INTERP, PMC *handle); typedef void (*io_vtable_set_flags) (PARROT_INTERP, PMC *handle, INTVAL flags); typedef INTVAL (*io_vtable_get_flags) (PARROT_INTERP, PMC *handle); -typedef void (*io_vtable_ensure_buffer)(PARROT_INTERP, PMC *handle, INTVAL buffer_no, size_t size, INTVAL flags); typedef size_t (*io_vtable_total_size) (PARROT_INTERP, PMC *handle); typedef PIOHANDLE (*io_vtable_get_piohandle)(PARROT_INTERP, PMC *handle); typedef const STR_VTABLE *(*io_vtable_get_encoding) (PARROT_INTERP, PMC *handle); typedef struct _io_vtable { - const char * name; - INTVAL number; - INTVAL flags; - io_vtable_read_b read_b; - io_vtable_write_b write_b; - io_vtable_flush flush; - io_vtable_is_eof is_eof; - io_vtable_open open; - io_vtable_is_open is_open; - io_vtable_close close; - io_vtable_tell tell; - io_vtable_seek seek; - io_vtable_get_flags get_flags; - io_vtable_set_flags set_flags; - io_vtable_get_encoding get_encoding; - io_vtable_ensure_buffer ensure_buffer; - io_vtable_total_size total_size; - io_vtable_get_piohandle get_piohandle; + const char * name; /* Name of this vtable type */ + INTVAL number; /* Index number of this vtable */ + INTVAL flags; /* Flags for this type */ + io_vtable_read_b read_b; /* Read bytes from the handle */ + io_vtable_write_b write_b; /* Write bytes to the handle */ + io_vtable_flush flush; /* Flush the handle */ + io_vtable_is_eof is_eof; /* Determine if at end-of-file */ + io_vtable_open open; /* Open the handle */ + io_vtable_is_open is_open; /* Determine if the handle is open */ + io_vtable_close close; /* Close the handle */ + io_vtable_tell tell; /* Get on-disk file position */ + io_vtable_seek seek; /* Seek to new position */ + io_vtable_adv_position adv_position; /* Advance handle (in-mem) position */ + io_vtable_set_position set_position; /* Set handle (in-mem) position */ + io_vtable_get_position get_position; /* Get handle (in-mem) position */ + io_vtable_get_flags get_flags; /* Get the flags */ + io_vtable_set_flags set_flags; /* Set the flags */ + io_vtable_get_encoding get_encoding; /* Get the handle encoding */ + io_vtable_total_size total_size; /* Get the total size, if possible */ + io_vtable_get_piohandle get_piohandle; /* Get the raw file PIOHANDLE */ } IO_VTABLE; #define IO_VTABLE_FILEHANDLE 0 @@ -561,7 +565,7 @@ PIOOFF_T Parrot_io_tell_handle(PARROT_INTERP, ARGMOD(PMC *handle)) PARROT_EXPORT PARROT_WARN_UNUSED_RESULT -INTVAL Parrot_io_write_b(PARROT_INTERP, +size_t Parrot_io_write_b(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(const void *buffer), size_t byte_length) @@ -601,6 +605,7 @@ PIOHANDLE Parrot_io_get_os_handle(PARROT_INTERP, ARGIN(PMC *handle)) __attribute__nonnull__(2); PARROT_WARN_UNUSED_RESULT +PARROT_CAN_RETURN_NULL IO_VTABLE * Parrot_io_get_vtable(PARROT_INTERP, INTVAL idx, ARGIN_NULLOK(const char * name)) @@ -851,6 +856,12 @@ void Parrot_io_buffer_add_to_handle(PARROT_INTERP, __attribute__nonnull__(2) FUNC_MODIFIES(*handle); +void Parrot_io_buffer_advance_position(PARROT_INTERP, + ARGMOD_NULLOK(IO_BUFFER *buffer), + size_t len) + __attribute__nonnull__(1) + FUNC_MODIFIES(*buffer); + PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT IO_BUFFER * Parrot_io_buffer_allocate(PARROT_INTERP, @@ -972,6 +983,9 @@ size_t Parrot_io_buffer_write_b(PARROT_INTERP, __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_Parrot_io_buffer_advance_position \ + __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp)) #define ASSERT_ARGS_Parrot_io_buffer_allocate __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(owner)) diff --git a/src/io/api.c b/src/io/api.c index eba57fbfc3..2a85199f9c 100644 --- a/src/io/api.c +++ b/src/io/api.c @@ -136,6 +136,7 @@ Parrot_io_allocate_new_vtable(PARROT_INTERP, ARGIN(const char *name)) } PARROT_WARN_UNUSED_RESULT +PARROT_CAN_RETURN_NULL IO_VTABLE * Parrot_io_get_vtable(PARROT_INTERP, INTVAL idx, ARGIN_NULLOK(const char * name)) { @@ -186,7 +187,6 @@ Parrot_io_finish(PARROT_INTERP) } - /* =item C @@ -213,7 +213,6 @@ Parrot_io_mark(PARROT_INTERP, ARGIN(ParrotIOData *piodata)) } } - /* =head2 Generic I/O interface @@ -316,13 +315,10 @@ Parrot_io_open(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(STRING *path), /* If this type uses buffers by default, set them up, and if we're in an acceptable mode, set up buffers. */ - if ((flags & (PIO_F_READ | PIO_F_WRITE)) != (PIO_F_READ | PIO_F_WRITE) && - (vtable->flags & PIO_VF_DEFAULT_BUFFERS)) { - if (flags & PIO_F_READ) - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY, PIO_BF_BLKBUF); - if (flags & PIO_F_WRITE) - Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, PIO_BF_BLKBUF); - } + if (flags & PIO_F_READ) + Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_READ_BUFFER, BUFFER_SIZE_ANY, PIO_BF_BLKBUF); + if (flags & PIO_F_WRITE) + Parrot_io_buffer_add_to_handle(interp, handle, IO_PTR_IDX_WRITE_BUFFER, BUFFER_SIZE_ANY, PIO_BF_BLKBUF); } return handle; @@ -495,8 +491,11 @@ Parrot_io_close(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL autoflush) else { IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle); + IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle); if (write_buffer) Parrot_io_buffer_flush(interp, write_buffer, handle, vtable); + if (read_buffer) + Parrot_io_buffer_clear(interp, read_buffer); if (autoflush == -1) autoflush == (vtable->flags && PIO_VF_FLUSH_ON_CLOSE) ? 1 : 0; @@ -561,6 +560,10 @@ Parrot_io_flush(PARROT_INTERP, ARGMOD(PMC *handle)) if (PMC_IS_NULL(handle)) return 0; + if (Parrot_io_is_closed(interp, handle)) + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR, + "Cannot flush a closed handle"); + else { IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle); @@ -609,12 +612,20 @@ Parrot_io_read_s(PARROT_INTERP, ARGMOD(PMC *handle), size_t length) { IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); IO_BUFFER * read_buffer = IO_GET_READ_BUFFER(interp, handle); + IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle); const STR_VTABLE * encoding = vtable->get_encoding(interp, handle); + /* read_s requires us to read in a whole number of characters, which + might be multi-byte. This requires a read buffer. */ + /* TODO: If we have a fixed8 encoding or similar, we should be able to + avoid using a read_buffer here. Detect that case and don't assign + a buffer if not needed. */ if (read_buffer == NULL) read_buffer = io_verify_has_read_buffer(interp, handle, vtable, BUFFER_SIZE_ANY); io_verify_is_open_for(interp, handle, vtable, PIO_F_READ); + io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer); + return io_read_encoded_string(interp, handle, vtable, read_buffer, encoding, length); } } @@ -650,6 +661,7 @@ Parrot_io_readall_s(PARROT_INTERP, ARGMOD(PMC *handle)) "Attempt to read from null or invalid PMC"); { IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); + IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle); const STR_VTABLE * const encoding = io_get_encoding(interp, handle, vtable, PIO_F_READ); size_t total_size = vtable->total_size(interp, handle); @@ -657,6 +669,7 @@ Parrot_io_readall_s(PARROT_INTERP, ARGMOD(PMC *handle)) return Parrot_str_new_init(interp, "", 0, encoding, 0); if (total_size == PIO_UNKNOWN_SIZE) { IO_BUFFER * const read_buffer = io_verify_has_read_buffer(interp, handle, vtable, BUFFER_FLAGS_ANY); + io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer); size_t available_bytes = Parrot_io_buffer_fill(interp, read_buffer, handle, vtable); STRING * const s = io_get_new_empty_string(interp, encoding, -1, PIO_STRING_BUFFER_MINSIZE); while (available_bytes > 0) { @@ -666,6 +679,7 @@ Parrot_io_readall_s(PARROT_INTERP, ARGMOD(PMC *handle)) return s; } else { IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle); + io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer); STRING * const s = io_get_new_empty_string(interp, encoding, -1, total_size); io_read_chars_append_string(interp, s, handle, vtable, read_buffer, total_size); return s; @@ -715,13 +729,17 @@ Parrot_io_read_byte_buffer_pmc(PARROT_INTERP, ARGMOD(PMC *handle), char * content = VTABLE_get_pointer(interp, buffer); IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle); + IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle); size_t bytes_read; io_verify_is_open_for(interp, handle, vtable, PIO_F_READ); + io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer); + bytes_read = Parrot_io_buffer_read_b(interp, read_buffer, handle, vtable, content, byte_length); if (bytes_read != byte_length) VTABLE_set_integer_native(interp, buffer, byte_length); + vtable->adv_position(interp, handle, bytes_read); return buffer; } } @@ -785,9 +803,12 @@ Parrot_io_readline_s(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL terminator) { IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); IO_BUFFER * read_buffer = IO_GET_READ_BUFFER(interp, handle); + IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle); size_t bytes_read; STRING *result; + io_sync_buffers_for_read(interp, handle, vtable, read_buffer, write_buffer); + io_verify_is_open_for(interp, handle, vtable, PIO_F_READ); if (read_buffer == NULL) read_buffer = io_verify_has_read_buffer(interp, handle, vtable, BUFFER_SIZE_ANY); @@ -808,7 +829,7 @@ Writes C bytes from C<*buffer> to C<*pmc>. PARROT_EXPORT PARROT_WARN_UNUSED_RESULT -INTVAL +size_t Parrot_io_write_b(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(const void *buffer), size_t byte_length) { @@ -816,7 +837,7 @@ Parrot_io_write_b(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(const void *buffer), if (PMC_IS_NULL(handle)) Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR, - "Attempt to read bytes from a null or invalid PMC"); + "Attempt to write bytes to a null or invalid PMC"); if (!byte_length) return 0; @@ -824,10 +845,18 @@ Parrot_io_write_b(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(const void *buffer), { IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle); + IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle); + size_t bytes_written; io_verify_is_open_for(interp, handle, vtable, PIO_F_WRITE); - return Parrot_io_buffer_write_b(interp, write_buffer, handle, vtable, - (char *)buffer, byte_length); + io_sync_buffers_for_write(interp, handle, vtable, read_buffer, write_buffer); + bytes_written = Parrot_io_buffer_write_b(interp, write_buffer, handle, vtable, + (char *)buffer, byte_length); + vtable->adv_position(interp, handle, bytes_written); + /* If we are writing to a r/w handle, advance the pointer in the + associated read-buffer since we're overwriting those characters. */ + Parrot_io_buffer_advance_position(interp, read_buffer, bytes_written); + return bytes_written; } } @@ -848,12 +877,21 @@ Parrot_io_write_s(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING *s)) { IO_VTABLE * const vtable = IO_GET_VTABLE(interp, handle); IO_BUFFER * const write_buffer = IO_GET_WRITE_BUFFER(interp, handle); + IO_BUFFER * const read_buffer = IO_GET_READ_BUFFER(interp, handle); STRING *out_s; + size_t bytes_written; io_verify_is_open_for(interp, handle, vtable, PIO_F_WRITE); + io_sync_buffers_for_write(interp, handle, vtable, read_buffer, write_buffer); out_s = io_verify_string_encoding(interp, handle, vtable, s, PIO_F_WRITE); - return Parrot_io_buffer_write_b(interp, write_buffer, handle, vtable, out_s->strstart, out_s->bufused); + bytes_written = Parrot_io_buffer_write_b(interp, write_buffer, handle, + vtable, out_s->strstart, out_s->bufused); + vtable->adv_position(interp, handle, bytes_written); + /* If we are writing to a r/w handle, advance the pointer in the + associated read-buffer since we're overwriting those characters. */ + Parrot_io_buffer_advance_position(interp, read_buffer, bytes_written); + return bytes_written; } } @@ -906,8 +944,11 @@ Parrot_io_seek(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset, INTVAL w) if (write_buffer) Parrot_io_buffer_flush(interp, write_buffer, handle, vtable); - if (read_buffer && w != SEEK_END) - return Parrot_io_buffer_seek(interp, read_buffer, handle, vtable, offset, w); + if (read_buffer && w != SEEK_END) { + PIOOFF_T new_offset = Parrot_io_buffer_seek(interp, read_buffer, handle, vtable, offset, w); + vtable->set_position(interp, handle, new_offset); + return new_offset; + } return vtable->seek(interp, handle, offset, w); } diff --git a/src/io/buffer.c b/src/io/buffer.c index 0e6f15d398..078fe6e06f 100644 --- a/src/io/buffer.c +++ b/src/io/buffer.c @@ -431,6 +431,20 @@ Parrot_io_buffer_content_size(SHIM_INTERP, ARGIN(IO_BUFFER *buffer)) return BUFFER_USED_SIZE(buffer); } +void +Parrot_io_buffer_advance_position(PARROT_INTERP, ARGMOD_NULLOK(IO_BUFFER *buffer), size_t len) +{ + ASSERT_ARGS(Parrot_io_buffer_advance_position) + if (!buffer || BUFFER_IS_EMPTY(buffer)) + return; + if (BUFFER_USED_SIZE(buffer) <= len) { + Parrot_io_buffer_clear(interp, buffer); + return; + } + buffer->buffer_start += len; + io_buffer_normalize(interp, buffer); +} + /* =item Cget_position(interp, handle); + PIOOFF_T pos_diff; - /* TODO: Try to seek inside the read buffer */ - offset -= BUFFER_USED_SIZE(buffer); - Parrot_io_buffer_clear(interp, buffer); - return vtable->seek(interp, handle, offset, w); + PARROT_ASSERT(w == SEEK_SET); + + if (cur_pos == offset) + return; + if (offset < cur_pos) { + /* write buffers are flushed before seeking, so this is a read buffer. + if we're not seeking to a position inside the buffer just clear it. + */ + Parrot_io_buffer_clear(interp, buffer); + return vtable->seek(interp, handle, offset, w); + } + pos_diff = offset - cur_pos; + PARROT_ASSERT(pos_diff > 0); + + if (pos_diff > BUFFER_USED_SIZE(buffer)) { + Parrot_io_buffer_clear(interp, buffer); + return vtable->seek(interp, handle, offset, w); + } + + /* If we're here, we can seek inside this buffer */ + buffer->buffer_start += (size_t)pos_diff; + io_buffer_normalize(interp, buffer); + return offset; } /* diff --git a/src/io/filehandle.c b/src/io/filehandle.c index 1739cabd79..e0a5275f29 100644 --- a/src/io/filehandle.c +++ b/src/io/filehandle.c @@ -24,6 +24,13 @@ L. /* HEADERIZER BEGIN: static */ /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ +static void io_filehandle_adv_position(PARROT_INTERP, + ARGMOD(PMC *handle), + size_t len) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static INTVAL io_filehandle_close(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -50,6 +57,12 @@ static PIOHANDLE io_filehandle_get_piohandle(PARROT_INTERP, __attribute__nonnull__(1) __attribute__nonnull__(2); +static PIOOFF_T io_filehandle_get_position(PARROT_INTERP, + ARGMOD(PMC *handle)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static INTVAL io_filehandle_is_eof(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -95,6 +108,13 @@ static void io_filehandle_set_flags(PARROT_INTERP, __attribute__nonnull__(1) __attribute__nonnull__(2); +static PIOOFF_T io_filehandle_set_position(PARROT_INTERP, + ARGMOD(PMC *handle), + PIOOFF_T pos) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static PIOOFF_T io_filehandle_tell(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -113,6 +133,9 @@ static INTVAL io_filehandle_write_b(PARROT_INTERP, __attribute__nonnull__(3) FUNC_MODIFIES(*handle); +#define ASSERT_ARGS_io_filehandle_adv_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_filehandle_close __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -128,6 +151,9 @@ static INTVAL io_filehandle_write_b(PARROT_INTERP, #define ASSERT_ARGS_io_filehandle_get_piohandle __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_io_filehandle_get_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_filehandle_is_eof __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -149,6 +175,9 @@ static INTVAL io_filehandle_write_b(PARROT_INTERP, #define ASSERT_ARGS_io_filehandle_set_flags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_io_filehandle_set_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_filehandle_tell __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -163,7 +192,7 @@ static INTVAL io_filehandle_write_b(PARROT_INTERP, /* HEADERIZER END: static */ void -io_filehandle_setup_vtable(PARROT_INTERP, IO_VTABLE *vtable, INTVAL idx) +io_filehandle_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx) { ASSERT_ARGS(io_filehandle_setup_vtable) if (vtable == NULL) @@ -177,6 +206,9 @@ io_filehandle_setup_vtable(PARROT_INTERP, IO_VTABLE *vtable, INTVAL idx) vtable->is_eof = io_filehandle_is_eof; vtable->tell = io_filehandle_tell; vtable->seek = io_filehandle_seek; + vtable->adv_position = io_filehandle_adv_position; + vtable->set_position = io_filehandle_set_position; + vtable->get_position = io_filehandle_get_position; vtable->open = io_filehandle_open; vtable->is_open = io_filehandle_is_open; vtable->close = io_filehandle_close; @@ -244,11 +276,36 @@ io_filehandle_seek(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset, INTVAL w ASSERT_ARGS(io_filehandle_seek) const PIOHANDLE os_handle = io_filehandle_get_os_handle(interp, handle); Parrot_FileHandle_attributes * const attrs = PARROT_FILEHANDLE(handle); - INTVAL status = Parrot_io_internal_seek(interp, os_handle, offset, whence); + PIOOFF_T new_pos = Parrot_io_internal_seek(interp, os_handle, offset, whence); attrs->flags &= ~PIO_F_EOF; attrs->last_pos = attrs->file_pos; - attrs->file_pos = offset; - return status; + attrs->file_pos = new_pos; + return new_pos; +} + +static void +io_filehandle_adv_position(PARROT_INTERP, ARGMOD(PMC *handle), size_t len) +{ + ASSERT_ARGS(io_filehandle_adv_position) + Parrot_FileHandle_attributes * const attrs = PARROT_FILEHANDLE(handle); + attrs->last_pos = attrs->file_pos; + attrs->file_pos += len; +} + +static PIOOFF_T +io_filehandle_set_position(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T pos) +{ + ASSERT_ARGS(io_filehandle_set_position) + Parrot_FileHandle_attributes * const attrs = PARROT_FILEHANDLE(handle); + attrs->file_pos = pos; +} + +static PIOOFF_T +io_filehandle_get_position(PARROT_INTERP, ARGMOD(PMC *handle)) +{ + ASSERT_ARGS(io_filehandle_get_position) + Parrot_FileHandle_attributes * const attrs = PARROT_FILEHANDLE(handle); + return attrs->file_pos; } static INTVAL @@ -291,6 +348,7 @@ io_filehandle_open(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING *path), INTV SETATTR_FileHandle_flags(interp, handle, flags); SETATTR_FileHandle_filename(interp, handle, path); SETATTR_FileHandle_mode(interp, handle, mode); + SETATTR_FileHandle_file_pos(interp, handle, 0); return 1; } diff --git a/src/io/io_private.h b/src/io/io_private.h index 7494ead45c..556a36b8e4 100644 --- a/src/io/io_private.h +++ b/src/io/io_private.h @@ -134,7 +134,7 @@ struct _ParrotIOData { #define PIO_UNKNOWN_SIZE (size_t)-1 /* Buffer Macros */ -#define BUFFER_IS_EMPTY(b) (b->buffer_start == b->buffer_end) +#define BUFFER_IS_EMPTY(b) (b->buffer_start >= b->buffer_end) #define BUFFER_IS_FULL(b) ((size_t)(b->buffer_end - b->buffer_start) == b->buffer_size) #define BUFFER_USED_SIZE(b) ((size_t)(b->buffer_end - b->buffer_start)) #define BUFFER_AVAILABLE_SIZE(b) (b->buffer_size - ((size_t)(b->buffer_end - b->buffer_start))) @@ -184,13 +184,12 @@ void io_read_chars_append_string(PARROT_INTERP, ARGMOD(STRING * s), ARGMOD(PMC *handle), ARGIN(IO_VTABLE *vtable), - ARGMOD(IO_BUFFER *buffer), + ARGMOD_NULLOK(IO_BUFFER *buffer), size_t byte_length) __attribute__nonnull__(1) __attribute__nonnull__(2) __attribute__nonnull__(3) __attribute__nonnull__(4) - __attribute__nonnull__(5) FUNC_MODIFIES(* s) FUNC_MODIFIES(*handle) FUNC_MODIFIES(*buffer); @@ -225,6 +224,32 @@ STRING * io_readline_encoded_string(PARROT_INTERP, FUNC_MODIFIES(*handle) FUNC_MODIFIES(*buffer); +void io_sync_buffers_for_read(PARROT_INTERP, + ARGMOD(PMC *handle), + ARGIN(IO_VTABLE *vtable), + ARGMOD_NULLOK(IO_BUFFER *read_buffer), + ARGMOD_NULLOK(IO_BUFFER * write_buffer)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + __attribute__nonnull__(3) + FUNC_MODIFIES(*handle) + FUNC_MODIFIES(*read_buffer) + FUNC_MODIFIES(* write_buffer); + +void io_sync_buffers_for_write(PARROT_INTERP, + ARGMOD(PMC *handle), + ARGIN(IO_VTABLE *vtable), + ARGMOD_NULLOK(IO_BUFFER *read_buffer), + ARGMOD_NULLOK(IO_BUFFER * write_buffer)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + __attribute__nonnull__(3) + FUNC_MODIFIES(*handle) + FUNC_MODIFIES(*read_buffer) + FUNC_MODIFIES(* write_buffer); + +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL IO_BUFFER * io_verify_has_read_buffer(PARROT_INTERP, ARGIN(PMC *handle), ARGIN(IO_VTABLE *vtable), @@ -270,8 +295,7 @@ STRING * io_verify_string_encoding(PARROT_INTERP, PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(s) \ , PARROT_ASSERT_ARG(handle) \ - , PARROT_ASSERT_ARG(vtable) \ - , PARROT_ASSERT_ARG(buffer)) + , PARROT_ASSERT_ARG(vtable)) #define ASSERT_ARGS_io_read_encoded_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle) \ @@ -282,6 +306,14 @@ STRING * io_verify_string_encoding(PARROT_INTERP, , PARROT_ASSERT_ARG(handle) \ , PARROT_ASSERT_ARG(vtable) \ , PARROT_ASSERT_ARG(buffer)) +#define ASSERT_ARGS_io_sync_buffers_for_read __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle) \ + , PARROT_ASSERT_ARG(vtable)) +#define ASSERT_ARGS_io_sync_buffers_for_write __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle) \ + , PARROT_ASSERT_ARG(vtable)) #define ASSERT_ARGS_io_verify_has_read_buffer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle) \ @@ -324,9 +356,10 @@ void io_filehandle_set_os_handle(PARROT_INTERP, FUNC_MODIFIES(*filehandle); void io_filehandle_setup_vtable(PARROT_INTERP, - IO_VTABLE *vtable, + ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx) - __attribute__nonnull__(1); + __attribute__nonnull__(1) + FUNC_MODIFIES(*vtable); #define ASSERT_ARGS_io_filehandle_get_file_position \ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ @@ -346,8 +379,11 @@ void io_filehandle_setup_vtable(PARROT_INTERP, /* HEADERIZER BEGIN: src/io/pipe.c */ /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ -void io_pipe_setup_vtable(PARROT_INTERP, IO_VTABLE *vtable, INTVAL idx) - __attribute__nonnull__(1); +void io_pipe_setup_vtable(PARROT_INTERP, + ARGMOD_NULLOK(IO_VTABLE *vtable), + INTVAL idx) + __attribute__nonnull__(1) + FUNC_MODIFIES(*vtable); #define ASSERT_ARGS_io_pipe_setup_vtable __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) @@ -358,9 +394,10 @@ void io_pipe_setup_vtable(PARROT_INTERP, IO_VTABLE *vtable, INTVAL idx) /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ void io_socket_setup_vtable(PARROT_INTERP, - ARGIN_NULLOK(IO_VTABLE *vtable), + ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx) - __attribute__nonnull__(1); + __attribute__nonnull__(1) + FUNC_MODIFIES(*vtable); #define ASSERT_ARGS_io_socket_setup_vtable __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) @@ -371,9 +408,10 @@ void io_socket_setup_vtable(PARROT_INTERP, /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ void io_stringhandle_setup_vtable(PARROT_INTERP, - IO_VTABLE *vtable, + ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx) - __attribute__nonnull__(1); + __attribute__nonnull__(1) + FUNC_MODIFIES(*vtable); #define ASSERT_ARGS_io_stringhandle_setup_vtable __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) @@ -384,9 +422,10 @@ void io_stringhandle_setup_vtable(PARROT_INTERP, /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ void io_userhandle_setup_vtable(PARROT_INTERP, - IO_VTABLE *vtable, + ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx) - __attribute__nonnull__(1); + __attribute__nonnull__(1) + FUNC_MODIFIES(*vtable); #define ASSERT_ARGS_io_userhandle_setup_vtable __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) diff --git a/src/io/pipe.c b/src/io/pipe.c index 218b3eb718..c632585804 100644 --- a/src/io/pipe.c +++ b/src/io/pipe.c @@ -8,6 +8,13 @@ /* HEADERIZER BEGIN: static */ /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ +static void io_pipe_adv_position(PARROT_INTERP, + ARGMOD(PMC *handle), + PIOOFF_T offset) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static INTVAL io_pipe_close(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -33,6 +40,11 @@ static PIOHANDLE io_pipe_get_piohandle(PARROT_INTERP, ARGIN(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2); +static PIOOFF_T io_pipe_get_position(PARROT_INTERP, ARGMOD(PMC *handle)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static INTVAL io_pipe_is_eof(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -78,6 +90,13 @@ static void io_pipe_set_flags(PARROT_INTERP, __attribute__nonnull__(1) __attribute__nonnull__(2); +static PIOOFF_T io_pipe_set_position(PARROT_INTERP, + ARGMOD(PMC *handle), + PIOOFF_T pos) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static PIOOFF_T io_pipe_tell(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -96,6 +115,9 @@ static INTVAL io_pipe_write_b(PARROT_INTERP, __attribute__nonnull__(3) FUNC_MODIFIES(*handle); +#define ASSERT_ARGS_io_pipe_adv_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_pipe_close __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -111,6 +133,9 @@ static INTVAL io_pipe_write_b(PARROT_INTERP, #define ASSERT_ARGS_io_pipe_get_piohandle __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_io_pipe_get_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_pipe_is_eof __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -132,6 +157,9 @@ static INTVAL io_pipe_write_b(PARROT_INTERP, #define ASSERT_ARGS_io_pipe_set_flags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_io_pipe_set_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_pipe_tell __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -146,7 +174,7 @@ static INTVAL io_pipe_write_b(PARROT_INTERP, /* HEADERIZER END: static */ void -io_pipe_setup_vtable(PARROT_INTERP, IO_VTABLE *vtable, INTVAL idx) +io_pipe_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx) { ASSERT_ARGS(io_pipe_setup_vtable) if (vtable == NULL) @@ -160,6 +188,9 @@ io_pipe_setup_vtable(PARROT_INTERP, IO_VTABLE *vtable, INTVAL idx) vtable->is_eof = io_pipe_is_eof; vtable->tell = io_pipe_tell; vtable->seek = io_pipe_seek; + vtable->adv_position = io_pipe_adv_position; + vtable->set_position = io_pipe_set_position; + vtable->get_position = io_pipe_get_position; vtable->open = io_pipe_open; vtable->is_open = io_pipe_is_open; vtable->close = io_pipe_close; @@ -233,6 +264,28 @@ io_pipe_seek(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset, INTVAL whence) return 0; } +static void +io_pipe_adv_position(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset) +{ + ASSERT_ARGS(io_pipe_adv_position) + /* Pipes don't keep track of file position internally. Ignore this. */ +} + +static PIOOFF_T +io_pipe_set_position(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T pos) +{ + ASSERT_ARGS(io_pipe_set_position) + /* Pipes don't keep track of file position internally. Ignore. */ +} + +static PIOOFF_T +io_pipe_get_position(PARROT_INTERP, ARGMOD(PMC *handle)) +{ + ASSERT_ARGS(io_pipe_get_position) + /* Pipes don't keep track of file position internally. Return 0 */ + return (PIOOFF_T)0; +} + static INTVAL io_pipe_open(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING *path), INTVAL flags, ARGIN(STRING *mode)) { @@ -268,6 +321,7 @@ io_pipe_open(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING *path), INTVAL fla SETATTR_FileHandle_flags(interp, handle, flags); SETATTR_FileHandle_filename(interp, handle, path); SETATTR_FileHandle_mode(interp, handle, mode); + SETATTR_FileHandle_file_pos(interp, handle, 0); return 1; } diff --git a/src/io/socket.c b/src/io/socket.c index 0fd997d595..bd7d29b501 100644 --- a/src/io/socket.c +++ b/src/io/socket.c @@ -30,6 +30,13 @@ These are the primary interface functions for working with socket objects. /* HEADERIZER BEGIN: static */ /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ +static void io_socket_adv_position(PARROT_INTERP, + ARGMOD(PMC *handle), + PIOOFF_T offset) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static INTVAL io_socket_close(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -55,6 +62,11 @@ static PIOHANDLE io_socket_get_piohandle(PARROT_INTERP, ARGIN(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2); +static PIOOFF_T io_socket_get_position(PARROT_INTERP, ARGMOD(PMC *handle)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static INTVAL io_socket_is_eof(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -100,6 +112,13 @@ static void io_socket_set_flags(PARROT_INTERP, __attribute__nonnull__(1) __attribute__nonnull__(2); +static PIOOFF_T io_socket_set_position(PARROT_INTERP, + ARGMOD(PMC *handle), + PIOOFF_T pos) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static PIOOFF_T io_socket_tell(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -118,6 +137,9 @@ static INTVAL io_socket_write_b(PARROT_INTERP, __attribute__nonnull__(3) FUNC_MODIFIES(*handle); +#define ASSERT_ARGS_io_socket_adv_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_socket_close __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -133,6 +155,9 @@ static INTVAL io_socket_write_b(PARROT_INTERP, #define ASSERT_ARGS_io_socket_get_piohandle __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_io_socket_get_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_socket_is_eof __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -154,6 +179,9 @@ static INTVAL io_socket_write_b(PARROT_INTERP, #define ASSERT_ARGS_io_socket_set_flags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_io_socket_set_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_socket_tell __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -168,7 +196,7 @@ static INTVAL io_socket_write_b(PARROT_INTERP, /* HEADERIZER END: static */ void -io_socket_setup_vtable(PARROT_INTERP, ARGIN_NULLOK(IO_VTABLE *vtable), INTVAL idx) +io_socket_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx) { ASSERT_ARGS(io_socket_setup_vtable) if (vtable == NULL) @@ -182,6 +210,9 @@ io_socket_setup_vtable(PARROT_INTERP, ARGIN_NULLOK(IO_VTABLE *vtable), INTVAL id vtable->is_eof = io_socket_is_eof; vtable->tell = io_socket_tell; vtable->seek = io_socket_seek; + vtable->adv_position = io_socket_adv_position; + vtable->set_position = io_socket_set_position; + vtable->get_position = io_socket_get_position; vtable->open = io_socket_open; vtable->is_open = io_socket_is_open; vtable->close = io_socket_close; @@ -246,6 +277,28 @@ io_socket_seek(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset, INTVAL whenc return 0; } +static void +io_socket_adv_position(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset) +{ + ASSERT_ARGS(io_socket_adv_position) + /* Socket doesn't keep track of position internally. Ignore this. */ +} + +static PIOOFF_T +io_socket_set_position(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T pos) +{ + ASSERT_ARGS(io_socket_set_position) + /* Socket doesn't keep track of position internally. Ignore. */ +} + +static PIOOFF_T +io_socket_get_position(PARROT_INTERP, ARGMOD(PMC *handle)) +{ + ASSERT_ARGS(io_socket_get_position) + /* Socket doesn't keep track of position internally. Return 0 */ + return (PIOOFF_T)0; +} + static INTVAL io_socket_open(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING *path), INTVAL flags, ARGIN(STRING * mode)) diff --git a/src/io/stringhandle.c b/src/io/stringhandle.c index 25f3c535b4..7586341faf 100644 --- a/src/io/stringhandle.c +++ b/src/io/stringhandle.c @@ -21,6 +21,13 @@ src/io/stringhandle.c - StringHandle vtables and helper routines /* HEADERIZER BEGIN: static */ /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ +static void io_stringhandle_adv_position(PARROT_INTERP, + ARGMOD(PMC *handle), + PIOOFF_T offset) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static INTVAL io_stringhandle_close(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -47,6 +54,12 @@ static PIOHANDLE io_stringhandle_get_piohandle(PARROT_INTERP, __attribute__nonnull__(1) __attribute__nonnull__(2); +static PIOOFF_T io_stringhandle_get_position(PARROT_INTERP, + ARGMOD(PMC *handle)) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static INTVAL io_stringhandle_is_eof(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -92,6 +105,13 @@ static void io_stringhandle_set_flags(PARROT_INTERP, __attribute__nonnull__(1) __attribute__nonnull__(2); +static PIOOFF_T io_stringhandle_set_position(PARROT_INTERP, + ARGMOD(PMC *handle), + PIOOFF_T pos) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + FUNC_MODIFIES(*handle); + static PIOOFF_T io_stringhandle_tell(PARROT_INTERP, ARGMOD(PMC *handle)) __attribute__nonnull__(1) __attribute__nonnull__(2) @@ -110,6 +130,9 @@ static INTVAL io_stringhandle_write_b(PARROT_INTERP, __attribute__nonnull__(3) FUNC_MODIFIES(*handle); +#define ASSERT_ARGS_io_stringhandle_adv_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_stringhandle_close __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -125,6 +148,9 @@ static INTVAL io_stringhandle_write_b(PARROT_INTERP, #define ASSERT_ARGS_io_stringhandle_get_piohandle __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_io_stringhandle_get_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_stringhandle_is_eof __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -146,6 +172,9 @@ static INTVAL io_stringhandle_write_b(PARROT_INTERP, #define ASSERT_ARGS_io_stringhandle_set_flags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) +#define ASSERT_ARGS_io_stringhandle_set_position __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(handle)) #define ASSERT_ARGS_io_stringhandle_tell __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(handle)) @@ -161,7 +190,7 @@ static INTVAL io_stringhandle_write_b(PARROT_INTERP, void -io_stringhandle_setup_vtable(PARROT_INTERP, IO_VTABLE *vtable, INTVAL idx) +io_stringhandle_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx) { ASSERT_ARGS(io_stringhandle_setup_vtable) // TODO: readline and other operations requiring a buffer should be able to be @@ -178,6 +207,9 @@ io_stringhandle_setup_vtable(PARROT_INTERP, IO_VTABLE *vtable, INTVAL idx) vtable->is_eof = io_stringhandle_is_eof; vtable->tell = io_stringhandle_tell; vtable->seek = io_stringhandle_seek; + vtable->adv_position = io_stringhandle_adv_position; + vtable->set_position = io_stringhandle_set_position; + vtable->get_position = io_stringhandle_get_position; vtable->open = io_stringhandle_open; vtable->is_open = io_stringhandle_is_open; vtable->close = io_stringhandle_close; @@ -282,6 +314,27 @@ io_stringhandle_seek(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset, INTVAL return 0; /* TODO: What should this be? */ } +static void +io_stringhandle_adv_position(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T offset) +{ + ASSERT_ARGS(io_stringhandle_adv_position) + /* StringHandle keeps track of position directly. Ignore this. */ +} + +static PIOOFF_T +io_stringhandle_set_position(PARROT_INTERP, ARGMOD(PMC *handle), PIOOFF_T pos) +{ + ASSERT_ARGS(io_stringhandle_set_position) + /* StringHandle keeps track of position directly. Ignore this. */ +} + +static PIOOFF_T +io_stringhandle_get_position(PARROT_INTERP, ARGMOD(PMC *handle)) +{ + ASSERT_ARGS(io_stringhandle_get_position) + return io_stringhandle_tell(interp, handle); +} + static INTVAL io_stringhandle_open(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING *path), INTVAL flags, ARGIN(STRING *mode)) { diff --git a/src/io/userhandle.c b/src/io/userhandle.c index 9d57852609..944be7eacc 100644 --- a/src/io/userhandle.c +++ b/src/io/userhandle.c @@ -145,7 +145,7 @@ static INTVAL io_userhandle_write_b(PARROT_INTERP, /* HEADERIZER END: static */ void -io_userhandle_setup_vtable(PARROT_INTERP, IO_VTABLE *vtable, INTVAL idx) +io_userhandle_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx) { ASSERT_ARGS(io_userhandle_setup_vtable) if (vtable == NULL) diff --git a/src/io/utilities.c b/src/io/utilities.c index 850a0ea3f1..54be1e723e 100644 --- a/src/io/utilities.c +++ b/src/io/utilities.c @@ -140,6 +140,8 @@ io_verify_is_open_for(PARROT_INTERP, ARGIN(PMC *handle), "IO PMC %s is not in mode %d", vtable->name, flags); } +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL IO_BUFFER * io_verify_has_read_buffer(PARROT_INTERP, ARGIN(PMC *handle), ARGIN(IO_VTABLE *vtable), INTVAL flags) @@ -201,6 +203,8 @@ io_read_encoded_string(PARROT_INTERP, ARGMOD(PMC *handle), { ASSERT_ARGS(io_read_encoded_string) STRING * const s = Parrot_gc_new_string_header(interp, 0); + size_t total_bytes_read = 0; + s->bufused = 0; s->strlen = 0; @@ -222,10 +226,12 @@ io_read_encoded_string(PARROT_INTERP, ARGMOD(PMC *handle), /* Append buffer to result */ io_read_chars_append_string(interp, s, handle, vtable, buffer, bytes_to_read); + total_bytes_read += bytes_to_read; if (bounds.chars == char_length) break; } + vtable->adv_position(interp, handle, total_bytes_read); return s; } @@ -248,9 +254,11 @@ reading. void io_read_chars_append_string(PARROT_INTERP, ARGMOD(STRING * s), ARGMOD(PMC *handle), ARGIN(IO_VTABLE *vtable), - ARGMOD(IO_BUFFER *buffer), size_t byte_length) + ARGMOD_NULLOK(IO_BUFFER *buffer), size_t byte_length) { + ASSERT_ARGS(io_read_chars_append_string) const size_t alloc_size = s->bufused + byte_length; + size_t bytes_read = 0; PARROT_ASSERT(s->encoding); if (alloc_size > s->_buflen) { @@ -260,10 +268,16 @@ io_read_chars_append_string(PARROT_INTERP, ARGMOD(STRING * s), Parrot_gc_allocate_string_storage(interp, s, alloc_size); } - Parrot_io_buffer_read_b(interp, buffer, handle, vtable, - s->strstart + s->bufused, byte_length); + if (buffer) + bytes_read = Parrot_io_buffer_read_b(interp, buffer, handle, vtable, + s->strstart + s->bufused, byte_length); + else + bytes_read = vtable->read_b(interp, handle, s->strstart + s->bufused, + byte_length); + PARROT_ASSERT(bytes_read == byte_length); s->bufused += byte_length; + vtable->adv_position(interp, handle, byte_length); STRING_scan(interp, s); } @@ -288,6 +302,8 @@ io_readline_encoded_string(PARROT_INTERP, ARGMOD(PMC *handle), { ASSERT_ARGS(io_readline_encoded_string) STRING * const s = Parrot_gc_new_string_header(interp, 0); + size_t total_bytes_read = 0; + s->bufused = 0; s->strlen = 0; @@ -307,13 +323,14 @@ io_readline_encoded_string(PARROT_INTERP, ARGMOD(PMC *handle), /* Append buffer to result */ io_read_chars_append_string(interp, s, handle, vtable, buffer, bytes_to_read); + total_bytes_read += bytes_to_read; - /* If we've found the delimiter, we're at the end of line. Return - it */ + /* If we've found the delimiter, we're at the end of line. Return it */ if (bounds.delim == rs) break; } + vtable->adv_position(interp, handle, total_bytes_read); return s; } @@ -322,6 +339,7 @@ PARROT_WARN_UNUSED_RESULT const STR_VTABLE * io_get_encoding(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(IO_VTABLE *vtable), INTVAL flags) { + ASSERT_ARGS(io_get_encoding) const STR_VTABLE * const encoding = vtable->get_encoding(interp, handle); if (encoding != NULL) return encoding; @@ -332,6 +350,37 @@ io_get_encoding(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(IO_VTABLE *vtable), IN return Parrot_default_encoding_ptr; } +void +io_sync_buffers_for_read(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(IO_VTABLE *vtable), ARGMOD_NULLOK(IO_BUFFER *read_buffer), ARGMOD_NULLOK(IO_BUFFER * write_buffer)) +{ + ASSERT_ARGS(io_sync_buffers_for_read) + + /* If we have a non-empty write buffer, we have to flush it first + and advance the cursor before we attempt to read. Otherwise we'll be + reading data from the buffer that has already been overwritten, from a + position several bytes before where we're supposed to be. */ + if (write_buffer && !BUFFER_IS_EMPTY(write_buffer)) { + size_t bytes_written = Parrot_io_buffer_flush(interp, write_buffer, handle, vtable); + Parrot_io_buffer_advance_position(interp, read_buffer, bytes_written); + } +} + +void +io_sync_buffers_for_write(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(IO_VTABLE *vtable), ARGMOD_NULLOK(IO_BUFFER *read_buffer), ARGMOD_NULLOK(IO_BUFFER * write_buffer)) +{ + ASSERT_ARGS(io_sync_buffers_for_write) + + /* If we have a read buffer, the on-disk file position is ahead of the + current cursor. We need to clear the read buffer and reset the on-disk + position to match what we expect it to be, so the written data goes + to the correct place */ + if (read_buffer && !BUFFER_IS_EMPTY(read_buffer)) { + size_t buffer_size = BUFFER_USED_SIZE(read_buffer); + Parrot_io_buffer_clear(interp, read_buffer); + vtable->seek(interp, handle, -buffer_size, SEEK_CUR); + } +} + /* =back