fn
fn fs_read(path: string) -> string
Read the entire contents of path into a heap-allocated string. Returns "" on any error (missing file, permission denied, …). Use fs_exists first when you need to distinguish "missing" from "empty file".
glide
let body: string = fs_read("config.toml");
if body.eq("") { eprintln("config missing or empty"); }
fn
fn fs_write(path: string, content: string) -> bool
Write content to path, replacing any existing file. Returns true on success.
glide
if !fs_write("out.txt", "hello\n") {
eprintln("write failed");
}
fn
fn fs_exists(path: string) -> bool
true if path is openable for reading. Cheap stat-style check — returns false for missing files and unreadable ones alike.
glide
if fs_exists("cache.bin") {
skip the slow recompute
}
fn
fn fs_list(dir: string, suffix: string) -> *Vector<string>
List filenames directly under dir (no recursion). Returns names only, not full paths. Filter by suffix (e.g. ".glide"); pass "" to keep all. Sorted ascending so output is stable across platforms.
glide
let files: *Vector<string> = fs_list("src/stdlib", ".glide");
defer files.free();
for i in 0..files.len() {
println!("- ", files.get(i));
}
fn
fn fs_read_lines(path: string) -> *Vector<string>
Read path and split on \n. The trailing empty entry caused by a final newline is dropped, so iterating is straightforward and len() matches the user's intuitive line count.
glide
let lines: *Vector<string> = fs_read_lines("words.txt");
defer lines.free();
for i in 0..lines.len() {
let w: string = lines.get(i).trim();
if w.len() >= 5 { println!(w); }
}
fn
fn fs_basename(path: string) -> string
Last path component (everything after the final / or \). Returns the input untouched when there's no separator.
glide
fs_basename("src/stdlib/fs.glide"); // "fs.glide"
fs_basename("/usr/local/bin/glide"); // "glide"
fs_basename("C:\\Program Files\\Glide\\bin"); // "bin"
fs_basename("noslash.txt"); // "noslash.txt"
fn
fn fs_extension(path: string) -> string
File extension *without* the leading dot, lower-case. Handles names with multiple dots (archive.tar.gz → gz) and returns "" when there's no extension at all.
glide
fs_extension("config.toml"); // "toml"
fs_extension("archive.tar.gz"); // "gz"
fs_extension("Makefile"); // ""
fs_extension(".bashrc"); // "" (leading dot only)
fn
fn fs_lines_count(path: string) -> int
Number of \n characters in the file plus one if the file is non-empty and lacks a trailing newline. Cheaper than fs_read_lines(path).len() because it doesn't allocate a vector. Returns 0 for empty / missing files.
glide
let n: int = fs_lines_count("README.md");
println!("readme has", n, "lines");
fn
fn fs_read_or_default(path: string, fallback: string) -> string
Read path if it exists, otherwise return fallback. Distinguishes "missing file" from "file exists but empty" — fs_read collapses both into "".
glide
let cfg: string = fs_read_or_default("config.toml", "verbose=false\n");
fn
fn fs_mkdir_p(path: string) -> bool
Create path and any missing parent directories. Idempotent — a pre-existing directory at any step is treated as success. Returns false only on a real error (permissions, file-in-the-way, …).
glide
if !fs_mkdir_p("cache/sub/leaf") { eprintln("can't make cache"); }
fn
fn fs_is_dir(path: string) -> bool
true if path is an existing directory. Distinguishes "directory" from "file" — fs_exists returns true for either.
glide
if fs_is_dir(".git") { /* it's a repo */ }
fn
fn fs_write_bytes(path: string, data: *void, n: int) -> bool
Write n bytes from data to path in binary mode, replacing any existing file. Returns true on success. Use this instead of fs_write when the payload contains embedded NULs (binary data, gzip output, …).
glide
fs_write_bytes("out.bin", buf, 1024);
fn
fn fs_write_slice(path: string, data: string, offset: int, n: int) -> bool
Write a length-bounded slice of data (n bytes starting at offset) to path in binary mode. Use for extracting binary content from an in-memory archive without copying through Glide-side substring (which would force an extra alloc).
glide
fs_write_slice("out/file.bin", archive_bytes, header_end, file_size);
fn
fn fs_read_bytes(path: string, out_len: *int) -> string
Read path as raw bytes, returning a Glide string that survives embedded NULs (unlike fs_read, which truncates at the first 0x00). out_len receives the exact byte count. Returns "" and 0 on failure.
glide
let mut n: int = 0;
let buf: string = fs_read_bytes("archive.tar.gz", &n);
if n > 0 { /* hand off to tar / gzip helpers */ }
fn
fn fs_symlink(target: string, link: string) -> bool
Make link a directory-shaped symlink to target. Idempotent — existing links are left alone. POSIX uses symlink(2); Windows uses a directory junction (mklink /J), which doesn't require admin privileges. Returns true on success or when link already exists.
glide
fs_symlink("/cache/abc123", "./glide_modules/auth");
fn
fn fs_remove_file(path: string) -> bool
Delete a single file. Returns true on success or when the file is already absent (idempotent). Returns false only on a real I/O error (permissions, mount issues).
glide
fs_remove_file("glide.lock");
fn
fn fs_remove_dir_rec(path: string) -> bool
Recursively delete path and everything under it. Idempotent — missing paths report success. Shells out to rm -rf (POSIX) or rmdir /S /Q (Windows) so the implementation stays small.
glide
fs_remove_dir_rec("glide_modules");
fn
fn fs_copy_file(src: string, dst: string) -> bool
Binary-safe file copy. Overwrites the destination if it exists. Returns false on any I/O error (missing source, write-protected destination, …).
glide
fs_copy_file("target/my_app", "/usr/local/bin/my_app");
fn
fn fs_copy_dir_rec(src: string, dst: string) -> bool
Recursively copy src directory into dst, creating dst if missing. Shells out to cp -r (POSIX) or xcopy /S (Windows). Returns false on any I/O error.
glide
fs_copy_dir_rec("src", "/install/dir/src");
fn
fn fs_list_rec(dir: string, suffix: string) -> *Vector<string>
Recursively list every file under dir whose name ends in suffix (pass "" to keep all). Returns full relative paths, not basenames. Skips dot-prefixed directories (.git, .glide_*) plus glide_modules/ and target/ so doc / lint passes don't crawl deps or build output. Sorted ascending so output is stable across platforms.
glide
let files: *Vector<string> = fs_list_rec("src", ".glide");