Something went wrong. Try again.
Jam Programming Language jamlang.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137// std.fs — file I/O. A `File` wraps a libc `FILE*`.//// const { File } = import("std/fs");//// match (File.open("path.txt")) {// Some(f) { var data: Vec(u8) = f.readAll(); f.close(); }// None { /* open failed */ }// }//// Methods are `pub` so they dispatch from importing modules. Fallibility// is carried in the return type via `Option`, mirroring Zig's `!File` /// Rust's `io::Result<File>`. The libc declarations are `pub extern` so// importers can also use them directly (single source of the file FFI).
const { Option } = import("option");const { Vec } = import("collections");
pub extern fn fopen(path: *const[] u8, mode: *const[] u8) *mut[] u8;pub extern fn fread(buf: *mut[] u8, size: u64, n: u64, f: *mut[] u8) u64;pub extern fn fwrite(buf: *const[] u8, size: u64, n: u64, f: *mut[] u8) u64;pub extern fn fclose(f: *mut[] u8) i32;pub extern fn fseek(f: *mut[] u8, off: i64, whence: i32) i32;pub extern fn ftell(f: *mut[] u8) i64;pub extern fn access(path: *const[] u8, mode: i32) i32;pub extern fn fgetc(f: *mut[] u8) i32;pub extern fn feof(f: *mut[] u8) i32;pub extern fn realpath(path: *const[] u8, resolved: *mut[] u8) *mut[] u8;
pub const SEEK_SET: i32 = 0;pub const SEEK_CUR: i32 = 1;pub const SEEK_END: i32 = 2;
// Copy a `[]u8` path into a caller-provided buffer with a trailing NUL.// A `[]u8` carries no NUL (Zig `toPosixPath` / Rust `CString` style).// `pub` because File.open/create/exists (pub fns) call it, and an// imported pub fn's body is codegen'd in the caller's module — its// callees must be visible there too.pub fn cpath(path: []u8, buf: *mut[] u8) { var i: u64 = 0; while (i < path.len && i < 4095) { buf[i] = path.ptr[i]; i = i + 1; } buf[i] = 0;}
pub fn openMode(path: []u8, mode: *const[] u8) Option(File) { var buf: [4096]u8 = [0; 4096]; cpath(path, buf.asMutPtr()); var h: *mut[] u8 = fopen(buf.asPtr(), mode); // libc returns NULL on failure; Jam can't compare a pointer to null // directly, so reinterpret the handle as an integer address. if ((h as u64) == 0) { return Option(File).None(); } return Option(File).Some(File { handle: h });}
pub const File = struct { handle: *mut[] u8,
// Open `path` for binary reading; None if it can't be opened. pub fn open(path: []u8) Option(File) { var mode: []u8 = "rb"; return openMode(path, mode.ptr); }
// Create/truncate `path` for binary writing; None on failure. pub fn create(path: []u8) Option(File) { var mode: []u8 = "wb"; return openMode(path, mode.ptr); }
// Read up to `dst.len` bytes into `dst`; returns the number read. pub fn read(self: File, dst: []u8) u64 { return fread(dst.ptr as *mut[] u8, 1, dst.len, self.handle); }
// Write all of `data`; returns the number of bytes written. pub fn write(self: File, data: []u8) u64 { return fwrite(data.ptr, 1, data.len, self.handle); }
// Reposition the read/write cursor (whence = SEEK_SET/CUR/END). pub fn seek(self: File, off: i64, whence: i32) i32 { return fseek(self.handle, off, whence); }
// Total size of the file in bytes (restores the cursor to start). pub fn size(self: File) u64 { fseek(self.handle, 0, SEEK_END); var n: i64 = ftell(self.handle); fseek(self.handle, 0, SEEK_SET); return n as u64; }
// Read the whole file into a freshly-allocated Vec(u8). pub fn readAll(self: File) Vec(u8) { var n: u64 = self.size(); var v: Vec(u8) = Vec(u8).withCapacity(n as u32); var got: u64 = fread(v.ptr, 1, n, self.handle); v.setLen(got as u32); return v; }
// Read one byte; returns 0..255, or -1 at EOF (libc fgetc semantics), // so streaming parsers can loop on the result. pub fn readByte(self: File) i32 { return fgetc(self.handle); }
// True once the end-of-file indicator is set (after a read past end). pub fn eof(self: File) bool { return feof(self.handle) != 0; }
pub fn close(self: File) { fclose(self.handle); }};
// True if `path` exists and is accessible (libc access(path, F_OK)).pub fn exists(path: []u8) bool { var buf: [4096]u8 = [0; 4096]; cpath(path, buf.asMutPtr()); return access(buf.asPtr(), 0) == 0;}
// Resolve `path` (symlinks, relative segments) into `out` — a caller// buffer of at least PATH_MAX bytes. Wraps libc realpath; mirrors// Rust's fs::canonicalize / Zig's realpath.pub fn canonicalize(path: []u8, out: *mut[] u8) { var buf: [4096]u8 = [0; 4096]; cpath(path, buf.asMutPtr()); realpath(buf.asPtr(), out);}