Flash 60 lines
// readfile — copy named files to fd 1, with errors carried as values.
//
// The first Flash port built on the v0.2 error-union surface. `dup` opens a path
// and returns a `!i32`: it `try`s the descriptor, then registers an `errdefer`
// so a failed validation closes it before the error propagates — on the success
// path ownership passes to the caller and the errdefer does not run. `copy`
// `try`s that helper, `defer`s the close so it runs on every exit, and `try`s
// each read so an I/O fault unwinds cleanly. `main` recovers with `catch |e|`,
// turning any error into a diagnostic instead of a crash. Every failure edge is
// spelled in the source — no hidden control flow.
//
// Pulls in the same flibc surface as the other coreutils; only the error model
// is new (`!T`, `try`, `catch`, `defer`, `errdefer`).
use flibc
link "flibc_start"
link "flibc_mem"
const BUF_LEN usize = 512
fn dup(path cstr) !i32 {
fd := try flibc.sys.open(path)
errdefer _ = flibc.sys.close(fd)
_ = try flibc.sys.fstat(fd)
return fd
}
fn copy(path cstr) !usize {
fd := try dup(path)
defer _ = flibc.sys.close(fd)
var buf [BUF_LEN]u8 = undefined
var total usize = 0
while true {
n := try flibc.sys.read(fd, &buf, buf.len)
if n == 0 {
break
}
_ = flibc.sys.write_fd(1, &buf, #intCast(n))
total += n
}
return total
}
fn report(e flibc.Error) usize {
_ = e
_ = flibc.sys.write_fd(2, "readfile: I/O error\n", 20)
return 0
}
export fn main(argc usize, argv argv) noreturn {
var i usize = 1
while i < argc {
path := argv[i] orelse break
_ = copy(path) catch |e| report(e)
i += 1
}
flibc.exit()
}