From a8fc877aa93bb9c2dcc9ccde372a943dcfd25cfb Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 17 Jun 2015 11:07:21 +0200 Subject: Implement ifdstream, file descriptor input stream This is a portable replacement for GNU . --- butl/buildfile | 2 +- butl/dummy.cxx | 0 butl/fdstream | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ butl/fdstream.cxx | 71 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 1 deletion(-) delete mode 100644 butl/dummy.cxx create mode 100644 butl/fdstream create mode 100644 butl/fdstream.cxx diff --git a/butl/buildfile b/butl/buildfile index 5ccc75a..76629d5 100644 --- a/butl/buildfile +++ b/butl/buildfile @@ -2,5 +2,5 @@ # copyright : Copyright (c) 2014-2015 Code Synthesis Ltd # license : MIT; see accompanying LICENSE file -lib{butl}: cxx{dummy} +lib{butl}: cxx{fdstream} lib{butl}: cxx.export.poptions = -I$src_root diff --git a/butl/dummy.cxx b/butl/dummy.cxx deleted file mode 100644 index e69de29..0000000 diff --git a/butl/fdstream b/butl/fdstream new file mode 100644 index 0000000..01a19b7 --- /dev/null +++ b/butl/fdstream @@ -0,0 +1,86 @@ +// file : butl/fdstream -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BUTL_FDSTREAM +#define BUTL_FDSTREAM + +#include + +namespace butl +{ + // An input stream that is initialized with a file descriptor + // rather than a file name. + // + // Notes and limitations: + // + // - char only + // - input only + // - no support for put back + // - throws std::system_error in case of a read() 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) {close (); fd_ = fd; setg (buf_, buf_, buf_);} + + bool + is_open () const {return fd_ != -1;} + + // basic_streambuf input interface. + // + public: + using int_type = std::basic_streambuf::int_type; + using traits_type = std::basic_streambuf::traits_type; + + virtual std::streamsize + showmanyc (); + + virtual int_type + underflow (); + + private: + bool + load (); + + private: + int fd_ = -1; + char buf_[2048]; + }; + + class ifdstream_base + { + protected: + ifdstream_base () = default; + ifdstream_base (int fd): buf_ (fd) {} + + protected: + fdbuf buf_; + }; + + class ifdstream: ifdstream_base, public std::istream + { + public: + ifdstream (): std::istream (&buf_) {} + ifdstream (int fd): ifdstream_base (fd), std::istream (&buf_) {} + + void close () {buf_.close ();} + void open (int fd) {buf_.open (fd);} + bool is_open () const {return buf_.is_open ();} + }; +} + +#endif // BUTL_FDSTREAM diff --git a/butl/fdstream.cxx b/butl/fdstream.cxx new file mode 100644 index 0000000..6d7532a --- /dev/null +++ b/butl/fdstream.cxx @@ -0,0 +1,71 @@ +// file : butl/fdstream.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#ifndef _WIN32 +# include // close, read +#else +# include // _close, _read +#endif + +#include + +using namespace std; + +namespace butl +{ + fdbuf:: + ~fdbuf () {close ();} + + void fdbuf:: + close () + { + if (fd_ != -1) + { +#ifndef _WIN32 + ::close (fd_); +#else + _close (fd_); +#endif + fd_ = -1; + } + } + + streamsize fdbuf:: + showmanyc () + { + return is_open () ? static_cast (egptr () - gptr ()) : -1; + } + + fdbuf::int_type fdbuf:: + underflow () + { + int_type r = traits_type::eof (); + + if (is_open ()) + { + if (gptr () < egptr () || load ()) + r = traits_type::to_int_type (*gptr ()); + } + + return r; + } + + bool fdbuf:: + load () + { +#ifndef _WIN32 + ssize_t n (::read (fd_, buf_, sizeof (buf_))); +#else + int n (_read (fd_, buf_, sizeof (buf_))); +#endif + + if (n == -1) + throw system_error (errno, system_category ()); + + setg (buf_, buf_, buf_ + n); + return n != 0; + } +} -- cgit v1.1