1 // Copyright (C) 2005 and later by various people
2 // see monotone commit logs for details and authors
3 //
4 // This program is made available under the GNU GPL version 2.0 or
5 // greater. See the accompanying file COPYING for details.
6 //
7 // This program is distributed WITHOUT ANY WARRANTY; without even the
8 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9 // PURPOSE.
10 
11 #ifndef __AUTOMATE_OSTREAM_HH__
12 #define __AUTOMATE_OSTREAM_HH__
13 
14 #include <iostream>
15 #include <vector>
16 #include "lexical_cast.hh"
17 
18 using boost::lexical_cast;
19 
20 template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
21 class basic_automate_streambuf : public std::basic_streambuf<_CharT, _Traits>
22 {
23   typedef _Traits traits_type;
24   typedef typename _Traits::int_type int_type;
25   size_t _bufsize;
26   std::basic_ostream<_CharT, _Traits> *out;
27   int cmdnum;
28 
29 public:
basic_automate_streambuf(std::ostream & o,size_t bufsize)30   basic_automate_streambuf(std::ostream & o, size_t bufsize)
31     : std::basic_streambuf<_CharT, _Traits>(), _bufsize(bufsize), out(&o), cmdnum(0)
32   {
33     _CharT *inbuf = new _CharT[_bufsize];
34     this->setp(inbuf, inbuf + _bufsize);
35   }
36 
basic_automate_streambuf()37   basic_automate_streambuf()
38   {}
39 
~basic_automate_streambuf()40   ~basic_automate_streambuf()
41   {}
42 
end_cmd(int errcode)43   void end_cmd(int errcode)
44   {
45     _M_sync();
46     write_out_of_band('l', lexical_cast<std::string>(errcode));
47     ++cmdnum;
48   }
49 
sync()50   virtual int sync()
51   {
52     _M_sync();
53     return 0;
54   }
55 
_M_sync()56   void _M_sync()
57   {
58     if (!out)
59       {
60         this->setp(this->pbase(), this->pbase() + _bufsize);
61         return;
62       }
63     int num = this->pptr() - this->pbase();
64     if (num)
65       {
66         (*out) << cmdnum << ':'
67                << 'm' << ':'
68                << num << ':'
69                << std::basic_string<_CharT,_Traits>(this->pbase(), num);
70         this->setp(this->pbase(), this->pbase() + _bufsize);
71         out->flush();
72       }
73   }
74 
write_out_of_band(char type,std::string const & data)75   void write_out_of_band(char type, std::string const & data)
76   {
77     unsigned chunksize = _bufsize;
78     size_t length = data.size(), offset = 0;
79     do
80     {
81       if (offset+chunksize>length)
82         chunksize = length-offset;
83       (*out) << cmdnum << ':' << type << ':' << chunksize
84              << ':' << data.substr(offset, chunksize);
85       offset+= chunksize;
86     } while (offset<length);
87     out->flush();
88   }
89 
write_headers(std::vector<std::pair<std::string,std::string>> const & headers)90   void write_headers(std::vector<std::pair<std::string,std::string> > const & headers)
91   {
92     for (std::vector<std::pair<std::string, std::string> >::const_iterator h = headers.begin();
93          h != headers.end(); ++h)
94       {
95         (*out) << h->first << ": " << h->second << '\n';
96       }
97     (*out) << '\n';
98     out->flush();
99   }
100 
101   int_type
overflow(int_type c=traits_type::eof ())102   overflow(int_type c = traits_type::eof())
103   {
104     sync();
105     this->sputc(c);
106     return 0;
107   }
108 };
109 
110 template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
111 struct basic_automate_ostream : public std::basic_ostream<_CharT, _Traits>
112 {
113   typedef basic_automate_streambuf<_CharT, _Traits> streambuf_type;
114   streambuf_type _M_autobuf;
115 
basic_automate_ostreambasic_automate_ostream116   basic_automate_ostream(std::basic_ostream<_CharT, _Traits> &out,
117                    size_t blocksize)
118     : std::basic_ostream<_CharT, _Traits>(&_M_autobuf),
119       _M_autobuf(out, blocksize)
120   { /* this->init(&_M_autobuf); */ }
121 
122 protected:
basic_automate_ostreambasic_automate_ostream123   basic_automate_ostream() { }
124 public:
125 
~basic_automate_ostreambasic_automate_ostream126   virtual ~basic_automate_ostream()
127   {}
128 
129   streambuf_type *
rdbufbasic_automate_ostream130   rdbuf() const
131   { return const_cast<streambuf_type *>(&_M_autobuf); }
132 
end_cmdbasic_automate_ostream133   virtual void end_cmd(int errcode)
134   { _M_autobuf.end_cmd(errcode); }
135 
write_out_of_bandbasic_automate_ostream136   virtual void write_out_of_band(char type, std::string const & data)
137   { _M_autobuf.write_out_of_band(type, data); }
138 
write_headersbasic_automate_ostream139   virtual void write_headers(std::vector<std::pair<std::string,std::string> > const & headers)
140   { _M_autobuf.write_headers(headers); }
141 };
142 
143 typedef basic_automate_streambuf<char> automate_streambuf;
144 typedef basic_automate_ostream<char> automate_ostream;
145 
146 #endif
147 
148 // Local Variables:
149 // mode: C++
150 // fill-column: 76
151 // c-file-style: "gnu"
152 // indent-tabs-mode: nil
153 // End:
154 // vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:
155