// SPDX-License-Identifier: MIT #ifndef RGBDS_FILE_HPP #define RGBDS_FILE_HPP #include #include #include #include #include #include #include #include "either.hpp" #include "helpers.hpp" // assume #include "platform.hpp" #include "gfx/main.hpp" class File { Either _file; public: File() : _file(nullptr) {} // This should only be called once, and before doing any `->` operations. // Returns `nullptr` on error, and a non-null pointer otherwise. File *open(std::string const &path, std::ios_base::openmode mode) { if (path != "-") { _file.emplace(); return _file.get().open(path, mode) ? this : nullptr; } else if (mode & std::ios_base::in) { assume(!(mode & std::ios_base::out)); _file.emplace(std::cin.rdbuf()); if (setmode(STDIN_FILENO, (mode & std::ios_base::binary) ? O_BINARY : O_TEXT) == -1) { fatal( "Failed to set stdin to %s mode: %s", mode & std::ios_base::binary ? "binary" : "text", strerror(errno) ); } } else { assume(mode & std::ios_base::out); _file.emplace(std::cout.rdbuf()); } return this; } std::streambuf &operator*() { return _file.holds() ? _file.get() : *_file.get(); } std::streambuf const &operator*() const { // The non-`const` version does not perform any modifications, so it's okay. return **const_cast(this); } std::streambuf *operator->() { return &**this; } std::streambuf const *operator->() const { // See the `operator*` equivalent. return const_cast(this)->operator->(); } char const *c_str(std::string const &path) const { return _file.holds() ? path.c_str() : _file.get() == std::cin.rdbuf() ? "" : ""; } }; #endif // RGBDS_FILE_HPP