#include #include #include #include namespace psemek::io { static void throw_fopen [[noreturn]] (std::filesystem::path const & path) { throw util::system_error(std::error_code{errno, std::system_category()}, "Failed to open " + path.string()); } static FILE * safe_fopen(std::filesystem::path const & path, const char * mode) { std::string path_str = path.string(); auto f = std::fopen(path_str.c_str(), mode); if (!f) throw_fopen(path); return f; } file_istream::file_istream(std::filesystem::path const & path) : file_{safe_fopen(path.c_str(), "rb")} {} void file_istream::reset() { if (file_) std::fclose(file_); file_ = nullptr; } std::size_t file_istream::read(char * p, std::size_t size) { if (!file_) throw null_istream{}; return std::fread(p, 1, size, file_); } static char const * fopen_write_mode(unsigned flags) { switch (flags) { case 0: return "wb"; case file_ostream::append: return "ab"; default: throw util::exception("Unknown file_ostream open flags"); } } file_ostream::file_ostream(std::filesystem::path const & path, unsigned flags) : file_{safe_fopen(path.c_str(), fopen_write_mode(flags))} {} void file_ostream::reset() { if (file_) std::fclose(file_); file_ = nullptr; } std::size_t file_ostream::write(char const * p, std::size_t size) { if (!file_) throw null_ostream{}; return std::fwrite(p, 1, size, file_); } void file_ostream::flush() { if (!file_) throw null_ostream{}; std::fflush(file_); } }