9 #ifndef STK_UTIL_UTIL_INDENTSTREAMBUF_HPP
10 #define STK_UTIL_UTIL_INDENTSTREAMBUF_HPP
17 static const char PUSH =
'\016';
18 static const char POP =
'\017';
19 static const char LEFT =
'\021';
39 template<
class Ch,
class Tr = std::
char_traits<Ch> >
69 : m_streamBuffer(stream_buffer),
74 m_indentSize(indent_size),
75 m_flags((
Flags) flags),
86 delete[] m_indentString;
93 void redirect(std::basic_streambuf<Ch, Tr> *stream_buffer) {
94 m_streamBuffer = stream_buffer;
105 return m_streamBuffer;
117 m_indentSize = indent_size;
119 delete[] m_indentString;
121 std::fill(m_indentString, m_indentString +
MAX_INDENT_LEVEL*m_indentSize, static_cast<Ch>(
' '));
132 m_flags = (
Flags) flags;
142 size_t indent_level() {
143 return std::min(m_indentLevel*m_indentSize, (
size_t)
MAX_INDENT_LEVEL*m_indentSize);
154 m_streamBuffer->sputn(m_indentString, indent_level());
155 m_leftJustify =
false;
156 m_atLineBegin =
false;
165 if (m_nextIndentLevel > m_indentLevel) {
167 m_streamBuffer->sputn(
" {", 2);
168 m_streamBuffer->sputc(Tr::to_int_type(
'\n'));
170 else if (m_nextIndentLevel < m_indentLevel) {
171 m_indentLevel = m_nextIndentLevel;
173 m_streamBuffer->sputc(Tr::to_int_type(
'\n'));
175 m_streamBuffer->sputn(m_indentString, indent_level());
176 m_streamBuffer->sputc(Tr::to_int_type(
'}'));
177 m_streamBuffer->sputc(Tr::to_int_type(
'\n'));
180 else if (!m_atLineBegin || (m_flags &
BLANK_LINES))
181 m_streamBuffer->sputc(Tr::to_int_type(
'\n'));
183 m_indentLevel = m_nextIndentLevel;
184 m_atLineBegin =
true;
197 virtual typename std::basic_streambuf<Ch, Tr>::int_type
overflow(
typename std::basic_streambuf<Ch, Tr>::int_type c) {
198 if (c == Tr::to_int_type(
'\n'))
200 else if (c == Tr::to_int_type(
POP)) {
201 if (m_nextIndentLevel != m_indentLevel)
203 if (m_indentLevel > 0)
204 m_nextIndentLevel = m_indentLevel - 1;
206 else if (c == Tr::to_int_type(
PUSH)) {
207 if (m_nextIndentLevel != m_indentLevel)
209 m_nextIndentLevel = m_indentLevel + 1;
211 else if (c == Tr::to_int_type(
LEFT)) {
212 m_leftJustify =
true;
216 m_streamBuffer->sputc(c);
235 virtual std::streamsize
xsputn(
const Ch *p, std::streamsize n) {
236 const Ch *p_end = p + n;
237 for (
const Ch *q = p; q != p_end; ++q) {
240 if (p == q && m_atLineBegin) {
241 if (Tr::to_int_type(*p) == Tr::to_int_type(
'\n')) {
245 else if (Tr::to_int_type(*p) == Tr::to_int_type(
POP)) {
247 if (m_nextIndentLevel != m_indentLevel)
249 if (m_indentLevel > 0)
250 m_nextIndentLevel = m_indentLevel - 1;
252 else if (Tr::to_int_type(*p) == Tr::to_int_type(
PUSH)) {
254 if (m_nextIndentLevel != m_indentLevel)
256 m_nextIndentLevel = m_indentLevel + 1;
258 else if (Tr::to_int_type(*p) == Tr::to_int_type(
LEFT)) {
260 m_leftJustify =
true;
266 if (Tr::to_int_type(*q) == Tr::to_int_type(
'\n')) {
268 m_streamBuffer->sputn(p, q - p);
272 else if (Tr::to_int_type(*q) == Tr::to_int_type(
POP)) {
274 m_streamBuffer->sputn(p, q - p);
276 if (m_nextIndentLevel != m_indentLevel)
278 if (m_indentLevel > 0)
279 m_nextIndentLevel = m_indentLevel - 1;
281 else if (Tr::to_int_type(*q) == Tr::to_int_type(
PUSH)) {
283 m_streamBuffer->sputn(p, q - p);
285 if (m_nextIndentLevel != m_indentLevel)
287 m_nextIndentLevel = m_indentLevel + 1;
289 else if (Tr::to_int_type(*q) == Tr::to_int_type(
LEFT)) {
290 m_leftJustify =
true;
297 m_streamBuffer->sputn(p, p_end - p);
298 m_atLineBegin =
false;
310 return m_streamBuffer->pubsync();
318 std::streambuf * m_streamBuffer;
321 size_t m_indentLevel;
322 size_t m_nextIndentLevel;
328 template<
class Ch,
class Tr>
329 std::basic_ostream<Ch, Tr> &push(std::basic_ostream<Ch, Tr> &os) {
336 template<
class Ch,
class Tr>
337 std::basic_ostream<Ch, Tr> &pop(std::basic_ostream<Ch, Tr> &os) {
345 template<
class Ch,
class Tr>
346 class indent_streambuf_throwsafe
348 explicit indent_streambuf_throwsafe(basic_indent_streambuf<Ch, Tr> &sb)
349 : m_indentStreambuf(sb),
350 m_indentLevel(sb.indent_level())
353 ~indent_streambuf_throwsafe() {
354 while (m_indentStreambuf.indent_level() > m_indentLevel)
355 m_indentStreambuf.pop();
359 basic_indent_streambuf<Ch, Tr> & m_indentStreambuf;
360 size_t m_indentLevel;
368 inline IndentFlags indent_flags(
int flags) {
374 template<
class Ch,
class Tr>
375 std::basic_ostream<Ch, Tr> &
376 operator<<(std::basic_ostream<Ch, Tr> &os, IndentFlags indent_flags) {
377 basic_indent_streambuf<Ch, Tr> *osb =
dynamic_cast<basic_indent_streambuf<Ch, Tr> *
>(os.rdbuf());
379 osb->set_flags(indent_flags.m_flags);
388 #endif // STK_UTIL_UTIL_INDENTSTREAMBUF_HPP