Sistema de Arquivos & I/O
O módulo stdlib::fs envolve as primitivas de arquivo do runtime C em auxiliares Glide mais seguros (listagens ordenadas, retornos Vector<string>, remoção de newlines finais, leituras seguras para binários). O módulo stdlib::io cobre leituras de stdin, gravações brutas em stdout, flush e logging em stderr — as partes que as macros print! / println! não alcançam.
Importação
import stdlib::fs::*; // arquivos, diretórios, caminhos
import stdlib::io::*; // stdin / stdout / stderr
Os dois módulos são independentes; importe apenas o que for usar. Note que eprintln vive em stdlib::io, então qualquer programa de arquivo que registra erros precisa das duas importações.
Superfície pública de relance
| Módulo | Itens |
|---|---|
stdlib::fs |
fs_read · fs_read_or_default · fs_read_lines · fs_lines_count · fs_write · fs_exists · fs_is_dir · fs_size · fs_list · fs_list_rec · fs_basename · fs_extension · fs_mkdir_p · fs_remove_file · fs_remove_dir_rec · fs_copy_file · fs_copy_dir_rec · fs_symlink · fs_read_bytes · fs_write_bytes · fs_write_slice |
stdlib::io |
read_line · read_int · read_bytes · prompt · read_yes_no · io_write · io_write_bytes · flush · eprintln |
Ambos os módulos expõem apenas funções livres — sem structs, enums ou traits públicos. Os externs __glide_* / read_file / write_file sobre os quais são construídos são privados ao módulo; o código do usuário sempre passa pelos invólucros fs_* / io_*.
Lendo arquivos
fs_read / fs_read_or_default
pub fn fs_read(path: string) -> string
pub fn fs_read_or_default(path: string, fallback: string) -> string
fs_read retorna o arquivo inteiro como uma string no heap, ou "" em qualquer erro (arquivo ausente, permissão negada). Como tanto "ausente" quanto "vazio" colapsam para "", use fs_read_or_default quando precisar de um fallback real — ele verifica a existência antes e só retorna fallback quando o arquivo está ausente (um arquivo que existe mas está vazio ainda produz "").
Este é o padrão canônico de "ler um arquivo de configuração": grava um padrão quando o arquivo está ausente, depois lê e analisa linha por linha.
import stdlib::fs::*;
import stdlib::io::*;
fn main() -> i32 {
let path: string = "app.conf";
// Distingue ausente de vazio.
if !fs_exists(path) {
eprintln("no config; writing a default");
fs_write(path, "verbose=false\nport=8080\n");
}
let body: string = fs_read(path);
if body.eq("") {
eprintln("config missing or empty");
return 1;
}
// Analisa linhas simples no formato chave=valor.
let lines: *Vector<string> = body.split("\n");
defer lines.free();
for let i: i32 = 0; i < lines.len(); i++ {
let line: string = lines.get(i).trim();
if line.eq("") { continue; }
if line.starts_with("#") { continue; }
let kv: *Vector<string> = line.split("=");
defer kv.free();
if kv.len() == 2 {
println!("key:", kv.get(0).trim(), "value:", kv.get(1).trim());
}
}
// Variante com fallback: nunca dá erro para arquivo ausente.
let raw: string = fs_read_or_default("missing.conf", "default=1\n");
println!("fallback length:", raw.len());
return 0;
}
fs_read_lines / fs_lines_count
pub fn fs_read_lines(path: string) -> *Vector<string>
pub fn fs_lines_count(path: string) -> i32
fs_read_lines lê path e divide em \n, descartando a entrada vazia final causada por um newline final — assim len() corresponde à contagem intuitiva de linhas. fs_lines_count retorna essa mesma contagem sem alocar um vetor (varre em busca de \n, mais um se o arquivo for não vazio e não terminado em newline); retorna 0 para arquivos vazios ou ausentes. Um arquivo ausente também produz um vetor vazio de fs_read_lines — sem erro, sem crash.
import stdlib::fs::*;
import stdlib::io::*;
fn main() -> i32 {
fs_write("words.txt", "alpha\nbeta\ngamma\n");
let lines: *Vector<string> = fs_read_lines("words.txt");
defer lines.free();
println!("got", lines.len(), "lines"); // 3, não 4 — "" final descartado
for let i: i32 = 0; i < lines.len(); i++ {
let w: string = lines.get(i).trim();
if w.len() >= 5 { println!(w); } // "alpha", "gamma"
}
let n: i32 = fs_lines_count("words.txt");
println!("lines_count:", n); // 3
// Arquivo ausente -> 0 / vetor vazio, sem crash.
let missing: *Vector<string> = fs_read_lines("nope.txt");
defer missing.free();
println!("missing len:", missing.len(), "count:", fs_lines_count("nope.txt"));
return 0;
}
O vetor retornado é um *Vector<string> bruto — libere-o (ou use defer .free()) quando terminar.
Escrevendo arquivos
fs_write
pub fn fs_write(path: string, content: string) -> bool
Grava content em path no modo binário ("wb"), substituindo qualquer arquivo existente. Retorna true somente quando todos os bytes foram gravados. O número de bytes gravados é content.len() medido como string C, então um 0x00 embutido trunca a saída — use `fs_write_bytes` para payloads binários.
import stdlib::fs::*;
import stdlib::io::*;
fn main() -> i32 {
if !fs_write("out.txt", "hello\n") {
eprintln("write failed");
return 1;
}
return 0;
}
Existência, tamanho e tipo
| Função | Assinatura | Descrição |
|---|---|---|
fs_exists |
fn fs_exists(path: string) -> bool |
true se path pode ser aberto para leitura. false para ausente ou ilegível. |
fs_is_dir |
fn fs_is_dir(path: string) -> bool |
true somente se path é um diretório existente (distingue diretório de arquivo). |
fs_size |
fn fs_size(path: string) -> i64 |
Tamanho do arquivo em bytes; -1 se o caminho está ausente ou stat falha. Uma syscall stat, sem abertura. |
import stdlib::fs::*;
import stdlib::io::*;
fn main() -> i32 {
fs_write("favicon.ico", "icon-bytes");
if fs_exists("favicon.ico") { println!("exists"); }
if fs_is_dir(".") { println!("cwd is a dir"); }
if !fs_is_dir("favicon.ico") { println!("favicon is a file, not a dir"); }
let n: i64 = fs_size("favicon.ico");
if n > 0 { println!("serve it,", n, "bytes"); }
let missing: i64 = fs_size("does-not-exist");
if missing == -1 { println!("size of missing path is -1"); }
return 0;
}
Listando diretórios
fs_list
pub fn fs_list(dir: string, suffix: string) -> *Vector<string>
Lista nomes de arquivo diretamente sob dir (sem recursão). Retorna apenas nomes, não caminhos completos, ordenados de forma ascendente para saída estável. Filtra por suffix (ex.: ".glide"); passe "" para manter todos. Diretórios são excluídos; no POSIX, entradas com prefixo de ponto também são ignoradas. Um diretório ausente produz um vetor vazio (sem erro).
import stdlib::fs::*;
import stdlib::io::*;
fn main() -> i32 {
let files: *Vector<string> = fs_list("src/stdlib", ".glide");
defer files.free();
for let i: i32 = 0; i < files.len(); i++ {
println!("- ", files.get(i));
}
return 0;
}
fs_list_rec
pub fn fs_list_rec(dir: string, suffix: string) -> *Vector<string>
Lista recursivamente todos os arquivos sob dir cujo nome termina em suffix (passe "" para todos). Retorna caminhos relativos completos (cada um prefixado com dir/...), não basenames. Ignora diretórios com prefixo de ponto mais glide_modules/, build/, target/ e node_modules/, para que passagens de documentação e lint não varram dependências ou saída de build. Ordenado dentro de cada nível de diretório, percorrido em profundidade.
Este é o padrão de "percorrer uma árvore e inspecionar cada arquivo", combinado com os auxiliares de caminho abaixo:
import stdlib::fs::*;
import stdlib::io::*;
fn main() -> i32 {
// Filhos imediatos, apenas nomes, filtrados por sufixo.
let top: *Vector<string> = fs_list("src", ".glide");
defer top.free();
for let i: i32 = 0; i < top.len(); i++ {
println!("- ", top.get(i));
}
// Recursivo, caminhos relativos completos.
let all: *Vector<string> = fs_list_rec("src", ".glide");
defer all.free();
println!("found", all.len(), "glide files");
for let i: i32 = 0; i < all.len(); i++ {
let p: string = all.get(i);
println!(fs_basename(p), "ext:", fs_extension(p));
}
return 0;
}
Auxiliares de caminho
Estas são funções de string puras — não tocam o sistema de arquivos.
| Função | Assinatura | Descrição |
|---|---|---|
fs_basename |
fn fs_basename(path: string) -> string |
Último componente do caminho (após o último / ou \). Retorna a entrada inalterada quando não há separador. |
fs_extension |
fn fs_extension(path: string) -> string |
Extensão sem o ponto inicial, em minúsculas. "" quando não há extensão. |
import stdlib::fs::*;
import stdlib::io::*;
fn main() -> i32 {
println!(fs_basename("src/stdlib/fs.glide")); // fs.glide
println!(fs_basename("/usr/local/bin/glide")); // glide
println!(fs_basename("noslash.txt")); // noslash.txt
println!(fs_extension("config.toml")); // toml
println!(fs_extension("archive.tar.gz")); // gz
println!(fs_extension("Makefile")); // ""
println!(fs_extension(".bashrc")); // ""
return 0;
}
fs_basename trata ambos os separadores, então fs_basename("C:\\Program Files\\Glide\\bin") é "bin".
Criando e modificando diretórios
| Função | Assinatura | Descrição |
|---|---|---|
fs_mkdir_p |
fn fs_mkdir_p(path: string) -> bool |
Cria path e todos os pais ausentes. Idempotente; false apenas em um erro real. |
fs_remove_file |
fn fs_remove_file(path: string) -> bool |
Remove um arquivo. true em sucesso ou se já estava ausente. |
fs_remove_dir_rec |
fn fs_remove_dir_rec(path: string) -> bool |
Remove path recursivamente. Idempotente (ausente → sucesso). Delega para rm -rf / rmdir /S /Q. |
fs_copy_file |
fn fs_copy_file(src: string, dst: string) -> bool |
Cópia de arquivo segura para binário, sobrescrevendo dst. false em qualquer erro de I/O. |
fs_copy_dir_rec |
fn fs_copy_dir_rec(src: string, dst: string) -> bool |
Copia src recursivamente para dst, criando dst. Delega para cp -r / xcopy /S. |
fs_symlink |
fn fs_symlink(target: string, link: string) -> bool |
Faz link ser um link no formato de diretório apontando para target. Idempotente. symlink(2) no POSIX; junction de diretório no Windows (mklink /J, sem admin). |
import stdlib::fs::*;
import stdlib::io::*;
fn main() -> i32 {
if !fs_mkdir_p("cache/sub/leaf") {
eprintln("can't make cache");
return 1;
}
fs_write("cache/a.txt", "hello");
if !fs_copy_file("cache/a.txt", "cache/b.txt") {
eprintln("copy failed");
}
fs_copy_dir_rec("cache", "backup/cache");
fs_symlink("cache/sub", "cache/link");
// Limpeza é idempotente — não são necessárias pré-verificações.
fs_remove_file("cache/a.txt");
fs_remove_dir_rec("cache");
fs_remove_dir_rec("backup");
println!("done");
return 0;
}
I/O Binário
Estas sobrevivem a bytes NUL embutidos, ao contrário de fs_read / fs_write.
fs_read_bytes / fs_write_bytes / fs_write_slice
pub fn fs_read_bytes(path: string, out_len: *i32) -> string
pub fn fs_write_bytes(path: string, data: *void, n: i32) -> bool
pub fn fs_write_slice(path: string, data: string, offset: i32, n: i32) -> bool
fs_read_byteslêpathcomo bytes brutos em uma string Glide prefixada por comprimento;out_lenrecebe a contagem exata de bytes. Retorna""e0em falha. (Internamente libera o buffer C após copiar para uma string rastreada pela arena, sem vazamentos.)fs_write_bytesgravanbytes de um buffer*voidno modo binário.fs_write_slicegravanbytes a partir deoffsetdentro de uma string Glide — útil para extrair um arquivo de um arquivo compactado em memória sem uma cópia extra desubstring. Sem verificação de limites: o chamador garante queoffset + nestá dentro do intervalo.
import stdlib::fs::*;
import stdlib::io::*;
fn main() -> i32 {
// Lê bytes brutos (sobrevive a NUL embutido).
let mut n: i32 = 0;
let buf: string = fs_read_bytes("favicon.ico", &n);
if n > 0 {
// Round-trip de uma fatia do buffer sem cópia extra.
fs_write_slice("copy.ico", buf, 0, n);
println!("copied", n, "bytes");
}
// Grava a partir de um buffer *void bruto.
let blob: *void = malloc(16) as *void;
if fs_write_bytes("out.bin", blob, 16) {
println!("wrote 16 bytes");
}
free(blob);
fs_remove_file("copy.ico");
fs_remove_file("out.bin");
return 0;
}
Entrada padrão
read_line
pub fn read_line() -> string
Lê uma linha do stdin incluindo o newline final se presente; "" em EOF. Apoiado por um buffer fixo de 8 KiB (fgets), então uma única chamada retorna no máximo ~8191 bytes de uma linha muito longa. Use isso quando precisar da linha bruta (piping linha a linha); use `prompt` quando quiser o newline removido.
read_int
pub fn read_int() -> !i32
Lê uma linha, remove espaços em branco e faz o parse — o único !T nesses módulos. Inspecione com .ok / .val / .err, ou propagule com ?.
read_bytes
pub fn read_bytes(n: i32) -> string
Lê até n bytes brutos; a string retornada pode ser mais curta que n próximo ao EOF, e é "" para n <= 0.
prompt / read_yes_no
pub fn prompt(msg: string) -> string
pub fn read_yes_no(prompt_msg: string) -> bool
prompt grava msg, faz flush, então lê uma linha e a retorna sem o newline final (trata tanto \n quanto \r\n). read_yes_no exibe o prompt e retorna true quando a resposta aparada começa com y ou Y.
Um programa interativo completo tocando todos os auxiliares de stdin:
import stdlib::io::*;
fn main() -> i32 {
let name: string = prompt("name? ");
println!("hello,", name);
let raw: string = read_line(); // mantém o newline final
println!("raw line len:", raw.len());
let age: !i32 = read_int();
if age.ok { println!("age:", age.val); }
else { println!("not an i32:", age.err); }
if read_yes_no("continue? ") {
println!("continuing");
}
let chunk: string = read_bytes(4096);
println!("read", chunk.len(), "bytes");
return 0;
}
Saída padrão e stderr
| Função | Assinatura | Descrição |
|---|---|---|
io_write |
fn io_write(s: string) |
Grava s em stdout, sem newline. Chamado io_write (não write) para evitar colisão com write(2) da libc. |
io_write_bytes |
fn io_write_bytes(s: string, n: i32) |
Grava exatamente n bytes de s — seguro para NULs embutidos. |
flush |
fn flush() |
Força o flush do stdout. Importa para prompts/progresso quando stdout é um pipe (buffer de bloco). |
eprintln |
fn eprintln(s: string) |
Grava s em stderr com um newline final. Stderr não tem buffer, então não é necessário flush. |
import stdlib::io::*;
fn main() -> i32 {
io_write("> "); // sem newline; precisa de flush para aparecer antes de uma leitura
flush();
let header: string = "ABCDEFGHIJKLMNOP";
io_write_bytes(header, 16); // gravação em stdout segura para binário
io_write("\n");
flush();
eprintln("warning: missing config file, using defaults");
return 0;
}