import "./core.zc" import "./result.zc" import "./string.zc" import "./vec.zc" import "./mem.zc" def Z_SEEK_SET = 0; def Z_SEEK_END = 2; def Z_F_OK = 0; include include include include include // TODO: restructure this tomorrow (lol). raw { typedef struct DirEntry* DirEntryPtr; // Wrappers for FILE* handling due to opaque pointer casting 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, int64_t offset, int whence) { return fseek((FILE*)stream, (long)offset, whence); } int64_t _z_fs_ftell(void* stream) { return (int64_t)ftell((FILE*)stream); } // Wrappers needed because C headers declare these with 'const char*' // but Zen C externs generate 'char*', leading to conflicting types. 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); } // Wrappers for DIR* handling void* _z_fs_opendir(char* name) { return opendir(name); } int _z_fs_closedir(void* dir) { return closedir((DIR*)dir); } // struct stat / struct dirent helpers 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 } } // Direct externs extern fn malloc(size: usize) -> void*; extern fn free(ptr: void*); 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: I64, whence: int) -> int; extern fn _z_fs_ftell(stream: void*) -> I64; extern fn _z_fs_opendir(name: char*) -> void*; extern fn _z_fs_closedir(dir: void*) -> int; 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; 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 { let 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); let size = _z_fs_ftell(self.handle); _z_fs_fseek(self.handle, 0, Z_SEEK_SET); let buffer: char* = malloc((usize)size + 1); if (buffer == NULL) { return Result::Err("Out of memory"); } let read = _z_fs_fread(buffer, 1, size, self.handle); buffer[read] = 0; let s = String::new(buffer); free(buffer); let res = Result::Ok(s); s.forget(); let ret = res; res.forget(); return ret; } fn read_all(path: char*) -> Result { let res = File::open(path, "rb"); if (res.is_err()) { return Result::Err(res.err); } let f: File = res.unwrap(); let s_res = f.read_to_string(); f.close(); let 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"); } let len = strlen(content); let 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 { let size: uint64_t; let is_d: int; let 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 > { let dir = _z_fs_opendir(path); if (dir == NULL) { return Result< Vec >::Err("Failed to open directory"); } let entries = Vec::new(); let name_buf: char* = malloc(256); if (name_buf == NULL) { _z_fs_closedir(dir); return Result< Vec >::Err("Out of memory"); } let 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; } let s = String::new(name_buf); let 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(); } free(name_buf); _z_fs_closedir(dir); let res = Result< Vec >::Ok(entries); entries.forget(); let ret = res; res.forget(); return ret; } }