#include #include #include #include #include static SharedPtr g_stdin = {}; static SharedPtr g_stdout = {}; static SharedPtr g_stderr = {}; namespace os { File::File(Badge) { } File::~File() { if (m_fd >= 0) close(m_fd); } void File::initialize_standard_streams() { g_stdin = adopt_shared_if_nonnull(new (std::nothrow) File({})) .expect_release_value("Cannot open standard input stream"); g_stdin->m_fd = STDIN_FILENO; g_stdout = adopt_shared_if_nonnull(new (std::nothrow) File({})) .expect_release_value("Cannot open standard output stream"); g_stdout->m_fd = STDOUT_FILENO; g_stderr = adopt_shared_if_nonnull(new (std::nothrow) File({})) .expect_release_value("Cannot open standard error stream"); g_stderr->m_fd = STDERR_FILENO; } SharedPtr File::standard_input() { if (!g_stdin) initialize_standard_streams(); return g_stdin; } SharedPtr File::standard_output() { if (!g_stdout) initialize_standard_streams(); return g_stdout; } SharedPtr File::standard_error() { if (!g_stderr) initialize_standard_streams(); return g_stderr; } Result> File::construct(StringView path, int flags, mode_t mode) { auto file = TRY(adopt_shared_if_nonnull(new (std::nothrow) File({}))); long rc = syscall(SYS_openat, AT_FDCWD, path.chars(), flags, mode); int fd = TRY(Result::from_syscall(rc)); file->m_fd = fd; return file; } Result> File::open(StringView path, OpenMode flags) { return construct(path, (int)flags, 0); } Result> File::open_or_create(StringView path, OpenMode flags, mode_t mode) { return construct(path, (int)flags | O_CREAT, mode); } Result> File::create(StringView path, OpenMode flags, mode_t mode) { return construct(path, (int)flags | (O_CREAT | O_EXCL), mode); } Result File::raw_read(u8* buf, usize length) { long rc = syscall(SYS_read, m_fd, buf, length); return Result::from_syscall(rc); } Result File::raw_write(const u8* buf, usize length) { long rc = syscall(SYS_write, m_fd, buf, length); return Result::from_syscall(rc); } Result File::write(StringView str) { TRY(raw_write((const u8*)str.chars(), str.length())); return {}; } Result File::write(const Buffer& buf) { TRY(raw_write(buf.data(), buf.size())); return {}; } Result File::read_line(bool keep_newline) { Vector data; int current; while (true) { current = TRY(getchar()); if (current == -1) break; TRY(data.try_append((char)current)); if (current == '\n') { if (!keep_newline) data.try_pop(); break; } } if (!data.size()) return String {}; TRY(data.try_append('\0')); return String::from_cstring(data.data()); } Result File::read(Buffer& buf, usize size) { u8* slice = TRY(buf.slice(0, size)); usize nread = TRY(raw_read(slice, size)); TRY(buf.try_resize(nread)); return {}; } Result File::getchar() { char value; usize nread = TRY(raw_read((u8*)&value, 1)); if (!nread) return -1; return value; } void File::set_close_on_exec() { fcntl(m_fd, F_SETFD, FD_CLOEXEC); } }