//---------------------------------------------------------------------------- // The constructor of the prfxbuf initializes its pointer to the streambuf // with the argument sb: It is assumed that this streambuf is initialized // correctly. In addition no ownership is assumed for this streambuf. It // is not deleted in the destructor. Then the length of the prefix string // is cached and the prefix string is copied into a private version: This // is done to avoid problems when the user modifies or deletes the string // passed as constructor argument. The member i_newline is set to indicate // that the processing it at the beginning of a new line: in either case // (reading or writing) it starts with a new line. When reading a file a // prefix has to be skipped and when writing a file a prefix has to be // added. EOF is used to indicate that the cache does not contain any // valid character. //
// In the body of the constructor the put area and the get area are // initialized to be empty: no buffering is done by this streambuf. All // buffering is deferred to the actually used streambuf. This makes sure // that the function overflow() is called whenever a character is written // to this streambuf and that the function underflow() is called whenever // a character is read from this streambuf. The put buffer is specified // using streambuf::setp() and the get buffer is specified using // streambuf::setg(). //
// 
// The destructor of prfxbuf has to release the copy of the prefix. //
// 
//---------------------------------------------------------------------------- //
// Please send comments, suggestions, problem reports, bug fixes etc. to //
// Dietmar Kühl: // Dietmar.Kuehl@claas-solutions.de #ifndef prfxbuf_H #define prfxbuf_H #include #include #include #include #include #include #include class prfxbuf: public std::streambuf { protected: std::streambuf *i_sbuf; // the actual streambuf used to read and write chars std::streamsize i_len; // the length of the prefix char *i_prfx; // the prefix bool i_newline; // remember whether we are at a new line int i_cache; // may cache a read character std::vector i_buf; bool skip_prefix () { if (i_sbuf->sgetn(&i_buf[0], i_len) != i_len) return false; if (std::strncmp(&i_buf[0], i_prfx, i_len)) { // an expection could be thrown here... return false; } i_newline = false; return true; } int overflow (int c) { if (c != EOF) { if (i_newline) { if (i_sbuf->sputn(i_prfx, i_len) != i_len) return EOF; else i_newline = false; } char cc = traits_type::to_char_type(c); int rc = i_sbuf->sputc(cc); if (cc == '\n') i_newline = true; return rc; } return 0; } int underflow () { if (i_cache == EOF) { if (i_newline) if (!skip_prefix()) return EOF; i_cache = i_sbuf->sbumpc(); if (i_cache == traits_type::to_int_type('\n')) i_newline = true; return i_cache; } else return i_cache; } int uflow () { if (i_cache == EOF) { if (i_newline) if (!skip_prefix()) return EOF; int rc = i_sbuf->sbumpc(); if (rc == traits_type::to_int_type('\n')) i_newline = true; return rc; } else { int rc = i_cache; i_cache = EOF; return rc; } } int sync () { return i_sbuf->pubsync(); } public: prfxbuf (std::streambuf *sb, const char *prfx): std::streambuf(), i_sbuf(sb), i_len(0), i_prfx(NULL), i_newline(true), i_cache(EOF), i_buf(1) { prefix(prfx); setp(0, 0); setg(0, 0, 0); } ~prfxbuf () { delete[] i_prfx; } void prefix (const char* prfx) { i_len = std::strlen(prfx); if (i_prfx) delete[] i_prfx; i_prfx = std::strcpy(new char[i_len + 1], prfx); i_buf.resize(i_len); } }; class iprfxstream: public std::istream { prfxbuf* b; public: iprfxstream (std::streambuf *sb, const char *prfx): std::istream(new prfxbuf(sb, prfx)), b((prfxbuf*)rdbuf()) { } ~iprfxstream () { delete rdbuf(); } void prefix (const char* prfx) { b->prefix(prfx); } }; class oprfxstream: public std::ostream { prfxbuf* b; public: oprfxstream (std::streambuf *sb, const char *prfx = ""): std::ostream(new prfxbuf(sb, prfx)), b((prfxbuf*)rdbuf()) { } ~oprfxstream () { delete rdbuf(); } void prefix (const char* prfx) { b->prefix(prfx); } }; #endif /* !prfxbuf_H */ #ifdef TEST_PRFXBUF #include #include int main () { std::ostream* debugStreamP = &std::cout; std::ostream** debugStream = &debugStreamP; oprfxstream coutstream((*debugStream)->rdbuf(), "Test prefix: "); std::ostream* debugStreamQ = &coutstream; std::ostream** oldDebugStream = debugStream; debugStream = &debugStreamQ; (**debugStream) << "This should have been prefixed.\nAlong with this."; coutstream.prefix("Prefix two: "); (**debugStream) << "\n" << 10 << std::endl; coutstream.prefix("Prefix three: "); (**debugStream) << "\n" << 3.14 << std::endl; debugStream = oldDebugStream; coutstream.flush(); std::stringstream ss; oprfxstream strstream(ss.rdbuf()); strstream.prefix("Test prefix: "); strstream << "This should have been prefixed.\nAlong with this."; strstream.prefix("Prefix two: "); strstream << "\n" << 10 << std::endl; strstream.prefix("Prefix three: "); strstream << "\n" << 3.14 << std::endl; std::cout << "begin [[" << std::endl; std::cout << ss.str(); std::cout << "]] end" << std::endl; return 0; } #endif /* TEST_PRFXBUF */