mirror of
https://git.planet-casio.com/Vhex-Kernel-Core/fxlibc.git
synced 2024-12-29 13:03:38 +01:00
stdio: opening primitives for FILE (WIP)
This commit is contained in:
parent
51528170bb
commit
a12b84f1ef
11 changed files with 280 additions and 30 deletions
|
@ -120,9 +120,13 @@ 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/fclose.c
|
||||||
|
src/libc/stdio/fdopen.c
|
||||||
src/libc/stdio/fflush.c
|
src/libc/stdio/fflush.c
|
||||||
src/libc/stdio/fileutil.c
|
src/libc/stdio/fileutil.c
|
||||||
|
src/libc/stdio/fopen.c
|
||||||
src/libc/stdio/fprintf.c
|
src/libc/stdio/fprintf.c
|
||||||
|
src/libc/stdio/freopen.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
|
||||||
src/libc/stdio/printf/format_fp.c
|
src/libc/stdio/printf/format_fp.c
|
||||||
|
|
47
STATUS
47
STATUS
|
@ -84,18 +84,21 @@ TEST: Function/symbol/macro needs to be 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 (no wide-oriented streams *)
|
||||||
No wide-oriented streams (see notes)
|
|
||||||
7.19.4.1 remove TEST
|
7.19.4.1 remove TEST
|
||||||
7.19.4.2 rename TODO
|
7.19.4.2 rename TODO
|
||||||
7.19.4.3 tmpfile TODO
|
7.19.4.3 tmpfile TODO
|
||||||
7.19.4.4 tmpnam TODO
|
7.19.4.4 tmpnam TODO
|
||||||
7.19.5.1 fclose TODO
|
|
||||||
7.19.5.2 fflush TODO
|
7.19.5.1 fclose TEST
|
||||||
7.19.5.3 fopen TODO
|
7.19.5.2 fflush TEST
|
||||||
|
7.19.5.3 fopen TEST
|
||||||
|
(EXT) fdopen TEST
|
||||||
7.19.5.4 freopen TODO
|
7.19.5.4 freopen TODO
|
||||||
7.19.5.5 setbuf TODO
|
7.19.5.5 setbuf TEST
|
||||||
7.19.5.6 setvbuf TODO
|
7.19.5.6 setvbuf TEST
|
||||||
|
|
||||||
7.19.6.1 fprintf LDEPS(fwrite)
|
7.19.6.1 fprintf LDEPS(fwrite)
|
||||||
7.19.6.2 fscanf TODO
|
7.19.6.2 fscanf TODO
|
||||||
7.19.6.3 printf LDEPS(fwrite, stdout)
|
7.19.6.3 printf LDEPS(fwrite, stdout)
|
||||||
|
@ -114,10 +117,32 @@ TEST: Function/symbol/macro needs to be tested
|
||||||
(EXT) vasprintf -
|
(EXT) vasprintf -
|
||||||
(EXT) dprintf TEST
|
(EXT) dprintf TEST
|
||||||
(EXT) vdprintf TEST
|
(EXT) vdprintf TEST
|
||||||
7.19.7 Character input/output TODO
|
|
||||||
7.19.8 Direct input/output TODO
|
7.19.7.1 fgetc TODO
|
||||||
7.19.9 File positioning TODO
|
7.19.7.2 fgets TODO
|
||||||
7.19.10 Error-handling TODO
|
7.19.7.3 fputc TODO
|
||||||
|
7.19.7.4 fputs TODO
|
||||||
|
7.19.7.5 getc TODO
|
||||||
|
7.19.7.6 getchar TODO
|
||||||
|
7.19.7.7 gets TODO
|
||||||
|
7.19.7.8 putc TODO
|
||||||
|
7.19.7.9 putchar TODO
|
||||||
|
7.19.7.10 puts TODO
|
||||||
|
7.19.7.11 ungetc TODO
|
||||||
|
|
||||||
|
7.19.8.1 fread TODO
|
||||||
|
7.19.8.2 fwrite TODO
|
||||||
|
|
||||||
|
7.19.9.1 fgetpos TODO
|
||||||
|
7.19.9.2 fseek TODO
|
||||||
|
7.19.9.3 fsetpos TODO
|
||||||
|
7.19.9.4 ftell TODO
|
||||||
|
7.19.9.5 rewind TODO
|
||||||
|
|
||||||
|
7.19.10.1 clearerr TODO
|
||||||
|
7.19.10.2 feof TODO
|
||||||
|
7.19.10.3 ferror TODO
|
||||||
|
7.19.10.4 perror TODO
|
||||||
|
|
||||||
7.20 <stdlib.h>
|
7.20 <stdlib.h>
|
||||||
7.20 MB_CUR_MAX TODO
|
7.20 MB_CUR_MAX TODO
|
||||||
|
|
|
@ -66,9 +66,26 @@ extern int remove(char const *__filename);
|
||||||
** File access functions.
|
** File access functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Flush the stream and disassociate it from the underlying file. */
|
||||||
|
extern int fclose(FILE *__fp);
|
||||||
|
|
||||||
/* Flush any written data in the FILE's internal buffer. */
|
/* Flush any written data in the FILE's internal buffer. */
|
||||||
extern int fflush(FILE *__fp);
|
extern int fflush(FILE *__fp);
|
||||||
|
|
||||||
|
/* Open a file and associate a stream with it. */
|
||||||
|
extern FILE *fopen(
|
||||||
|
char const * __restrict__ __filename,
|
||||||
|
char const * __restrict__ __mode);
|
||||||
|
|
||||||
|
/* Open a file descriptor and associate a stream with it. */
|
||||||
|
extern FILE *fdopen(int __fd, char const *__mode);
|
||||||
|
|
||||||
|
/* Reopen a stream with another file, or change its mode. */
|
||||||
|
extern FILE *freopen(
|
||||||
|
char const * __restrict__ __filename,
|
||||||
|
char const * __restrict__ __mode,
|
||||||
|
FILE * __restrict__ __fp);
|
||||||
|
|
||||||
/* Use __buf as a buffer (of size BUFSIZ) for access to __fp. */
|
/* Use __buf as a buffer (of size BUFSIZ) for access to __fp. */
|
||||||
extern void setbuf(FILE * __restrict__ __fp, char * __restrict__ __buf);
|
extern void setbuf(FILE * __restrict__ __fp, char * __restrict__ __buf);
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,20 @@
|
||||||
|
|
||||||
In writing mode, the region [0..bufpos) contains data received through API
|
In writing mode, the region [0..bufpos) contains data received through API
|
||||||
but not yet written to the file descriptor. ftell() reports fdpos + bufpos.
|
but not yet written to the file descriptor. ftell() reports fdpos + bufpos.
|
||||||
The rest of the buffer is undefined. */
|
The rest of the buffer is undefined.
|
||||||
|
|
||||||
|
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 {
|
typedef struct {
|
||||||
/* File descriptor */
|
/* File descriptor */
|
||||||
int fd;
|
int fd;
|
||||||
|
|
10
src/libc/stdio/fclose.c
Normal file
10
src/libc/stdio/fclose.c
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "fileutil.h"
|
||||||
|
|
||||||
|
int fclose(FILE *fp)
|
||||||
|
{
|
||||||
|
__fp_close(fp, true);
|
||||||
|
return 0;
|
||||||
|
}
|
24
src/libc/stdio/fdopen.c
Normal file
24
src/libc/stdio/fdopen.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "fileutil.h"
|
||||||
|
|
||||||
|
FILE *fdopen(int fd, char const *mode)
|
||||||
|
{
|
||||||
|
FILE *fp = calloc(1, sizeof *fp);
|
||||||
|
if(!fp) goto err;
|
||||||
|
|
||||||
|
int flags = __fp_parse_mode(mode, fp);
|
||||||
|
if(flags < 0) goto err;
|
||||||
|
|
||||||
|
__fp_open(fp, fd, true);
|
||||||
|
|
||||||
|
/* TODO: fdopen(): Seek to the current file offset of the fd */
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if(fp && fp->bufowned)
|
||||||
|
free(fp->buf);
|
||||||
|
free(fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -13,21 +13,21 @@ int fflush(FILE *fp)
|
||||||
if(!fp->buf)
|
if(!fp->buf)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
/* In reading mode, reset the file offset */
|
/* In reading mode, reset the file offset */
|
||||||
if(fp->bufmode == __FILE_BUF_READ && fp->bufpos < fp->bufread) {
|
if(fp->bufmode == __FILE_BUF_READ && fp->bufpos < fp->bufread) {
|
||||||
fp->fdpos = fp->fdpos - fp->bufread + fp->bufpos;
|
fp->fdpos = fp->fdpos - fp->bufread + fp->bufpos;
|
||||||
lseek(fp->fd, fp->fdpos, SEEK_SET);
|
lseek(fp->fd, fp->fdpos, SEEK_SET);
|
||||||
fp->bufpos = 0;
|
fp->bufpos = 0;
|
||||||
fp->bufread = 0;
|
fp->bufread = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In writing mode, write pending data */
|
/* In writing mode, write pending data */
|
||||||
else if(fp->bufmode == __FILE_BUF_WRITE && fp->bufpos > 0) {
|
if(fp->bufmode == __FILE_BUF_WRITE && fp->bufpos > 0) {
|
||||||
rc = __fp_write(fp, fp->buf, fp->bufpos);
|
ssize_t written = __fp_write(fp, fp->buf, fp->bufpos);
|
||||||
fp->bufpos = 0;
|
fp->bufpos = 0;
|
||||||
|
return (written == (ssize_t)fp->bufpos ? 0 : EOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,107 @@
|
||||||
#include "fileutil.h"
|
#include "fileutil.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
int __fp_write(FILE *fp, void const *data, size_t size)
|
int __fp_open(FILE *fp, int fd, bool use_buffering)
|
||||||
{
|
{
|
||||||
if(!fp)
|
/* We initialize fdpos to 0 even in append mode (7.19.3§1) */
|
||||||
return EOF;
|
fp->fd = fd;
|
||||||
|
fp->fdpos = 0;
|
||||||
|
|
||||||
ssize_t rc = write(fp->fd, data, size);
|
/* We assume all files in the filesystem are non-interactive in order
|
||||||
|
to conform to (7.19.5.3§7)
|
||||||
|
TODO: Vhex might want something more elaborate here */
|
||||||
|
if(use_buffering && setvbuf(fp, NULL, _IOFBF, BUFSIZ))
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(rc < 0) {
|
return 0;
|
||||||
fp->error = 1;
|
}
|
||||||
return EOF;
|
|
||||||
}
|
void __fp_close(FILE *fp, bool free_fp)
|
||||||
else {
|
{
|
||||||
fp->fdpos += rc;
|
fflush(fp);
|
||||||
return 0;
|
close(fp->fd);
|
||||||
}
|
if(fp->bufowned)
|
||||||
|
free(fp->buf);
|
||||||
|
if(free_fp)
|
||||||
|
free(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t __fp_read(FILE *fp, void *data, size_t size)
|
||||||
|
{
|
||||||
|
size_t read_ = 0;
|
||||||
|
|
||||||
|
while(read_ < size) {
|
||||||
|
ssize_t rc = read(fp->fd, data + read_, size - read_);
|
||||||
|
|
||||||
|
if(rc < 0) {
|
||||||
|
fp->error = 1;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
if(rc == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
fp->fdpos += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t __fp_write(FILE *fp, void const *data, size_t size)
|
||||||
|
{
|
||||||
|
size_t written = 0;
|
||||||
|
|
||||||
|
while(written < size) {
|
||||||
|
ssize_t rc = write(fp->fd, data + written, size - written);
|
||||||
|
|
||||||
|
if(rc < 0) {
|
||||||
|
fp->error = 1;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
if(rc == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
fp->fdpos += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __fp_parse_mode(char const *mode, FILE *fp)
|
||||||
|
{
|
||||||
|
int base = 0;
|
||||||
|
bool binary = false;
|
||||||
|
bool update = false;
|
||||||
|
|
||||||
|
for(int i = 0; mode[i]; i++) {
|
||||||
|
if(mode[i] == 'r' || mode[i] == 'w' || mode[i] == 'a') {
|
||||||
|
if(base) goto err;
|
||||||
|
base = mode[i];
|
||||||
|
}
|
||||||
|
else if(mode[i] == 'b')
|
||||||
|
binary = true;
|
||||||
|
else if(mode[i] == '+')
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
if(!base) goto err;
|
||||||
|
|
||||||
|
if(fp) {
|
||||||
|
fp->readable = (base == 'r' || update);
|
||||||
|
fp->writable = (base == 'w' || base == 'a' || update);
|
||||||
|
fp->append = (base == 'a');
|
||||||
|
fp->text = !binary;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(base == 'r')
|
||||||
|
return (update ? O_RDWR : O_RDONLY);
|
||||||
|
if(base == 'w')
|
||||||
|
return (update ? O_RDWR : O_WRONLY) | O_CREAT | O_TRUNC;
|
||||||
|
if(base == 'a')
|
||||||
|
return (update ? O_RDWR : O_WRONLY) | O_CREAT;
|
||||||
|
/* Fallthrough */
|
||||||
|
|
||||||
|
err:
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,27 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
/* Open a file descriptor in a pre-allocated FILE. */
|
||||||
|
int __fp_open(FILE *fp, int fd, bool use_buffering);
|
||||||
|
|
||||||
|
/* Close fp and free all of its resources. */
|
||||||
|
void __fp_close(FILE *fp, bool free_fp);
|
||||||
|
|
||||||
|
/* Reads data from a file descriptor; updates the fdpos and sets the error
|
||||||
|
indicator. Returns 0 on success, EOF on error. */
|
||||||
|
ssize_t __fp_read(FILE *fp, void *data, size_t size);
|
||||||
|
|
||||||
/* Write data to a file descriptor; updates the fdpos and sets the error
|
/* Write data to 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. */
|
||||||
int __fp_write(FILE *fp, void const *data, size_t size);
|
ssize_t __fp_write(FILE *fp, void const *data, size_t size);
|
||||||
|
|
||||||
|
/* Parse mode bits. Returns corresponding open() flags if successful, -1 if the
|
||||||
|
mode is invalid. If [fp != NULL], also sets the fields of [fp]. Sets
|
||||||
|
errno = EINVAL in case of error. */
|
||||||
|
int __fp_parse_mode(char const *mode, FILE *fp);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
25
src/libc/stdio/fopen.c
Normal file
25
src/libc/stdio/fopen.c
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "fileutil.h"
|
||||||
|
|
||||||
|
FILE *fopen(char const * restrict filename, char const * restrict mode)
|
||||||
|
{
|
||||||
|
FILE *fp = calloc(1, sizeof *fp);
|
||||||
|
if(!fp) goto err;
|
||||||
|
|
||||||
|
int flags = __fp_parse_mode(mode, fp);
|
||||||
|
if(flags < 0) goto err;
|
||||||
|
|
||||||
|
int fd = open(filename, flags, 0755);
|
||||||
|
if(fd < 0) goto err;
|
||||||
|
|
||||||
|
__fp_open(fp, fd, true);
|
||||||
|
return fp;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if(fp && fp->bufowned)
|
||||||
|
free(fp->buf);
|
||||||
|
free(fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
27
src/libc/stdio/freopen.c
Normal file
27
src/libc/stdio/freopen.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "fileutil.h"
|
||||||
|
|
||||||
|
FILE *freopen(char const * restrict filename, char const * restrict mode,
|
||||||
|
FILE * restrict fp)
|
||||||
|
{
|
||||||
|
__fp_close(fp, false);
|
||||||
|
memset(fp, 0, sizeof *fp);
|
||||||
|
|
||||||
|
int flags = __fp_parse_mode(mode, fp);
|
||||||
|
if(flags < 0) goto err;
|
||||||
|
|
||||||
|
int fd = open(filename, flags, 0755);
|
||||||
|
if(fd < 0) goto err;
|
||||||
|
|
||||||
|
__fp_open(fp, fd, true);
|
||||||
|
return fp;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if(fp && fp->bufowned)
|
||||||
|
free(fp->buf);
|
||||||
|
free(fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
Loading…
Reference in a new issue