file_io

Ergonomic wrappers around the low-level fs package. Provides Python-style convenience for reading entire files, writing strings, copying, renaming, and working with paths. Depends on fs.jda.

Usage

import fs
import file_io

fn main() {
    // Read an entire file
    let buf = fs_slurp("/tmp/data.txt")
    let size = fs_file_size("/tmp/data.txt")

    // Count lines
    let lines = buf_count_lines(buf, size)
    print(lines)

    // Write a string to a file
    fs_write_str("/tmp/out.txt", "hello world\n", 12)

    // Copy a file
    fs_copy("/tmp/out.txt", "/tmp/backup.txt")

    // Path manipulation
    let out: &i8 = alloc_pages(1)
    let len = path_join("/home/user", 10, "file.txt", 8, out)
    // out now contains: /home/user/file.txt
}

Function Reference

FunctionSignatureDescription
fs_slurp(path: &i8) -> i64Read entire file into a buffer
fs_write_str(path: &i8, data: &i8, len: i64) -> i64Write string to file
fs_append_str(path: &i8, data: &i8, len: i64) -> i64Append string to file
fs_copy(src: &i8, dst: &i8) -> i64Copy a file
fs_rename(src: &i8, dst: &i8) -> i64Rename/move a file
fs_tmpname(out: &i8, suffix: i64) -> i64Generate a temp file path
buf_count_lines(buf: &i8, len: i64) -> i64Count lines in a buffer
buf_line_start(buf: &i8, len: i64, line_idx: i64) -> i64Get offset of line N
buf_line_len(buf: &i8, total_len: i64, start: i64) -> i64Get length of line at offset
path_join(dir: &i8, dir_len: i64, name: &i8, name_len: i64, out: &i8) -> i64Join directory and filename
path_basename(path: &i8, len: i64) -> i64Find basename offset in path
path_ext(path: &i8, len: i64) -> i64Find extension dot offset
cstr_length(s: &i8) -> i64Length of null-terminated string
buf_eq(a: &i8, b: &i8, n: i64) -> i64Compare n bytes for equality

Detailed API

fs_slurp

fn fs_slurp(path: &i8) -> i64

Read an entire file into an auto-allocated buffer. Uses fs_file_size to determine the size, allocates pages, and reads the file contents. Use fs_file_size separately to get the byte count.

let buf: &i8 = fs_slurp("/etc/hostname")
let size = fs_file_size("/etc/hostname")
// buf[0..size] now contains the file contents

Returns: Pointer to the buffer (cast to i64), or 0 on error.

fs_write_str

fn fs_write_str(path: &i8, data: &i8, len: i64) -> i64

Write len bytes from data to a file, creating or truncating it. Like Python’s open(f, 'w').write(data).

let msg = "Hello, World!\n"
let n = fs_write_str("/tmp/greeting.txt", msg, 14)
print(n)   // 14 (bytes written)

Returns: Number of bytes written, or -1 on error.

fs_append_str

fn fs_append_str(path: &i8, data: &i8, len: i64) -> i64

Append len bytes to an existing file. Like Python’s open(f, 'a').write(data).

fs_append_str("/tmp/log.txt", "entry 1\n", 8)
fs_append_str("/tmp/log.txt", "entry 2\n", 8)

Returns: Number of bytes written, or -1 on error.

fs_copy

fn fs_copy(src: &i8, dst: &i8) -> i64

Copy a file from src to dst. Reads the entire source file into memory and writes it to the destination.

let r = fs_copy("/tmp/original.txt", "/tmp/backup.txt")
if r < 0 { print("copy failed") }

Returns: Bytes written on success, -1 on error.

fs_rename

fn fs_rename(src: &i8, dst: &i8) -> i64

Rename or move a file. Uses Linux rename syscall (82).

fs_rename("/tmp/old.txt", "/tmp/new.txt")

Returns: 0 on success, -1 on error.

fs_tmpname

fn fs_tmpname(out: &i8, suffix: i64) -> i64

Generate a temporary file path of the form /tmp/jda_NNNN where NNNN is the decimal representation of suffix. The path is null-terminated.

let out: &i8 = alloc_pages(1)
let len = fs_tmpname(out, 12345)
// out now contains: /tmp/jda_12345\0

Returns: Length of the path (not including null terminator).

buf_count_lines

fn buf_count_lines(buf: &i8, len: i64) -> i64

Count the number of lines in a buffer. Counts newline characters, adding 1 if the buffer does not end with a newline.

let text = "line1\nline2\nline3"
let n = buf_count_lines(text, 17)
print(n)   // 3

buf_line_start

fn buf_line_start(buf: &i8, len: i64, line_idx: i64) -> i64

Get the byte offset where line number line_idx (0-indexed) begins.

let text = "aaa\nbbb\nccc"
let start = buf_line_start(text, 11, 1)
print(start)   // 4 (start of "bbb")

buf_line_len

fn buf_line_len(buf: &i8, total_len: i64, start: i64) -> i64

Get the length of a line starting at offset start, excluding the newline character.

let text = "aaa\nbbb\nccc"
let start = buf_line_start(text, 11, 1)
let llen = buf_line_len(text, 11, start)
print(llen)   // 3 (length of "bbb")

path_join

fn path_join(dir: &i8, dir_len: i64, name: &i8, name_len: i64, out: &i8) -> i64

Join a directory and filename with /. If the directory already ends with /, no extra separator is added. The result is null-terminated.

let out: &i8 = alloc_pages(1)
let len = path_join("/home/user", 10, "data.txt", 8, out)
// out contains: /home/user/data.txt\0
print(len)   // 19

Returns: Length of the resulting path.

path_basename

fn path_basename(path: &i8, len: i64) -> i64

Find the offset where the filename begins in a path (after the last /).

let offset = path_basename("/foo/bar/baz.txt", 16)
print(offset)   // 9 (points to 'b' in "baz.txt")

Returns: Byte offset of the basename.

path_ext

fn path_ext(path: &i8, len: i64) -> i64

Find the position of the last . in the filename portion of a path. Returns len if there is no extension.

let dot = path_ext("/foo/bar.txt", 12)
print(dot)   // 8 (position of '.')

Returns: Offset of the extension dot, or len if no extension.

cstr_length

fn cstr_length(s: &i8) -> i64

Get the length of a null-terminated C string by scanning for the \0 byte.

let len = cstr_length("hello")
print(len)   // 5

buf_eq

fn buf_eq(a: &i8, b: &i8, n: i64) -> i64

Compare n bytes of two buffers for equality.

print(buf_eq("abc", "abc", 3))   // 1
print(buf_eq("abc", "abd", 3))   // 0

Returns: 1 if all bytes match, 0 otherwise.