Search code examples
c++c++11formattingostream

make std::ostream automatically ident when encountering special characters


I would like to have some facility which makes a std::ostream (or derived) automatically ident on encountering special characters (or special objects). Let's assume that the special characters are < and >. In this case the following input test0<test1<test2, test3<test4> > > should produce the following output:

test0<
    test1<
        test2,
        test3<
            test4
        >
    >
>

How would one go to implement this?


Solution

  • boost::iostreams makes this fairly easy, you can define filters then chain them together with an output stream to transform the input to the desired output:

    #include <iostream>
    #include <boost/iostreams/filtering_stream.hpp>
    
    namespace io = boost::iostreams;
    
    struct QuoteOutputFilter {
      typedef char                   char_type;
      typedef io::output_filter_tag  category;
    
      int indent = 0;
    
      template<typename Sink>
      bool newLine(Sink& snk)
      {
        std::string str = "\n" + std::string(indent * 4, ' ');
        return io::write(snk, str.c_str(), str.size());
      }
    
      template<typename Sink>
      bool put(Sink& snk, char c)
      {
        switch (c)
        {
          case '<':
            io::put(snk, c);
            indent += 1;
            return newLine(snk);
          case ',':
            io::put(snk, c);
            return newLine(snk);
          case '>':
            indent -= 1;
            newLine(snk);
            return io::put(snk, c);
          default:
            return io::put(snk, c);
        }
      }
    };
    
    int main()
    {
      io::filtering_ostream out;
      out.push(QuoteOutputFilter());
      out.push(std::cout);
    
      out << "test0<test1<test2, test3<test4> > >";
    }