diff options
Diffstat (limited to 'libbutl/fdstream.hxx')
-rw-r--r-- | libbutl/fdstream.hxx | 84 |
1 files changed, 80 insertions, 4 deletions
diff --git a/libbutl/fdstream.hxx b/libbutl/fdstream.hxx index 4dc89a3..9c8f786 100644 --- a/libbutl/fdstream.hxx +++ b/libbutl/fdstream.hxx @@ -137,6 +137,11 @@ namespace butl class LIBBUTL_SYMEXPORT fdstreambuf: public bufstreambuf { public: + // Reasonable (for stack allocation) buffer size that provides decent + // performance. + // + static const std::size_t buffer_size = 8192; + fdstreambuf () = default; // Unless specified, the current read/write position is assumed to @@ -174,6 +179,9 @@ namespace butl bool blocking (bool); + bool + blocking () const {return !non_blocking_;} + public: using base = bufstreambuf; @@ -238,7 +246,7 @@ namespace butl private: auto_fd fd_; - char buf_[8192]; + char buf_[buffer_size]; bool non_blocking_ = false; }; @@ -271,7 +279,9 @@ namespace butl binary = 0x02, skip = 0x04, blocking = 0x08, - non_blocking = 0x10 + non_blocking = 0x10, + + none = 0 }; inline fdstream_mode operator& (fdstream_mode, fdstream_mode); @@ -311,6 +321,9 @@ namespace butl int fd () const {return buf_.fd ();} + bool + blocking () const {return buf_.blocking ();} + protected: fdstreambuf buf_; }; @@ -641,6 +654,54 @@ namespace butl LIBBUTL_SYMEXPORT ifdstream& getline (ifdstream&, std::string&, char delim = '\n'); + // The non-blocking getline() version that reads the line in potentially + // multiple calls. Key differences compared to getline(): + // + // - Stream must be in the non-blocking mode and exception mask must have + // at least badbit. + // + // - Return type is bool instead of stream. Return true if the line has been + // read or false if it should be called again once the stream has more + // data to read. Also return true on failure. + // + // - The string must be empty on the first call. + // + // - There could still be data to read in the stream's buffer (as opposed to + // file descriptor) after this function returns true and you should be + // careful not to block on fdselect() in this case. In fact, the + // recommended pattern is to call this function first and only call + // fdselect() if it returns false. + // + // The typical usage in combination with the eof() helper: + // + // fdselect_set fds {is.fd (), ...}; + // fdselect_state& ist (fds[0]); + // fdselect_state& ...; + // + // for (string l; ist.fd != nullfd || ...; ) + // { + // if (ist.fd != nullfd && getline_non_blocking (is, l)) + // { + // if (eof (is)) + // ist.fd = nullfd; + // else + // { + // // Consume line. + // + // l.clear (); + // } + // + // continue; + // } + // + // ifdselect (fds); + // + // // Handle other ready fds. + // } + // + LIBBUTL_SYMEXPORT bool + getline_non_blocking (ifdstream&, std::string&, char delim = '\n'); + // Open a file returning an auto_fd that holds its file descriptor on // success and throwing ios::failure otherwise. // @@ -840,6 +901,14 @@ namespace butl LIBBUTL_SYMEXPORT bool fdterm (int); + // Test whether a terminal file descriptor supports ANSI color output. If + // the enable argument is true, then also try to enable color output (only + // applicable on some platforms, such as Windows). Throw ios::failure on the + // underlying OS error. + // + LIBBUTL_SYMEXPORT bool + fdterm_color (int, bool enable); + // Wait until one or more file descriptors becomes ready for input (reading) // or output (writing). Return the pair of numbers of descriptors that are // ready. Throw std::invalid_argument if anything is wrong with arguments @@ -847,7 +916,7 @@ namespace butl // underlying OS error. // // Note that the function clears all the previously-ready entries on each - // call. Entries with nullfd are ignored. + // call. Entries with nullfd are ignored (but cleared). // // On Windows only pipes and only their input (read) ends are supported. // @@ -855,11 +924,13 @@ namespace butl { int fd; bool ready; + void* data; // Arbitrary data which can be associated with the descriptor. // Note: intentionally non-explicit to allow implicit initialization when // pushing to fdselect_set. // - fdselect_state (int fd): fd (fd), ready (false) {} + fdselect_state (int fd, void* d = nullptr) + : fd (fd), ready (false), data (d) {} }; using fdselect_set = small_vector<fdselect_state, 4>; @@ -912,6 +983,11 @@ namespace butl // LIBBUTL_SYMEXPORT std::streamsize fdread (int, void*, std::size_t); + + // POSIX write() function wrapper, for uniformity. + // + LIBBUTL_SYMEXPORT std::streamsize + fdwrite (int, const void*, std::size_t); } #include <libbutl/fdstream.ixx> |