import "./core.zc" import "./result.zc" import "./string.zc" import "./vec.zc" const Z_SEEK_SET: int = 0; const Z_SEEK_END: int = 2; const Z_F_OK: int = 0; // TODO: restructure this tomorrow. raw { #include #include #include // typedef needed for Vec generation if inferred typedef struct DirEntry* DirEntryPtr; void* _z_fs_fopen(char* path, char* mode) { return fopen(path, mode); } int _z_fs_fclose(void* stream) { return fclose((FILE*)stream); } size_t _z_fs_fread(void* ptr, size_t size, size_t nmemb, void* stream) { return fread(ptr, size, nmemb, (FILE*)stream); } size_t _z_fs_fwrite(void* ptr, size_t size, size_t nmemb, void* stream) { return fwrite(ptr, size, nmemb, (FILE*)stream); } int _z_fs_fseek(void* stream, long offset, int whence) { return fseek((FILE*)stream, offset, whence); } long _z_fs_ftell(void* stream) { return ftell((FILE*)stream); } int _z_fs_access(char* pathname, int mode) { return access(pathname, mode); } int _z_fs_unlink(char* pathname) { return unlink(pathname); } int _z_fs_rmdir(char* pathname) { return rmdir(pathname); } void* _z_fs_opendir(char* name) { return opendir(name); } int _z_fs_closedir(void* dir) { return closedir((DIR*)dir); } void* _z_fs_malloc(size_t size) { return malloc(size); } void _z_fs_free(void* ptr) { free(ptr); } int _z_fs_get_metadata(char* path, uint64_t* size, int* is_dir, int* is_file) { struct stat st; if (stat(path, &st) != 0) return -1; *size = st.st_size; *is_dir = S_ISDIR(st.st_mode); *is_file = S_ISREG(st.st_mode); return 0; } int _z_fs_read_entry(void* dir, char* out_name, int buf_size, int* is_dir) { struct dirent* ent = readdir((DIR*)dir); if (!ent) return 0; strncpy(out_name, ent->d_name, buf_size - 1); out_name[buf_size - 1] = 0; *is_dir = (ent->d_type == DT_DIR); return 1; } int _z_fs_mkdir(char* path) { #ifdef _WIN32 return mkdir(path); #else return mkdir(path, 0777); #endif } } extern fn _z_fs_mkdir(path: char*) -> int; extern fn _z_fs_get_metadata(path: char*, size: U64*, is_dir: int*, is_file: int*) -> int; extern fn _z_fs_read_entry(dir: void*, out_name: char*, buf_size: int, is_dir: int*) -> int; extern fn _z_fs_fopen(path: char*, mode: char*) -> void*; extern fn _z_fs_fclose(stream: void*) -> int; extern fn _z_fs_fread(ptr: void*, size: usize, nmemb: usize, stream: void*) -> usize; extern fn _z_fs_fwrite(ptr: void*, size: usize, nmemb: usize, stream: void*) -> usize; extern fn _z_fs_fseek(stream: void*, offset: long, whence: int) -> int; extern fn _z_fs_ftell(stream: void*) -> long; extern fn _z_fs_access(pathname: char*, mode: int) -> int; extern fn _z_fs_unlink(pathname: char*) -> int; extern fn _z_fs_rmdir(pathname: char*) -> int; extern fn _z_fs_opendir(name: char*) -> void*; extern fn _z_fs_closedir(dir: void*) -> int; extern fn _z_fs_malloc(size: usize) -> void*; extern fn _z_fs_free(ptr: void*); struct File { handle: void*; } struct Metadata { size: U64; is_dir: bool; is_file: bool; } struct DirEntry { name: String; is_dir: bool; } impl File { fn open(path: char*, mode: char*) -> Result { var h = _z_fs_fopen(path, mode); if (h == NULL) { return Result::Err("Failed to open file"); } return Result::Ok(File { handle: h }); } fn close(self) { if (self.handle) { _z_fs_fclose(self.handle); self.handle = NULL; } } fn read_to_string(self) -> Result { if (self.handle == NULL) { return Result::Err("File not open"); } _z_fs_fseek(self.handle, 0, Z_SEEK_END); var size = _z_fs_ftell(self.handle); _z_fs_fseek(self.handle, 0, Z_SEEK_SET); var buffer: char* = _z_fs_malloc((usize)size + 1); if (buffer == NULL) { return Result::Err("Out of memory"); } var read = _z_fs_fread(buffer, 1, size, self.handle); buffer[read] = 0; var s = String::new(buffer); _z_fs_free(buffer); var res = Result::Ok(s); s.forget(); var ret = res; res.forget(); return ret; } fn read_all(path: char*) -> Result { var res = File::open(path, "rb"); if (res.is_err()) { return Result::Err(res.err); } var f: File = res.unwrap(); var s_res = f.read_to_string(); f.close(); var ret = s_res; s_res.forget(); return ret; } fn write_string(self, content: char*) -> Result { if (self.handle == NULL) { return Result::Err("File not open"); } var len = strlen(content); var written = _z_fs_fwrite(content, 1, len, self.handle); if (written != len) { return Result::Err("Write incomplete"); } return Result::Ok(true); } fn exists(path: char*) -> bool { return _z_fs_access(path, Z_F_OK) == 0; } fn metadata(path: char*) -> Result { var size: uint64_t; var is_d: int; var is_f: int; if (_z_fs_get_metadata(path, &size, &is_d, &is_f) != 0) { return Result::Err("Failed to get metadata"); } return Result::Ok(Metadata { size: (U64)size, is_dir: is_d != 0, is_file: is_f != 0 }); } fn create_dir(path: char*) -> Result { if (_z_fs_mkdir(path) != 0) { return Result::Err("Failed to create directory"); } return Result::Ok(true); } fn remove_file(path: char*) -> Result { if (_z_fs_unlink(path) != 0) { return Result::Err("Failed to remove file"); } return Result::Ok(true); } fn remove_dir(path: char*) -> Result { if (_z_fs_rmdir(path) != 0) { return Result::Err("Failed to remove directory"); } return Result::Ok(true); } fn read_dir(path: char*) -> Result< Vec > { var dir = _z_fs_opendir(path); if (dir == NULL) { return Result< Vec >::Err("Failed to open directory"); } var entries = Vec::new(); var name_buf: char* = _z_fs_malloc(256); if (name_buf == NULL) { _z_fs_closedir(dir); return Result< Vec >::Err("Out of memory"); } var is_d: int = 0; while (_z_fs_read_entry(dir, name_buf, 256, &is_d)) { if (strcmp(name_buf, ".") == 0 || strcmp(name_buf, "..") == 0) { continue; } var s = String::new(name_buf); var ent = DirEntry { name: s, is_dir: is_d != 0 }; // Transfer ownership: String -> DirEntry s.forget(); entries.push(ent); // Transfer ownership: DirEntry -> Vec ent.name.forget(); } _z_fs_free(name_buf); _z_fs_closedir(dir); var res = Result< Vec >::Ok(entries); entries.forget(); var ret = res; res.forget(); return ret; } }