aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--butl/fdstream50
-rw-r--r--butl/fdstream.cxx68
2 files changed, 102 insertions, 16 deletions
diff --git a/butl/fdstream b/butl/fdstream
index 01a19b7..2814d4b 100644
--- a/butl/fdstream
+++ b/butl/fdstream
@@ -6,18 +6,19 @@
#define BUTL_FDSTREAM
#include <istream>
+#include <ostream>
namespace butl
{
- // An input stream that is initialized with a file descriptor
- // rather than a file name.
+ // An iostream that is initialized with a file descriptor rather than
+ // a file name.
//
// Notes and limitations:
//
// - char only
- // - input only
+ // - input or output but not both
// - no support for put back
- // - throws std::system_error in case of a read() error
+ // - throws std::system_error in case of a read()/write() error
// - not movable, though can be easily supported
//
class fdbuf: public std::basic_streambuf<char>
@@ -35,17 +36,18 @@ namespace butl
close ();
void
- open (int fd) {close (); fd_ = fd; setg (buf_, buf_, buf_);}
+ open (int fd);
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;
+ // basic_streambuf input interface.
+ //
+ public:
virtual std::streamsize
showmanyc ();
@@ -56,26 +58,50 @@ namespace butl
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_[2048];
};
- class ifdstream_base
+ class fdstream_base
{
protected:
- ifdstream_base () = default;
- ifdstream_base (int fd): buf_ (fd) {}
+ fdstream_base () = default;
+ fdstream_base (int fd): buf_ (fd) {}
protected:
fdbuf buf_;
};
- class ifdstream: ifdstream_base, public std::istream
+ class ifdstream: fdstream_base, public std::istream
{
public:
ifdstream (): std::istream (&buf_) {}
- ifdstream (int fd): ifdstream_base (fd), std::istream (&buf_) {}
+ ifdstream (int fd): fdstream_base (fd), std::istream (&buf_) {}
+
+ void close () {buf_.close ();}
+ void open (int fd) {buf_.open (fd);}
+ bool is_open () const {return buf_.is_open ();}
+ };
+
+ class ofdstream: fdstream_base, public std::ostream
+ {
+ public:
+ ofdstream (): std::ostream (&buf_) {}
+ ofdstream (int fd): fdstream_base (fd), std::ostream (&buf_) {}
void close () {buf_.close ();}
void open (int fd) {buf_.open (fd);}
diff --git a/butl/fdstream.cxx b/butl/fdstream.cxx
index 6d7532a..0386f49 100644
--- a/butl/fdstream.cxx
+++ b/butl/fdstream.cxx
@@ -5,9 +5,9 @@
#include <butl/fdstream>
#ifndef _WIN32
-# include <unistd.h> // close, read
+# include <unistd.h> // close(), read(), write()
#else
-# include <io.h> // _close, _read
+# include <io.h> // _close(), _read(), _write()
#endif
#include <system_error>
@@ -20,9 +20,18 @@ namespace butl
~fdbuf () {close ();}
void fdbuf::
+ open (int fd)
+ {
+ close ();
+ fd_ = fd;
+ setg (buf_, buf_, buf_);
+ setp (buf_, buf_ + sizeof (buf_) - 1); // Keep space for overflow's char.
+ }
+
+ void fdbuf::
close ()
{
- if (fd_ != -1)
+ if (is_open ())
{
#ifndef _WIN32
::close (fd_);
@@ -42,7 +51,7 @@ namespace butl
fdbuf::int_type fdbuf::
underflow ()
{
- int_type r = traits_type::eof ();
+ int_type r (traits_type::eof ());
if (is_open ())
{
@@ -68,4 +77,55 @@ namespace butl
setg (buf_, buf_, buf_ + n);
return n != 0;
}
+
+ fdbuf::int_type fdbuf::
+ overflow (int_type c)
+ {
+ int_type r (traits_type::eof ());
+
+ if (is_open () && c != traits_type::eof ())
+ {
+ // Store last character in the space we reserved in open(). Note
+ // that pbump() doesn't do any checks.
+ //
+ *pptr () = traits_type::to_char_type (c);
+ pbump (1);
+
+ if (save ())
+ r = c;
+ }
+
+ return r;
+ }
+
+ int fdbuf::
+ sync ()
+ {
+ return is_open () && save () ? 0 : -1;
+ }
+
+ bool fdbuf::
+ save ()
+ {
+ size_t n (pptr () - pbase ());
+
+ if (n != 0)
+ {
+#ifndef _WIN32
+ ssize_t m (::write (fd_, buf_, n));
+#else
+ int m (_write (fd_, buf_, static_cast<unsigned int> (sizeof (buf_))));
+#endif
+
+ if (m == -1)
+ throw system_error (errno, system_category ());
+
+ if (n != static_cast<size_t> (m))
+ return false;
+
+ setp (buf_, buf_ + sizeof (buf_) - 1);
+ }
+
+ return true;
+ }
}