// file : butl/fdstream -*- C++ -*- // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef BUTL_FDSTREAM #define BUTL_FDSTREAM #include #include #include // uint16_t #include #include // permissions namespace butl { // An iostream that is initialized with a file descriptor rather than // a file name. // // Notes and limitations: // // - char only // - input or output but not both // - no support for put back // - throws std::system_error in case of a read()/write() error // - not movable, though can be easily supported // class fdbuf: public std::basic_streambuf { public: virtual ~fdbuf (); fdbuf () = default; fdbuf (int fd) {open (fd);} fdbuf (const fdbuf&) = delete; fdbuf& operator= (const fdbuf&) = delete; void close (); void open (int fd); bool is_open () const {return fd_ != -1;} public: using int_type = std::basic_streambuf::int_type; using traits_type = std::basic_streambuf::traits_type; // basic_streambuf input interface. // public: virtual std::streamsize showmanyc (); virtual int_type underflow (); private: bool load (); // basic_streambuf output interface. // public: virtual int_type overflow (int_type); virtual int sync (); private: bool save (); private: int fd_ = -1; char buf_[4096]; }; // File descriptor translation mode. It has the same semantics as the // binary/text opening modes in std::fstream. Specifically, this is a // noop for POSIX systems where the two modes are the same. // enum class fdtranslate { text, binary }; class fdstream_base { protected: fdstream_base () = default; fdstream_base (int fd): buf_ (fd) {} fdstream_base (int, fdtranslate); protected: fdbuf buf_; }; // Note that the destructor may throw. // class ifdstream: fdstream_base, public std::istream { public: ifdstream (): std::istream (&buf_) {} ifdstream (int fd): fdstream_base (fd), std::istream (&buf_) {} ifdstream (int fd, fdtranslate m) : fdstream_base (fd, m), std::istream (&buf_) {} void close () {buf_.close ();} void open (int fd) {buf_.open (fd);} bool is_open () const {return buf_.is_open ();} }; // Note that the destructor flushes the stream and may throw. // class ofdstream: fdstream_base, public std::ostream { public: ofdstream (): std::ostream (&buf_) {} ofdstream (int fd): fdstream_base (fd), std::ostream (&buf_) {} ofdstream (int fd, fdtranslate m) : fdstream_base (fd, m), std::ostream (&buf_) {} ~ofdstream () override {if (is_open () && good ()) buf_.sync ();} void close () {flush (); buf_.close ();} void open (int fd) {buf_.open (fd);} bool is_open () const {return buf_.is_open ();} }; // File open flags. // enum class fdopen_mode: std::uint16_t { in = 0x01, // Open for reading. out = 0x02, // Open for writing. append = 0x04, // Seek to the end of file before each write. truncate = 0x08, // Discard the file contents on open. create = 0x10, // Create a file if not exists. exclusive = 0x20, // Fail if the file exists and the create flag is set. binary = 0x40, // Set binary translation mode. none = 0 // Usefull when build the mode incrementally. }; fdopen_mode operator& (fdopen_mode, fdopen_mode); fdopen_mode operator| (fdopen_mode, fdopen_mode); fdopen_mode operator&= (fdopen_mode&, fdopen_mode); fdopen_mode operator|= (fdopen_mode&, fdopen_mode); // Open a file returning the file descriptor on success and throwing // std::system_error otherwise. // // The mode argument should have at least one of the in or out flags set. // The append and truncate flags are meaningless in the absense of the out // flag and are ignored without it. The exclusive flag is meaningless in the // absense of the create flag and is ignored without it. Note also that if // the exclusive flag is specified then a dangling symbolic link is treated // as an existing file. // // The permissions argument is taken into account only if the file is // created. Note also that permissions can be adjusted while being set in a // way specific for the OS. On POSIX systems they are modified with the // process' umask, so effective permissions are permissions & ~umask. On // Windows permissions other than ru and wu are unlikelly to have effect. // int fdopen (const path&, fdopen_mode, permissions = permissions::ru | permissions::wu | permissions::rg | permissions::wg | permissions::ro | permissions::wo); // Set the translation mode for the file descriptor. Return the previous // mode on success, throw std::system_error otherwise. // fdtranslate fdmode (int, fdtranslate); // Convenience functions for setting the translation mode for standard // streams. // fdtranslate stdin_fdmode (fdtranslate); fdtranslate stdout_fdmode (fdtranslate); fdtranslate stderr_fdmode (fdtranslate); // Low-level, nothrow file descriptor API. // // Close the file descriptor. Return true on success, set errno and return // false otherwise. // bool fdclose (int) noexcept; // Open the null device (e.g., /dev/null) that discards all data written to // it and provides no data for read operations (i.e., yelds EOF on read). // Return file descriptor on success, set errno and return -1 otherwise. // Note that it's the caller's responsibility to close the returned file // descriptor. // int fdnull () noexcept; } #include #endif // BUTL_FDSTREAM