1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
12 #include "cmUVHandlePtr.h"
15 * This file is based on example code from:
17 * http://www.voidcn.com/article/p-vjnlygmc-gy.html
19 * The example code was distributed under the following license:
21 * Copyright 2007 Edd Dawson.
22 * Distributed under the Boost Software License, Version 1.0.
24 * Boost Software License - Version 1.0 - August 17th, 2003
26 * Permission is hereby granted, free of charge, to any person or organization
27 * obtaining a copy of the software and accompanying documentation covered by
28 * this license (the "Software") to use, reproduce, display, distribute,
29 * execute, and transmit the Software, and to prepare derivative works of the
30 * Software, and to permit third-parties to whom the Software is furnished to
31 * do so, all subject to the following:
33 * The copyright notices in the Software and this entire statement, including
34 * the above license grant, this restriction and the following disclaimer,
35 * must be included in all copies of the Software, in whole or in part, and
36 * all derivative works of the Software, unless such copies or derivative
37 * works are solely in the form of machine-executable object code generated by
38 * a source language processor.
40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
43 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
44 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
45 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
46 * DEALINGS IN THE SOFTWARE.
49 template <typename CharT, typename Traits = std::char_traits<CharT>>
50 class cmBasicUVStreambuf : public std::basic_streambuf<CharT, Traits>
53 cmBasicUVStreambuf(std::size_t bufSize = 256, std::size_t putBack = 8);
54 ~cmBasicUVStreambuf() override;
58 cmBasicUVStreambuf* open(uv_stream_t* stream);
60 cmBasicUVStreambuf* close();
63 typename cmBasicUVStreambuf<CharT, Traits>::int_type underflow() override;
64 std::streamsize showmanyc() override;
66 // FIXME: Add write support
69 uv_stream_t* Stream = nullptr;
70 void* OldStreamData = nullptr;
71 const std::size_t PutBack = 0;
72 std::vector<CharT> InputBuffer;
73 bool EndOfFile = false;
75 void StreamReadStartStop();
77 void StreamRead(ssize_t nread);
78 void HandleAlloc(uv_buf_t* buf);
81 template <typename CharT, typename Traits>
82 cmBasicUVStreambuf<CharT, Traits>::cmBasicUVStreambuf(std::size_t bufSize,
84 : PutBack(std::max<std::size_t>(putBack, 1))
85 , InputBuffer(std::max<std::size_t>(this->PutBack, bufSize) + this->PutBack)
90 template <typename CharT, typename Traits>
91 cmBasicUVStreambuf<CharT, Traits>::~cmBasicUVStreambuf()
96 template <typename CharT, typename Traits>
97 bool cmBasicUVStreambuf<CharT, Traits>::is_open() const
99 return this->Stream != nullptr;
102 template <typename CharT, typename Traits>
103 cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::open(
107 this->Stream = stream;
108 this->EndOfFile = false;
110 this->OldStreamData = this->Stream->data;
111 this->Stream->data = this;
113 this->StreamReadStartStop();
117 template <typename CharT, typename Traits>
118 cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::close()
121 uv_read_stop(this->Stream);
122 this->Stream->data = this->OldStreamData;
124 this->Stream = nullptr;
125 CharT* readEnd = this->InputBuffer.data() + this->InputBuffer.size();
126 this->setg(readEnd, readEnd, readEnd);
130 template <typename CharT, typename Traits>
131 typename cmBasicUVStreambuf<CharT, Traits>::int_type
132 cmBasicUVStreambuf<CharT, Traits>::underflow()
134 if (!this->is_open()) {
135 return Traits::eof();
138 if (this->gptr() < this->egptr()) {
139 return Traits::to_int_type(*this->gptr());
142 this->StreamReadStartStop();
143 while (this->in_avail() == 0) {
144 uv_run(this->Stream->loop, UV_RUN_ONCE);
146 if (this->in_avail() == -1) {
147 return Traits::eof();
149 return Traits::to_int_type(*this->gptr());
152 template <typename CharT, typename Traits>
153 std::streamsize cmBasicUVStreambuf<CharT, Traits>::showmanyc()
155 if (!this->is_open() || this->EndOfFile) {
161 template <typename CharT, typename Traits>
162 void cmBasicUVStreambuf<CharT, Traits>::StreamReadStartStop()
165 uv_read_stop(this->Stream);
166 if (this->gptr() >= this->egptr()) {
169 [](uv_handle_t* handle, size_t /* unused */, uv_buf_t* buf) {
171 static_cast<cmBasicUVStreambuf<CharT, Traits>*>(handle->data);
172 streambuf->HandleAlloc(buf);
174 [](uv_stream_t* stream2, ssize_t nread, const uv_buf_t* /* unused */) {
176 static_cast<cmBasicUVStreambuf<CharT, Traits>*>(stream2->data);
177 streambuf->StreamRead(nread);
183 template <typename CharT, typename Traits>
184 void cmBasicUVStreambuf<CharT, Traits>::HandleAlloc(uv_buf_t* buf)
186 auto size = this->egptr() - this->gptr();
187 std::memmove(this->InputBuffer.data(), this->gptr(),
188 this->egptr() - this->gptr());
189 this->setg(this->InputBuffer.data(), this->InputBuffer.data(),
190 this->InputBuffer.data() + size);
191 buf->base = this->egptr();
193 # define BUF_LEN_TYPE ULONG
195 # define BUF_LEN_TYPE size_t
197 buf->len = BUF_LEN_TYPE(
198 (this->InputBuffer.data() + this->InputBuffer.size() - this->egptr()) *
203 template <typename CharT, typename Traits>
204 void cmBasicUVStreambuf<CharT, Traits>::StreamRead(ssize_t nread)
207 this->setg(this->eback(), this->gptr(),
208 this->egptr() + nread / sizeof(CharT));
209 uv_read_stop(this->Stream);
210 } else if (nread < 0 /*|| nread == UV_EOF*/) {
211 this->EndOfFile = true;
212 uv_read_stop(this->Stream);
216 using cmUVStreambuf = cmBasicUVStreambuf<char>;