use encoding::utf8; use io; use types::c; @symbol("close") fn close(int) int; @symbol("dup") fn dup(int) int; @symbol("dup2") fn dup2(int, int) int; @symbol("lseek") fn lseek(int, io::off, int) io::off; @symbol("mkstemp") fn mkstemp(*c::char) int; @symbol("perror") fn perror(nullable *const c::char) void; @symbol("read") fn read(int, *opaque, size) c::ssize; @symbol("unlink") fn unlink(*const c::char) int; @symbol("write") fn write(int, *const opaque, size) c::ssize; type error = !str; def STDOUT_FILENO: int = 1; def STDERR_FILENO: int = 2; let stderr = -1; let tmpfd = -1; let tmpname: [_]u8 = ['/', 't', 'm', 'p', '/', 'X', 'X', 'X', 'X', 'X', 'X', '\0']; @init fn tmp() void = { stderr = dup(STDERR_FILENO); assert(stderr != -1); tmpfd = mkstemp(tmpname[..]: *[*]u8: *c::char); assert(tmpfd != -1); // libc wrapper functions will set stderr back to actual stderr before // performing any operation on it // (in this demo i didn't bother with this, but like hypothetically) const n = dup2(tmpfd, STDERR_FILENO); assert(n != -1); }; @fini fn tmp() void = { if (tmpfd != -1) { close(tmpfd); unlink(tmpname[..]: *[*]u8: *const c::char); }; }; export fn main() void = { // set errno to EBADF to demonstrate const n = close(-1); assert(n == -1); const err = errno(); write(STDOUT_FILENO, *(&err: **const opaque), len(err)); write(STDOUT_FILENO, &10u8, 1); }; fn errno() error = { perror(null); if (write(STDERR_FILENO, &0u8, 1) == -1) { return "Unknown error"; }; // we don't know the value of SEEK_SET, so iterate from 0 to 2 and check // which one has expected seek behavior // technically the value may not be from 0 to 2, but if that's the case // then eh just abort, i think this is a reasonable assumption to make let i = 0; for (i < 2; i += 1) { if (lseek(STDERR_FILENO, 0, i) == 0) { break; }; }; assert(i < 2); defer { // seek to beginning of file when function returns, so next time // errno() is called the position is already set (necessary // since lseek may overwrite errno) lseek(STDERR_FILENO, 0, i); }; static let buf: [1024]u8 = [0...]; const n = read(STDERR_FILENO, &buf, len(buf)); if (n == -1) { return "Unknown error"; }; const n = c::strlen(buf[..]: *[*]u8: *const c::char); if (n == 0 || !utf8::valid(buf[..n - 1])) { return "Unknown error"; }; return *(&buf[..n - 1]: *str); };