From f3e2312d357a6bd0ec69100639d53f03162b8be3 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Wed, 11 May 2022 22:06:28 +0100 Subject: [PATCH] Implemented fgets() and enhanced IO buffering --- photon/libc/include/stdio.h | 3 + photon/libc/stdio/fgetc.c | 4 +- photon/libc/stdio/fgets.c | 32 ++++++++ photon/libc/stdio/ungetc.c | 4 + photon/libc/sys/horizon/__fio.h | 12 +-- photon/libc/sys/horizon/fio.c | 126 ++++++++++++++++++++++++++++---- photon/libc/sys/horizon/init.c | 2 + 7 files changed, 162 insertions(+), 21 deletions(-) create mode 100644 photon/libc/stdio/fgets.c diff --git a/photon/libc/include/stdio.h b/photon/libc/include/stdio.h index 362bd8c..905a9ae 100644 --- a/photon/libc/include/stdio.h +++ b/photon/libc/include/stdio.h @@ -11,6 +11,8 @@ #define FILENAME_MAX 1024 #endif +#define BUFSIZ __FIO_BUFSZ + #define SEEK_SET __SEEK_SET #define SEEK_CUR __SEEK_CUR #define SEEK_END __SEEK_END @@ -41,6 +43,7 @@ extern int fileno(FILE *fp); extern int fputs(const char *str, FILE *fp); extern int fputc(int c, FILE *fp); extern int fgetc(FILE *fp); +extern char *fgets(char *restrict str, int count, FILE *restrict fp); extern int putchar(int c); extern int ungetc(int c, FILE *fp); diff --git a/photon/libc/stdio/fgetc.c b/photon/libc/stdio/fgetc.c index 7f37fb8..4d95b36 100644 --- a/photon/libc/stdio/fgetc.c +++ b/photon/libc/stdio/fgetc.c @@ -4,8 +4,8 @@ int fgetc(FILE *fp) { char ch = 0; - __fio_read(fp, &ch, 1); - if (__fio_error(fp)) { + unsigned int r = __fio_read(fp, &ch, 1); + if (r == 0 || __fio_error(fp) || __fio_eof(fp)) { return EOF; } diff --git a/photon/libc/stdio/fgets.c b/photon/libc/stdio/fgets.c new file mode 100644 index 0000000..d55fe9d --- /dev/null +++ b/photon/libc/stdio/fgets.c @@ -0,0 +1,32 @@ +#include + +char *fgets(char *restrict str, int count, FILE *restrict fp) +{ + if (count < 1) { + return NULL; + } + + if (count == 1) { + str[0] = '\0'; + return str; + } + + int r = 0; + + while (1) { + int c = fgetc(fp); + if (c == EOF) { + str[r] = '\0'; + break; + } + + str[r++] = c; + + if (r == count - 1 || c == '\n') { + str[r] = '\0'; + break; + } + } + + return r > 0 ? str : NULL; +} diff --git a/photon/libc/stdio/ungetc.c b/photon/libc/stdio/ungetc.c index b8fdea0..ab3b99c 100644 --- a/photon/libc/stdio/ungetc.c +++ b/photon/libc/stdio/ungetc.c @@ -3,6 +3,10 @@ int ungetc(int c, FILE *fp) { + if (c == EOF) { + return EOF; + } + int res = __fio_ungetc(fp, c); return res == -1 ? EOF : c; } diff --git a/photon/libc/sys/horizon/__fio.h b/photon/libc/sys/horizon/__fio.h index 7b0131e..c55891d 100644 --- a/photon/libc/sys/horizon/__fio.h +++ b/photon/libc/sys/horizon/__fio.h @@ -8,11 +8,12 @@ extern "C" { #endif struct __io_file { - char buf[__FIO_BUFSZ]; - unsigned long buf_idx; - int fd; - char err; - char unget; + char in_buf[__FIO_BUFSZ]; + char out_buf[__FIO_BUFSZ]; + unsigned long in_buf_ptr, in_buf_len; + unsigned long out_buf_len; + int fd, unget; + char err, eof; }; extern int __fileno(struct __io_file *f); @@ -21,6 +22,7 @@ extern unsigned int __fio_read(struct __io_file *f, char *buf, unsigned int sz); extern unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz); extern unsigned int __fio_flush(struct __io_file *f); extern int __fio_error(struct __io_file *f); +extern int __fio_eof(struct __io_file *f); extern int __fio_ungetc(struct __io_file *f, char c); extern int __fio_fopen(const char *path, const char *mode, struct __io_file *out); diff --git a/photon/libc/sys/horizon/fio.c b/photon/libc/sys/horizon/fio.c index c910f84..5c975fd 100644 --- a/photon/libc/sys/horizon/fio.c +++ b/photon/libc/sys/horizon/fio.c @@ -1,5 +1,5 @@ -#include #include +#include #include #include "sys/types.h" #include "__fio.h" @@ -13,6 +13,20 @@ static int flags_from_mode(const char *r) return 0; } +static int refill(struct __io_file *fp) +{ + ssize_t err = read(fp->fd, fp->in_buf, sizeof fp->in_buf); + if (err < 0) { + fp->err = 1; + return 0; + } + + fp->in_buf_ptr = 0; + fp->in_buf_len = err; + + return err; +} + FILE *__get_stdio_file(int i) { switch (i) { @@ -36,17 +50,37 @@ void __fio_init(int in, int out, int err) int __fio_fopen(const char *path, const char *mode, struct __io_file *fp) { - return -1; + /* TODO */ + int fd = open(path, 0); + if (fd == -1) { + return -1; + } + + fp->fd = fd; + + return 0; } int __fio_fclose(struct __io_file *fp) { - return -1; + if (fp->fd == -1) { + return -1; + } + + close(fp->fd); + fp->fd = -1; + return 0; } int __fio_fdopen(int fd, const char *mode, struct __io_file *fp) { - return -1; + if (fd == -1) { + return -1; + } + + fp->fd = fd; + + return 0; } int __fileno(struct __io_file *f) @@ -56,23 +90,77 @@ int __fileno(struct __io_file *f) unsigned int __fio_read(struct __io_file *f, char *buf, unsigned int sz) { - ssize_t err = read(f->fd, buf, sz); - if (err < 0) { - f->err = 1; + if (sz == 0) { return 0; } - return err; + size_t r = 0; + char *out = buf; + + if (f->unget) { + *out++ = f->unget; + f->unget = 0; + r++; + sz--; + } + + size_t available = f->in_buf_len - f->in_buf_ptr; + + size_t bufread = sz; + if (bufread > available) { + bufread = available; + } + + memcpy(out, f->in_buf + f->in_buf_ptr, bufread); + f->in_buf_ptr += bufread; + out += bufread; + sz -= bufread; + r += bufread; + + if (sz == 0) { + return r; + } + + while (1) { + refill(f); + + available = f->in_buf_len - f->in_buf_ptr; + if (available == 0) { + f->eof = 1; + break; + } + + bufread = sz; + if (bufread > available) { + bufread = available; + } + + memcpy(out, f->in_buf + f->in_buf_ptr, bufread); + f->in_buf_ptr += bufread; + out += bufread; + sz -= bufread; + r += bufread; + + if (sz == 0 || f->err || f->eof) { + break; + } + } + + if (sz > 0) { + f->eof = 1; + } + + return r; } unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz) { for (unsigned int i = 0; i < sz; i++) { - if (f->buf_idx >= __FIO_BUFSZ) { + if (f->out_buf_len >= __FIO_BUFSZ) { __fio_flush(f); } - f->buf[f->buf_idx++] = buf[i]; + f->out_buf[f->out_buf_len++] = buf[i]; if (buf[i] == '\n') { __fio_flush(f); } @@ -83,18 +171,23 @@ unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz) int __fio_ungetc(struct __io_file *f, char c) { + if (f->unget) { + return -1; + } + + f->unget = c; return 0; } unsigned int __fio_flush(struct __io_file *f) { - ssize_t res = write(f->fd, f->buf, f->buf_idx); - if (res != f->buf_idx) { + ssize_t res = write(f->fd, f->out_buf, f->out_buf_len); + if (res != f->out_buf_len) { f->err = 1; } - size_t flushed = f->buf_idx; - f->buf_idx = 0; + size_t flushed = f->out_buf_len; + f->out_buf_len = 0; return flushed; } @@ -102,3 +195,8 @@ int __fio_error(struct __io_file *f) { return f->err != 0; } + +int __fio_eof(struct __io_file *f) +{ + return f->eof != 0; +} diff --git a/photon/libc/sys/horizon/init.c b/photon/libc/sys/horizon/init.c index 7500969..3831f4a 100644 --- a/photon/libc/sys/horizon/init.c +++ b/photon/libc/sys/horizon/init.c @@ -240,6 +240,8 @@ int __crt_init(mx_handle_t bootstrap) dbg_log("calling main\n"); int ret = main(msg->args_num, argv); + fflush(stdout); + fflush(stderr); __crt_run_atexit(); mio_fd_cleanup(); mio_fs_cleanup();