// SPDX-License-Identifier: MIT #ifndef RGBDS_FILE_HPP #define RGBDS_FILE_HPP #include #include #include #include #include #include #include #include "helpers.hpp" // assume #include "platform.hpp" class File { std::variant _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 != "-") { return _file.emplace().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) { return nullptr; } } else { assume(mode & std::ios_base::out); _file.emplace(std::cout.rdbuf()); } return this; } std::streambuf &operator*() { return std::holds_alternative(_file) ? std::get(_file) : *std::get(_file); } 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 std::holds_alternative(_file) ? path.c_str() : std::get(_file) == std::cin.rdbuf() ? "" : ""; } }; #endif // RGBDS_FILE_HPP