| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- // Copyright 2019 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // https://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "dap/io.h"
- #include <atomic>
- #include <condition_variable>
- #include <cstdarg>
- #include <cstdio>
- #include <cstring> // strlen
- #include <deque>
- #include <mutex>
- #include <string>
- namespace {
- class Pipe : public dap::ReaderWriter {
- public:
- // dap::ReaderWriter compliance
- bool isOpen() override {
- std::unique_lock<std::mutex> lock(mutex);
- return !closed;
- }
- void close() override {
- std::unique_lock<std::mutex> lock(mutex);
- closed = true;
- cv.notify_all();
- }
- size_t read(void* buffer, size_t bytes) override {
- std::unique_lock<std::mutex> lock(mutex);
- auto out = reinterpret_cast<uint8_t*>(buffer);
- size_t n = 0;
- while (true) {
- cv.wait(lock, [&] { return closed || data.size() > 0; });
- if (closed) {
- return n;
- }
- for (; n < bytes && data.size() > 0; n++) {
- out[n] = data.front();
- data.pop_front();
- }
- if (n == bytes) {
- return n;
- }
- }
- }
- bool write(const void* buffer, size_t bytes) override {
- std::unique_lock<std::mutex> lock(mutex);
- if (closed) {
- return false;
- }
- if (bytes == 0) {
- return true;
- }
- auto notify = data.size() == 0;
- auto src = reinterpret_cast<const uint8_t*>(buffer);
- for (size_t i = 0; i < bytes; i++) {
- data.emplace_back(src[i]);
- }
- if (notify) {
- cv.notify_all();
- }
- return true;
- }
- private:
- std::mutex mutex;
- std::condition_variable cv;
- std::deque<uint8_t> data;
- bool closed = false;
- };
- class RW : public dap::ReaderWriter {
- public:
- RW(const std::shared_ptr<Reader>& r, const std::shared_ptr<Writer>& w)
- : r(r), w(w) {}
- // dap::ReaderWriter compliance
- bool isOpen() override { return r->isOpen() && w->isOpen(); }
- void close() override {
- r->close();
- w->close();
- }
- size_t read(void* buffer, size_t n) override { return r->read(buffer, n); }
- bool write(const void* buffer, size_t n) override {
- return w->write(buffer, n);
- }
- private:
- const std::shared_ptr<dap::Reader> r;
- const std::shared_ptr<dap::Writer> w;
- };
- class File : public dap::ReaderWriter {
- public:
- File(FILE* f, bool closable) : f(f), closable(closable) {}
- ~File() { close(); }
- // dap::ReaderWriter compliance
- bool isOpen() override { return !closed; }
- void close() override {
- if (closable) {
- if (!closed.exchange(true)) {
- fclose(f);
- }
- }
- }
- size_t read(void* buffer, size_t n) override {
- std::unique_lock<std::mutex> lock(readMutex);
- auto out = reinterpret_cast<char*>(buffer);
- for (size_t i = 0; i < n; i++) {
- int c = fgetc(f);
- if (c == EOF) {
- return i;
- }
- out[i] = char(c);
- }
- return n;
- }
- bool write(const void* buffer, size_t n) override {
- std::unique_lock<std::mutex> lock(writeMutex);
- if (fwrite(buffer, 1, n, f) == n) {
- fflush(f);
- return true;
- }
- return false;
- }
- private:
- FILE* const f;
- const bool closable;
- std::mutex readMutex;
- std::mutex writeMutex;
- std::atomic<bool> closed = {false};
- };
- class ReaderSpy : public dap::Reader {
- public:
- ReaderSpy(const std::shared_ptr<dap::Reader>& r,
- const std::shared_ptr<dap::Writer>& s,
- const std::string& prefix)
- : r(r), s(s), prefix(prefix) {}
- // dap::Reader compliance
- bool isOpen() override { return r->isOpen(); }
- void close() override { r->close(); }
- size_t read(void* buffer, size_t n) override {
- auto c = r->read(buffer, n);
- if (c > 0) {
- auto chars = reinterpret_cast<const char*>(buffer);
- std::string buf = prefix;
- buf.append(chars, chars + c);
- s->write(buf.data(), buf.size());
- }
- return c;
- }
- private:
- const std::shared_ptr<dap::Reader> r;
- const std::shared_ptr<dap::Writer> s;
- const std::string prefix;
- };
- class WriterSpy : public dap::Writer {
- public:
- WriterSpy(const std::shared_ptr<dap::Writer>& w,
- const std::shared_ptr<dap::Writer>& s,
- const std::string& prefix)
- : w(w), s(s), prefix(prefix) {}
- // dap::Writer compliance
- bool isOpen() override { return w->isOpen(); }
- void close() override { w->close(); }
- bool write(const void* buffer, size_t n) override {
- if (!w->write(buffer, n)) {
- return false;
- }
- auto chars = reinterpret_cast<const char*>(buffer);
- std::string buf = prefix;
- buf.append(chars, chars + n);
- s->write(buf.data(), buf.size());
- return true;
- }
- private:
- const std::shared_ptr<dap::Writer> w;
- const std::shared_ptr<dap::Writer> s;
- const std::string prefix;
- };
- } // anonymous namespace
- namespace dap {
- std::shared_ptr<ReaderWriter> ReaderWriter::create(
- const std::shared_ptr<Reader>& r,
- const std::shared_ptr<Writer>& w) {
- return std::make_shared<RW>(r, w);
- }
- std::shared_ptr<ReaderWriter> pipe() {
- return std::make_shared<Pipe>();
- }
- std::shared_ptr<ReaderWriter> file(FILE* f, bool closable /* = true */) {
- return std::make_shared<File>(f, closable);
- }
- std::shared_ptr<ReaderWriter> file(const char* path) {
- if (auto f = fopen(path, "wb")) {
- return std::make_shared<File>(f, true);
- }
- return nullptr;
- }
- // spy() returns a Reader that copies all reads from the Reader r to the Writer
- // s, using the given optional prefix.
- std::shared_ptr<Reader> spy(const std::shared_ptr<Reader>& r,
- const std::shared_ptr<Writer>& s,
- const char* prefix /* = "\n<-" */) {
- return std::make_shared<ReaderSpy>(r, s, prefix);
- }
- // spy() returns a Writer that copies all writes to the Writer w to the Writer
- // s, using the given optional prefix.
- std::shared_ptr<Writer> spy(const std::shared_ptr<Writer>& w,
- const std::shared_ptr<Writer>& s,
- const char* prefix /* = "\n->" */) {
- return std::make_shared<WriterSpy>(w, s, prefix);
- }
- bool writef(const std::shared_ptr<Writer>& w, const char* msg, ...) {
- char buf[2048];
- va_list vararg;
- va_start(vararg, msg);
- vsnprintf(buf, sizeof(buf), msg, vararg);
- va_end(vararg);
- return w->write(buf, strlen(buf));
- }
- } // namespace dap
|