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 */
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++;