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