# from [d4ff673e1080a7b081d79a1876a6bb203d05640d] # to [25c7b475b5557d8bca633176092fc5237e31dcbc] # # patch "automate_ostream_demuxed.hh" # from [d5e068c3a9dadfabf27db883b6a2bb2379eea34e] # to [cb7df1aa2d3d7b6406f5d98c045e1c42fe6465ca] --- +++ @@ -0,0 +1,154 @@ +// Copyright (C) 2005 and later by various people +// see monotone commit logs for details and authors +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +#ifndef __AUTOMATE_OSTREAM_HH__ +#define __AUTOMATE_OSTREAM_HH__ + +#include +#include +#include "lexical_cast.hh" + +using boost::lexical_cast; + +template > +class basic_automate_streambuf : public std::basic_streambuf<_CharT, _Traits> +{ + typedef _Traits traits_type; + typedef typename _Traits::int_type int_type; + size_t _bufsize; + std::basic_ostream<_CharT, _Traits> *out; + int cmdnum; + +public: + basic_automate_streambuf(std::ostream & o, size_t bufsize) + : std::streambuf(), _bufsize(bufsize), out(&o), cmdnum(0) + { + _CharT *inbuf = new _CharT[_bufsize]; + this->setp(inbuf, inbuf + _bufsize); + } + + basic_automate_streambuf() + {} + + ~basic_automate_streambuf() + {} + + void end_cmd(int errcode) + { + _M_sync(); + write_out_of_band('l', lexical_cast(errcode)); + ++cmdnum; + } + + virtual int sync() + { + _M_sync(); + return 0; + } + + void _M_sync() + { + if (!out) + { + this->setp(this->pbase(), this->pbase() + _bufsize); + return; + } + int num = this->pptr() - this->pbase(); + if (num) + { + (*out) << cmdnum << ':' + << 'm' << ':' + << num << ':' + << std::basic_string<_CharT,_Traits>(this->pbase(), num); + this->setp(this->pbase(), this->pbase() + _bufsize); + out->flush(); + } + } + + void write_out_of_band(char type, std::string const & data) + { + unsigned chunksize = _bufsize; + size_t length = data.size(), offset = 0; + do + { + if (offset+chunksize>length) + chunksize = length-offset; + (*out) << cmdnum << ':' << type << ':' << chunksize + << ':' << data.substr(offset, chunksize); + offset+= chunksize; + } while (offsetflush(); + } + + void write_headers(std::vector > const & headers) + { + for (std::vector >::const_iterator h = headers.begin(); + h != headers.end(); ++h) + { + (*out) << h->first << ": " << h->second << '\n'; + } + (*out) << '\n'; + out->flush(); + } + + int_type + overflow(int_type c = traits_type::eof()) + { + sync(); + this->sputc(c); + return 0; + } +}; + +template > +struct basic_automate_ostream : public std::basic_ostream<_CharT, _Traits> +{ + typedef basic_automate_streambuf<_CharT, _Traits> streambuf_type; + streambuf_type _M_autobuf; + + basic_automate_ostream(std::basic_ostream<_CharT, _Traits> &out, + size_t blocksize) + : std::basic_ostream<_CharT, _Traits>(&_M_autobuf), + _M_autobuf(out, blocksize) + { /* this->init(&_M_autobuf); */ } + +protected: + basic_automate_ostream() { } +public: + + virtual ~basic_automate_ostream() + {} + + streambuf_type * + rdbuf() const + { return const_cast(&_M_autobuf); } + + virtual void end_cmd(int errcode) + { _M_autobuf.end_cmd(errcode); } + + virtual void write_out_of_band(char type, std::string const & data) + { _M_autobuf.write_out_of_band(type, data); } + + virtual void write_headers(std::vector > const & headers) + { _M_autobuf.write_headers(headers); } +}; + +typedef basic_automate_streambuf automate_streambuf; +typedef basic_automate_ostream automate_ostream; + +#endif + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: --- automate_ostream_demuxed.hh +++ automate_ostream_demuxed.hh @@ -0,0 +1,156 @@ +// Copyright (C) 2009 and later by various people +// see monotone commit logs for details and authors +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +#ifndef __AUTOMATE_OSTREAM_DEMUXED_HH__ +#define __AUTOMATE_OSTREAM_DEMUXED_HH__ + +#include + +#include "automate_ostream.hh" +#include "simplestring_xform.hh" + +template > +class basic_automate_streambuf_demuxed : public std::basic_streambuf<_CharT, _Traits> +{ + typedef _Traits traits_type; + typedef typename _Traits::int_type int_type; + size_t _bufsize; + std::basic_ostream<_CharT, _Traits> *mystdout; + std::basic_ostream<_CharT, _Traits> *errout; +public: + basic_automate_streambuf_demuxed(std::ostream & out, std::ostream & err, + size_t bufsize) : + std::streambuf(), + _bufsize(bufsize), + mystdout(&out), + errout(&err) + { + _CharT * inbuf = new _CharT[_bufsize]; + this->setp(inbuf, inbuf + _bufsize); + } + + ~basic_automate_streambuf_demuxed() { } + + void end_cmd() + { + _M_sync(); + } + + virtual int sync() + { + _M_sync(); + return 0; + } + + void write_out_of_band(char type, std::string const & data) + { + // FIXME: ignore tickers, because we'd have to track their state + // here and they would pollute the output too much anyways + if (type == 't') + return; + + std::string out; + i18n_format prefix; + if (type == 'w') + prefix = F("%s: remote warning: ") % prog_name; + else if (type == 'e') + prefix = F("%s: remote error: ") % prog_name; + else if (type == 'p') + prefix = F("%s: remote message: ") % prog_name; + else + I(false); + + prefix_lines_with(prefix.str(), data, out); + (*errout) << out << std::endl; + } + + void write_headers(std::vector > const & headers) + { + i18n_format prefix = F("%s: remote header: ") % prog_name; + for (std::vector >::const_iterator h = headers.begin(); + h != headers.end(); ++h) + { + (*errout) << prefix.str() << h->first << ": " << h->second << std::endl; + } + } + + int_type overflow(int_type c = traits_type::eof()) + { + sync(); + this->sputc(c); + return 0; + } +private: + void _M_sync() + { + if (!mystdout) + { + this->setp(this->pbase(), this->pbase() + _bufsize); + return; + } + int num = this->pptr() - this->pbase(); + if (num) + { + (*mystdout) << std::basic_string<_CharT, _Traits>(this->pbase(), num); + this->setp(this->pbase(), this->pbase() + _bufsize); + mystdout->flush(); + } + } +}; + +template > +struct basic_automate_ostream_demuxed : public basic_automate_ostream<_CharT, _Traits> +{ + typedef basic_automate_streambuf_demuxed<_CharT, _Traits> streambuf_type; + streambuf_type _M_autobuf; + int errcode; + +public: + basic_automate_ostream_demuxed(std::basic_ostream<_CharT, _Traits> &out, + std::basic_ostream<_CharT, _Traits> &err, + size_t blocksize) + : _M_autobuf(out, err, blocksize) + { this->init(&_M_autobuf); } + + virtual ~basic_automate_ostream_demuxed() + {} + + streambuf_type * + rdbuf() const + { return const_cast(&_M_autobuf); } + + virtual void end_cmd(int error) + { + errcode = error; + _M_autobuf.end_cmd(); + } + + int get_error() const + { return errcode; } + + virtual void write_out_of_band(char type, std::string const & data) + { _M_autobuf.write_out_of_band(type, data); } + + virtual void write_headers(std::vector > const & headers) + { _M_autobuf.write_headers(headers); } +}; + +typedef basic_automate_streambuf_demuxed automate_streambuf_demuxed; +typedef basic_automate_ostream_demuxed automate_ostream_demuxed; + +#endif + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: