stdio: initial versions of fputc() and fputs() (TEST)

This commit is contained in:
Lephenixnoir 2022-01-13 21:21:23 +01:00
parent 6ec0c24e2d
commit f1512125d0
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
7 changed files with 99 additions and 46 deletions

View File

@ -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

14
STATUS
View File

@ -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 -

View File

@ -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))

View File

@ -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.

32
src/libc/stdio/fputc.c Normal file
View File

@ -0,0 +1,32 @@
#include <stdio.h>
#include <string.h>
#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;
}

9
src/libc/stdio/fputs.c Normal file
View File

@ -0,0 +1,9 @@
#include <stdio.h>
#include <string.h>
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;
}

View File

@ -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;
}