[NFC][Coroutines] Use structured binding with llvm::enumerate in CoroSplit (#116879)
[llvm-project.git] / lldb / tools / lldb-dap / IOStream.cpp
blobd2e8ec40b0a7b855af169c618eea0e29509bafce
1 //===-- IOStream.cpp --------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "IOStream.h"
11 #if defined(_WIN32)
12 #include <io.h>
13 #else
14 #include <netinet/in.h>
15 #include <sys/socket.h>
16 #include <unistd.h>
17 #endif
19 #include <fstream>
20 #include <string>
22 using namespace lldb_dap;
24 StreamDescriptor::StreamDescriptor() = default;
26 StreamDescriptor::StreamDescriptor(StreamDescriptor &&other) {
27 *this = std::move(other);
30 StreamDescriptor::~StreamDescriptor() {
31 if (!m_close)
32 return;
34 if (m_is_socket)
35 #if defined(_WIN32)
36 ::closesocket(m_socket);
37 #else
38 ::close(m_socket);
39 #endif
40 else
41 ::close(m_fd);
44 StreamDescriptor &StreamDescriptor::operator=(StreamDescriptor &&other) {
45 m_close = other.m_close;
46 other.m_close = false;
47 m_is_socket = other.m_is_socket;
48 if (m_is_socket)
49 m_socket = other.m_socket;
50 else
51 m_fd = other.m_fd;
52 return *this;
55 StreamDescriptor StreamDescriptor::from_socket(SOCKET s, bool close) {
56 StreamDescriptor sd;
57 sd.m_is_socket = true;
58 sd.m_socket = s;
59 sd.m_close = close;
60 return sd;
63 StreamDescriptor StreamDescriptor::from_file(int fd, bool close) {
64 StreamDescriptor sd;
65 sd.m_is_socket = false;
66 sd.m_fd = fd;
67 sd.m_close = close;
68 return sd;
71 bool OutputStream::write_full(llvm::StringRef str) {
72 while (!str.empty()) {
73 int bytes_written = 0;
74 if (descriptor.m_is_socket)
75 bytes_written = ::send(descriptor.m_socket, str.data(), str.size(), 0);
76 else
77 bytes_written = ::write(descriptor.m_fd, str.data(), str.size());
79 if (bytes_written < 0) {
80 if (errno == EINTR || errno == EAGAIN)
81 continue;
82 return false;
84 str = str.drop_front(bytes_written);
87 return true;
90 bool InputStream::read_full(std::ofstream *log, size_t length,
91 std::string &text) {
92 std::string data;
93 data.resize(length);
95 char *ptr = &data[0];
96 while (length != 0) {
97 int bytes_read = 0;
98 if (descriptor.m_is_socket)
99 bytes_read = ::recv(descriptor.m_socket, ptr, length, 0);
100 else
101 bytes_read = ::read(descriptor.m_fd, ptr, length);
103 if (bytes_read == 0) {
104 if (log)
105 *log << "End of file (EOF) reading from input file.\n";
106 return false;
108 if (bytes_read < 0) {
109 int reason = 0;
110 #if defined(_WIN32)
111 if (descriptor.m_is_socket)
112 reason = WSAGetLastError();
113 else
114 reason = errno;
115 #else
116 reason = errno;
117 if (reason == EINTR || reason == EAGAIN)
118 continue;
119 #endif
121 if (log)
122 *log << "Error " << reason << " reading from input file.\n";
123 return false;
126 assert(bytes_read >= 0 && (size_t)bytes_read <= length);
127 ptr += bytes_read;
128 length -= bytes_read;
130 text += data;
131 return true;
134 bool InputStream::read_line(std::ofstream *log, std::string &line) {
135 line.clear();
136 while (true) {
137 if (!read_full(log, 1, line))
138 return false;
140 if (llvm::StringRef(line).ends_with("\r\n"))
141 break;
143 line.erase(line.size() - 2);
144 return true;
147 bool InputStream::read_expected(std::ofstream *log, llvm::StringRef expected) {
148 std::string result;
149 if (!read_full(log, expected.size(), result))
150 return false;
151 if (expected != result) {
152 if (log)
153 *log << "Warning: Expected '" << expected.str() << "', got '" << result
154 << "\n";
156 return true;