From: Brendan Hansen Date: Wed, 18 May 2022 11:21:35 +0000 (-0500) Subject: file remove/rename; alloc bugfixes; string additions X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=fff151a83099bb73e219da6c0500d6b8a3b398e8;p=onyx.git file remove/rename; alloc bugfixes; string additions --- diff --git a/core/alloc/arena.onyx b/core/alloc/arena.onyx index fba77287..eaf8fdef 100644 --- a/core/alloc/arena.onyx +++ b/core/alloc/arena.onyx @@ -130,8 +130,12 @@ auto :: #match { alloc :: package core.alloc arena := alloc.arena.make(alloc.heap_allocator, size); + old_allocator := #unquote dest; (#unquote dest) = alloc.arena.make_allocator(^arena); - defer alloc.arena.free(^arena); + defer { + alloc.arena.free(^arena); + (#unquote dest) = old_allocator; + } }, macro (body: Code, size := 32 * 1024) -> i32 { diff --git a/core/alloc/auto_heap.onyx b/core/alloc/auto_heap.onyx index fd8bc399..05349be2 100644 --- a/core/alloc/auto_heap.onyx +++ b/core/alloc/auto_heap.onyx @@ -56,8 +56,12 @@ auto :: #match { alloc :: package core.alloc auto_heap := alloc.heap.auto_heap_make(); + old_allocator := context.allocator; context.allocator = alloc.heap.auto_heap_make_allocator(^auto_heap); - defer alloc.heap.auto_heap_free(^auto_heap); + defer { + alloc.heap.auto_heap_free(^auto_heap); + context.allocator = old_allocator; + } }, macro (body: Code) -> i32 { diff --git a/core/io/reader.onyx b/core/io/reader.onyx index 83b10586..56b40690 100644 --- a/core/io/reader.onyx +++ b/core/io/reader.onyx @@ -35,6 +35,8 @@ Reader :: struct { advance_line :: advance_line; skip_whitespace :: skip_whitespace; skip_bytes :: skip_bytes; + + lines :: lines; } reader_make :: (s: ^Stream, buffer_size := 4096, allocator := context.allocator) -> Reader { @@ -535,6 +537,27 @@ skip_bytes :: (use reader: ^Reader, bytes: u32) -> (skipped: i32, err: Error) { return 0, .None; } +lines :: (r: ^Reader, inplace := false) -> Iterator(str) { + Context :: struct { + r: ^Reader; + inplace: bool; + } + + c := new(Context, allocator=context.temp_allocator); + c.r = r; + c.inplace = inplace; + + next :: (use c: ^Context) -> (str, bool) { + line := r->read_line(consume_newline=true, inplace=inplace); + + if line.count > 0 do return line, true; + else do return "", false; + } + + return .{ c, next }; +} + + #local reader_consume_error :: (use reader: ^Reader) -> Error { defer error = .None; return error; diff --git a/core/onyx/fs.onyx b/core/onyx/fs.onyx index 0585cb42..ea0124c0 100644 --- a/core/onyx/fs.onyx +++ b/core/onyx/fs.onyx @@ -23,6 +23,8 @@ __file_open :: (path: str, mode := os.OpenMode.Read) -> (FileData, os.FileError) __file_close :: (fd: FileData) -> os.FileError --- __file_exists :: (path: str) -> bool --- + __file_remove :: (path: str) -> bool --- + __file_rename :: (old_path: str, new_path: str) -> bool --- __file_seek :: (handle: FileData.Handle, to: i32, whence: io.SeekFrom) -> i32 --- __file_tell :: (handle: FileData.Handle) -> u32 --- @@ -31,9 +33,10 @@ __file_open :: (path: str, mode := os.OpenMode.Read) -> (FileData, os.FileError) __file_flush :: (handle: FileData.Handle) -> io.Error --- __file_size :: (handle: FileData.Handle) -> u32 --- - __dir_open :: (path: str, dir: ^DirectoryData) -> bool --- - __dir_close :: (dir: DirectoryData) -> void --- - __dir_read :: (dir: DirectoryData, out_entry: ^os.DirectoryEntry) -> bool --- + __dir_open :: (path: str, dir: ^DirectoryData) -> bool --- + __dir_close :: (dir: DirectoryData) -> void --- + __dir_read :: (dir: DirectoryData, out_entry: ^os.DirectoryEntry) -> bool --- + __dir_remove :: (path: str) -> bool --- } __file_stream_vtable := io.Stream_Vtable.{ diff --git a/core/os/dir.onyx b/core/os/dir.onyx index 863fce0e..b97c7878 100644 --- a/core/os/dir.onyx +++ b/core/os/dir.onyx @@ -41,3 +41,5 @@ dir_read :: (dir: Directory, out_entry: ^DirectoryEntry) -> bool { } dir_exists :: fs.__file_exists +dir_remove :: fs.__dir_remove +dir_rename :: fs.__file_rename \ No newline at end of file diff --git a/core/os/file.onyx b/core/os/file.onyx index 0e8367ce..98026b55 100644 --- a/core/os/file.onyx +++ b/core/os/file.onyx @@ -24,18 +24,9 @@ File :: struct { use data : fs.FileData; } -// Are these even necessary?? -#local { - file_open :: (path: str, mode := OpenMode.Read) -> (fs.FileData, FileError) { - return fs.__file_open(path, mode); - } - - file_close :: (file: fs.FileData) -> FileError { - return fs.__file_close(file); - } -} - file_exists :: fs.__file_exists +remove_file :: fs.__file_remove +rename_file :: fs.__file_rename get_contents_from_file :: (file: ^File) -> str { size := cast(u32) io.stream_size(file); @@ -58,7 +49,7 @@ open :: (path: str, mode := OpenMode.Read) -> (os.FileError, File) { data = .{}, }; - file_data, error := file_open(path, mode); + file_data, error := fs.__file_open(path, mode); if error != .None do return error, file; file.data = file_data; @@ -67,7 +58,7 @@ open :: (path: str, mode := OpenMode.Read) -> (os.FileError, File) { } close :: (file: ^File) { - file_close(file.data); + fs.__file_close(file.data); file.stream.vtable = null; } diff --git a/core/os/os.onyx b/core/os/os.onyx index 064be058..6eb4c57a 100644 --- a/core/os/os.onyx +++ b/core/os/os.onyx @@ -7,6 +7,7 @@ package core.os #local { runtime :: package runtime + string :: package core.string } list_directory :: (path: str) -> Iterator(DirectoryEntry) { @@ -41,6 +42,24 @@ list_directory :: (path: str) -> Iterator(DirectoryEntry) { return .{ c, next, close }; } +remove_directory :: (path: str) -> bool { + // This is quite a bit of space, and could result in a stack overrun + // if the directory being deleted has a lot of descendents. + full_path_buffer: [512] u8; + + for list_directory(path) { + full_path := string.concat(full_path_buffer, path, "/", it->name()); + + if it.type == .Directory { + if !remove_directory(full_path) do return false; + } else { + remove_file(full_path); + } + } + + return dir_remove(path); +} + exit :: (exitcode: i32) { runtime.__exit(exitcode); } diff --git a/core/os/process.onyx b/core/os/process.onyx index 76186568..e685849b 100644 --- a/core/os/process.onyx +++ b/core/os/process.onyx @@ -37,12 +37,25 @@ process_destroy :: (use p: ^Process) => { __process_destroy(process_handle); } +#local Process_Read_Error :: enum { + None :: 0x00; + Process_Dead :: 0x01; + Unknown :: 0x02; +} + #local process_stream_vtable := io.Stream_Vtable.{ read = (use p: ^Process, buffer: [] u8) -> (io.Error, u32) { // Read from the process stdout if cast(i64) process_handle == 0 do return .BadFile, 0; bytes_read := __process_read(process_handle, buffer); + if bytes_read < 0 { + switch cast(Process_Read_Error) -bytes_read { + case .None do return .None, 0; + case .Process_Dead do return .EOF, 0; + case .Unknown do return .BadFile, 0; + } + } return .None, bytes_read; }, diff --git a/core/string.onyx b/core/string.onyx index 682aa322..dae084dc 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -11,6 +11,12 @@ alloc_copy :: (original: str, allocator := context.allocator) -> str { return new_str; } +temp_copy :: (original: str) -> str { + new_str := make([] u8, original.count, allocator=context.temp_allocator); + copy(original, new_str); + return new_str; +} + copy :: (orig: str, dest: str) { len := orig.count; if dest.count < len do len = dest.count; @@ -189,6 +195,20 @@ ends_with :: (s: str, suffix: str) -> bool { is_empty :: macro (s: str) => s.count == 0 || s.data == null; +index_of :: (s: str, c: u8) -> i32 { + for s.count { + if s[it] == c do return it; + } + return -1; +} + +last_index_of :: (s: str, c: u8) -> i32 { + for range.{s.count, 0, -1} { + if s[it] == c do return it; + } + return -1; +} + strip_whitespace :: #match { (s: ^str) { strip_leading_whitespace(s); strip_trailing_whitespace(s); }, (s: str) => s |> strip_leading_whitespace() |> strip_trailing_whitespace() diff --git a/core/wasi/wasi_fs.onyx b/core/wasi/wasi_fs.onyx index 7c7c2f6a..b4b89709 100644 --- a/core/wasi/wasi_fs.onyx +++ b/core/wasi/wasi_fs.onyx @@ -122,6 +122,16 @@ __file_exists :: (path: str) -> bool { return exists; } +__file_remove :: (path: str) -> bool { + removed := false; + for .[3, 4] { // Trying both preopened directories + err := wasi.path_unlink_file(it, path); + if err == .Success do removed = true; + } + + return removed; +} + __file_stream_vtable := io.Stream_Vtable.{ seek = (use fs: ^os.File, to: i32, whence: io.SeekFrom) -> io.Error { // Currently, the new offset is just ignored. diff --git a/include/bh.h b/include/bh.h index b187b96d..58123d72 100644 --- a/include/bh.h +++ b/include/bh.h @@ -377,6 +377,7 @@ i32 bh_file_write(bh_file* file, void* buffer, isize buff_size); void bh_file_flush(bh_file* file); i64 bh_file_size(bh_file* file); b32 bh_file_exists(char const* filename); +b32 bh_file_remove(char const* filename); char* bh_path_get_full_name(char const* filename, bh_allocator a); char* bh_path_get_parent(char const* filename, bh_allocator a); char* bh_path_convert_separators(char* path); @@ -1637,6 +1638,15 @@ b32 bh_file_exists(char const* filename) { return stat(filename, &s) != -1; } +b32 bh_file_remove(char const* filename) { +#if defined(_BH_WINDOWS) + return DeleteFileA(filename); + +#elif defined(_BH_LINUX) + return unlink(filename) == 0; +#endif +} + char* bh_path_get_full_name(char const* filename, bh_allocator a) { #if defined(_BH_WINDOWS) char buffer[4096]; diff --git a/include/small_windows.h b/include/small_windows.h index 45d8c1c4..fe2ba6fa 100644 --- a/include/small_windows.h +++ b/include/small_windows.h @@ -418,6 +418,9 @@ GB_DLL_IMPORT BOOL WINAPI FindClose (HANDLE find_file); GB_DLL_IMPORT BOOL WINAPI GetFileAttributesExW(wchar_t const *path, GET_FILEEX_INFO_LEVELS info_level_id, WIN32_FILE_ATTRIBUTE_DATA *data); GB_DLL_IMPORT BOOL WINAPI CopyFileW(wchar_t const *old_f, wchar_t const *new_f, BOOL fail_if_exists); GB_DLL_IMPORT BOOL WINAPI MoveFileW(wchar_t const *old_f, wchar_t const *new_f); +GB_DLL_IMPORT BOOL WINAPI DeleteFileA (char const *path); +GB_DLL_IMPORT BOOL WINAPI RemoveDirectoryA(char const *path); +GB_DLL_IMPORT BOOL WINAPI MoveFileA (char const *old_path, char const *new_path); GB_DLL_IMPORT DWORD WINAPI GetFullPathNameA(char const *lpFileName, DWORD nBufferLength, char *lpBuffer, char **lpFilePart); diff --git a/src/onyx_runtime.c b/src/onyx_runtime.c index 33410e02..4144d082 100644 --- a/src/onyx_runtime.c +++ b/src/onyx_runtime.c @@ -84,6 +84,18 @@ ONYX_DEF(__file_exists, (WASM_I32, WASM_I32), (WASM_I32)) { return NULL; } +ONYX_DEF(__file_remove, (WASM_I32, WASM_I32), (WASM_I32)) { + char *path_ptr = ONYX_PTR(params->data[0].of.i32); + int path_len = params->data[1].of.i32; + + char path[512] = {0}; + strncpy(path, path_ptr, path_len); + path[path_len] = 0; + + results->data[0] = WASM_I32_VAL(bh_file_remove(path)); + return NULL; +} + ONYX_DEF(__file_seek, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) { i64 fd = params->data[0].of.i64; i32 offset = params->data[1].of.i32; @@ -173,6 +185,32 @@ ONYX_DEF(__file_get_standard, (WASM_I32, WASM_I32), (WASM_I32)) { return NULL; } +ONYX_DEF(__file_rename, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { + char *old_path_ptr = ONYX_PTR(params->data[0].of.i32); + int old_path_len = params->data[1].of.i32; + + char old_path[512] = {0}; + strncpy(old_path, old_path_ptr, old_path_len); + old_path[old_path_len] = 0; + + char *new_path_ptr = ONYX_PTR(params->data[2].of.i32); + int new_path_len = params->data[3].of.i32; + + char new_path[512] = {0}; + strncpy(new_path, new_path_ptr, new_path_len); + new_path[new_path_len] = 0; + +#ifdef _BH_WINDOWS + results->data[0] = WASM_I32_VAL(MoveFileA(old_path, new_path)); + return NULL; +#endif + +#ifdef _BH_LINUX + results->data[0] = WASM_I32_VAL(rename(old_path, new_path) == 0); + return NULL; +#endif +} + // // Directories // @@ -301,6 +339,24 @@ ONYX_DEF(__dir_close, (WASM_I64), ()) { return NULL; } +ONYX_DEF(__dir_remove, (WASM_I32, WASM_I32), (WASM_I32)) { + char *path_ptr = ONYX_PTR(params->data[0].of.i32); + int path_len = params->data[1].of.i32; + + char path[512] = {0}; + strncpy(path, path_ptr, path_len); + path[path_len] = 0; + +#ifdef _BH_WINDOWS + results->data[0] = WASM_I32_VAL(RemoveDirectoryA(path)); + return NULL; +#endif + +#ifdef _BH_LINUX + results->data[0] = WASM_I32_VAL(rmdir(path) == 0); + return NULL; +#endif +} // // THREADS @@ -469,6 +525,7 @@ ONYX_DEF(__process_spawn, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (W process->magic_number = ONYX_PROCESS_MAGIC_NUMBER; #ifdef _BH_LINUX + // :Security - alloca a user controlled string. char **process_args = alloca(sizeof(char *) * (args_len + 2)); byte_t* array_loc = ONYX_PTR(args_ptr); fori (i, 0, args_len) { @@ -605,12 +662,20 @@ ONYX_DEF(__process_read, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) { i32 bytes_read; #ifdef _BH_LINUX bytes_read = read(process->proc_to_host[0], buffer, output_len); - bytes_read = bh_max(bytes_read, 0); // Silently consume errors + if (bytes_read < 0) { + switch (errno) { + case EAGAIN: bytes_read = 0; break; + case EBADF: bytes_read = -1; break; + default: bytes_read = -2; break; + } + } #endif #ifdef _BH_WINDOWS i32 success = ReadFile(process->proc_to_host_read, buffer, output_len, &bytes_read, NULL); - if (!success) bytes_read = 0; + if (!success) { + bytes_read = -1; + } #endif results->data[0] = WASM_I32_VAL(bytes_read); @@ -1123,6 +1188,7 @@ ONYX_LIBRARY { ONYX_FUNC(__file_open_impl) ONYX_FUNC(__file_close) ONYX_FUNC(__file_exists) + ONYX_FUNC(__file_remove) ONYX_FUNC(__file_seek) ONYX_FUNC(__file_tell) ONYX_FUNC(__file_read) @@ -1130,10 +1196,12 @@ ONYX_LIBRARY { ONYX_FUNC(__file_flush) ONYX_FUNC(__file_size) ONYX_FUNC(__file_get_standard) + ONYX_FUNC(__file_rename) ONYX_FUNC(__dir_open) ONYX_FUNC(__dir_read) ONYX_FUNC(__dir_close) + ONYX_FUNC(__dir_remove) ONYX_FUNC(__spawn_thread) ONYX_FUNC(__kill_thread) diff --git a/tests/struct_use_pointer_member b/tests/struct_use_pointer_member index 260ae428..d606442d 100644 --- a/tests/struct_use_pointer_member +++ b/tests/struct_use_pointer_member @@ -1,2 +1,2 @@ Hello, I am Billy! -Go away!! func[52] +Go away!! 0xEDF4 diff --git a/tests/struct_use_pointer_member.onyx b/tests/struct_use_pointer_member.onyx index bf091635..c2b8d445 100644 --- a/tests/struct_use_pointer_member.onyx +++ b/tests/struct_use_pointer_member.onyx @@ -19,7 +19,7 @@ nice_person := Person_Vtable.{ mean_person := Person_Vtable.{ greet = (use p: ^Person) { - printf("Go away!! {}\n", greet); + printf("Go away!! {}\n", ^greet); } }