From 4250d51f088fcaf454feb2a4888bae843a33c6c4 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Sun, 18 Jun 2017 15:42:54 -0600 Subject: [PATCH] rktio: more text-mode repairs --- racket/src/rktio/rktio_fd.c | 112 ++++++++++++++++++++++++------------ 1 file changed, 75 insertions(+), 37 deletions(-) diff --git a/racket/src/rktio/rktio_fd.c b/racket/src/rktio/rktio_fd.c index 5dbbbf57e4..b2b89f86c0 100644 --- a/racket/src/rktio/rktio_fd.c +++ b/racket/src/rktio/rktio_fd.c @@ -40,7 +40,8 @@ struct rktio_fd_t { struct Win_FD_Output_Thread *oth; /* output mode */ int unblocked; /* whether non-blocking mode is installed */ char *buffer; /* shared with reading thread */ - int pending_cr; /* for text-mode input, may be dropped by a following lf */ + int has_pending_byte; /* for text-mode input, may be dropped by a following lf */ + int pending_byte; /* for text-mode input, either a CR waiting to decode, or byte that didn't fit */ #endif }; @@ -120,9 +121,12 @@ static CSI_proc get_csi(void) return csi; } -static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_cnoverted, intptr_t got); -static const char *rktio_adjust_output_text(const char *buffer, intptr_t *towrite); -static intptr_t rktio_recount_output_text(const char *orig_buffer, const char *buffer, intptr_t wrote); +static intptr_t adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_converted, + intptr_t got, intptr_t offset); +static intptr_t adjust_input_text_for_pending_cr(rktio_fd_t *rfd, char *buffer, char *is_converted, + intptr_t got); +static const char *adjust_output_text(const char *buffer, intptr_t *towrite); +static intptr_t recount_output_text(const char *orig_buffer, const char *buffer, intptr_t wrote); #endif @@ -775,31 +779,41 @@ intptr_t rktio_read_converted(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, int if (!rfd->th) { /* We can read directly. This must be a regular file, where reading never blocks. */ - DWORD rgot; + DWORD rgot, offset = 0; - if (rfd->pending_cr && len) { - /* just in case we need to add the cr */ - len--; + if (rfd->has_pending_byte) { + if (!len) + return 0; + buffer[0] = rfd->pending_byte; + if (len == 1) { + if (rfd->pending_byte == '\r') { + /* We have to read one more byte and then decode, + shifting the new byte into pending position + if it's not '\n' */ + } else { + if (is_converted) is_converted[0] = 0; + rfd->has_pending_byte = 0; + return 1; + } + } else { + /* read after first byte installed into the buffer */ + offset = 1; + } } - if (!ReadFile((HANDLE)rfd->fd, buffer, len, &rgot, NULL)) { + if (!ReadFile((HANDLE)rfd->fd, buffer + offset, len - offset, &rgot, NULL)) { get_windows_error(); return RKTIO_READ_ERROR; } + rgot += offset; - if (!rgot) { - if (rfd->pending_cr) { - if (len) { - buffer[0] = '\r'; - rfd->pending_cr = 0; - if (is_converted) is_converted[0] = 0; - return 1; - } else - return 0; - } else - return RKTIO_READ_EOF; - } else if (rfd->modes & RKTIO_OPEN_TEXT) - return rktio_adjust_input_text(rfd, buffer, is_converted, rgot); + if (rfd->has_pending_byte) { + /* We had a buffer of size 1 and a pending '\r'... */ + return adjust_input_text_for_pending_cr(rfd, buffer, is_converted, rgot); + } else if (!rgot) + return RKTIO_READ_EOF; + else if (rfd->modes & RKTIO_OPEN_TEXT) + return adjust_input_text(rfd, buffer, is_converted, rgot, offset); else return rgot; } else { @@ -849,24 +863,21 @@ RKTIO_EXTERN intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd) # endif #endif #ifdef RKTIO_SYSTEM_WINDOWS - return (fd->pending_cr ? 1 : 0); + return (fd->has_pending_byte ? 1 : 0); #endif } #ifdef RKTIO_SYSTEM_WINDOWS -static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_converted, intptr_t got) +static intptr_t adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_converted, + intptr_t got, intptr_t offset) { int i, j; - if (rfd->pending_cr) { - memmove(buffer+1, buffer, got); - buffer[0] = '\r'; - rfd->pending_cr = 0; - got++; - } - if (got && (buffer[got-1] == '\r')) { - rfd->pending_cr = 1; + if (got && (buffer[got-1] == '\r') && !offset) { + /* Save '\r' that might be followed by '\n' */ + rfd->pending_byte = '\r'; + rfd->has_pending_byte = 1; --got; } @@ -888,6 +899,31 @@ static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_ return j; } +static intptr_t adjust_input_text_for_pending_cr(rktio_fd_t *rfd, char *buffer, char *is_converted, + intptr_t got) +{ + if (!got) { + /* There are no more bytes to decode. Report the final '\r' by itself */ + buffer[0] = '\r'; + rfd->has_pending_byte = 0; + if (is_converted) is_converted[0] = 0; + return 1; + } else { + /* Combine the one new byte with a preceding '\r' */ + if (buffer[0] == '\n') { + /* Decode */ + rfd->has_pending_byte = 0; + if (is_converted) is_converted[0] = 1; + return 1; + } else { + /* Save the new byte as pending while returning a '\r' by itself */ + rfd->pending_byte = buffer[0]; + buffer[0] = '\r'; + if (is_converted) is_converted[0] = 0; + return 1; + } + } +} static void init_read_fd(rktio_t *rktio, rktio_fd_t *rfd) { @@ -1130,7 +1166,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr int err; if (rfd->modes & RKTIO_OPEN_TEXT) - buffer = rktio_adjust_output_text(buffer, &towrite); + buffer = adjust_output_text(buffer, &towrite); while (1) { ok = WriteFile((HANDLE)rfd->fd, buffer, towrite, &winwrote, NULL); @@ -1152,12 +1188,14 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr if (!ok) { get_windows_error(); + if (buffer != orig_buffer) + free((char *)buffer); return RKTIO_WRITE_ERROR; } if (buffer != orig_buffer) { /* Convert converted count back to original count: */ - winwrote = rktio_recount_output_text(orig_buffer, buffer, winwrote); + winwrote = recount_output_text(orig_buffer, buffer, winwrote); free((char *)buffer); } @@ -1363,7 +1401,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr #ifdef RKTIO_SYSTEM_WINDOWS -static const char *rktio_adjust_output_text(const char *buffer, intptr_t *towrite) +static const char *adjust_output_text(const char *buffer, intptr_t *towrite) { intptr_t len = *towrite, i, j, newlines = 0; char *new_buffer; @@ -1396,12 +1434,12 @@ static const char *rktio_adjust_output_text(const char *buffer, intptr_t *towrit return new_buffer; } -static intptr_t rktio_recount_output_text(const char *orig_buffer, const char *buffer, intptr_t wrote) +static intptr_t recount_output_text(const char *orig_buffer, const char *buffer, intptr_t wrote) { intptr_t i = 0, j = 0; while (j < wrote) { - if (buffer[i] == '\n') + if (orig_buffer[i] == '\n') j += 2; else j++;