stdio: share the FILE implementation between all versions

This commit is contained in:
Lephenixnoir 2022-01-13 21:28:19 +01:00
parent f1512125d0
commit 294fda9731
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
8 changed files with 91 additions and 163 deletions

View File

@ -11,7 +11,7 @@ extern "C" {
** parse options, lay out strings, and generate output.
*/
#include <bits/types/FILE.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>

View File

@ -7,9 +7,97 @@ extern "C" {
#include <stddef.h>
#include <stdarg.h>
#include <stdint.h>
#include <sys/types.h>
/* Type of FILE handlers. */
#include <bits/types/FILE.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.
The ungetc() function pushes back characters into the buffer; if the FILE is
unbuffered, then it's made buffered temporarily to hold the characters and
cleared at the next fflush() or read. The buffer is put in reading mode. For
this reason, reading functions should test [fp->buf] to check whether there
is a buffer instead of [fp->bufmode != _IONBF].
Many fields in the FILE structure are abstracted away by API calls in layers:
1. [fd], [fdpos] and [error] are updated by the primitive functions of
fileutil.c which essentially wrap kernel I/O (plus clearerr() obviously).
2. [buf], [bufsize], [bufmode] and [bufowned] are handled by setbuf(),
setvbuf() and fclose().
3. [bufpos], [bufread] and [bufdir] are set by primitive read/write functions
like fgets() or fwrite(), and cleared by fflush().
4. [readable], [writable], [append] and [text] are set by fopen() and
freopen(), and used as read-only by the primitive functions of 3. */
typedef struct {
/* File descriptor */
int fd;
/* 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;
/* Number of ungetc()'d characters at the start of buffer data */
int bufungetc;
/* 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 immediately 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;
/* Type of positions within files. We don't have wide-oriented streams. */
typedef size_t fpos_t;

View File

@ -1,7 +0,0 @@
#ifndef __BITS_TYPES_FILE_H__
# define __BITS_TYPES_FILE_H__
typedef struct {
} FILE;
#endif /*__BITS_TYPES_FILE_H__*/

View File

@ -1,7 +0,0 @@
#ifndef __BITS_TYPES_FILE_H__
# define __BITS_TYPES_FILE_H__
typedef struct {
} FILE;
#endif /*__BITS_TYPES_FILE_H__*/

View File

@ -1,99 +0,0 @@
#ifndef __BITS_TYPES_FILE_H__
# 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.
The ungetc() function pushes back characters into the buffer; if the FILE is
unbuffered, then it's made buffered temporarily to hold the characters and
cleared at the next fflush() or read. The buffer is put in reading mode. For
this reason, reading functions should test [fp->buf] to check whether there
is a buffer instead of [fp->bufmode != _IONBF].
Many fields in the FILE structure are abstracted away by API calls in layers:
1. [fd], [fdpos] and [error] are updated by the primitive functions of
fileutil.c which essentially wrap kernel I/O (plus clearerr() obviously).
2. [buf], [bufsize], [bufmode] and [bufowned] are handled by setbuf(),
setvbuf() and fclose().
3. [bufpos], [bufread] and [bufdir] are set by primitive read/write functions
like fgets() or fwrite(), and cleared by fflush().
4. [readable], [writable], [append] and [text] are set by fopen() and
freopen(), and used as read-only by the primitive functions of 3.
TODO: EOF indicator */
typedef struct {
/* File descriptor */
int fd;
/* 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;
/* Number of ungetc()'d characters at the start of buffer data */
int bufungetc;
/* 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 immediately 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__*/

View File

@ -1,13 +0,0 @@
#ifndef __BITS_TYPES_FILE_H__
# define __BITS_TYPES_FILE_H__
// opaque definition of the _IO_FILE
struct _IO_FILE;
/*
** The opaque type of streams.
** This is the definition used elsewhere.
*/
typedef struct _IO_FILE FILE;
#endif /*__BITS_TYPES_FILE_H__*/

View File

@ -1,8 +0,0 @@
#ifndef __BITS_TYPES___FILE_H__
# define ___BITS_TYPES___FILE_H__
// define opaque definition of the FILE type
struct _IO_FILE;
typedef struct _IO_FILE __FILE;
#endif /*__BITS_TYPES___FILE_H__*/

View File

@ -1,26 +0,0 @@
#ifndef __BITS_TYPES_STRUCT_FILE_H__
# define __BITS_TYPES_STRUCT_FILE_H__
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>
//---
// TODO: VFS abstraction ? or ABI-spesific abstraction ?
//---
// Define _IO_FILE
// TODO: add open flags
// TODO: add file descriptor ?
// TODO: update me !
struct _IO_FILE
{
off_t cursor;
int permission;
void *file_op;
void *private;
};
#endif /*__BITS_TYPES_STRUCT_FILE_H__*/