aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-06-17 11:07:21 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-06-17 11:07:21 +0200
commita8fc877aa93bb9c2dcc9ccde372a943dcfd25cfb (patch)
treed8aba766721b486b17f2d9378516784a977d4418
parenteac6ad21038ccfb1edd33612f33539bd0bb45b2a (diff)
Implement ifdstream, file descriptor input stream
This is a portable replacement for GNU <ext/stdio_filebuf>.
-rw-r--r--butl/buildfile2
-rw-r--r--butl/dummy.cxx0
-rw-r--r--butl/fdstream86
-rw-r--r--butl/fdstream.cxx71
4 files changed, 158 insertions, 1 deletions
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
--- a/butl/dummy.cxx
+++ /dev/null
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 <istream>
+
+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<char>
+ {
+ 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<char>::int_type;
+ using traits_type = std::basic_streambuf<char>::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 <butl/fdstream>
+
+#ifndef _WIN32
+# include <unistd.h> // close, read
+#else
+# include <io.h> // _close, _read
+#endif
+
+#include <system_error>
+
+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<streamsize> (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;
+ }
+}