stdio: FILE barebones with buffering model (WIP)

This commit is contained in:
Lephenixnoir 2022-01-01 17:11:04 +01:00
parent b53078776d
commit 51528170bb
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
11 changed files with 349 additions and 107 deletions

View file

@ -120,6 +120,8 @@ set(SOURCES
# stdio # stdio
src/libc/stdio/asprintf.c src/libc/stdio/asprintf.c
src/libc/stdio/dprintf.c src/libc/stdio/dprintf.c
src/libc/stdio/fflush.c
src/libc/stdio/fileutil.c
src/libc/stdio/fprintf.c src/libc/stdio/fprintf.c
src/libc/stdio/printf.c src/libc/stdio/printf.c
src/libc/stdio/printf/format_fixed.c src/libc/stdio/printf/format_fixed.c
@ -129,6 +131,9 @@ set(SOURCES
src/libc/stdio/printf/util.c src/libc/stdio/printf/util.c
src/libc/stdio/putc.c src/libc/stdio/putc.c
src/libc/stdio/puts.c src/libc/stdio/puts.c
src/libc/stdio/remove.c
src/libc/stdio/setbuf.c
src/libc/stdio/setvbuf.c
src/libc/stdio/snprintf.c src/libc/stdio/snprintf.c
src/libc/stdio/sprintf.c src/libc/stdio/sprintf.c
src/libc/stdio/vasprintf.c src/libc/stdio/vasprintf.c

213
STATUS
View file

@ -31,51 +31,49 @@ TODO: Function/symbol/macro is not implemented/defined
BDEPS(...): Function/symbol/macro needs ... to build BDEPS(...): Function/symbol/macro needs ... to build
LDEPS(...): Function/symbol/macro needs ... to link LDEPS(...): Function/symbol/macro needs ... to link
TEST: Function/symbol/macro needs to be tested TEST: Function/symbol/macro needs to be tested
DONE: Function/symbol/macro is defined, builds, links, and is tested -: Function/symbol/macro is defined, builds, links, and is tested
7.2 <assert.h> 7.2 <assert.h>
! 7.2.1 assert: LDEPS(fprintf,stderr) 7.2.1 assert LDEPS(fprintf,stderr)
7.3 <complex.h> => OpenLibm 7.3 <complex.h> => OpenLibm
7.4 <ctype.h> 7.4 <ctype.h>
7.4.1 is*: DONE 7.4.1 is* -
7.4.2 to*: DONE 7.4.2 to* -
7.5 <errno.h> 7.5 <errno.h>
7.5.2 EDOM EILSEQ ERANGE: DONE 7.5.2 EDOM, EILSEQ, ERANGE -
7.6 <fenv.h> => OpenLibm 7.6 <fenv.h> => OpenLibm
7.7 <float.h> => GCC 7.7 <float.h> => GCC
7.8 <inttypes.h> 7.8 <inttypes.h>
! 7.8.1 PRI* macros: LDEPS(*printf) 7.8.1 PRI* macros -
! 7.8.1 SCN* macros: LDEPS(*scanf) 7.8.1 SCN* macros -
7.8.2.1 imaxabs: DONE 7.8.2.1 imaxabs -
7.8.2.2 imaxdiv: DONE 7.8.2.2 imaxdiv -
7.8.2.3 strtoimax strtoumax: DONE 7.8.2.3 strtoimax, strtoumax -
! 7.8.2.4 wcstoimax wcstoumax: TODO 7.8.2.4 wcstoimax, wcstoumax TODO
7.9 <iso646.h> => GCC 7.9 <iso646.h> => GCC
7.10 <limits.h> => GCC 7.10 <limits.h> => GCC
7.11 <locale.h> 7.11 <locale.h>
! 7.11.1 setlocale: TEST 7.11.1 setlocale TEST
! 7.11.2 localeconv: TEST 7.11.2 localeconv TEST
7.12 <math.h> => OpenLibm 7.12 <math.h> => OpenLibm
7.13 <setjmp.h> 7.13 <setjmp.h>
7.13.1 setjmp: DONE 7.13.1 setjmp -
7.13.2 longjmp: DONE 7.13.2 longjmp -
7.14 <signal.h> 7.14 <signal.h>
7.14 sig_atomic_t SIG_DFL SIG_ERR SIG_IGN: DONE 7.14.1.1 signal -
7.14 SIGABRT SIGFPE SIGILL SIGINT SIGSEGV SIGTERM: DONE 7.14.1.2 raise -
7.14.1.1 signal: DONE
7.14.1.2 raise: DONE
7.15 <stdarg.h> => GCC 7.15 <stdarg.h> => GCC
@ -86,93 +84,114 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested
7.18 <stdint.h> => GCC 7.18 <stdint.h> => GCC
7.19 <stdio.h> 7.19 <stdio.h>
7.19.1 Introduction: TEST 7.19.1 Introduction TEST
TODO: Handle wide-oriented streams? (see notes) No wide-oriented streams (see notes)
! 7.19.4 Operations on files: TODO 7.19.4.1 remove TEST
! 7.19.5 File access functions: TODO 7.19.4.2 rename TODO
! 7.19.6 Formatted input/output functions: TODO 7.19.4.3 tmpfile TODO
! 7.19.7 Character input/output functions: TODO 7.19.4.4 tmpnam TODO
! 7.19.8 Direct input/output functions: TODO 7.19.5.1 fclose TODO
! 7.19.9 File positioning functions: TODO 7.19.5.2 fflush TODO
! 7.19.10 Error-handling functions: TODO 7.19.5.3 fopen TODO
7.19.5.4 freopen TODO
7.19.5.5 setbuf TODO
7.19.5.6 setvbuf TODO
7.19.6.1 fprintf LDEPS(fwrite)
7.19.6.2 fscanf TODO
7.19.6.3 printf LDEPS(fwrite, stdout)
7.19.6.4 scanf TODO
7.19.6.5 snprintf -
7.19.6.6 sprintf -
7.19.6.7 sscanf TODO
7.19.6.8 vfprintf LDEPS(fwrite)
7.19.6.9 vfscanf TODO
7.19.6.10 vprintf LDEPS(fwrite, stdout)
7.19.6.11 vscanf TODO
7.19.6.12 vsnprintf -
7.19.6.13 vsprintf -
7.19.6.14 vsscanf TODO
(EXT) asprintf -
(EXT) vasprintf -
(EXT) dprintf TEST
(EXT) vdprintf TEST
7.19.7 Character input/output TODO
7.19.8 Direct input/output TODO
7.19.9 File positioning TODO
7.19.10 Error-handling TODO
7.20 <stdlib.h> 7.20 <stdlib.h>
7.20 RAND_MAX: DONE 7.20 MB_CUR_MAX TODO
! 7.20 MB_CUR_MAX: TODO 7.20.1.1 atof -
7.20.1.1 atof: DONE 7.20.1.2 atoi, atol, atoll -
7.20.1.2 atoi, atol, atoll: DONE 7.20.1.3 strtod, strtof, strtold -
7.20.1.3 strtod, strtof, strtold: DONE 7.20.1.4 strtol, strtoul -
7.20.1.4 strtol, strtoul, strtoll, strtoull: DONE 7.20.1.4 strtoll, strtoull -
7.20.2.1 rand: DONE 7.20.2.1 rand -
7.20.2.2 srand: DONE 7.20.2.2 srand -
7.20.3.1 calloc: DONE 7.20.3.1 calloc -
7.20.3.2 free: DONE (at least gint) 7.20.3.2 free - (gint)
7.20.3.3 malloc: DONE (at least gint) 7.20.3.3 malloc - (gint)
7.20.3.4 realloc: DONE (at least gint) 7.20.3.4 realloc - (gint)
7.20.4.1 abort: DONE 7.20.4.1 abort - (stream flushing/closing/etc?)
! 7.20.4.2 atexit: TODO 7.20.4.2 atexit TODO
7.20.4.3 exit: DONE (missing stream flushing/closing/etc) 7.20.4.3 exit - (stream flushing/closing/etc?)
7.20.4.4 _Exit: DONE (gint only) 7.20.4.4 _Exit - (gint)
! 7.20.4.5 getenv: TODO 7.20.4.5 getenv TODO
! 7.20.4.6 system: TODO 7.20.4.6 system TODO
! 7.20.5.1 bsearch: TODO 7.20.5.1 bsearch TODO
! 7.20.5.2 qsort: TEST 7.20.5.2 qsort TEST
7.20.6.1 abs, labs, llabs: DONE 7.20.6.1 abs, labs, llabs -
7.20.6.2 div, ldiv, lldiv: DONE 7.20.6.2 div, ldiv, lldiv -
! 7.20.7 Multibyte/wide character conversion functions: TODO 7.20.7 Multibyte/wide char conv TODO
! 7.20.8 Multibyte/wide string conversion functions: TODO 7.20.8 Multibyte/wide string conv TODO
7.21 <string.h> 7.21 <string.h>
7.21.2.1 memcpy: DONE 7.21.2.1 memcpy -
7.21.2.2 memmove: DONE (Unoptimized: byte-by-byte) 7.21.2.2 memmove - (Unoptimized: byte-by-byte)
7.21.2.3 strcpy: DONE 7.21.2.3 strcpy -
7.21.2.4 strncpy: DONE 7.21.2.4 strncpy -
7.21.3.1 strcat: DONE 7.21.3.1 strcat -
7.21.3.2 strncat: DONE 7.21.3.2 strncat -
7.21.4.1 memcmp: DONE 7.21.4.1 memcmp -
7.21.4.2 strcmp: DONE 7.21.4.2 strcmp -
7.21.4.3 strcoll: DONE 7.21.4.3 strcoll -
7.21.4.4 strncmp: DONE 7.21.4.4 strncmp -
7.21.4.5 strxfrm: DONE 7.21.4.5 strxfrm -
7.21.5.1 memchr: DONE 7.21.5.1 memchr -
7.21.5.2 strchr: DONE 7.21.5.2 strchr -
7.21.5.3 strcspn: DONE 7.21.5.3 strcspn -
7.21.5.4 strpbrk: DONE 7.21.5.4 strpbrk -
7.21.5.5 strrchr: DONE 7.21.5.5 strrchr -
7.21.5.6 strspn: DONE 7.21.5.6 strspn -
7.21.5.7 strstr: DONE 7.21.5.7 strstr -
7.21.5.8 strtok: DONE 7.21.5.8 strtok -
7.21.6.1 memset: DONE 7.21.6.1 memset -
7.21.6.2 strerror: DONE 7.21.6.2 strerror -
7.21.6.3 strlen: DONE 7.21.6.3 strlen -
Extensions: (EXT) strnlen -
- strnlen: DONE (EXT) strchrnul -
- strchrnul: DONE (EXT) strcasestr -
- strcasestr: DONE (EXT) strcasecmp -
- strcasecmp: DONE (EXT) strncasecmp -
- strncasecmp: DONE (EXT) strdup -
- strdup: DONE (EXT) strndup -
- strndup: DONE
7.22 <tgmath.h> => GCC 7.22 <tgmath.h> => GCC
7.23 <time.h> 7.23 <time.h>
7.23.1 Components of time: DONE 7.23.2.1 clock -
7.23.2.1 clock: DONE 7.23.2.2 difftime -
7.23.2.2 difftime: DONE 7.23.2.3 mktime - (DST flag ignored)
7.23.2.3 mktime: DONE (DST flag ignored) 7.23.2.4 time -
7.23.2.4 time: DONE 7.23.3.1 asctime -
7.23.3.1 asctime: DONE 7.23.3.2 ctime -
7.23.3.2 ctime: DONE 7.23.3.3 gmtime -
7.23.3.3 gmtime: DONE 7.23.3.4 localtime - (No timezones; same as gmtime)
7.23.3.4 localtime: DONE (No timezones; same as gmtime) 7.23.3.5 strftime - (No %g, %G, %U, %V, %W, %z, %Z)
7.23.3.5 strftime: DONE (No %g/%G/%U/%V/%W; timezones %z/%Z empty)
7.24 <wchar.h> 7.24 <wchar.h> TODO (not a priority)
TODO (not a priority)
7.25 <wctype.h> 7.25 <wctype.h> TODO (not a priority)
TODO (not a priority)
# Supporting locales # Supporting locales
@ -188,7 +207,7 @@ What if we wanted to support more locales?
# Supporting text and binary files (newline translation) # Supporting text and binary files (newline translation)
Because of 7.19.2%1,223 we don't need to support newline translation. Because of 7.19.2§1.223 we don't need to support newline translation.
# Support wide-oriented streams # Support wide-oriented streams

View file

@ -8,7 +8,7 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
/* Hide by default in C++ (7.8.1§1.181) */ /* Hide by default in C++ (7.8.1§1.182) */
#if !defined __cplusplus || defined __STDC_FORMAT_MACROS #if !defined __cplusplus || defined __STDC_FORMAT_MACROS
/* Printing signed fixed-width types, decimal */ /* Printing signed fixed-width types, decimal */

View file

@ -20,8 +20,7 @@ typedef size_t fpos_t;
#define _IONBF 2 #define _IONBF 2
/* Some buffer size for file buffering. */ /* Some buffer size for file buffering. */
/* TODO: We might want a larger BUFSIZ than 256 on fx-CG 50. */ #define BUFSIZ 512
#define BUFSIZ 256
/* End-of-file marker. */ /* End-of-file marker. */
#define EOF ((int)(-1)) #define EOF ((int)(-1))
@ -55,6 +54,28 @@ extern FILE *stderr;
#define stdout stdout #define stdout stdout
#define stderr stderr #define stderr stderr
/*
** Operations on files.
*/
/* Remove a file from the filesystem.
In gint, the file must not be open (open files' names are not tracked). */
extern int remove(char const *__filename);
/*
** File access functions.
*/
/* Flush any written data in the FILE's internal buffer. */
extern int fflush(FILE *__fp);
/* Use __buf as a buffer (of size BUFSIZ) for access to __fp. */
extern void setbuf(FILE * __restrict__ __fp, char * __restrict__ __buf);
/* Changer the buffering mode and buffer address for __fp. */
extern int setvbuf(FILE * __restrict__ __fp, char * __restrict__ __buf,
int __mode, size_t __size);
/* /*
** Formatted input/output functions. ** Formatted input/output functions.
** **

View file

@ -2,16 +2,77 @@
# define __BITS_TYPES_FILE_H__ # define __BITS_TYPES_FILE_H__
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#define __FILE_BUF_READ 0
#define __FILE_BUF_WRITE 1
/* The FILE structure is mostly a buffer around kernel-level I/O. Most of the
work is maintaining that buffer to provide the basic fgetc()/fputc()
functions, then everything else is built on top of the abstracted stream.
The buffer of a FILE can either be in reading or writing mode. When in
reading mode, the buffer contains pre-fetched data from a previous read that
hasn't yet been requested by the user. When in writing mode, the buffer
contains data written by the user which hasn't yet been sent to the kernel.
The buffer has the following structure:
0 bufpos bufread bufsize
+--------+---------+---------+
|xxxxxxxx|rrrrrrrrr|uuuuuuuuu| (When reading)
+--------+---------+---------+
|wwwwwwww|uuuuuuuuuuuuuuuuuuu| (When writing)
+--------+-------------------+
x: Data read from file descriptor and returned to user
r: Data read from file descriptor not yet returned to user
w: Data written by user not yet sent to file descriptor
u: Undefined
In reading mode, the region [0..bufread) contains data obtained from the
file. bufpos marks how much has been read, in the sense that [0..bufpos) has
already been returned to the user while [bufpos..bufread) has not. The offset
on the underlying file descriptor sits at bufread, so the position reported
by ftell() is fdpos - bufread + bufpos. The rest of the buffer is undefined.
In writing mode, the region [0..bufpos) contains data received through API
but not yet written to the file descriptor. ftell() reports fdpos + bufpos.
The rest of the buffer is undefined. */
typedef struct { typedef struct {
/* BFile handler */ /* File descriptor */
int fd; int fd;
/* Current position in file */ /* Current position in file, as tracked by the file descriptor (ie. not
size_t pos; accounting for buffer operations) */
/* Buffering mode */ size_t fdpos;
// TODO
/* Opening mode */ /* Pointer to buffer (NULL if _IONBF) */
// TODO char *buf;
/* Current position in buffer, water mark of read data in buffer, and
buffer size; see header comment for details */
size_t bufpos;
size_t bufread;
size_t bufsize;
/* Buffering mode; one of _IOFBF, _IOLBF, or _IONBF */
uint8_t bufmode :2;
/* We own the buffer and it needs to be freed */
uint8_t bufowned :1;
/* __FILE_BUF_READ if the buffer is in reading mode
__FILE_BUF_WRITE if it's in writing mode
This mode can only be changed when bufpos=0, ie. just after fflush(). */
uint8_t bufdir :1;
/* Opening flags */
uint8_t readable :1;
uint8_t writable :1;
uint8_t append :1;
/* Non-zero if text mode, zero if binary mode */
uint8_t text :1;
/* EOF indicator */
uint8_t eof :1;
/* Error indicator */
uint8_t error :1;
} FILE; } FILE;
#endif /*__BITS_TYPES_FILE_H__*/ #endif /*__BITS_TYPES_FILE_H__*/

33
src/libc/stdio/fflush.c Normal file
View file

@ -0,0 +1,33 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include "fileutil.h"
int fflush(FILE *fp)
{
// TODO: fflush(NULL) should flush "all" files (do we track them?)
if(!fp) {
errno = EINVAL;
return EOF;
}
if(!fp->buf)
return 0;
int rc = 0;
/* In reading mode, reset the file offset */
if(fp->bufmode == __FILE_BUF_READ && fp->bufpos < fp->bufread) {
fp->fdpos = fp->fdpos - fp->bufread + fp->bufpos;
lseek(fp->fd, fp->fdpos, SEEK_SET);
fp->bufpos = 0;
fp->bufread = 0;
}
/* In writing mode, write pending data */
else if(fp->bufmode == __FILE_BUF_WRITE && fp->bufpos > 0) {
rc = __fp_write(fp, fp->buf, fp->bufpos);
fp->bufpos = 0;
}
return rc;
}

19
src/libc/stdio/fileutil.c Normal file
View file

@ -0,0 +1,19 @@
#include "fileutil.h"
#include <unistd.h>
int __fp_write(FILE *fp, void const *data, size_t size)
{
if(!fp)
return EOF;
ssize_t rc = write(fp->fd, data, size);
if(rc < 0) {
fp->error = 1;
return EOF;
}
else {
fp->fdpos += rc;
return 0;
}
}

18
src/libc/stdio/fileutil.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef __FILEUTIL_H__
# define __FILEUTIL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
/* Write data to a file descriptor; updates the fdpos and sets the error
indicator. Returns 0 on success, EOF on error. */
int __fp_write(FILE *fp, void const *data, size_t size);
#ifdef __cplusplus
}
#endif
#endif /*__FILEUTIL_H__*/

19
src/libc/stdio/remove.c Normal file
View file

@ -0,0 +1,19 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
int remove(char const *filename)
{
struct stat st;
int rc = stat(filename, &st);
if(rc < 0)
return -1;
if(S_ISDIR(st.st_mode)) {
return rmdir(filename);
}
else {
return unlink(filename);
}
}

11
src/libc/stdio/setbuf.c Normal file
View file

@ -0,0 +1,11 @@
#include <stdio.h>
void setbuf(FILE * restrict fp, char * restrict buf)
{
if(buf) {
setvbuf(fp, buf, _IOFBF, BUFSIZ);
}
else {
setvbuf(fp, buf, _IONBF, 0);
}
}

36
src/libc/stdio/setvbuf.c Normal file
View file

@ -0,0 +1,36 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int setvbuf(FILE * restrict fp, char * restrict buf, int mode, size_t size)
{
if(fp->bufmode != _IONBF) {
fflush(fp);
if(fp->bufowned)
free(fp->buf);
}
fp->buf = NULL;
fp->bufowned = false;
fp->bufmode = _IONBF;
fp->bufsize = 0;
if(mode == _IONBF)
return 0;
if(buf) {
fp->buf = buf;
fp->bufsize = size;
fp->bufmode = mode;
}
else {
fp->buf = malloc(size);
if(!fp->buf)
return -1;
fp->bufsize = size;
fp->bufowned = true;
fp->bufmode = mode;
}
return 0;
}