|
Sierra Toolkit
Version of the Day
|
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_classic { 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_classic::basic_indent_streambuf<char> indent_streambuf; 00385 00386 } // namespace stk_classic 00387 00388 #endif // STK_UTIL_UTIL_INDENTSTREAMBUF_HPP