From 93f6be9319f42283659bb34c35c3262b0b64327b Mon Sep 17 00:00:00 2001 From: apio Date: Mon, 10 Oct 2022 21:08:57 +0200 Subject: [PATCH] libc: Implement the start of a FILE* API (the standard, portable C way of doing file stuff) --- apps/src/init.c | 20 +++++----- libs/libc/include/bits/error.h | 2 + libs/libc/include/stdio.h | 2 +- libs/libc/src/file.cpp | 61 ++++++++++++++++++++++++++++ libs/libc/src/printf.cpp | 42 +++++++++++++++++++ libs/libc/src/stdio.cpp | 73 ++-------------------------------- 6 files changed, 120 insertions(+), 80 deletions(-) create mode 100644 libs/libc/src/file.cpp diff --git a/apps/src/init.c b/apps/src/init.c index e8850e0a..9a7ecdd3 100644 --- a/apps/src/init.c +++ b/apps/src/init.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -32,19 +32,21 @@ int main() printf("Opening %s for reading...\n", filename); - int fd = open(filename, O_RDONLY); - if (fd < 0) + FILE* config = fopen(filename, "r"); + if (!config) { - perror("open"); + perror("fopen"); // return 1; } char buf[4096]; - ssize_t nread = read(fd, buf, sizeof(buf)); - if (nread < 0) + size_t nread = fread(buf, sizeof(buf), 1, config); + if (nread == 0 && errno != 0) // FIXME: looks like our only way of checking whether a zero-read is an error or eof + // right now is checking errno, since fread() does not differentiate between the two, + // and feof() and ferror() are not yet implemented { - perror("read"); + perror("fread"); // return 1; } else @@ -56,9 +58,9 @@ int main() printf("%s", buf); } - if (close(fd) < 0) + if (fclose(config) < 0) { - perror("close"); + perror("fclose"); // return 1; } diff --git a/libs/libc/include/bits/error.h b/libs/libc/include/bits/error.h index 43d4a195..8e92d81f 100644 --- a/libs/libc/include/bits/error.h +++ b/libs/libc/include/bits/error.h @@ -10,6 +10,7 @@ errno = (int)(-rc); \ return -1; \ } \ + errno = 0; \ return (type)rc; \ } while (0) @@ -20,6 +21,7 @@ errno = (int)((rc)&0xff); \ return (type)-1; \ } \ + errno = 0; \ return (type)rc; \ } while (0) diff --git a/libs/libc/include/stdio.h b/libs/libc/include/stdio.h index adea55f3..97d11e24 100644 --- a/libs/libc/include/stdio.h +++ b/libs/libc/include/stdio.h @@ -8,7 +8,7 @@ typedef struct { - int unused; + int fd; } FILE; #ifdef __cplusplus diff --git a/libs/libc/src/file.cpp b/libs/libc/src/file.cpp new file mode 100644 index 00000000..8bc63ef1 --- /dev/null +++ b/libs/libc/src/file.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +extern "C" +{ + int fclose(FILE* stream) + { + int status = close(stream->fd); + free(stream); // We do not want to leak memory. man fclose(3) says that whether fclose() fails or not, any + // further operation on the stream results in undefined behavior. So we are free to free the + // stream. + return status; + } + + int fflush(FILE*) + { + return 0; // FIXME: Implement buffered IO. + } + + FILE* fopen(const char* pathname, const char*) + { + int fd = open(pathname, O_RDONLY); // FIXME: Use the mode string. + if (fd < 0) { return 0; } + FILE* stream = (FILE*)malloc(sizeof(FILE)); + stream->fd = fd; + return stream; + } + + size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream) + { + ssize_t status = read(stream->fd, buf, size * nmemb); + if (status < 0) + return 0; // FIXME: The manual says that fread() does not differentiate between EOF and error, and that + // ferror() and feof() should be called to determine such. So right now, we just mask the error, + // until that is implemented. + return (size_t)status; + } + + int fseek(FILE*, long, int) + { + NOT_IMPLEMENTED("fseek"); + } + + long ftell(FILE*) + { + NOT_IMPLEMENTED("ftell"); + } + + size_t fwrite(const void*, size_t, size_t, FILE*) + { + NOT_IMPLEMENTED("fwrite"); + } + + void setbuf(FILE*, char*) + { + NOT_IMPLEMENTED("setbuf"); + } +} \ No newline at end of file diff --git a/libs/libc/src/printf.cpp b/libs/libc/src/printf.cpp index 31f9750f..86b418b3 100644 --- a/libs/libc/src/printf.cpp +++ b/libs/libc/src/printf.cpp @@ -329,4 +329,46 @@ extern "C" }, max == 0 ? 0 : max - 1, ap); } + + int snprintf(char* str, size_t max, const char* format, ...) + { + va_list ap; + va_start(ap, format); + int written = vsnprintf(str, max, format, ap); + va_end(ap); + return written; + } + + int sprintf(char* str, const char* format, ...) + { + va_list ap; + va_start(ap, format); + int written = vsprintf(str, format, ap); + va_end(ap); + return written; + } + + int printf(const char* format, ...) + { + va_list ap; + va_start(ap, format); + int written = vprintf(format, ap); + va_end(ap); + return written; + } + + int fprintf(FILE*, const char* format, ...) // FIXME: Make fprintf print to the selected file instead of stdout. + { + va_list ap; + va_start(ap, format); + int written = vprintf(format, ap); + va_end(ap); + return written; + } + + int vfprintf(FILE*, const char* format, + va_list ap) // FIXME: Make vfprintf print to the selected file instead of stdout. + { + return vprintf(format, ap); + } } \ No newline at end of file diff --git a/libs/libc/src/stdio.cpp b/libs/libc/src/stdio.cpp index 7768dc77..c19aff27 100644 --- a/libs/libc/src/stdio.cpp +++ b/libs/libc/src/stdio.cpp @@ -8,51 +8,6 @@ extern "C" { - int fclose(FILE*) - { - NOT_IMPLEMENTED("fclose"); - } - int fflush(FILE*) - { - NOT_IMPLEMENTED("fflush"); - } - FILE* fopen(const char*, const char*) - { - NOT_IMPLEMENTED("fopen"); - } - int fprintf(FILE*, const char* format, ...) // FIXME: Make fprintf print to the selected file instead of stdout. - { - va_list ap; - va_start(ap, format); - int written = vprintf(format, ap); - va_end(ap); - return written; - } - size_t fread(void*, size_t, size_t, FILE*) - { - NOT_IMPLEMENTED("fread"); - } - int fseek(FILE*, long, int) - { - NOT_IMPLEMENTED("fseek"); - } - long ftell(FILE*) - { - NOT_IMPLEMENTED("ftell"); - } - size_t fwrite(const void*, size_t, size_t, FILE*) - { - NOT_IMPLEMENTED("fwrite"); - } - void setbuf(FILE*, char*) - { - NOT_IMPLEMENTED("setbuf"); - } - int vfprintf(FILE*, const char* format, - va_list ap) // FIXME: Make vfprintf print to the selected file instead of stdout. - { - return vprintf(format, ap); - } int puts(const char* s) { long nwritten = syscall(SYS_write, s, strlen(s)); @@ -60,33 +15,11 @@ extern "C" nwritten += syscall(SYS_write, "\n", 1); return (int)nwritten; } - int snprintf(char* str, size_t max, const char* format, ...) - { - va_list ap; - va_start(ap, format); - int written = vsnprintf(str, max, format, ap); - va_end(ap); - return written; - } - int sprintf(char* str, const char* format, ...) - { - va_list ap; - va_start(ap, format); - int written = vsprintf(str, format, ap); - va_end(ap); - return written; - } - int printf(const char* format, ...) - { - va_list ap; - va_start(ap, format); - int written = vprintf(format, ap); - va_end(ap); - return written; - } void perror(const char* s) // FIXME: Print to stderr, whenever we have an stderr. { + int savederr = + errno; // This was necessary before, but even more now since we clear errno on successful syscalls now. if (s && *s) { printf("%s: ", s); } - printf("%s\n", strerror(errno)); + printf("%s\n", strerror(savederr)); } } \ No newline at end of file