stdio: fgetc(), fgets(), tests for fputc() and fputs() (DONE)

This commit is contained in:
Lephenixnoir 2022-01-14 17:16:04 +01:00
parent 294fda9731
commit ed873a652e
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
7 changed files with 108 additions and 19 deletions

View File

@ -126,7 +126,9 @@ set(SOURCES
src/libc/stdio/ferror.c
src/libc/stdio/feof.c
src/libc/stdio/fflush.c
src/libc/stdio/fgetc.c
src/libc/stdio/fgetpos.c
src/libc/stdio/fgets.c
src/libc/stdio/fileutil.c
src/libc/stdio/fopen.c
src/libc/stdio/fprintf.c

20
STATUS
View File

@ -119,16 +119,16 @@ TEST: Function/symbol/macro needs to be tested
(EXT) dprintf TEST
(EXT) vdprintf TEST
7.19.7.1 fgetc TODO
7.19.7.2 fgets 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 TEST
7.19.7.9 putchar TEST
7.19.7.10 puts TEST
7.19.7.1 fgetc -
7.19.7.2 fgets -
7.19.7.3 fputc -
7.19.7.4 fputs -
7.19.7.5 getc -
7.19.7.6 getchar LDEPS(stdin)
7.19.7.7 gets LDEPS(stdin)
7.19.7.8 putc -
7.19.7.9 putchar LDEPS(stdout)
7.19.7.10 puts LDEPS(stdout)
7.19.7.11 ungetc -
7.19.8.1 fread -

43
src/libc/stdio/fgetc.c Normal file
View File

@ -0,0 +1,43 @@
#include <stdio.h>
#include "fileutil.h"
int fgetc(FILE *fp)
{
if(!fp->readable) {
fp->error = 1;
return EOF;
}
/* For this function we inline __fp_fread2() and__fp_buffered_read() in
order to maintain decent performance */
unsigned char c;
__fp_buffer_mode_read(fp);
/* No buffered data available, non-buffered mode */
if(!fp->buf) {
ssize_t rc = __fp_read(fp, &c, 1);
return (rc == 1) ? c : EOF;
}
/* If there is no data, get some */
if(fp->bufpos >= fp->bufread) {
ssize_t rc = __fp_read(fp, fp->buf, fp->bufsize);
if(rc <= 0)
return EOF;
fp->bufread = rc;
}
/* Get a byte from the buffer */
c = fp->buf[fp->bufpos++];
fp->bufungetc -= (fp->bufungetc > 0);
/* Rewind the buffer if at end, and clear _IONBF ungetc() buffers */
if(fp->bufpos >= fp->bufread) {
fp->bufread = 0;
fp->bufpos = 0;
if(fp->bufmode == _IONBF)
__fp_remove_buffer(fp);
}
return c;
}

11
src/libc/stdio/fgets.c Normal file
View File

@ -0,0 +1,11 @@
#include <stdio.h>
#include "fileutil.h"
char *fgets(char * restrict s, int n, FILE * restrict fp)
{
ssize_t read_size = __fp_fread2(fp, s, n - 1, '\n');
if(read_size <= 0)
return NULL;
s[read_size] = 0;
return s;
}

View File

@ -1,5 +1,4 @@
#include "fileutil.h"
#include <gint/defs/util.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
@ -98,10 +97,26 @@ ssize_t __fp_fread2(FILE *fp, void *data, size_t request_size, int stop_char)
while(read_size < request_size) {
int remaining = request_size - read_size;
int chunk = __fp_buffered_read(fp, data+read_size, remaining);
int chunk = __fp_buffered_read(fp, data+read_size, remaining,
stop_char);
/* Stream is not/no longer buffered, finish unbuffered */
if(chunk < 0) {
if(chunk < 0 && stop_char >= 0) {
unsigned char c;
/* When there is a stop char, we can only read one
byte at a time, which is reaaaally slow */
for(int i = 0; i < remaining; i++) {
ssize_t rc = __fp_read(fp, &c, 1);
if(rc != 1)
break;
((char *)data)[read_size++] = c;
if(c == stop_char)
break;
}
return read_size;
}
else if(chunk < 0) {
ssize_t rc = __fp_read(fp, data+read_size, remaining);
return read_size + (rc == EOF ? 0 : rc);
}
@ -110,6 +125,11 @@ ssize_t __fp_fread2(FILE *fp, void *data, size_t request_size, int stop_char)
if(read_size >= request_size)
break;
/* If a stop char has been read, stop */
if(stop_char >= 0 && read_size > 0 &&
((char *)data)[read_size-1] == stop_char)
break;
/* Get more data from the file descriptor into the buffer */
if(fp->buf) {
ssize_t rc = __fp_read(fp, fp->buf, fp->bufsize);
@ -122,18 +142,29 @@ ssize_t __fp_fread2(FILE *fp, void *data, size_t request_size, int stop_char)
return read_size;
}
ssize_t __fp_buffered_read(FILE *fp, void *data, size_t request_size)
ssize_t __fp_buffered_read(FILE *fp, void *data, size_t request_size,
int stop_char)
{
if(!fp->buf || __fp_hasbuf_write(fp))
return -1;
int read_size = min((int)request_size, fp->bufread - fp->bufpos);
int read_size = request_size;
if(read_size > (int)(fp->bufread - fp->bufpos))
read_size = fp->bufread - fp->bufpos;
if(read_size <= 0)
return 0;
if(stop_char >= 0) {
char *end = memchr(fp->buf+fp->bufpos, stop_char, read_size);
if(end != NULL)
read_size = end - (fp->buf + fp->bufpos) + 1;
}
memcpy(data, fp->buf + fp->bufpos, read_size);
fp->bufpos += read_size;
fp->bufungetc = max(fp->bufungetc - read_size, 0);
fp->bufungetc = fp->bufungetc - read_size;
if(fp->bufungetc < 0)
fp->bufungetc = 0;
/* Rewind the buffer if we read it fully */
if(fp->bufpos >= fp->bufread) {

View File

@ -43,7 +43,7 @@ ssize_t __fp_fread2(FILE *fp, void *data, size_t request_size, int stop_char);
Returns amount of data read; if >= 0 but < size, the buffer should be
refilled. Returns -1 to indicate that unbuffered access should be used.
Allows reading from temporary ungetc() buffers and cleans them. */
ssize_t __fp_buffered_read(FILE *fp, void *data, size_t size);
ssize_t __fp_buffered_read(FILE *fp, void *data, size_t size, int stop_char);
/* Reads data from a file descriptor; updates the fdpos and sets the error
indicator. Returns 0 on success, EOF on error. */

View File

@ -15,8 +15,10 @@ int fputc(int c_int, FILE *fp)
return 0;
}
if(!fp->buf)
return __fp_write(fp, &c, 1);
if(!fp->buf) {
ssize_t rc = __fp_write(fp, &c, 1);
return (rc == 1) ? c : EOF;
}
__fp_buffer_mode_write(fp);