diff --git a/STATUS b/STATUS index c617b0b..5f0899a 100644 --- a/STATUS +++ b/STATUS @@ -91,13 +91,13 @@ TEST: Function/symbol/macro needs to be tested 7.19.4.3 tmpfile TODO 7.19.4.4 tmpnam TODO - 7.19.5.1 fclose TEST - 7.19.5.2 fflush TEST - 7.19.5.3 fopen TEST + 7.19.5.1 fclose - + 7.19.5.2 fflush - + 7.19.5.3 fopen TEST ("a" and "+" modes remain) (EXT) fdopen TEST 7.19.5.4 freopen TEST - 7.19.5.5 setbuf TEST - 7.19.5.6 setvbuf TEST + 7.19.5.5 setbuf - + 7.19.5.6 setvbuf - 7.19.6.1 fprintf LDEPS(fwrite) 7.19.6.2 fscanf TODO @@ -130,14 +130,14 @@ TEST: Function/symbol/macro needs to be tested 7.19.7.10 puts LDEPS(fputs) 7.19.7.11 ungetc TODO - 7.19.8.1 fread TEST - 7.19.8.2 fwrite TEST + 7.19.8.1 fread TEST ("a" and "+" modes remain) + 7.19.8.2 fwrite TEST ("a" and "+" modes remain) - 7.19.9.1 fgetpos TEST - 7.19.9.2 fseek TEST - 7.19.9.3 fsetpos TEST - 7.19.9.4 ftell TEST - 7.19.9.5 rewind TEST + 7.19.9.1 fgetpos - + 7.19.9.2 fseek - + 7.19.9.3 fsetpos - + 7.19.9.4 ftell - + 7.19.9.5 rewind - 7.19.10.1 clearerr - 7.19.10.2 feof - diff --git a/src/libc/stdio/fileutil.c b/src/libc/stdio/fileutil.c index 4afe624..a55de18 100644 --- a/src/libc/stdio/fileutil.c +++ b/src/libc/stdio/fileutil.c @@ -77,6 +77,12 @@ ssize_t __fp_write(FILE *fp, void const *data, size_t size) { size_t written = 0; + if(fp->append) { + int rc = fseek(fp, 0, SEEK_END); + if(rc < 0) + return EOF; + } + while(written < size) { ssize_t rc = write(fp->fd, data + written, size - written); diff --git a/src/libc/stdio/fread.c b/src/libc/stdio/fread.c index e8bc584..053136c 100644 --- a/src/libc/stdio/fread.c +++ b/src/libc/stdio/fread.c @@ -4,6 +4,11 @@ size_t fread(void *data, size_t membsize, size_t nmemb, FILE *fp) { + if(!fp->readable) { + fp->error = 1; + return 0; + } + size_t size; if(__builtin_umul_overflow(membsize, nmemb, &size)) { fp->error = 1; diff --git a/src/libc/stdio/fsetpos.c b/src/libc/stdio/fsetpos.c index ffaa4e0..b1cbdcb 100644 --- a/src/libc/stdio/fsetpos.c +++ b/src/libc/stdio/fsetpos.c @@ -6,7 +6,10 @@ int fsetpos(FILE *fp, fpos_t const *pos) if(fflush(fp) == EOF) return -1; - lseek(fp->fd, *pos, SEEK_SET); + off_t rc = lseek(fp->fd, *pos, SEEK_SET); + if(rc < 0) + return -1; + fp->fdpos = *pos; fp->eof = 0; return 0; diff --git a/src/libc/stdio/fwrite.c b/src/libc/stdio/fwrite.c index 065949d..fd9f33b 100644 --- a/src/libc/stdio/fwrite.c +++ b/src/libc/stdio/fwrite.c @@ -4,6 +4,11 @@ size_t fwrite(void const *data, size_t membsize, size_t nmemb, FILE *fp) { + if(!fp->writable) { + fp->error = 1; + return 0; + } + size_t size; if(__builtin_umul_overflow(membsize, nmemb, &size)) { fp->error = 1; @@ -17,20 +22,29 @@ size_t fwrite(void const *data, size_t membsize, size_t nmemb, FILE *fp) __fp_buffer_mode_write(fp); - // TODO: fwrite: line buffering - size_t size_written = 0; + while(size_written < size) { - /* Fill the buffer */ size_t size_frag = fp->bufsize - fp->bufpos; - if(size_frag > size - size_written) + void const *last_line = NULL; + + if(size_frag >= size - size_written) { size_frag = size - size_written; + /* In the last run, if line buffering is enabled and + there is a newline, stop at that newline and flush + before the last write to buffer */ + if(fp->bufmode == _IOLBF) last_line = memrchr( + data + size_written, '\n', size_frag); + } + if(last_line) + size_frag = (last_line + 1) - (data + size_written); + memcpy(fp->buf + fp->bufpos, data + size_written, size_frag); size_written += size_frag; fp->bufpos += size_frag; - if(fp->bufpos >= fp->bufsize) { + if(fp->bufpos >= fp->bufsize || last_line) { ssize_t rc = __fp_write(fp, fp->buf, fp->bufpos); if(rc <= 0) /* error */ break;