From 5e177fae5029492edc374cf51cb0369abc1d7c7f Mon Sep 17 00:00:00 2001 From: flysand7 Date: Fri, 28 Jul 2023 00:49:53 +1100 Subject: [PATCH] Quick and dirty file api --- build.py | 14 +++--- include/stdio.h | 25 +++++++++++ {src => include}/tinyrt.h | 22 ++++++---- src/impl/stdlib-file/file.c | 85 +++++++++++++++++++++++++++++++++++++ src/library.json | 14 +++++- src/linux/entry.c | 3 ++ src/linux/tinyrt.c | 15 ++++++- tests/empty.c | 17 +------- 8 files changed, 162 insertions(+), 33 deletions(-) create mode 100644 include/stdio.h rename {src => include}/tinyrt.h (87%) create mode 100644 src/impl/stdlib-file/file.c diff --git a/build.py b/build.py index 8f24b2d..359d093 100755 --- a/build.py +++ b/build.py @@ -123,10 +123,8 @@ try: ciabatta_header.write('\n') ciabatta_header.write('// This file is AUTO-GENERATED by library.json\n') ciabatta_header.write('\n') - # Write includes - for include in library_config['includes']: - ciabatta_header.write(f'#include <{include}>\n') - ciabatta_header.write('\n') + # Write main include + ciabatta_header.write('#include \n') # Write platform includes platform_config = None for platform in library_config['platforms']: @@ -138,10 +136,14 @@ try: include_path = os.path.join(platform_config['path'], include) ciabatta_header.write(f'#include "{include_path}"\n') ciabatta_header.write(f'#include "{target}/tinyrt-iface.h"\n') - ciabatta_header.write(f'#include "tinyrt.h"\n') + ciabatta_header.write(f'#include \n') for tinyrt_source in platform_config['tinyrt']: ciabatta_header.write(f'#include "{target}/{tinyrt_source}"\n') - # Write API includes + # Write module includes + for include in library_config['includes']: + ciabatta_header.write(f'#include <{include}>\n') + ciabatta_header.write('\n') + # Write module sources ciabatta_header.write('\n') for api in library_config['apis']: api_name = api['name'] diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..9048a92 --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,25 @@ + +#pragma once + +#include +#include + +typedef u64 size_t; + +typedef struct FILE FILE; +struct FILE { + _RT_File rt_file; +}; + +#define EOF (-1) + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +FILE *fopen(const char *restrict filename, const char *restrict mode); +int fgetc(FILE *file); +int fputc(int c, FILE *file); +size_t fread(void *restrict buf, size_t size, size_t count, FILE *restrict file); +size_t fwrite(void const *restrict buf, size_t size, size_t count, FILE *restrict file); +int fclose(FILE *file); diff --git a/src/tinyrt.h b/include/tinyrt.h similarity index 87% rename from src/tinyrt.h rename to include/tinyrt.h index 1171b0c..6099e32 100644 --- a/src/tinyrt.h +++ b/include/tinyrt.h @@ -50,16 +50,20 @@ static _RT_Status _rt_deinit(); #endif // File API -#if _RT_API_FILE == 1 - struct _RT_File typedef _RT_File; - struct _RT_File { - union { - void *handle; - u64 fd; - }; - i32 flags; +struct _RT_File typedef _RT_File; +struct _RT_File { + union { + void *handle; + u64 fd; }; - static _RT_Status _rt_file_open(_RT_File *file, char *name, int flags); + i32 flags; +}; +#if _RT_API_FILE == 1 + static _RT_File _rt_file_stdin; + static _RT_File _rt_file_stdout; + static _RT_File _rt_file_stderr; + static _RT_Status _rt_file_std_handles_init(); + static _RT_Status _rt_file_open(_RT_File *file, char const *name, int flags); static _RT_Status _rt_file_read(u64 size, void *buffer, _RT_File *from, u64 *out_bytes_read); static _RT_Status _rt_file_write(_RT_File *to, u64 size, void *buffer, u64 *out_bytes_written); static _RT_Status _rt_file_close(_RT_File *file); diff --git a/src/impl/stdlib-file/file.c b/src/impl/stdlib-file/file.c new file mode 100644 index 0000000..3d482ed --- /dev/null +++ b/src/impl/stdlib-file/file.c @@ -0,0 +1,85 @@ + +FILE *stdin; +FILE *stdout; +FILE *stderr; + +// TODO: memory allocation +static FILE _files[64]; +static int _files_cnt = 0; + +static void _fileapi_init() { + _rt_file_std_handles_init(); + stdin = &_files[_files_cnt++]; + stdin->rt_file = _rt_file_stdin; + stdout = &_files[_files_cnt++]; + stdout->rt_file = _rt_file_stdout; + stderr = &_files[_files_cnt++]; + stderr->rt_file = _rt_file_stderr; +} + +FILE *fopen(char const *restrict filename, char const *restrict mode) { + _RT_File rt_file; + int flags = 0; + while(*mode) { + if(*mode == 'r') flags |= _RT_FILE_READ; + if(*mode == 'w') flags |= _RT_FILE_WRITE; + // TODO: other flags + mode += 1; + } + _RT_Status status = _rt_file_open(&rt_file, filename, flags); + if(status != _RT_STATUS_OK) { + return NULL; + } + FILE *file = &_files[_files_cnt]; + _files_cnt += 1; + file->rt_file = rt_file; + return file; +} + +int fgetc(FILE *file) { + int c = 0; + u64 bytes_read; + _RT_Status status = _rt_file_read(1, &c, &file->rt_file, &bytes_read); + if(status == _RT_STATUS_FILE_EOF) { + return EOF; + } + else if(status != _RT_STATUS_OK) { + return EOF; + } + return c; +} + +int fputc(int c, FILE *file) { + u64 bytes_written; + _RT_Status status = _rt_file_write(&file->rt_file, 1, &c, &bytes_written); + if(status != _RT_STATUS_OK) { + return EOF; + } + return c; +} + +size_t fread(void *restrict buf, size_t size, size_t count, FILE *restrict file) { + u64 bytes_read; + _RT_Status status = _rt_file_read(size*count, buf, &file->rt_file, &bytes_read); + if(status != _RT_STATUS_OK) { + return 0; + } + return bytes_read / size; +} + +size_t fwrite(void const *restrict buf, size_t size, size_t count, FILE *restrict file) { + u64 bytes_written; + _RT_Status status = _rt_file_write(&file->rt_file, size*count, (void *)buf, &bytes_written); + if(status != _RT_STATUS_OK) { + return 0; + } + return bytes_written / size; +} + +int fclose(FILE *file) { + _RT_Status status = _rt_file_close(&file->rt_file); + if(status != _RT_STATUS_OK) { + return EOF; + } + return 0; +} diff --git a/src/library.json b/src/library.json index ffd94ea..ac2fab8 100644 --- a/src/library.json +++ b/src/library.json @@ -24,8 +24,8 @@ // this module will not be included in the final build includes: [ - "cia-def.h", - "stdlib.h" + "stdlib.h", + "stdio.h", ], platforms: [ @@ -60,6 +60,16 @@ apis: [ "rt_api_program", ] }, + { + name: "stdlib_file", + path: "impl/stdlib-file", + includes: [ + "file.c" + ], + reqs: [ + "rt_api_file" + ] + } ] // END diff --git a/src/linux/entry.c b/src/linux/entry.c index 1978600..aabb0d2 100644 --- a/src/linux/entry.c +++ b/src/linux/entry.c @@ -10,6 +10,8 @@ void __stack_chk_fail(void) { syscall_exit(1); } +static void _fileapi_init(); + void __libc_start_main( int (*main)(int, char**, char**), int argc, char **argv, @@ -21,6 +23,7 @@ void __libc_start_main( // Get the envp char **envp = argv + (argc + 1); init(argc, argv, envp); + _fileapi_init(); main(argc, argv, envp); fini(); // glibc bug diff --git a/src/linux/tinyrt.c b/src/linux/tinyrt.c index 23bdee1..ec0b7ca 100644 --- a/src/linux/tinyrt.c +++ b/src/linux/tinyrt.c @@ -1,7 +1,20 @@ // See src/tinyrt.h file for the interface this file implements -static _RT_Status _rt_file_open(_RT_File *file, char *name, int _rt_flags) { +static _RT_File _rt_file_stdin; +static _RT_File _rt_file_stderr; + +static _RT_Status _rt_file_std_handles_init() { + _rt_file_stdin.fd = 0; + _rt_file_stdin.flags = _RT_FILE_READ; + _rt_file_stdout.fd = 1; + _rt_file_stdout.flags = _RT_FILE_WRITE; + _rt_file_stderr.fd = 2; + _rt_file_stdout.flags = _RT_FILE_WRITE; + return _RT_STATUS_OK; +} + +static _RT_Status _rt_file_open(_RT_File *file, char const *name, int _rt_flags) { if((_rt_flags & 0x3) == 0) { return _RT_ERROR_BAD_PARAM; } diff --git a/tests/empty.c b/tests/empty.c index 9354f3c..3de02c0 100644 --- a/tests/empty.c +++ b/tests/empty.c @@ -1,22 +1,9 @@ #include - -#define STDOUT_FILENO 1 -#define SYS_write 1 - -static __inline i64 __syscall3(i64 n, i64 a1, i64 a2, i64 a3) { - i64 ret; - __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), - "d"(a3) : "rcx", "r11", "memory"); - return ret; -} - -static inline i64 syscall_write(u32 fd, char const *buf, u64 count) { - return __syscall3(SYS_write, (i64)fd, (i64)buf, (u64)count); -} +#include int main(int argc, char **argv, char **envp) { char string[] = "Hello, world!\n"; - syscall_write(STDOUT_FILENO, string, sizeof string); + fwrite(string, 1, sizeof string-1, stdout); return 0; }