summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcppdap/src/io.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcppdap/src/io.cpp')
-rw-r--r--Utilities/cmcppdap/src/io.cpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/Utilities/cmcppdap/src/io.cpp b/Utilities/cmcppdap/src/io.cpp
new file mode 100644
index 0000000..b4133e5
--- /dev/null
+++ b/Utilities/cmcppdap/src/io.cpp
@@ -0,0 +1,258 @@
+// 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