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 {
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 {
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 {
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;
__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 ---
__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.{
}
dir_exists :: fs.__file_exists
+dir_remove :: fs.__dir_remove
+dir_rename :: fs.__file_rename
\ No newline at end of file
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);
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;
}
close :: (file: ^File) {
- file_close(file.data);
+ fs.__file_close(file.data);
file.stream.vtable = null;
}
#local {
runtime :: package runtime
+ string :: package core.string
}
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);
}
__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;
},
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;
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()
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.
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);
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];
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);
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;
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
//
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
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) {
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);
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)
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)
Hello, I am Billy!
-Go away!! func[52]
+Go away!! 0xEDF4
mean_person := Person_Vtable.{
greet = (use p: ^Person) {
- printf("Go away!! {}\n", greet);
+ printf("Go away!! {}\n", ^greet);
}
}