Sierra Toolkit Version of the Day
IndentStreambuf.hpp
00001 /*------------------------------------------------------------------------*/
00002 /*                 Copyright 2010 Sandia Corporation.                     */
00003 /*  Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive   */
00004 /*  license for use of this work by or on behalf of the U.S. Government.  */
00005 /*  Export of this program may require a license from the                 */
00006 /*  United States Government.                                             */
00007 /*------------------------------------------------------------------------*/
00008 
00009 #ifndef STK_UTIL_UTIL_INDENTSTREAMBUF_HPP
00010 #define STK_UTIL_UTIL_INDENTSTREAMBUF_HPP
00011 
00012 #include <streambuf>
00013 #include <utility>
00014 
00015 namespace stk {
00016 
00017 static const char PUSH = '\016';                                
00018 static const char POP = '\017';                                 
00019 static const char LEFT = '\021';                                
00020 
00039 template<class Ch, class Tr = std::char_traits<Ch> >
00040 class basic_indent_streambuf : public std::basic_streambuf<Ch, Tr>
00041 {
00042 public:
00043   enum {
00044     MAX_INDENT_LEVEL = 50                                       
00045   };
00046 
00051   enum Flags {
00052     NO_BRACES      = 0x00,                                      
00053     NO_BLANK_LINES = 0x00,                                      
00054     BRACES         = 0x01,                                      
00055     BLANK_LINES    = 0x02                                       
00056   };
00057 
00068   explicit basic_indent_streambuf(std::basic_streambuf<Ch, Tr> *stream_buffer, size_t indent_size = 2, unsigned flags = BRACES)
00069     : m_streamBuffer(stream_buffer),
00070       m_atLineBegin(true),
00071       m_leftJustify(false),
00072       m_indentLevel(0),
00073       m_nextIndentLevel(0),
00074       m_indentSize(indent_size),
00075       m_flags((Flags) flags),
00076       m_indentString(0)
00077   {
00078     set_indent_size(indent_size);
00079   }
00080 
00085   virtual ~basic_indent_streambuf() {
00086     delete[] m_indentString;
00087   }
00088 
00093   void redirect(std::basic_streambuf<Ch, Tr> *stream_buffer) {
00094     m_streamBuffer = stream_buffer;
00095   }
00096 
00104   std::streambuf *get_stream_buffer() {
00105     return m_streamBuffer;
00106   }
00107   
00116   void set_indent_size(size_t indent_size) {
00117     m_indentSize = indent_size;
00118 
00119     delete[] m_indentString;
00120     m_indentString = new Ch[MAX_INDENT_LEVEL*m_indentSize];
00121     std::fill(m_indentString, m_indentString + MAX_INDENT_LEVEL*m_indentSize, static_cast<Ch>(' '));
00122   }
00123 
00131   void set_flags(unsigned flags) {
00132     m_flags = (Flags) flags;
00133   }
00134 
00135 
00136 private:
00142   size_t indent_level() {
00143     return std::min(m_indentLevel*m_indentSize, (size_t) MAX_INDENT_LEVEL*m_indentSize);
00144   }
00145 
00151   void prefix() {
00152     if (m_atLineBegin) {
00153       if (!m_leftJustify)
00154         m_streamBuffer->sputn(m_indentString, indent_level());
00155       m_leftJustify = false;
00156       m_atLineBegin = false;
00157     }
00158   }
00159 
00164   void next_line() {
00165     if (m_nextIndentLevel > m_indentLevel) {
00166       if (m_flags & BRACES) 
00167   m_streamBuffer->sputn(" {", 2);
00168       m_streamBuffer->sputc(Tr::to_int_type('\n'));
00169     }
00170     else if (m_nextIndentLevel < m_indentLevel) {
00171       m_indentLevel = m_nextIndentLevel;
00172       if (!m_atLineBegin)
00173         m_streamBuffer->sputc(Tr::to_int_type('\n'));
00174       if (m_flags & BRACES) {
00175         m_streamBuffer->sputn(m_indentString, indent_level());
00176         m_streamBuffer->sputc(Tr::to_int_type('}'));
00177         m_streamBuffer->sputc(Tr::to_int_type('\n'));
00178       }
00179     }
00180     else if (!m_atLineBegin || (m_flags & BLANK_LINES))
00181       m_streamBuffer->sputc(Tr::to_int_type('\n'));
00182 
00183     m_indentLevel = m_nextIndentLevel;
00184     m_atLineBegin = true;
00185   }
00186 
00187 public:
00197   virtual typename std::basic_streambuf<Ch, Tr>::int_type overflow(typename std::basic_streambuf<Ch, Tr>::int_type c) {
00198     if (c == Tr::to_int_type('\n'))
00199       next_line();
00200     else if (c == Tr::to_int_type(POP)) {
00201       if (m_nextIndentLevel != m_indentLevel)
00202   next_line();
00203       if (m_indentLevel > 0)
00204   m_nextIndentLevel = m_indentLevel - 1;
00205     }
00206     else if (c == Tr::to_int_type(PUSH)) {
00207       if (m_nextIndentLevel != m_indentLevel)
00208   next_line();
00209       m_nextIndentLevel = m_indentLevel + 1;
00210     }
00211     else if (c == Tr::to_int_type(LEFT)) {
00212       m_leftJustify = true;
00213     }
00214     else {
00215       prefix();
00216       m_streamBuffer->sputc(c);
00217     }
00218 
00219     return c;
00220   }
00221 
00235   virtual std::streamsize xsputn(const Ch *p,  std::streamsize n) {
00236     const Ch *p_end = p + n;
00237     for (const Ch *q = p; q != p_end; ++q) {
00238 
00239 // If at start of line, PUSH and POP have immediate effect
00240       if (p == q && m_atLineBegin) {
00241   if (Tr::to_int_type(*p) == Tr::to_int_type('\n')) {
00242     next_line();
00243     ++p;
00244   }
00245   else if (Tr::to_int_type(*p) == Tr::to_int_type(POP)) {
00246     ++p;
00247     if (m_nextIndentLevel != m_indentLevel)
00248       next_line();
00249     if (m_indentLevel > 0)
00250       m_nextIndentLevel = m_indentLevel - 1;
00251   }
00252   else if (Tr::to_int_type(*p) == Tr::to_int_type(PUSH)) {
00253     ++p;
00254     if (m_nextIndentLevel != m_indentLevel)
00255       next_line();
00256     m_nextIndentLevel = m_indentLevel + 1;
00257   }
00258         else if (Tr::to_int_type(*p) == Tr::to_int_type(LEFT)) {
00259           ++p;
00260           m_leftJustify = true;
00261         }
00262       }
00263 
00264 // If not at start, PUSH and POP are for the next line.
00265       else {
00266   if (Tr::to_int_type(*q) == Tr::to_int_type('\n')) {
00267     prefix();
00268     m_streamBuffer->sputn(p, q - p);
00269     next_line();
00270     p = q + 1;
00271   }
00272   else if (Tr::to_int_type(*q) == Tr::to_int_type(POP)) {
00273     prefix();
00274     m_streamBuffer->sputn(p, q - p);
00275     p = q + 1;
00276     if (m_nextIndentLevel != m_indentLevel)
00277       next_line();
00278     if (m_indentLevel > 0)
00279       m_nextIndentLevel = m_indentLevel - 1;
00280   }
00281   else if (Tr::to_int_type(*q) == Tr::to_int_type(PUSH)) {
00282     prefix();
00283     m_streamBuffer->sputn(p, q - p);
00284     p = q + 1;
00285     if (m_nextIndentLevel != m_indentLevel)
00286       next_line();
00287     m_nextIndentLevel = m_indentLevel + 1;
00288   }
00289         else if (Tr::to_int_type(*q) == Tr::to_int_type(LEFT)) {
00290           m_leftJustify = true;
00291     p = q + 1;
00292         }
00293       }
00294     }
00295     if (p != p_end) {
00296       prefix();
00297       m_streamBuffer->sputn(p, p_end - p);
00298       m_atLineBegin = false;
00299     }
00300 
00301     return n;
00302   }
00303 
00309   virtual int sync() {
00310     return m_streamBuffer->pubsync();
00311   }
00312 
00313 private:
00314   basic_indent_streambuf(const basic_indent_streambuf &);
00315   basic_indent_streambuf &operator=(const basic_indent_streambuf &);
00316   
00317 private:
00318   std::streambuf *  m_streamBuffer;         
00319   bool      m_atLineBegin;          
00320   bool                  m_leftJustify;          
00321   size_t    m_indentLevel;          
00322   size_t    m_nextIndentLevel;      
00323   size_t    m_indentSize;           
00324   Flags     m_flags;                
00325   Ch *      m_indentString;         
00326 };
00327 
00328 template<class Ch, class Tr>
00329 std::basic_ostream<Ch, Tr> &push(std::basic_ostream<Ch, Tr> &os) {
00330   os.put(PUSH);
00331 //  os.put('\n');
00332   os.flush();
00333   return os;
00334 }
00335 
00336 template<class Ch, class Tr>
00337 std::basic_ostream<Ch, Tr> &pop(std::basic_ostream<Ch, Tr> &os) {
00338   os.put(POP);
00339 //  os.put('\n');
00340   os.flush();
00341   return os;
00342 }
00343 
00344 
00345 template<class Ch, class Tr>
00346 class indent_streambuf_throwsafe
00347 {
00348   explicit indent_streambuf_throwsafe(basic_indent_streambuf<Ch, Tr> &sb)
00349     : m_indentStreambuf(sb),
00350       m_indentLevel(sb.indent_level())
00351   {}
00352 
00353   ~indent_streambuf_throwsafe() {
00354     while (m_indentStreambuf.indent_level() > m_indentLevel)
00355       m_indentStreambuf.pop();
00356   }
00357 
00358 private:
00359   basic_indent_streambuf<Ch, Tr> &      m_indentStreambuf;
00360   size_t                                m_indentLevel;
00361 };
00362 
00363 
00364 struct IndentFlags {
00365   int           m_flags;
00366 };
00367 
00368 inline IndentFlags indent_flags(int flags) {
00369   IndentFlags f;
00370   f.m_flags = flags;
00371   return f;
00372 }
00373 
00374 template<class Ch, class Tr>
00375 std::basic_ostream<Ch, Tr> &
00376 operator<<(std::basic_ostream<Ch, Tr> &os, IndentFlags indent_flags) {
00377   basic_indent_streambuf<Ch, Tr> *osb = dynamic_cast<basic_indent_streambuf<Ch, Tr> *>(os.rdbuf());
00378   if (osb)
00379     osb->set_flags(indent_flags.m_flags);
00380       
00381   return os;
00382 }
00383 
00384 typedef stk::basic_indent_streambuf<char> indent_streambuf;
00385 
00386 } // namespace stk
00387 
00388 #endif //  STK_UTIL_UTIL_INDENTSTREAMBUF_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines