From 5c0104111d7b13fab7d96dfe9c38dd47155448db Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 12 Mar 2023 10:23:08 +0100 Subject: [PATCH] libc: Implement fopen, fclose, fread, feof, ferror, and clearerr --- libc/include/stdio.h | 25 ++++++++++++++--- libc/src/stdio.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/libc/include/stdio.h b/libc/include/stdio.h index a5a1d5df..942eecd8 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -8,10 +8,13 @@ typedef struct { - int __unused; + int _fd; + int _err; + int _eof; } FILE; #define SEEK_SET 0 +#define EOF -1 extern FILE* stderr; #define stderr stderr @@ -23,15 +26,29 @@ extern "C" int fflush(FILE*); - FILE* fopen(const char*, const char*); - int fclose(FILE*); + /* Opens a file and binds a stream to it. */ + FILE* fopen(const char* path, const char* mode); + + /* Closes a file and frees up its stream. */ + int fclose(FILE* stream); + + /* Reads arbitrarily sized items from a stream. */ + size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream); - size_t fread(void*, size_t, size_t, FILE*); size_t fwrite(const void*, size_t, size_t, FILE*); int fseek(FILE*, long, int); long ftell(FILE*); + /* Returns whether the error indicator was set in stream. */ + int ferror(FILE* stream); + + /* Returns whether the end-of-file indicator was set in stream. */ + int feof(FILE* stream); + + /* Clears the error and end-of-file indicators in stream. */ + void clearerr(FILE* stream); + void setbuf(FILE*, char*); int fprintf(FILE*, const char*, ...); diff --git a/libc/src/stdio.cpp b/libc/src/stdio.cpp index ec90cac1..5305abbd 100644 --- a/libc/src/stdio.cpp +++ b/libc/src/stdio.cpp @@ -1,7 +1,9 @@ #define _LUNA_SYSTEM_ERROR_EXTENSIONS #include +#include #include #include +#include #include #include #include @@ -16,6 +18,69 @@ extern "C" __errno_return(rc, int); } + FILE* fopen(const char* path, const char*) + { + // FIXME: Parse the mode string. + int fd = open(path, 0); + if (fd < 0) return nullptr; + + FILE* f = (FILE*)malloc(sizeof(FILE)); + if (!f) + { + close(fd); + return nullptr; + } + + f->_fd = fd; + clearerr(f); + + return f; + } + + int fclose(FILE* stream) + { + if (close(stream->_fd) < 0) return EOF; + + free(stream); + + return 0; + } + + size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream) + { + if (size * nmemb == 0) return 0; + + ssize_t nread = read(stream->_fd, buf, size * nmemb); + + if (nread < 0) + { + stream->_err = 1; + return 0; + } + else if (nread == 0) + { + stream->_eof = 1; + return 0; + } + else + return (size_t)nread / size; + } + + int ferror(FILE* stream) + { + return stream->_err; + } + + int feof(FILE* stream) + { + return stream->_eof; + } + + void clearerr(FILE* stream) + { + stream->_eof = stream->_err = 0; + } + int vsnprintf(char* buf, size_t max, const char* format, va_list ap) { return (int)vstring_format(buf, max, format, ap);