Flash 55 lines
// cat — concatenate files to fd 1 for /bin/cat.
//
// With no arguments it copies fd 0 to fd 1 until EOF (the `echo hi | cat` case,
// where fd 0 is the pipe read end). With arguments it opens each path and copies
// its bytes to fd 1; a path that cannot be opened prints a diagnostic to fd 2
// and the next path is tried. No flags.
//
// Exercises a top-level `const`, an `if`/`else`, nested `while` loops with
// `continue` and `orelse break`, and a cross-module import alias
// (`use syscall_defs as defs`) for the EACCES error code. flibc_mem is imported
// for parity with the other coreutils.
use flibc
use syscall_defs as defs
link "flibc_start"
link "flibc_mem"
const BUF_LEN usize = 512
fn drain(fd i32) {
var buf [BUF_LEN]u8 = undefined
while true {
n := flibc.sys.read(fd, &buf, buf.len)
if n <= 0 {
break
}
_ = flibc.sys.write_fd(1, &buf, #intCast(n))
}
}
export fn main(argc usize, argv argv) noreturn {
if argc <= 1 {
drain(0)
} else {
var i usize = 1
while i < argc {
path := argv[i] orelse break
i += 1
fd := flibc.sys.open(path)
if fd < 0 {
var msg []u8 = "cat: cannot open\n"
if fd == -defs.EACCES {
msg = "cat: Permission denied\n"
}
_ = flibc.sys.write_fd(2, msg.ptr, msg.len)
continue
}
drain(fd)
_ = flibc.sys.close(fd)
}
}
flibc.exit()
}