ajhahn.de
← FlashOS
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()
}