From f1512125d0e1657fd5e2ff979209501fd0e1a770 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Thu, 13 Jan 2022 21:21:23 +0100 Subject: [PATCH] stdio: initial versions of fputc() and fputs() (TEST) --- CMakeLists.txt | 2 ++ STATUS | 14 ++++++------- src/libc/stdio/fileutil.c | 43 +++++++++++++++++++++++++++++++++++++++ src/libc/stdio/fileutil.h | 4 ++++ src/libc/stdio/fputc.c | 32 +++++++++++++++++++++++++++++ src/libc/stdio/fputs.c | 9 ++++++++ src/libc/stdio/fread.c | 41 ++----------------------------------- 7 files changed, 99 insertions(+), 46 deletions(-) create mode 100644 src/libc/stdio/fputc.c create mode 100644 src/libc/stdio/fputs.c diff --git a/CMakeLists.txt b/CMakeLists.txt index b6bf513..de39356 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,6 +130,8 @@ set(SOURCES src/libc/stdio/fileutil.c src/libc/stdio/fopen.c src/libc/stdio/fprintf.c + src/libc/stdio/fputc.c + src/libc/stdio/fputs.c src/libc/stdio/fread.c src/libc/stdio/freopen.c src/libc/stdio/fseek.c diff --git a/STATUS b/STATUS index aa3cfa0..d691127 100644 --- a/STATUS +++ b/STATUS @@ -95,8 +95,8 @@ TEST: Function/symbol/macro needs to be tested 7.19.5.1 fclose - 7.19.5.2 fflush - 7.19.5.3 fopen - - (EXT) fdopen TEST - 7.19.5.4 freopen TEST (mode changes untested) + (EXT) fdopen - + 7.19.5.4 freopen - 7.19.5.5 setbuf - 7.19.5.6 setvbuf - @@ -121,14 +121,14 @@ TEST: Function/symbol/macro needs to be tested 7.19.7.1 fgetc TODO 7.19.7.2 fgets TODO - 7.19.7.3 fputc TODO - 7.19.7.4 fputs TODO + 7.19.7.3 fputc TEST + 7.19.7.4 fputs TEST 7.19.7.5 getc LDEPS(fgetc) 7.19.7.6 getchar LDEPS(fgetc) 7.19.7.7 gets LDEPS(fgets) - 7.19.7.8 putc LDPES(fputc) - 7.19.7.9 putchar LDEPS(fputc) - 7.19.7.10 puts LDEPS(fputs) + 7.19.7.8 putc TEST + 7.19.7.9 putchar TEST + 7.19.7.10 puts TEST 7.19.7.11 ungetc - 7.19.8.1 fread - diff --git a/src/libc/stdio/fileutil.c b/src/libc/stdio/fileutil.c index 6ae5118..7d3873e 100644 --- a/src/libc/stdio/fileutil.c +++ b/src/libc/stdio/fileutil.c @@ -79,6 +79,49 @@ void __fp_buffer_mode_write(FILE *fp) fp->bufdir = __FILE_BUF_WRITE; } +ssize_t __fp_fread2(FILE *fp, void *data, size_t request_size, int stop_char) +{ + if(!fp->readable) { + fp->error = 1; + return -1; + } + + /* If the stream if unbuffered, we might have no buffer for the reads. + If it's buffered, we always have one. It's also possible that fp is + unbuffered (_IONBF) but has a buffer temporarily because ungetc() + has been used, in which case we have to transition from buffered + reads into direct reads midway. We use __fp_buffered_read() to + handle this. */ + + size_t read_size = 0; + __fp_buffer_mode_read(fp); + + while(read_size < request_size) { + int remaining = request_size - read_size; + int chunk = __fp_buffered_read(fp, data+read_size, remaining); + + /* Stream is not/no longer buffered, finish unbuffered */ + if(chunk < 0) { + ssize_t rc = __fp_read(fp, data+read_size, remaining); + return read_size + (rc == EOF ? 0 : rc); + } + + read_size += chunk; + if(read_size >= request_size) + break; + + /* Get more data from the file descriptor into the buffer */ + if(fp->buf) { + ssize_t rc = __fp_read(fp, fp->buf, fp->bufsize); + if(rc <= 0) /* EOF or error */ + break; + fp->bufread = rc; + } + } + + return read_size; +} + ssize_t __fp_buffered_read(FILE *fp, void *data, size_t request_size) { if(!fp->buf || __fp_hasbuf_write(fp)) diff --git a/src/libc/stdio/fileutil.h b/src/libc/stdio/fileutil.h index 5165f66..ea39dcc 100644 --- a/src/libc/stdio/fileutil.h +++ b/src/libc/stdio/fileutil.h @@ -35,6 +35,10 @@ void __fp_buffer_mode_read(FILE *fp); /* Set writing mode on the buffer. */ void __fp_buffer_mode_write(FILE *fp); +/* fread() with an extra option to stop at a certain character (usually '\n'); + set -1 to disable. */ +ssize_t __fp_fread2(FILE *fp, void *data, size_t request_size, int stop_char); + /* Reads data from the buffer. Always reads as much as possible, up to size. Returns amount of data read; if >= 0 but < size, the buffer should be refilled. Returns -1 to indicate that unbuffered access should be used. diff --git a/src/libc/stdio/fputc.c b/src/libc/stdio/fputc.c new file mode 100644 index 0000000..d11bf47 --- /dev/null +++ b/src/libc/stdio/fputc.c @@ -0,0 +1,32 @@ +#include +#include +#include "fileutil.h" + +int fputc(int c_int, FILE *fp) +{ + unsigned char c = c_int; + + if(!fp->writable) { + fp->error = 1; + return 0; + } + if(fp->append && fseek(fp, 0, SEEK_END) == EOF) { + fp->error = 1; + return 0; + } + + if(!fp->buf) + return __fp_write(fp, &c, 1); + + __fp_buffer_mode_write(fp); + + if(fp->bufpos >= fp->bufsize) + fflush(fp); + + fp->buf[fp->bufpos++] = c; + + if(fp->bufmode == _IOLBF && c == '\n') + fflush(fp); + + return c; +} diff --git a/src/libc/stdio/fputs.c b/src/libc/stdio/fputs.c new file mode 100644 index 0000000..890a4ea --- /dev/null +++ b/src/libc/stdio/fputs.c @@ -0,0 +1,9 @@ +#include +#include + +int fputs(char const * restrict s, FILE * restrict fp) +{ + size_t len = strlen(s); + size_t written = fwrite(s, 1, len, fp); + return (written < len) ? EOF : 0; +} diff --git a/src/libc/stdio/fread.c b/src/libc/stdio/fread.c index 442b9e8..8d94b7a 100644 --- a/src/libc/stdio/fread.c +++ b/src/libc/stdio/fread.c @@ -4,49 +4,12 @@ size_t fread(void *data, size_t membsize, size_t nmemb, FILE *fp) { - if(!fp->readable) { - fp->error = 1; - return 0; - } - size_t request_size; if(__builtin_umul_overflow(membsize, nmemb, &request_size)) { fp->error = 1; return 0; } - /* If the stream if unbuffered, we might have no buffer for the reads. - If it's buffered, we always have one. It's also possible that fp is - unbuffered (_IONBF) but has a buffer temporarily because ungetc() - has been used, in which case we have to transition from buffered - reads into direct reads midway. We use __fp_buffered_read() to - handle this. */ - - size_t read_size = 0; - __fp_buffer_mode_read(fp); - - while(read_size < request_size) { - int remaining = request_size - read_size; - int chunk = __fp_buffered_read(fp, data+read_size, remaining); - - /* Stream is not/no longer buffered, finish unbuffered */ - if(chunk < 0) { - ssize_t rc = __fp_read(fp, data+read_size, remaining); - return read_size + (rc == EOF ? 0 : rc); - } - - read_size += chunk; - if(read_size >= request_size) - break; - - /* Get more data from the file descriptor into the buffer */ - if(fp->buf) { - ssize_t rc = __fp_read(fp, fp->buf, fp->bufsize); - if(rc <= 0) /* EOF or error */ - break; - fp->bufread = rc; - } - } - - return read_size; + ssize_t read_size = __fp_fread2(fp, data, request_size, -1); + return (read_size < 0) ? 0 : read_size; }