Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Make sure we return complete lines from readline() and fix regressions #944

Open
wants to merge 11 commits into
from
View
@@ -32,10 +32,11 @@
#endif
/* Buffer flags */
-#define PIO_BF_MALLOC 0x0001 /* Buffer malloced */
-#define PIO_BF_MMAP 0x0002 /* Buffer mmap()ed */
-#define PIO_BF_LINEBUF 0x0004 /* Flushes on newline */
-#define PIO_BF_BLKBUF 0x0008 /* Raw block-based buffering */
+#define PIO_BF_MALLOC 0x0001 /* Buffer malloced */
+#define PIO_BF_MMAP 0x0002 /* Buffer mmap()ed */
+#define PIO_BF_LINEBUF 0x0004 /* Flushes on newline */
+#define PIO_BF_BLKBUF 0x0008 /* Raw block-based buffering */
+#define PIO_BF_UNDERFLOW 0x0010 /* Buffer failed to fill */
/* TODO: What is this? Figure it out and properly document it's use. */
#define PIO_NR_OPEN 256 /* Size of an "IO handle table" */
@@ -113,7 +114,6 @@ typedef struct _ParrotIOData ParrotIOData;
/* BUFFERING */
typedef struct _io_buffer {
INTVAL flags; /* Flags on this buffer */
- size_t raw_reads; /* Number of raw reads */
size_t buffer_size; /* Current allocated size */
const STR_VTABLE *encoding; /* Encoding used by this buffer */
char *buffer_ptr; /* ptr to the buffer mem block */
@@ -135,7 +135,6 @@ typedef INTVAL (*io_vtable_read_b) (PARROT_INTERP, PMC *handle, ARGOU
typedef INTVAL (*io_vtable_write_b) (PARROT_INTERP, PMC *handle, ARGIN(char * buffer), size_t byte_length);
typedef INTVAL (*io_vtable_flush) (PARROT_INTERP, PMC *handle);
typedef INTVAL (*io_vtable_is_eof) (PARROT_INTERP, PMC *handle);
-typedef void (*io_vtable_set_eof) (PARROT_INTERP, PMC *handle, INTVAL is_set);
typedef PIOOFF_T (*io_vtable_tell) (PARROT_INTERP, PMC *handle);
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);
@@ -158,7 +157,6 @@ typedef struct _io_vtable {
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_set_eof set_eof; /* Set or clear the passed-EOF flag */
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 */
View
@@ -867,8 +867,6 @@ Parrot_io_read_byte_buffer_pmc(PARROT_INTERP, ARGMOD(PMC *handle),
account for whatever we read. */
if (bytes_read != byte_length)
VTABLE_set_integer_native(interp, buffer, bytes_read);
- if (bytes_read == 0)
- vtable->set_eof(interp, handle, 1);
vtable->adv_position(interp, handle, bytes_read);
return buffer;
}
@@ -962,7 +960,7 @@ Parrot_io_readline_s(PARROT_INTERP, ARGMOD(PMC *handle), ARGIN(STRING * terminat
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);
+ read_buffer = io_verify_has_read_buffer(interp, handle, vtable, BUFFER_FLAGS_ANY);
/* Because of the way buffering works, the terminator sequence may be,
at most, one character shorter than half the size of the buffer.
View
@@ -117,8 +117,6 @@ Parrot_io_buffer_allocate(PARROT_INTERP, ARGMOD(PMC *owner), INTVAL flags,
buffer->buffer_end = buffer->buffer_ptr;
PARROT_ASSERT(BUFFER_IS_EMPTY(buffer));
- buffer->raw_reads = 0;
-
buffer->flags = flags;
return buffer;
}
@@ -293,8 +291,12 @@ Parrot_io_buffer_read_b(PARROT_INTERP, ARGMOD_NULLOK(IO_BUFFER *buffer),
size_t length)
{
ASSERT_ARGS(Parrot_io_buffer_read_b)
+ if(length == 0)
+ return 0;
+
if (!buffer)
return vtable->read_b(interp, handle, s, length);
+
{
size_t bytes_read = io_buffer_transfer_to_mem(interp, buffer, s, length);
PARROT_ASSERT(bytes_read <= length);
@@ -305,8 +307,11 @@ Parrot_io_buffer_read_b(PARROT_INTERP, ARGMOD_NULLOK(IO_BUFFER *buffer),
/* If we still need more data than the buffer can hold, just read it
directly. */
if (length > buffer->buffer_size) {
- bytes_read += vtable->read_b(interp, handle, s + bytes_read, length);
- buffer->raw_reads++;
+ const size_t count = vtable->read_b(interp, handle, s + bytes_read,
+ length);
+ bytes_read += count;
+ if (count == 0)
+ buffer->flags |= PIO_BF_UNDERFLOW;
}
/* Else, if we need to read an amount that the buffer can handle, fill
@@ -617,7 +622,9 @@ Parrot_io_buffer_fill(PARROT_INTERP, ARGMOD_NULLOK(IO_BUFFER *buffer),
return BUFFER_USED_SIZE(buffer);
read_bytes = vtable->read_b(interp, handle, buffer->buffer_end,
available_size);
- buffer->raw_reads++;
+ if (read_bytes == 0)
+ buffer->flags |= PIO_BF_UNDERFLOW;
+
buffer->buffer_end += read_bytes;
BUFFER_ASSERT_SANITY(buffer);
return BUFFER_USED_SIZE(buffer);
@@ -746,12 +753,9 @@ io_buffer_find_string_marker(PARROT_INTERP, ARGMOD(IO_BUFFER *buffer),
if (delim_bytelen == 1)
return bounds->bytes;
- /* If the buffer did not fill completely, we can assume there's nothing
- left for us to read because we tried to fill before we started this
- loop. If so, just return all the bytes in the buffer. If we've hit
- EOF and don't have the terminator, we'll never have it, so just
- return everything also. */
- if (BUFFER_FREE_END_SPACE(buffer) > 0 || vtable->is_eof(interp, handle))
+ /* If we've hit EOF and don't have the terminator, we'll never have it,
+ so just return all the bytes in the buffer. */
+ if (vtable->is_eof(interp, handle))
return bounds->bytes;
/* If the delimiter is multiple bytes, we might have part of it. We need
View
@@ -108,13 +108,6 @@ static PIOOFF_T io_filehandle_seek(PARROT_INTERP,
__attribute__nonnull__(2)
FUNC_MODIFIES(*handle);
-static void io_filehandle_set_eof(PARROT_INTERP,
- ARGMOD(PMC *handle),
- INTVAL is_set)
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*handle);
-
static void io_filehandle_set_flags(PARROT_INTERP,
ARGIN(PMC *handle),
INTVAL flags)
@@ -185,9 +178,6 @@ static INTVAL io_filehandle_write_b(PARROT_INTERP,
#define ASSERT_ARGS_io_filehandle_seek __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(handle))
-#define ASSERT_ARGS_io_filehandle_set_eof __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(handle))
#define ASSERT_ARGS_io_filehandle_set_flags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(handle))
@@ -235,7 +225,6 @@ io_filehandle_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTV
vtable->write_b = io_filehandle_write_b;
vtable->flush = io_filehandle_flush;
vtable->is_eof = io_filehandle_is_eof;
- vtable->set_eof = io_filehandle_set_eof;
vtable->tell = io_filehandle_tell;
vtable->seek = io_filehandle_seek;
vtable->adv_position = io_filehandle_adv_position;
@@ -269,6 +258,12 @@ io_filehandle_read_b(PARROT_INTERP, ARGMOD(PMC *handle), ARGOUT(char *buffer), s
ASSERT_ARGS(io_filehandle_read_b)
const PIOHANDLE os_handle = io_filehandle_get_os_handle(interp, handle);
const size_t bytes_read = Parrot_io_internal_read(interp, os_handle, buffer, byte_length);
+ if (bytes_read == 0) {
+ INTVAL flags;
+ GETATTR_FileHandle_flags(interp, handle, flags);
+ flags |= PIO_F_EOF;
+ SETATTR_FileHandle_flags(interp, handle, flags);
+ }
return bytes_read;
}
@@ -317,11 +312,6 @@ io_filehandle_flush(PARROT_INTERP, ARGMOD(PMC *handle))
Determine if this handle as at end-of-file.
-=item C<static void io_filehandle_set_eof(PARROT_INTERP, PMC *handle, INTVAL
-is_set)>
-
-Set or clear the EOF flag.
-
=cut
*/
@@ -337,16 +327,6 @@ io_filehandle_is_eof(PARROT_INTERP, ARGMOD(PMC *handle))
return 0;
}
-static void
-io_filehandle_set_eof(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL is_set)
-{
- ASSERT_ARGS(io_filehandle_set_eof)
- if (is_set)
- PARROT_FILEHANDLE(handle)->flags |= PIO_F_EOF;
- else
- PARROT_FILEHANDLE(handle)->flags &= ~PIO_F_EOF;
-}
-
/*
=item C<static PIOOFF_T io_filehandle_tell(PARROT_INTERP, PMC *handle)>
View
@@ -102,13 +102,6 @@ static PIOOFF_T io_pipe_seek(PARROT_INTERP,
__attribute__nonnull__(2)
FUNC_MODIFIES(*handle);
-static void io_pipe_set_eof(PARROT_INTERP,
- ARGMOD(PMC *handle),
- INTVAL is_set)
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*handle);
-
static void io_pipe_set_flags(PARROT_INTERP,
ARGIN(PMC *handle),
INTVAL flags)
@@ -179,9 +172,6 @@ static INTVAL io_pipe_write_b(PARROT_INTERP,
#define ASSERT_ARGS_io_pipe_seek __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(handle))
-#define ASSERT_ARGS_io_pipe_set_eof __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(handle))
#define ASSERT_ARGS_io_pipe_set_flags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(handle))
@@ -226,7 +216,6 @@ io_pipe_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL idx
vtable->write_b = io_pipe_write_b;
vtable->flush = io_pipe_flush;
vtable->is_eof = io_pipe_is_eof;
- vtable->set_eof = io_pipe_set_eof;
vtable->tell = io_pipe_tell;
vtable->seek = io_pipe_seek;
vtable->adv_position = io_pipe_adv_position;
@@ -312,10 +301,6 @@ io_pipe_flush(PARROT_INTERP, ARGMOD(PMC *handle))
Determine if the pipe thinks it's at the end of input.
-=item C<static void io_pipe_set_eof(PARROT_INTERP, PMC *handle, INTVAL is_set)>
-
-Do nothing.
-
=cut
*/
@@ -331,16 +316,6 @@ io_pipe_is_eof(PARROT_INTERP, ARGMOD(PMC *handle))
return 0;
}
-static void
-io_pipe_set_eof(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL is_set)
-{
- ASSERT_ARGS(io_pipe_set_eof)
- if (is_set)
- PARROT_FILEHANDLE(handle)->flags |= PIO_F_EOF;
- else
- PARROT_FILEHANDLE(handle)->flags &= ~PIO_F_EOF;
-}
-
/*
=item C<static PIOOFF_T io_pipe_tell(PARROT_INTERP, PMC *handle)>
View
@@ -106,13 +106,6 @@ static PIOOFF_T io_socket_seek(PARROT_INTERP,
__attribute__nonnull__(2)
FUNC_MODIFIES(*handle);
-static void io_socket_set_eof(PARROT_INTERP,
- ARGMOD(PMC *handle),
- INTVAL is_eof)
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*handle);
-
static void io_socket_set_flags(PARROT_INTERP,
ARGIN(PMC *handle),
INTVAL flags)
@@ -183,9 +176,6 @@ static INTVAL io_socket_write_b(PARROT_INTERP,
#define ASSERT_ARGS_io_socket_seek __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(handle))
-#define ASSERT_ARGS_io_socket_set_eof __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(handle))
#define ASSERT_ARGS_io_socket_set_flags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(handle))
@@ -230,7 +220,6 @@ io_socket_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), INTVAL i
vtable->write_b = io_socket_write_b;
vtable->flush = io_socket_flush;
vtable->is_eof = io_socket_is_eof;
- vtable->set_eof = io_socket_set_eof;
vtable->tell = io_socket_tell;
vtable->seek = io_socket_seek;
vtable->adv_position = io_socket_adv_position;
@@ -308,12 +297,8 @@ io_socket_flush(PARROT_INTERP, ARGMOD(PMC *handle))
=item C<static INTVAL io_socket_is_eof(PARROT_INTERP, PMC *handle)>
-Sockets are not "passed-the-end" so long as the connection is open. Return 0.
-
-=item C<static void io_socket_set_eof(PARROT_INTERP, PMC *handle, INTVAL
-is_eof)>
-
-Do nothing.
+Sockets are considered at EOF if the last buffered read failed to fill the
+buffer. Always return 0 for unbuffered sockets.
=cut
@@ -323,18 +308,11 @@ static INTVAL
io_socket_is_eof(PARROT_INTERP, ARGMOD(PMC *handle))
{
ASSERT_ARGS(io_socket_is_eof)
- UNUSED(interp);
- UNUSED(handle);
- return 0;
-}
+ IO_BUFFER * const buffer = IO_GET_READ_BUFFER(interp, handle);
+ if (!buffer)
+ return 0;
-static void
-io_socket_set_eof(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL is_eof)
-{
- ASSERT_ARGS(io_socket_set_eof)
- UNUSED(interp);
- UNUSED(handle);
- UNUSED(is_eof);
+ return !!(buffer->flags & PIO_BF_UNDERFLOW);
}
/*
View
@@ -106,13 +106,6 @@ static PIOOFF_T io_stringhandle_seek(PARROT_INTERP,
__attribute__nonnull__(2)
FUNC_MODIFIES(*handle);
-static void io_stringhandle_set_eof(PARROT_INTERP,
- ARGMOD(PMC *handle),
- INTVAL is_set)
- __attribute__nonnull__(1)
- __attribute__nonnull__(2)
- FUNC_MODIFIES(*handle);
-
static void io_stringhandle_set_flags(PARROT_INTERP,
ARGIN(PMC *handle),
INTVAL flags)
@@ -183,9 +176,6 @@ static INTVAL io_stringhandle_write_b(PARROT_INTERP,
#define ASSERT_ARGS_io_stringhandle_seek __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(handle))
-#define ASSERT_ARGS_io_stringhandle_set_eof __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(handle))
#define ASSERT_ARGS_io_stringhandle_set_flags __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(handle))
@@ -238,7 +228,6 @@ io_stringhandle_setup_vtable(PARROT_INTERP, ARGMOD_NULLOK(IO_VTABLE *vtable), IN
vtable->write_b = io_stringhandle_write_b;
vtable->flush = io_stringhandle_flush;
vtable->is_eof = io_stringhandle_is_eof;
- vtable->set_eof = io_stringhandle_set_eof;
vtable->tell = io_stringhandle_tell;
vtable->seek = io_stringhandle_seek;
vtable->adv_position = io_stringhandle_adv_position;
@@ -339,11 +328,6 @@ io_stringhandle_flush(PARROT_INTERP, ARGMOD(PMC *handle))
The StringHandle is at eof if the current read cursor is passed the end of the
string contents.
-=item C<static void io_stringhandle_set_eof(PARROT_INTERP, PMC *handle, INTVAL
-is_set)>
-
-Do nothing.
-
=cut
*/
@@ -359,15 +343,6 @@ io_stringhandle_is_eof(PARROT_INTERP, ARGMOD(PMC *handle))
return (UINTVAL)read_offs >= stringhandle->bufused;
}
-static void
-io_stringhandle_set_eof(PARROT_INTERP, ARGMOD(PMC *handle), INTVAL is_set)
-{
- ASSERT_ARGS(io_stringhandle_set_eof)
- UNUSED(interp);
- UNUSED(handle);
- UNUSED(is_set);
-}
-
/*
=item C<static PIOOFF_T io_stringhandle_tell(PARROT_INTERP, PMC *handle)>
Oops, something went wrong.