/************************************************************************ * * rw_streambuf.h - definition of the MyStreambuf class template * * $Id: rw_streambuf.h 590052 2007-10-30 12:44:14Z faridz $ * *************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Copyright 2004-2006 Rogue Wave Software. * **************************************************************************/ #ifndef RW_STREAMBUF_H_INCLUDED #define RW_STREAMBUF_H_INCLUDED #include // for memset() #include // for basic_streambuf #include #include // for make_char() #include // for rw_throw() enum MemFun { // bitmask with a bit for each virtual member function None = 0, Setbuf = 0x0001, Seekoff = 0x0002, Seekpos = 0x0004, Showmanyc = 0x0008, Xsgetn = 0x0010, Underflow = 0x0020, Uflow = 0x0040, Overflow = 0x0080, Pbackfail = 0x0100, Xsputn = 0x0200, Sync = 0x0400, // bit OR-ed with MemFun bits Throw = 0x1000, Failure = 0x2000 }; static const char* const streambuf_func_names[] = { "setbuf", "seekoff", "seekpos", "showmanyc", "xsgetn", "underflow", "uflow", "overflow", "pbackfail", "xsputn", "sync" }; template struct MyStreambuf: std::basic_streambuf { typedef charT char_type; typedef Traits traits_type; typedef std::basic_streambuf Base; typedef typename Base::int_type int_type; typedef typename Base::off_type off_type; typedef typename Base::pos_type pos_type; MyStreambuf (std::streamsize, int, int); MyStreambuf (const char*, std::streamsize, int, int); ~MyStreambuf () { delete[] buf_; } // public interface to base class protected members char_type* pubeback () const { return this->eback (); } char_type* pubgptr () const { return this->gptr (); } char_type* pubegptr () const { return this->egptr (); } char_type* pubpbase () const { return this->pbase (); } char_type* pubpptr () const { return this->pptr (); } char_type* pubepptr () const { return this->epptr (); } void pubsetg (charT *beg, charT *cur, charT *end) { this->setg (beg, cur, end); } void pubsetp (charT *beg, charT *cur, charT *end) { this->setp (beg, end); this->pbump (cur - beg); } private: // overridden protected virtual functions virtual Base* setbuf (char_type*, std::streamsize) { return test (Setbuf) ? this : 0; } virtual pos_type seekoff (off_type, std::ios_base::seekdir, std::ios_base::openmode) { test (Seekoff); return pos_type (off_type (-1)); } virtual pos_type seekpos (pos_type, std::ios_base::openmode) { test (Seekpos); return pos_type (off_type (-1)); } virtual std::streamsize showmanyc () { test (Showmanyc); return 0; } virtual std::streamsize xsgetn (char_type*, std::streamsize) { test (Xsgetn); return 0; } virtual int_type underflow (); virtual int_type uflow (); virtual int_type overflow (int_type = traits_type::eof ()); virtual int_type pbackfail (int_type = traits_type::eof ()); virtual std::streamsize xsputn (const char_type *buf, std::streamsize bufsize) { if (!test (Xsputn)) return 0; return Base::xsputn (buf, bufsize); } virtual int sync () { test (Sync); return 0; } public: int ncalls (MemFun) const; int memfun_inx (MemFun) const; char_type *buf_; std::streamsize bufsize_; int throw_set_; // functions that should throw int fail_set_; // functions that should fail MemFun threw_; // which function threw MemFun failed_; // which function failed int fail_when_; // call number on which to fail int throw_when_ [11]; // call number on which to throw for each func int allthrows_; // total number of thrown exceptions // max size of the pending input sequence static std::streamsize in_pending_; // max size of the pending output sequence static std::streamsize out_pending_; private: bool test (MemFun) const; int ncalls_ [11]; // number of calls made to each function int allcalls_; // total number of calls }; template std::streamsize MyStreambuf:: in_pending_ = 1; template std::streamsize MyStreambuf:: out_pending_ = 1; template MyStreambuf:: MyStreambuf (std::streamsize bufsize, int fail_set, int when) : Base (), buf_ (0), bufsize_ (bufsize), throw_set_ (0), fail_set_ (0), threw_ (None), failed_ (None), fail_when_ (when), allthrows_ (0), allcalls_ (0) { // reset the member function call counters std::memset (ncalls_, 0, sizeof ncalls_); // reset the member function throw counters std::memset (throw_when_, 0, sizeof throw_when_); // allocate a (possibly wide) character buffer for output buf_ = new charT [bufsize_]; // invalidate the contents of the buffer traits_type::assign (buf_, bufsize_, make_char ('\xfe', buf_)); // set the put area to 0 size to force a call to overflow() // on the first write attempt to the buffer this->setp (buf_, buf_); // set the fail and throw flags if (fail_set & Throw) { throw_set_ = fail_set & ~Throw; for (unsigned i = 0; i < 11; ++i) if (throw_set_ & (1U << i)) throw_when_ [i] = when; } else { fail_set_ = fail_set; } } template MyStreambuf:: MyStreambuf (const char *buf, std::streamsize bufsize, int fail_set, int when) : Base (), buf_ (0), bufsize_ (bufsize), throw_set_ (0), fail_set_ (0), threw_ (None), failed_ (None), fail_when_ (when), allthrows_ (0), allcalls_ (0) { // reset the member function call counters std::memset (ncalls_, 0, sizeof ncalls_); // reset the member function throw counters std::memset (throw_when_, 0, sizeof throw_when_); // as a convenience, if `bufsize == -1' compute the size // from the length of `buf' if (std::streamsize (-1) == bufsize_) bufsize_ = std::streamsize (std::char_traits::length (buf)) + 1; // allocate a (possibly wide) character buffer to copy // (and widen) the contents of `buf' into buf_ = new charT [bufsize_ + 1]; for (std::streamsize inx = 0; inx != bufsize_; ++inx) { typedef unsigned char UChar; buf_ [inx] = make_char (buf [inx], buf_); } // zero out the (non-dereferenceable) element just past the end // so that the buffer can be printed out as an ordinary string buf_ [bufsize_] = charT (); // set the get area to 0 size to force a call to underflow() // on the first read attempt from the buffer this->setg (buf_, buf_, buf_); // set the fail and throw flags if (fail_set & Throw) { throw_set_ = fail_set & ~Throw; for (unsigned i = 0; i < 11; ++i) if (throw_set_ & (1U << i)) throw_when_ [i] = when; } else { fail_set_ = fail_set; } } template typename MyStreambuf::int_type MyStreambuf:: underflow () { if (!test (Underflow)) return traits_type::eof (); if (this->egptr () - this->gptr () > 0) { this->gbump (1); return traits_type::to_int_type (*this->gptr ()); } if (this->egptr () < buf_ + bufsize_) { // increase the pending input sequence by no more than // the lesser of the available buffer space and `in_pending_' std::streamsize pending = buf_ + bufsize_ - this->egptr (); if (pending > in_pending_) pending = in_pending_; this->setg (this->eback (), this->gptr (), this->egptr () + pending); return traits_type::to_int_type (*this->gptr ()); } failed_ = Underflow; return traits_type::eof (); } template typename MyStreambuf::int_type MyStreambuf:: overflow (int_type c /* = traits_type::eof () */) { if (!test (Overflow)) return traits_type::eof (); if (this->epptr () - this->pptr () > 0) { traits_type::assign (*this->pptr (), traits_type::to_char_type (c)); this->pbump (1); return traits_type::not_eof (c); } if (this->epptr () < buf_ + bufsize_) { // increase the pending output sequence by no more than // the lesser of the available buffer space and `out_pending_' std::streamsize pending = buf_ + bufsize_ - this->epptr (); if (pending > out_pending_) pending = out_pending_; const std::streamsize pptr_off = this->pptr () - this->pbase (); this->setp (this->pbase (), this->epptr () + pending); this->pbump (pptr_off); traits_type::assign (*this->pptr (), traits_type::to_char_type (c)); this->pbump (1); return traits_type::not_eof (c); } failed_ = Overflow; return traits_type::eof (); } template typename MyStreambuf::int_type MyStreambuf:: pbackfail (int_type c /* = traits_type::eof () */) { if (!test (Pbackfail)) return traits_type::eof (); if (this->gptr () == buf_) { failed_ = Pbackfail; return traits_type::eof (); } this->setg (this->gptr () - 1, this->gptr () - 1, this->gptr ()); const int_type last = traits_type::to_int_type (*this->gptr ()); if (!traits_type::eq_int_type (c, traits_type::eof ())) traits_type::assign (*this->gptr (), traits_type::to_char_type (c)); return last; } template typename MyStreambuf::int_type MyStreambuf:: uflow () { if (!test (Uflow)) return traits_type::eof (); if (this->egptr () - this->gptr () > 0) { this->gbump (1); return traits_type::to_int_type (*this->gptr ()); } if (this->egptr () < buf_ + bufsize_) { // increase the pending input sequence by no more than // the lesser of the available buffer space and `in_pending_' std::streamsize pending = buf_ + bufsize_ - this->egptr (); if (pending > in_pending_) pending = in_pending_; this->setg (this->eback (), this->gptr (), this->egptr () + pending); return traits_type::to_int_type (*this->gptr ()); } failed_ = Uflow; return traits_type::eof (); } template int MyStreambuf:: memfun_inx (MemFun which) const { int inx = -1; for (unsigned i = 0; i < sizeof (which) * _RWSTD_CHAR_BIT; ++i) { if (which & (1U << i)) { if (inx < 0) inx = i; else return -1; } } return inx; } template int MyStreambuf:: ncalls (MemFun which) const { int inx = memfun_inx (which); if (0 <= inx) return ncalls_ [inx]; return -1; } template bool MyStreambuf:: test (MemFun which) const { MyStreambuf* const self = _RWSTD_CONST_CAST (MyStreambuf*, this); int inx = memfun_inx (which); if (-1 == inx) return true; // increment the counter tracking the number of calls made // to each member function; do so regardless of whether // an exception will be thrown below self->ncalls_ [inx] ++; self->allcalls_ ++; const int callno = self->ncalls_ [inx]; #ifndef _RWSTD_NO_EXCEPTIONS // if the call counter is equal to the `fail_when_' watermark // and `shich' is set in the `throw_set_' bitmask, throw an // exception with the value of the member id if (callno == throw_when_ [inx] && throw_set_ & which) { self->threw_ = which; self->allthrows_++; rw_throw (ex_stream, __FILE__, __LINE__, streambuf_func_names [inx], "%s", "test exception"); } #else // if defined (_RWSTD_NO_EXCEPTIONS) if (callno == throw_when_ [inx] && throw_set_ & which) { self->threw_ = which; return false; } #endif // _RWSTD_NO_EXCEPTIONS // ...otherwise check if the member should succeed or fail // and return true or false, respectively const bool success = !(fail_set_ & which) || callno != fail_when_; if (!success) self->failed_ = which; return success; } #endif // RW_STREAMBUF_H_INCLUDED