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
No known key found for this signature in database
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/ferror.c
src/libc/stdio/feof.c src/libc/stdio/feof.c
src/libc/stdio/fflush.c src/libc/stdio/fflush.c
src/libc/stdio/fgetc.c
src/libc/stdio/fgetpos.c src/libc/stdio/fgetpos.c
src/libc/stdio/fgets.c
src/libc/stdio/fileutil.c src/libc/stdio/fileutil.c
src/libc/stdio/fopen.c src/libc/stdio/fopen.c
src/libc/stdio/fprintf.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) dprintf TEST
(EXT) vdprintf TEST (EXT) vdprintf TEST
7.19.7.1 fgetc TODO 7.19.7.1 fgetc -
7.19.7.2 fgets TODO 7.19.7.2 fgets -
7.19.7.3 fputc TEST 7.19.7.3 fputc -
7.19.7.4 fputs TEST 7.19.7.4 fputs -
7.19.7.5 getc LDEPS(fgetc) 7.19.7.5 getc -
7.19.7.6 getchar LDEPS(fgetc) 7.19.7.6 getchar LDEPS(stdin)
7.19.7.7 gets LDEPS(fgets) 7.19.7.7 gets LDEPS(stdin)
7.19.7.8 putc TEST 7.19.7.8 putc -
7.19.7.9 putchar TEST 7.19.7.9 putchar LDEPS(stdout)
7.19.7.10 puts TEST 7.19.7.10 puts LDEPS(stdout)
7.19.7.11 ungetc - 7.19.7.11 ungetc -
7.19.8.1 fread - 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 "fileutil.h"
#include <gint/defs/util.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.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) { while(read_size < request_size) {
int remaining = request_size - read_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 */ /* 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); ssize_t rc = __fp_read(fp, data+read_size, remaining);
return read_size + (rc == EOF ? 0 : rc); 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) if(read_size >= request_size)
break; 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 */ /* Get more data from the file descriptor into the buffer */
if(fp->buf) { if(fp->buf) {
ssize_t rc = __fp_read(fp, fp->buf, fp->bufsize); 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; 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)) if(!fp->buf || __fp_hasbuf_write(fp))
return -1; 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) if(read_size <= 0)
return 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); memcpy(data, fp->buf + fp->bufpos, read_size);
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 */ /* Rewind the buffer if we read it fully */
if(fp->bufpos >= fp->bufread) { 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 Returns amount of data read; if >= 0 but < size, the buffer should be
refilled. Returns -1 to indicate that unbuffered access should be used. refilled. Returns -1 to indicate that unbuffered access should be used.
Allows reading from temporary ungetc() buffers and cleans them. */ 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 /* Reads data from a file descriptor; updates the fdpos and sets the error
indicator. Returns 0 on success, EOF on error. */ indicator. Returns 0 on success, EOF on error. */

View file

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