/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2010-2014 Danny Robson */ #pragma once #include "std.hpp" #include "platform.hpp" #include "posix/fd.hpp" #include #include #include #include #include #include #include #ifdef PLATFORM_WIN32 #include "win32/windows.hpp" #else #define O_BINARY 0 #endif namespace cruft { /////////////////////////////////////////////////////////////////////////// /// Reads an entire file into memory in one operation. template std::vector slurp (std::filesystem::path const&); ///------------------------------------------------------------------------ /// Read the entire contents of a FILE object into memory. /// /// * This may trigger an arbitrary number of read calls. /// * This may block indefinitely depending on the contents of the fd. template std::vector slurp (FILE *); ///------------------------------------------------------------------------ /// Read the entire contents of a file-descriptor into memory in one /// operation. /// /// * This may trigger an arbitrary number of read calls. /// * This may block indefinitely depending on the contents of the fd. template std::vector slurp (cruft::posix::fd&); /////////////////////////////////////////////////////////////////////////// /// Repeatedly calls FunctionT to transfer data from a supplied view to a /// file-like-object. /// /// FunctionT must return a view of the consumed data. /// /// The operation will iterate until the entire view has been consumed and /// hence may block for an indefinate period. /// /// An exception may be throw in the event forward progress is impossible /// (depending on the supplied FunctionT). /// /// TODO: enforce constness of view iterators template < typename DstT, typename FunctionT, typename ValueT, typename ...Args > [[nodiscard]] decltype(auto) drain ( DstT &&dst, FunctionT &&func, cruft::view const &src, Args&& ...args ) { auto cursor = reinterpret_cast (src.data ()); auto remain = src.size () * sizeof (ValueT); while (remain) { auto count = std::invoke (func, dst, cursor, remain, args...); cursor += count; remain -= count; } return src; } /////////////////////////////////////////////////////////////////////////// /// Drains all data from the supplied view `src` to the file-like-object /// `dst` by way of repeated calls to `write`. /// /// Returns a view over the consumed data. This SHOULD always be identical /// to `src`. template < typename DstT, typename ValueT > decltype(auto) write (DstT &&dst, cruft::view const &src) { constexpr auto func = &std::decay_t::write; return drain (std::forward (dst), func, src); } ///------------------------------------------------------------------------ /// Drain the supplied data view into the destination object by calling /// pwrite repeatedly. /// /// Returns a view over the consumed data. This SHOULD always be identical /// to `src`. template < typename DstT, typename ValueT > decltype(auto) pwrite (DstT &&dst, cruft::view const &src, size_t offset) { return drain (std::forward (dst), &std::decay_t::pwrite, src, offset); } ///------------------------------------------------------------------------ /// Read the number of bytes covered by the destination view from the /// source descriptor. template decltype (auto) read (SrcT &&src, cruft::view dst) { auto remain = dst; while (!remain.empty ()) { auto const count = src.read (remain.begin (), remain.size () * sizeof (decltype(dst)::value_type)); remain = remain.consume (count); } return dst; } template requires (std::is_trivial_v) ValueT read (cruft::posix::fd &src) { ValueT res; read (src, cruft::make_byte_view (res)); return res; } /////////////////////////////////////////////////////////////////////////// class indenter : public std::streambuf { protected: std::streambuf* m_dest; bool m_line_start; std::string m_indent; std::ostream* m_owner; protected: virtual int overflow (int ch) override; public: explicit indenter (std::streambuf* _dest, size_t _indent = 4); explicit indenter (std::ostream& _dest, size_t _indent = 4); virtual ~indenter (); }; //------------------------------------------------------------------------- // a wrapper type that implicitly indents a single value when passed to an // ostream operator. template struct indented { explicit indented (const ValueT &_data): data (_data) { ; } const ValueT &data; }; //------------------------------------------------------------------------- template std::ostream& operator<< (std::ostream &os, const cruft::indented &value) { cruft::indenter scoped_indent (os); return os << value.data; } //------------------------------------------------------------------------- class scoped_cwd { public: scoped_cwd (); ~scoped_cwd (); protected: std::string m_original; }; //------------------------------------------------------------------------- class path_error : public std::runtime_error { public: explicit path_error (std::filesystem::path const &path); std::filesystem::path const& path (void) const noexcept; private: std::filesystem::path const m_path; }; class expected_directory_error : public path_error { using path_error::path_error; }; class stream_error : public std::exception { public: const char* what (void) const noexcept override { return "error on C stream"; } }; } #ifdef PLATFORM_WIN32 #include "io_win32.hpp" #else #include "io_posix.hpp" #endif