| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #pragma once
- #include <algorithm>
- #include <cstring>
- #include <streambuf>
- #include <vector>
- #include <cm3p/uv.h>
- #include "cmUVHandlePtr.h"
- /*
- * This file is based on example code from:
- *
- * https://web.archive.org/web/20170515211805/
- * http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
- *
- * The example code was distributed under the following license:
- *
- * Copyright 2007 Edd Dawson.
- * Distributed under the Boost Software License, Version 1.0.
- *
- * Boost Software License - Version 1.0 - August 17th, 2003
- *
- * Permission is hereby granted, free of charge, to any person or organization
- * obtaining a copy of the software and accompanying documentation covered by
- * this license (the "Software") to use, reproduce, display, distribute,
- * execute, and transmit the Software, and to prepare derivative works of the
- * Software, and to permit third-parties to whom the Software is furnished to
- * do so, all subject to the following:
- *
- * The copyright notices in the Software and this entire statement, including
- * the above license grant, this restriction and the following disclaimer,
- * must be included in all copies of the Software, in whole or in part, and
- * all derivative works of the Software, unless such copies or derivative
- * works are solely in the form of machine-executable object code generated by
- * a source language processor.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
- * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
- * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- template <typename CharT, typename Traits = std::char_traits<CharT>>
- class cmBasicUVStreambuf : public std::basic_streambuf<CharT, Traits>
- {
- public:
- cmBasicUVStreambuf(std::size_t bufSize = 256, std::size_t putBack = 8);
- ~cmBasicUVStreambuf() override;
- bool is_open() const;
- cmBasicUVStreambuf* open(uv_stream_t* stream);
- cmBasicUVStreambuf* close();
- protected:
- typename cmBasicUVStreambuf<CharT, Traits>::int_type underflow() override;
- std::streamsize showmanyc() override;
- // FIXME: Add write support
- private:
- uv_stream_t* Stream = nullptr;
- void* OldStreamData = nullptr;
- const std::size_t PutBack = 0;
- std::vector<CharT> InputBuffer;
- bool EndOfFile = false;
- void StreamReadStartStop();
- void StreamRead(ssize_t nread);
- void HandleAlloc(uv_buf_t* buf);
- };
- template <typename CharT, typename Traits>
- cmBasicUVStreambuf<CharT, Traits>::cmBasicUVStreambuf(std::size_t bufSize,
- std::size_t putBack)
- : PutBack(std::max<std::size_t>(putBack, 1))
- , InputBuffer(std::max<std::size_t>(this->PutBack, bufSize) + this->PutBack)
- {
- this->close();
- }
- template <typename CharT, typename Traits>
- cmBasicUVStreambuf<CharT, Traits>::~cmBasicUVStreambuf()
- {
- this->close();
- }
- template <typename CharT, typename Traits>
- bool cmBasicUVStreambuf<CharT, Traits>::is_open() const
- {
- return this->Stream != nullptr;
- }
- template <typename CharT, typename Traits>
- cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::open(
- uv_stream_t* stream)
- {
- this->close();
- this->Stream = stream;
- this->EndOfFile = false;
- if (this->Stream) {
- this->OldStreamData = this->Stream->data;
- this->Stream->data = this;
- }
- this->StreamReadStartStop();
- return this;
- }
- template <typename CharT, typename Traits>
- cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::close()
- {
- if (this->Stream) {
- uv_read_stop(this->Stream);
- this->Stream->data = this->OldStreamData;
- }
- this->Stream = nullptr;
- CharT* readEnd = this->InputBuffer.data() + this->InputBuffer.size();
- this->setg(readEnd, readEnd, readEnd);
- return this;
- }
- template <typename CharT, typename Traits>
- typename cmBasicUVStreambuf<CharT, Traits>::int_type
- cmBasicUVStreambuf<CharT, Traits>::underflow()
- {
- if (!this->is_open()) {
- return Traits::eof();
- }
- if (this->gptr() < this->egptr()) {
- return Traits::to_int_type(*this->gptr());
- }
- this->StreamReadStartStop();
- while (this->in_avail() == 0) {
- uv_run(this->Stream->loop, UV_RUN_ONCE);
- }
- if (this->in_avail() == -1) {
- return Traits::eof();
- }
- return Traits::to_int_type(*this->gptr());
- }
- template <typename CharT, typename Traits>
- std::streamsize cmBasicUVStreambuf<CharT, Traits>::showmanyc()
- {
- if (!this->is_open() || this->EndOfFile) {
- return -1;
- }
- return 0;
- }
- template <typename CharT, typename Traits>
- void cmBasicUVStreambuf<CharT, Traits>::StreamReadStartStop()
- {
- if (this->Stream) {
- uv_read_stop(this->Stream);
- if (this->gptr() >= this->egptr()) {
- uv_read_start(
- this->Stream,
- [](uv_handle_t* handle, size_t /* unused */, uv_buf_t* buf) {
- auto streambuf =
- static_cast<cmBasicUVStreambuf<CharT, Traits>*>(handle->data);
- streambuf->HandleAlloc(buf);
- },
- [](uv_stream_t* stream2, ssize_t nread, const uv_buf_t* /* unused */) {
- auto streambuf =
- static_cast<cmBasicUVStreambuf<CharT, Traits>*>(stream2->data);
- streambuf->StreamRead(nread);
- });
- }
- }
- }
- template <typename CharT, typename Traits>
- void cmBasicUVStreambuf<CharT, Traits>::HandleAlloc(uv_buf_t* buf)
- {
- auto size = this->egptr() - this->gptr();
- std::memmove(this->InputBuffer.data(), this->gptr(),
- this->egptr() - this->gptr());
- this->setg(this->InputBuffer.data(), this->InputBuffer.data(),
- this->InputBuffer.data() + size);
- buf->base = this->egptr();
- #ifdef _WIN32
- # define BUF_LEN_TYPE ULONG
- #else
- # define BUF_LEN_TYPE size_t
- #endif
- buf->len = BUF_LEN_TYPE(
- (this->InputBuffer.data() + this->InputBuffer.size() - this->egptr()) *
- sizeof(CharT));
- #undef BUF_LEN_TYPE
- }
- template <typename CharT, typename Traits>
- void cmBasicUVStreambuf<CharT, Traits>::StreamRead(ssize_t nread)
- {
- if (nread > 0) {
- this->setg(this->eback(), this->gptr(),
- this->egptr() + nread / sizeof(CharT));
- uv_read_stop(this->Stream);
- } else if (nread < 0 /*|| nread == UV_EOF*/) {
- this->EndOfFile = true;
- uv_read_stop(this->Stream);
- }
- }
- using cmUVStreambuf = cmBasicUVStreambuf<char>;
|