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
src/libc/stdio/asprintf.c
src/libc/stdio/dprintf.c
src/libc/stdio/fflush.c
src/libc/stdio/fileutil.c
src/libc/stdio/fprintf.c
src/libc/stdio/printf.c
src/libc/stdio/printf/format_fixed.c
@ -129,6 +131,9 @@ set(SOURCES
src/libc/stdio/printf/util.c
src/libc/stdio/putc.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/sprintf.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
LDEPS(...): Function/symbol/macro needs ... to link
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.1 assert: LDEPS(fprintf,stderr)
7.2.1 assert LDEPS(fprintf,stderr)
7.3 <complex.h> => OpenLibm
7.4 <ctype.h>
7.4.1 is*: DONE
7.4.2 to*: DONE
7.4.1 is* -
7.4.2 to* -
7.5 <errno.h>
7.5.2 EDOM EILSEQ ERANGE: DONE
7.5.2 EDOM, EILSEQ, ERANGE -
7.6 <fenv.h> => OpenLibm
7.7 <float.h> => GCC
7.8 <inttypes.h>
! 7.8.1 PRI* macros: LDEPS(*printf)
! 7.8.1 SCN* macros: LDEPS(*scanf)
7.8.2.1 imaxabs: DONE
7.8.2.2 imaxdiv: DONE
7.8.2.3 strtoimax strtoumax: DONE
! 7.8.2.4 wcstoimax wcstoumax: TODO
7.8.1 PRI* macros -
7.8.1 SCN* macros -
7.8.2.1 imaxabs -
7.8.2.2 imaxdiv -
7.8.2.3 strtoimax, strtoumax -
7.8.2.4 wcstoimax, wcstoumax TODO
7.9 <iso646.h> => GCC
7.10 <limits.h> => GCC
7.11 <locale.h>
! 7.11.1 setlocale: TEST
! 7.11.2 localeconv: TEST
7.11.1 setlocale TEST
7.11.2 localeconv TEST
7.12 <math.h> => OpenLibm
7.13 <setjmp.h>
7.13.1 setjmp: DONE
7.13.2 longjmp: DONE
7.13.1 setjmp -
7.13.2 longjmp -
7.14 <signal.h>
7.14 sig_atomic_t SIG_DFL SIG_ERR SIG_IGN: DONE
7.14 SIGABRT SIGFPE SIGILL SIGINT SIGSEGV SIGTERM: DONE
7.14.1.1 signal: DONE
7.14.1.2 raise: DONE
7.14.1.1 signal -
7.14.1.2 raise -
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.19 <stdio.h>
7.19.1 Introduction: TEST
TODO: Handle wide-oriented streams? (see notes)
! 7.19.4 Operations on files: TODO
! 7.19.5 File access functions: TODO
! 7.19.6 Formatted input/output functions: TODO
! 7.19.7 Character input/output functions: TODO
! 7.19.8 Direct input/output functions: TODO
! 7.19.9 File positioning functions: TODO
! 7.19.10 Error-handling functions: TODO
7.19.1 Introduction TEST
No wide-oriented streams (see notes)
7.19.4.1 remove TEST
7.19.4.2 rename TODO
7.19.4.3 tmpfile TODO
7.19.4.4 tmpnam TODO
7.19.5.1 fclose TODO
7.19.5.2 fflush 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 RAND_MAX: DONE
! 7.20 MB_CUR_MAX: TODO
7.20.1.1 atof: DONE
7.20.1.2 atoi, atol, atoll: DONE
7.20.1.3 strtod, strtof, strtold: DONE
7.20.1.4 strtol, strtoul, strtoll, strtoull: DONE
7.20.2.1 rand: DONE
7.20.2.2 srand: DONE
7.20.3.1 calloc: DONE
7.20.3.2 free: DONE (at least gint)
7.20.3.3 malloc: DONE (at least gint)
7.20.3.4 realloc: DONE (at least gint)
7.20.4.1 abort: DONE
! 7.20.4.2 atexit: TODO
7.20.4.3 exit: DONE (missing stream flushing/closing/etc)
7.20.4.4 _Exit: DONE (gint only)
! 7.20.4.5 getenv: TODO
! 7.20.4.6 system: TODO
! 7.20.5.1 bsearch: TODO
! 7.20.5.2 qsort: TEST
7.20.6.1 abs, labs, llabs: DONE
7.20.6.2 div, ldiv, lldiv: DONE
! 7.20.7 Multibyte/wide character conversion functions: TODO
! 7.20.8 Multibyte/wide string conversion functions: TODO
7.20 MB_CUR_MAX TODO
7.20.1.1 atof -
7.20.1.2 atoi, atol, atoll -
7.20.1.3 strtod, strtof, strtold -
7.20.1.4 strtol, strtoul -
7.20.1.4 strtoll, strtoull -
7.20.2.1 rand -
7.20.2.2 srand -
7.20.3.1 calloc -
7.20.3.2 free - (gint)
7.20.3.3 malloc - (gint)
7.20.3.4 realloc - (gint)
7.20.4.1 abort - (stream flushing/closing/etc?)
7.20.4.2 atexit TODO
7.20.4.3 exit - (stream flushing/closing/etc?)
7.20.4.4 _Exit - (gint)
7.20.4.5 getenv TODO
7.20.4.6 system TODO
7.20.5.1 bsearch TODO
7.20.5.2 qsort TEST
7.20.6.1 abs, labs, llabs -
7.20.6.2 div, ldiv, lldiv -
7.20.7 Multibyte/wide char conv TODO
7.20.8 Multibyte/wide string conv TODO
7.21 <string.h>
7.21.2.1 memcpy: DONE
7.21.2.2 memmove: DONE (Unoptimized: byte-by-byte)
7.21.2.3 strcpy: DONE
7.21.2.4 strncpy: DONE
7.21.3.1 strcat: DONE
7.21.3.2 strncat: DONE
7.21.4.1 memcmp: DONE
7.21.4.2 strcmp: DONE
7.21.4.3 strcoll: DONE
7.21.4.4 strncmp: DONE
7.21.4.5 strxfrm: DONE
7.21.5.1 memchr: DONE
7.21.5.2 strchr: DONE
7.21.5.3 strcspn: DONE
7.21.5.4 strpbrk: DONE
7.21.5.5 strrchr: DONE
7.21.5.6 strspn: DONE
7.21.5.7 strstr: DONE
7.21.5.8 strtok: DONE
7.21.6.1 memset: DONE
7.21.6.2 strerror: DONE
7.21.6.3 strlen: DONE
Extensions:
- strnlen: DONE
- strchrnul: DONE
- strcasestr: DONE
- strcasecmp: DONE
- strncasecmp: DONE
- strdup: DONE
- strndup: DONE
7.21.2.1 memcpy -
7.21.2.2 memmove - (Unoptimized: byte-by-byte)
7.21.2.3 strcpy -
7.21.2.4 strncpy -
7.21.3.1 strcat -
7.21.3.2 strncat -
7.21.4.1 memcmp -
7.21.4.2 strcmp -
7.21.4.3 strcoll -
7.21.4.4 strncmp -
7.21.4.5 strxfrm -
7.21.5.1 memchr -
7.21.5.2 strchr -
7.21.5.3 strcspn -
7.21.5.4 strpbrk -
7.21.5.5 strrchr -
7.21.5.6 strspn -
7.21.5.7 strstr -
7.21.5.8 strtok -
7.21.6.1 memset -
7.21.6.2 strerror -
7.21.6.3 strlen -
(EXT) strnlen -
(EXT) strchrnul -
(EXT) strcasestr -
(EXT) strcasecmp -
(EXT) strncasecmp -
(EXT) strdup -
(EXT) strndup -
7.22 <tgmath.h> => GCC
7.23 <time.h>
7.23.1 Components of time: DONE
7.23.2.1 clock: DONE
7.23.2.2 difftime: DONE
7.23.2.3 mktime: DONE (DST flag ignored)
7.23.2.4 time: DONE
7.23.3.1 asctime: DONE
7.23.3.2 ctime: DONE
7.23.3.3 gmtime: DONE
7.23.3.4 localtime: DONE (No timezones; same as gmtime)
7.23.3.5 strftime: DONE (No %g/%G/%U/%V/%W; timezones %z/%Z empty)
7.23.2.1 clock -
7.23.2.2 difftime -
7.23.2.3 mktime - (DST flag ignored)
7.23.2.4 time -
7.23.3.1 asctime -
7.23.3.2 ctime -
7.23.3.3 gmtime -
7.23.3.4 localtime - (No timezones; same as gmtime)
7.23.3.5 strftime - (No %g, %G, %U, %V, %W, %z, %Z)
7.24 <wchar.h>
TODO (not a priority)
7.24 <wchar.h> TODO (not a priority)
7.25 <wctype.h>
TODO (not a priority)
7.25 <wctype.h> TODO (not a priority)
# Supporting locales
@ -188,7 +207,7 @@ What if we wanted to support more locales?
# 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

View file

@ -8,7 +8,7 @@ extern "C" {
#include <stdint.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
/* Printing signed fixed-width types, decimal */

View file

@ -20,8 +20,7 @@ typedef size_t fpos_t;
#define _IONBF 2
/* Some buffer size for file buffering. */
/* TODO: We might want a larger BUFSIZ than 256 on fx-CG 50. */
#define BUFSIZ 256
#define BUFSIZ 512
/* End-of-file marker. */
#define EOF ((int)(-1))
@ -55,6 +54,28 @@ extern FILE *stderr;
#define stdout stdout
#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.
**

View file

@ -2,16 +2,77 @@
# define __BITS_TYPES_FILE_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 {
/* BFile handler */
/* File descriptor */
int fd;
/* Current position in file */
size_t pos;
/* Buffering mode */
// TODO
/* Opening mode */
// TODO
/* Current position in file, as tracked by the file descriptor (ie. not
accounting for buffer operations) */
size_t fdpos;
/* Pointer to buffer (NULL if _IONBF) */
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;
#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;
}