std/fs.zc
Rama main · réplica de lectura del repositorio original.
import "./core.zc"
import "./mem.zc"
import "./result.zc"
import "./string.zc"
import "./vec.zc"
import "sys/fs.zc"
def Z_SEEK_SET = 0;
def Z_SEEK_END = 2;
def Z_F_OK = 0;
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_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 {
/// Opens a file with the given mode.
fn open(path: char*, mode: char*) -> Result<File> {
let h = fopen(path, mode);
if (h == NULL) {
return Result<File>::Err("Failed to open file");
}
return Result<File>::Ok(File { handle: h });
}
/// Closes the file handle.
fn close(self) {
if (self.handle) {
fclose((FILE*)self.handle);
self.handle = NULL;
}
}
/// Reads the whole file into a String.
fn read_to_string(self) -> Result<String> {
if (self.handle == NULL) {
return Result<String>::Err("File not open");
}
fseek((FILE*)self.handle, 0, Z_SEEK_END);
let size = ftell((FILE*)self.handle);
fseek((FILE*)self.handle, 0, Z_SEEK_SET);
let buffer: char* = alloc_n<char>((usize)size + 1);
if (buffer == NULL) {
return Result<String>::Err("Out of memory");
}
let read = fread(buffer, 1, size, (FILE*)self.handle);
buffer[read] = 0;
let s = String::new(buffer);
dealloc<char>(buffer);
let res = Result<String>::Ok(s);
s.forget();
let ret = res;
res.forget();
return ret;
}
/// Reads the whole file into a String.
fn read_all(path: char*) -> Result<String> {
let res = File::open(path, "rb");
if (res.is_err()) {
return Result<String>::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;
}
/// Writes a C string to the file.
fn write_string(self, content: char*) -> Result<bool> {
if (self.handle == NULL) {
return Result<bool>::Err("File not open");
}
let len = strlen(content);
let written = fwrite(content, 1, len, (FILE*)self.handle);
if (written != len) {
return Result<bool>::Err("Write incomplete");
}
return Result<bool>::Ok(true);
}
/// Reads all lines into a Vec of Strings.
fn read_lines(path: char*) -> Result< Vec<String> > {
let res = File::read_all(path);
if (res.is_err()) {
return Result< Vec<String> >::Err(res.err);
}
let content = res.unwrap();
let lines = content.split('\n');
// Remove trailing \r from lines if on windows or CRLF
for (let i: usize = 0; i < lines.len; i = i + 1) {
let line = lines.get_ref(i);
let len = line.length();
if (len > 0) {
let last_char = line.vec.get(len - 1);
if (last_char == '\r') {
let trimmed = line.substring(0, len - 1);
line.destroy();
lines.set(i, trimmed);
}
}
}
// Remove the final blank line if ending in a delimiter
if (lines.len > 0) {
let last_idx = lines.len - 1;
let last_line = lines.get_ref(last_idx);
if (last_line.length() == 0) {
let empty = lines.pop(); // Safe because it's the element itself
empty.destroy();
}
}
content.destroy();
let ret_res = Result< Vec<String> >::Ok(lines);
let ret = ret_res;
return ret;
}
/// Writes multiple lines to the file.
fn write_lines(path: char*, lines: Vec<String>*) -> Result<bool> {
let res = File::open(path, "wb");
if (res.is_err()) {
return Result<bool>::Err(res.err);
}
let f = res.unwrap();
for (let i: usize = 0; i < lines.len; i = i + 1) {
let line = lines.get_ref(i);
f.write_string(line.c_str());
f.write_string("\n");
}
f.close();
return Result<bool>::Ok(true);
}
/// Returns whether the path exists.
fn exists(path: char*) -> bool {
let zero: c_int = 0;
return access(path, Z_F_OK) == zero;
}
/// Returns the file metadata, or `None`.
fn metadata(path: char*) -> Result<Metadata> {
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<Metadata>::Err("Failed to get metadata");
}
return Result<Metadata>::Ok(Metadata {
size: (u64)size,
is_dir: is_d != non_zero,
is_file: is_f != non_zero
});
}
/// Creates a directory.
fn create_dir(path: char*) -> Result<bool> {
let status = _z_fs_mkdir(path);
let zero: c_int = 0;
if (status != zero) {
return Result<bool>::Err("Failed to create directory");
}
return Result<bool>::Ok(true);
}
/// Removes a file.
fn remove_file(path: char*) -> Result<bool> {
let status = unlink(path);
let zero: c_int = 0;
if (status != zero) {
return Result<bool>::Err("Failed to remove file");
}
return Result<bool>::Ok(true);
}
/// Removes a directory.
fn remove_dir(path: char*) -> Result<bool> {
let status = rmdir(path);
let zero: c_int = 0;
if (status != zero) {
return Result<bool>::Err("Failed to remove directory");
}
return Result<bool>::Ok(true);
}
/// Lists a directory as Vec of DirEntry.
fn read_dir(path: char*) -> Result< Vec<DirEntry> > {
let dir = _z_fs_opendir(path);
if (dir == NULL) {
return Result< Vec<DirEntry> >::Err("Failed to open directory");
}
let entries = Vec<DirEntry>::new();
let name_buf: char* = alloc_n<char>(256);
if (name_buf == NULL) {
_z_fs_closedir(dir);
return Result< Vec<DirEntry> >::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();
}
dealloc<char>(name_buf);
_z_fs_closedir(dir);
let res = Result< Vec<DirEntry> >::Ok(entries);
let ret = res;
return ret;
}
/// Returns the current working directory.
fn current_dir() -> Result<String> {
let buf: char* = alloc_n<char>(1024);
if (buf == NULL) return Result<String>::Err("Out of memory");
if (getcwd(buf, 1024) == NULL) {
dealloc<char>(buf);
return Result<String>::Err("Failed to get current directory");
}
let s = String::new(buf);
dealloc<char>(buf);
let res = Result<String>::Ok(s);
s.forget();
let ret = res;
res.forget();
return ret;
}
}
impl Drop for File {
fn drop(self) {
self.close();
}
}