// $Id:$ #ifndef INDENT_HPP #define INDENT_HPP #include #include #include #include // a small helper class to get global variable // behaviour for the stream pword index // for header only implementation // the expression xdent()() will always get // the same unique index template struct xdent { int operator() (){ if (!initialized) { index = std::ios::xalloc(); initialized = true; } return index; } private: static T index; static bool initialized; }; template T xdent::index; template bool xdent::initialized; // The indent_filter. // The ctor is private, so the filter can only be // created from its static push function. // This is to assert registration to the stream. class indent_filter : public boost::iostreams::output_filter { public: template bool put(Sink& dest, int c) { if (c == '\n') linestart_ = true; else if (linestart_) { for(int n=0; n void close(Sink&) { indent_ = 0; linestart_ = true; } void indent_in() { ++indent_; } void indent_out() { if (indent_>0) --indent_; } // Of course it would be more elegant to // modify the filtering_ostream push // function instead, ... static void push(boost::iostreams::filtering_ostream& os, int width = 4) { os.push(indent_filter(width)); indent_filter* pi = os.component(os.size()-1); os.pword(xdent()()) = pi; pi->pos_ = &os; } // When the filter is destroyed, it must be deregistered. ~indent_filter() { if (pos_) pos_->pword(xdent()()) = 0; } private: explicit indent_filter(int width) : indent_(0) , linestart_(true) , width_(width) , pos_(0) { } int indent_; bool linestart_; int width_; std::ostream* pos_; }; // This are the manipulators that change indentation. // Note that this will even work when the filter_stream // is accessed through its basic_ostream. // Uniqueness of xdent()() guarantees correct cast // from void* to indent_filter* . template inline std::basic_ostream& indent_in(std::basic_ostream& os) { indent_filter*p = (indent_filter*)os.pword(xdent()()); if (p) { os.flush(); p->indent_in(); } return os; } template inline std::basic_ostream& indent_out(std::basic_ostream& os) { indent_filter*p = (indent_filter*)os.pword(xdent()()); if (p) { os.flush(); p->indent_out(); } return os; } #endif // INDENT