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 // Direct externs for simple functions with const char* parameters extern fn access(pathname: const char*, mode: c_int) -> c_int; extern fn unlink(pathname: const char*) -> c_int; extern fn rmdir(pathname: const char*) -> c_int; extern fn malloc(size: usize) -> void*; extern fn free(ptr: void*); // Minimal raw block: required for opaque FILE*/DIR* types and C struct access // These cannot be expressed in Zen-C extern declarations without type conflicts raw { typedef struct DirEntry* DirEntryPtr; // FILE* wrappers - fopen/fclose/etc use FILE* which conflicts with void* void* _z_fs_fopen(const char* path, const 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); } // DIR* wrappers - opendir/closedir/readdir use DIR* which conflicts with void* void* _z_fs_opendir(const char* name) { return opendir(name); } int _z_fs_closedir(void* dir) { return closedir((DIR*)dir); } // struct stat access - cannot define matching Zen-C struct for stat int _z_fs_get_metadata(const 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; } // struct dirent access - readdir returns struct dirent* 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; } // mkdir has different signatures on Windows vs POSIX int _z_fs_mkdir(const char* path) { #ifdef _WIN32 return mkdir(path); #else return mkdir(path, 0777); #endif } } extern fn _z_fs_mkdir(path: const char*) -> c_int; extern fn _z_fs_get_metadata(path: const char*, size: U64*, is_dir: c_int*, is_file: c_int*) -> c_int; extern fn _z_fs_read_entry(dir: void*, out_name: char*, buf_size: c_int, is_dir: c_int*) -> c_int; extern fn _z_fs_fopen(path: const char*, mode: const char*) -> void*; extern fn _z_fs_fclose(stream: void*) -> c_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: c_int) -> c_int; extern fn _z_fs_ftell(stream: void*) -> I64; extern fn _z_fs_opendir(name: const char*) -> void*; extern fn _z_fs_closedir(dir: void*) -> c_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 { let zero: c_int = 0; return access(path, Z_F_OK) == zero; } fn metadata(path: char*) -> Result { let size: uint64_t; let is_d: c_int; let is_f: c_int; let res = _z_fs_get_metadata(path, &size, &is_d, &is_f); let non_zero: c_int = 0; if (res != non_zero) { return Result::Err("Failed to get metadata"); } return Result::Ok(Metadata { size: (U64)size, is_dir: is_d != non_zero, is_file: is_f != non_zero }); } fn create_dir(path: char*) -> Result { let res = _z_fs_mkdir(path); let zero: c_int = 0; if (res != zero) { return Result::Err("Failed to create directory"); } return Result::Ok(true); } fn remove_file(path: char*) -> Result { let res = unlink(path); let zero: c_int = 0; if (res != zero) { return Result::Err("Failed to remove file"); } return Result::Ok(true); } fn remove_dir(path: char*) -> Result { let res = rmdir(path); let zero: c_int = 0; if (res != zero) { 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: c_int = 0; let is_d_zero: c_int = 0; while (_z_fs_read_entry(dir, name_buf, 256, &is_d)) { let zero_cmp: c_int = 0; if (strcmp(name_buf, ".") == zero_cmp || strcmp(name_buf, "..") == zero_cmp) { continue; } let s = String::new(name_buf); let ent = DirEntry { name: s, is_dir: is_d != is_d_zero }; // 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; } }