From c2cc9e51290c09aae7eb91074d13079d5821b3af Mon Sep 17 00:00:00 2001 From: bumbread Date: Fri, 24 Jun 2022 14:54:51 +1100 Subject: [PATCH] Implement caching for file streams --- src/code/string.c | 1 + src/win/win_stdio.c | 92 ++++++++++++++++++++++++++++++++++++--------- test/test_io.c | 3 +- 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/src/code/string.c b/src/code/string.c index dddcc39..0668851 100644 --- a/src/code/string.c +++ b/src/code/string.c @@ -239,6 +239,7 @@ size_t strnlen_s(const char *s, size_t maxsize) { } char *strdup(const char *str1) { + if(str1 == NULL) return NULL; size_t len = strlen(str1); char *copy = calloc(len+1, 1); strcpy(copy, str1); diff --git a/src/win/win_stdio.c b/src/win/win_stdio.c index 2c6ec34..a404118 100644 --- a/src/win/win_stdio.c +++ b/src/win/win_stdio.c @@ -1,4 +1,6 @@ +#define __STDC_WANT_LIB_EXT2__ 1 + #include #include #include @@ -7,6 +9,7 @@ #include #include #include +#include enum str_type { STR_R, @@ -33,6 +36,7 @@ struct FILE { str_mode mode; int buftype; size_t bufsize; + int bufidx; char *buffer; mbstate_t mbstate; mtx_t lock; @@ -59,13 +63,20 @@ static inline FILE *new_file( ) { FILE *file = malloc(sizeof(FILE)); if(file == NULL) return NULL; + mtx_init(&file->lock, mtx_recursive); file->handle = handle; - file->name = name; // TODO: strdup this + file->name = strdup(name); file->type = type; file->flags = flags; file->mode = mode; + // Buffer for cache + file->buftype = buftype; + file->bufsize = bufsize; + file->buffer = buffer; + file->bufidx = 0; + // Multibyte state file->mbstate = (mbstate_t){0}; - mtx_init(&file->lock, mtx_recursive); + // Append to list of all streams if(file_list_last != NULL) { file_list_last->next = file; file->prev = file_list_last; @@ -86,9 +97,8 @@ static inline void dispose_file(FILE *file) { // Only close the file if it's not a standard handle if(file->name) { CloseHandle(file->handle); - //TODO: free(file->name); + free(file->name); } - // TODO: flush streams FILE *prev = file->prev; FILE *next = file->next; if(prev != NULL) prev->next = next; @@ -128,6 +138,7 @@ int setvbuf( int mode, size_t size ) { + mtx_lock(&stream->lock); if(mode == _IONBF) { stream->buftype = mode; stream->buffer = NULL; @@ -146,24 +157,52 @@ int setvbuf( stream->buftype = mode; stream->buffer = buf; stream->bufsize = size; + mtx_unlock(&stream->lock); return 0; } +void setbuf(FILE *restrict stream, char *restrict buf) { + int mode = _IOFBF; + if(buf == NULL) { + mode = _IONBF; + } + setvbuf(stream, buf, mode, BUFSIZ); +} + int fflush(FILE *stream) { - if(stream->mode == _IOFBF) { - - } - else if(stream->mode == _IONBF) { - + mtx_lock(&stream->lock); + if(stream->buftype != _IONBF) { + DWORD written; + BOOL ok = WriteFile( + stream->handle, + stream->buffer, + stream->bufidx, + &written, + NULL + ); + if(!ok) { + errno = EIO; + return EOF; + } + stream->bufidx = 0; } + mtx_unlock(&stream->lock); return 0; } -int fputc(int c, FILE *stream) { - mtx_lock(&stream->lock); +static int try_fputc(FILE *stream, char c) { + if(stream->buftype != _IONBF) { + stream->buffer[stream->bufidx++] = c; + if(stream->bufidx > stream->bufsize) { + return fflush(stream); + } + if(stream->buftype == _IOLBF && c == '\n') { + return fflush(stream); + } + return c; + } DWORD written; BOOL ok = WriteFile(stream->handle, &c, 1, &written, NULL); - mtx_unlock(&stream->lock); if(!ok) { errno = EIO; return EOF; @@ -171,9 +210,28 @@ int fputc(int c, FILE *stream) { return c; } -void setbuf(FILE *restrict stream, char *restrict buf) { - if(buf != NULL) - setvbuf(stream, buf, _IOFBF, BUFSIZ); - else - setvbuf(stream, buf, _IONBF, BUFSIZ); +static int try_fputs(FILE *stream, char *str, size_t len) { + for(size_t i = 0; i != len; ++i) { + int cw = try_fputc(stream, str[i]); + if(cw == EOF) return EOF; + } + return 1; +} + +int fputc(int c, FILE *stream) { + mtx_lock(&stream->lock); + int res = try_fputc(stream, c); + mtx_unlock(&stream->lock); + return res; +} + +int fputs(const char *restrict s, FILE *stream) { + mtx_lock(&stream->lock); + while(*s) { + int res = try_fputc(stream, *s); + if(res == EOF) return EOF; + ++s; + } + mtx_unlock(&stream->lock); + return 1; } diff --git a/test/test_io.c b/test/test_io.c index cb3034f..0ebd98a 100644 --- a/test/test_io.c +++ b/test/test_io.c @@ -2,6 +2,7 @@ #include int main() { - fputc('Z', stdout); + for(int i = 0; i != 512; ++i) + fputc('Z', stdout); return 0; }