Sierra Toolkit  Version of the Day
IndentStreambuf.hpp
1 /*------------------------------------------------------------------------*/
2 /* Copyright 2010 Sandia Corporation. */
3 /* Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive */
4 /* license for use of this work by or on behalf of the U.S. Government. */
5 /* Export of this program may require a license from the */
6 /* United States Government. */
7 /*------------------------------------------------------------------------*/
8 
9 #ifndef STK_UTIL_UTIL_INDENTSTREAMBUF_HPP
10 #define STK_UTIL_UTIL_INDENTSTREAMBUF_HPP
11 
12 #include <streambuf>
13 #include <utility>
14 
15 namespace stk_classic {
16 
17 static const char PUSH = '\016';
18 static const char POP = '\017';
19 static const char LEFT = '\021';
20 
39 template<class Ch, class Tr = std::char_traits<Ch> >
40 class basic_indent_streambuf : public std::basic_streambuf<Ch, Tr>
41 {
42 public:
43  enum {
45  };
46 
51  enum Flags {
52  NO_BRACES = 0x00,
53  NO_BLANK_LINES = 0x00,
54  BRACES = 0x01,
55  BLANK_LINES = 0x02
56  };
57 
68  explicit basic_indent_streambuf(std::basic_streambuf<Ch, Tr> *stream_buffer, size_t indent_size = 2, unsigned flags = BRACES)
69  : m_streamBuffer(stream_buffer),
70  m_atLineBegin(true),
71  m_leftJustify(false),
72  m_indentLevel(0),
73  m_nextIndentLevel(0),
74  m_indentSize(indent_size),
75  m_flags((Flags) flags),
76  m_indentString(0)
77  {
78  set_indent_size(indent_size);
79  }
80 
86  delete[] m_indentString;
87  }
88 
93  void redirect(std::basic_streambuf<Ch, Tr> *stream_buffer) {
94  m_streamBuffer = stream_buffer;
95  }
96 
104  std::streambuf *get_stream_buffer() {
105  return m_streamBuffer;
106  }
107 
116  void set_indent_size(size_t indent_size) {
117  m_indentSize = indent_size;
118 
119  delete[] m_indentString;
120  m_indentString = new Ch[MAX_INDENT_LEVEL*m_indentSize];
121  std::fill(m_indentString, m_indentString + MAX_INDENT_LEVEL*m_indentSize, static_cast<Ch>(' '));
122  }
123 
131  void set_flags(unsigned flags) {
132  m_flags = (Flags) flags;
133  }
134 
135 
136 private:
142  size_t indent_level() {
143  return std::min(m_indentLevel*m_indentSize, (size_t) MAX_INDENT_LEVEL*m_indentSize);
144  }
145 
151  void prefix() {
152  if (m_atLineBegin) {
153  if (!m_leftJustify)
154  m_streamBuffer->sputn(m_indentString, indent_level());
155  m_leftJustify = false;
156  m_atLineBegin = false;
157  }
158  }
159 
164  void next_line() {
165  if (m_nextIndentLevel > m_indentLevel) {
166  if (m_flags & BRACES)
167  m_streamBuffer->sputn(" {", 2);
168  m_streamBuffer->sputc(Tr::to_int_type('\n'));
169  }
170  else if (m_nextIndentLevel < m_indentLevel) {
171  m_indentLevel = m_nextIndentLevel;
172  if (!m_atLineBegin)
173  m_streamBuffer->sputc(Tr::to_int_type('\n'));
174  if (m_flags & BRACES) {
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'));
178  }
179  }
180  else if (!m_atLineBegin || (m_flags & BLANK_LINES))
181  m_streamBuffer->sputc(Tr::to_int_type('\n'));
182 
183  m_indentLevel = m_nextIndentLevel;
184  m_atLineBegin = true;
185  }
186 
187 public:
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'))
199  next_line();
200  else if (c == Tr::to_int_type(POP)) {
201  if (m_nextIndentLevel != m_indentLevel)
202  next_line();
203  if (m_indentLevel > 0)
204  m_nextIndentLevel = m_indentLevel - 1;
205  }
206  else if (c == Tr::to_int_type(PUSH)) {
207  if (m_nextIndentLevel != m_indentLevel)
208  next_line();
209  m_nextIndentLevel = m_indentLevel + 1;
210  }
211  else if (c == Tr::to_int_type(LEFT)) {
212  m_leftJustify = true;
213  }
214  else {
215  prefix();
216  m_streamBuffer->sputc(c);
217  }
218 
219  return c;
220  }
221 
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) {
238 
239 // If at start of line, PUSH and POP have immediate effect
240  if (p == q && m_atLineBegin) {
241  if (Tr::to_int_type(*p) == Tr::to_int_type('\n')) {
242  next_line();
243  ++p;
244  }
245  else if (Tr::to_int_type(*p) == Tr::to_int_type(POP)) {
246  ++p;
247  if (m_nextIndentLevel != m_indentLevel)
248  next_line();
249  if (m_indentLevel > 0)
250  m_nextIndentLevel = m_indentLevel - 1;
251  }
252  else if (Tr::to_int_type(*p) == Tr::to_int_type(PUSH)) {
253  ++p;
254  if (m_nextIndentLevel != m_indentLevel)
255  next_line();
256  m_nextIndentLevel = m_indentLevel + 1;
257  }
258  else if (Tr::to_int_type(*p) == Tr::to_int_type(LEFT)) {
259  ++p;
260  m_leftJustify = true;
261  }
262  }
263 
264 // If not at start, PUSH and POP are for the next line.
265  else {
266  if (Tr::to_int_type(*q) == Tr::to_int_type('\n')) {
267  prefix();
268  m_streamBuffer->sputn(p, q - p);
269  next_line();
270  p = q + 1;
271  }
272  else if (Tr::to_int_type(*q) == Tr::to_int_type(POP)) {
273  prefix();
274  m_streamBuffer->sputn(p, q - p);
275  p = q + 1;
276  if (m_nextIndentLevel != m_indentLevel)
277  next_line();
278  if (m_indentLevel > 0)
279  m_nextIndentLevel = m_indentLevel - 1;
280  }
281  else if (Tr::to_int_type(*q) == Tr::to_int_type(PUSH)) {
282  prefix();
283  m_streamBuffer->sputn(p, q - p);
284  p = q + 1;
285  if (m_nextIndentLevel != m_indentLevel)
286  next_line();
287  m_nextIndentLevel = m_indentLevel + 1;
288  }
289  else if (Tr::to_int_type(*q) == Tr::to_int_type(LEFT)) {
290  m_leftJustify = true;
291  p = q + 1;
292  }
293  }
294  }
295  if (p != p_end) {
296  prefix();
297  m_streamBuffer->sputn(p, p_end - p);
298  m_atLineBegin = false;
299  }
300 
301  return n;
302  }
303 
309  virtual int sync() {
310  return m_streamBuffer->pubsync();
311  }
312 
313 private:
316 
317 private:
318  std::streambuf * m_streamBuffer;
319  bool m_atLineBegin;
320  bool m_leftJustify;
321  size_t m_indentLevel;
322  size_t m_nextIndentLevel;
323  size_t m_indentSize;
324  Flags m_flags;
325  Ch * m_indentString;
326 };
327 
328 template<class Ch, class Tr>
329 std::basic_ostream<Ch, Tr> &push(std::basic_ostream<Ch, Tr> &os) {
330  os.put(PUSH);
331 // os.put('\n');
332  os.flush();
333  return os;
334 }
335 
336 template<class Ch, class Tr>
337 std::basic_ostream<Ch, Tr> &pop(std::basic_ostream<Ch, Tr> &os) {
338  os.put(POP);
339 // os.put('\n');
340  os.flush();
341  return os;
342 }
343 
344 
345 template<class Ch, class Tr>
346 class indent_streambuf_throwsafe
347 {
348  explicit indent_streambuf_throwsafe(basic_indent_streambuf<Ch, Tr> &sb)
349  : m_indentStreambuf(sb),
350  m_indentLevel(sb.indent_level())
351  {}
352 
353  ~indent_streambuf_throwsafe() {
354  while (m_indentStreambuf.indent_level() > m_indentLevel)
355  m_indentStreambuf.pop();
356  }
357 
358 private:
359  basic_indent_streambuf<Ch, Tr> & m_indentStreambuf;
360  size_t m_indentLevel;
361 };
362 
363 
364 struct IndentFlags {
365  int m_flags;
366 };
367 
368 inline IndentFlags indent_flags(int flags) {
369  IndentFlags f;
370  f.m_flags = flags;
371  return f;
372 }
373 
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());
378  if (osb)
379  osb->set_flags(indent_flags.m_flags);
380 
381  return os;
382 }
383 
384 typedef stk_classic::basic_indent_streambuf<char> indent_streambuf;
385 
386 } // namespace stk_classic
387 
388 #endif // STK_UTIL_UTIL_INDENTSTREAMBUF_HPP
virtual std::streamsize xsputn(const Ch *p, std::streamsize n)
Member function xsputn interprets the meta-characters or writes the specified characters to the desti...
void set_flags(unsigned flags)
Member function set_flags enables or disables the BLANK_LINES and BRACES written to the destination s...
virtual std::basic_streambuf< Ch, Tr >::int_type overflow(typename std::basic_streambuf< Ch, Tr >::int_type c)
Member function overflow interprets a meta-character or writes the specified character to the destina...
virtual int sync()
Member function sync syncs the destination output stream buffer.
Class basic_indent_streambuf implements a output streambuf that performs indentation, blank line removal and outline bracing, sending the result character stream to another output stream buffer.
static const char LEFT
Meta-character to force left justification.
basic_indent_streambuf(std::basic_streambuf< Ch, Tr > *stream_buffer, size_t indent_size=2, unsigned flags=BRACES)
std::streambuf * get_stream_buffer()
Member function get_stream_buffer returns the current destination output stream buffer.
Sierra Toolkit.
void set_indent_size(size_t indent_size)
Member function set_indent_size set the number of spaces to write for each indentation level...
static const char PUSH
Meta-character to increase indentation.
void redirect(std::basic_streambuf< Ch, Tr > *stream_buffer)
Member function redirect sets the destination output stream buffer.
static const char POP
Meta-character to decrease indentation.