rktio: more text-mode repairs

This commit is contained in:
Matthew Flatt 2017-06-18 15:42:54 -06:00
parent b96fc45133
commit 4250d51f08

View File

@ -40,7 +40,8 @@ struct rktio_fd_t {
struct Win_FD_Output_Thread *oth; /* output mode */ struct Win_FD_Output_Thread *oth; /* output mode */
int unblocked; /* whether non-blocking mode is installed */ int unblocked; /* whether non-blocking mode is installed */
char *buffer; /* shared with reading thread */ 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 #endif
}; };
@ -120,9 +121,12 @@ static CSI_proc get_csi(void)
return csi; return csi;
} }
static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_cnoverted, intptr_t got); static intptr_t adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_converted,
static const char *rktio_adjust_output_text(const char *buffer, intptr_t *towrite); intptr_t got, intptr_t offset);
static intptr_t rktio_recount_output_text(const char *orig_buffer, const char *buffer, intptr_t wrote); 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 #endif
@ -775,31 +779,41 @@ intptr_t rktio_read_converted(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, int
if (!rfd->th) { if (!rfd->th) {
/* We can read directly. This must be a regular file, where /* We can read directly. This must be a regular file, where
reading never blocks. */ reading never blocks. */
DWORD rgot; DWORD rgot, offset = 0;
if (rfd->pending_cr && len) { if (rfd->has_pending_byte) {
/* just in case we need to add the cr */ if (!len)
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(); get_windows_error();
return RKTIO_READ_ERROR; return RKTIO_READ_ERROR;
} }
rgot += offset;
if (!rgot) { if (rfd->has_pending_byte) {
if (rfd->pending_cr) { /* We had a buffer of size 1 and a pending '\r'... */
if (len) { return adjust_input_text_for_pending_cr(rfd, buffer, is_converted, rgot);
buffer[0] = '\r'; } else if (!rgot)
rfd->pending_cr = 0; return RKTIO_READ_EOF;
if (is_converted) is_converted[0] = 0; else if (rfd->modes & RKTIO_OPEN_TEXT)
return 1; return adjust_input_text(rfd, buffer, is_converted, rgot, offset);
} 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);
else else
return rgot; return rgot;
} else { } else {
@ -849,24 +863,21 @@ RKTIO_EXTERN intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd)
# endif # endif
#endif #endif
#ifdef RKTIO_SYSTEM_WINDOWS #ifdef RKTIO_SYSTEM_WINDOWS
return (fd->pending_cr ? 1 : 0); return (fd->has_pending_byte ? 1 : 0);
#endif #endif
} }
#ifdef RKTIO_SYSTEM_WINDOWS #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; int i, j;
if (rfd->pending_cr) { if (got && (buffer[got-1] == '\r') && !offset) {
memmove(buffer+1, buffer, got); /* Save '\r' that might be followed by '\n' */
buffer[0] = '\r'; rfd->pending_byte = '\r';
rfd->pending_cr = 0; rfd->has_pending_byte = 1;
got++;
}
if (got && (buffer[got-1] == '\r')) {
rfd->pending_cr = 1;
--got; --got;
} }
@ -888,6 +899,31 @@ static intptr_t rktio_adjust_input_text(rktio_fd_t *rfd, char *buffer, char *is_
return j; 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) 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; int err;
if (rfd->modes & RKTIO_OPEN_TEXT) if (rfd->modes & RKTIO_OPEN_TEXT)
buffer = rktio_adjust_output_text(buffer, &towrite); buffer = adjust_output_text(buffer, &towrite);
while (1) { while (1) {
ok = WriteFile((HANDLE)rfd->fd, buffer, towrite, &winwrote, NULL); 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) { if (!ok) {
get_windows_error(); get_windows_error();
if (buffer != orig_buffer)
free((char *)buffer);
return RKTIO_WRITE_ERROR; return RKTIO_WRITE_ERROR;
} }
if (buffer != orig_buffer) { if (buffer != orig_buffer) {
/* Convert converted count back to original count: */ /* 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); 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 #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; intptr_t len = *towrite, i, j, newlines = 0;
char *new_buffer; char *new_buffer;
@ -1396,12 +1434,12 @@ static const char *rktio_adjust_output_text(const char *buffer, intptr_t *towrit
return new_buffer; 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; intptr_t i = 0, j = 0;
while (j < wrote) { while (j < wrote) {
if (buffer[i] == '\n') if (orig_buffer[i] == '\n')
j += 2; j += 2;
else else
j++; j++;