diff options
Diffstat (limited to 'libraries/euler/cstdio.cpp')
-rw-r--r-- | libraries/euler/cstdio.cpp | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/libraries/euler/cstdio.cpp b/libraries/euler/cstdio.cpp new file mode 100644 index 0000000..367e7e0 --- /dev/null +++ b/libraries/euler/cstdio.cpp @@ -0,0 +1,102 @@ +#include <euler/syscall.hpp> +#include <cassert> +#include <cstring> +#include <cstdio> + +namespace euler { + + //read-only with no error bits for now + struct file_t { + + syscall::file_handle handle; + + //TODO: variable size buffer? maybe a multiple of block size for device? + char buffer[1024]; + //in bytes, aligned to buffer size; 1 for no buffer loaded + uint64_t buffer_start; + + bool is_offset_in_buffer() { + return + buffer_start != 1 && offset >= buffer_start && + offset < buffer_start + 1024; + } + + syscall::file_result ensure_offset_in_buffer() { + if (is_offset_in_buffer()) + return syscall::file_result::success; + uint64_t new_buffer_start = (offset / 1024) * 1024; + uint64_t new_buffer_end = new_buffer_start + 1024; + if (length < new_buffer_end) + new_buffer_end = length; + syscall::file_result result = _syscall_read_from_file( + handle, new_buffer_start, new_buffer_end - new_buffer_start, buffer); + if (result == syscall::file_result::success) + buffer_start = new_buffer_start; + return result; + } + + uint64_t offset; + uint64_t length; + + }; + +} + +namespace std { + + FILE *fopen(const char *path, const char *mode) { + + assert(mode[0] == 'r' && mode[1] == '\0'); + + euler::syscall::file_handle handle; + euler::syscall::file_result result = + _syscall_open_file(path, strlen(path), handle); + if (result != euler::syscall::file_result::success) + return 0; + + uint64_t length; + result = _syscall_get_file_length(handle, length); + if (result != euler::syscall::file_result::success) { + _syscall_close_file(handle); + return 0; + } + + return new FILE { + .handle = handle, + .buffer = {}, + .buffer_start = 1, + .offset = 0, + .length = length + }; + + } + + int fclose(FILE *file) { + _syscall_close_file(file->handle); + delete file; + return 0; + } + + int fgetc(FILE *from) { + if (from->offset >= from->length) + return EOF; + assert( + from->ensure_offset_in_buffer() == euler::syscall::file_result::success); + char ch = from->buffer[from->offset - from->buffer_start]; + ++from->offset; + return ch; + } + + int ungetc(int ch, FILE *from) { + if (ch == EOF || from->offset == 0) + return EOF; + --from->offset; + if (!from->is_offset_in_buffer()) { + ++from->offset; + return EOF; + } + from->buffer[from->offset - from->buffer_start] = ch; + return ch; + } + +} |