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//===----------------------------------------------------------------------===//
8
9#include "IOStream.h"
10
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
18
19#include <fstream>
20#include <string>
21#include <vector>
22
23using namespace lldb_dap;
24
25StreamDescriptor::StreamDescriptor() = default;
26
27StreamDescriptor::StreamDescriptor(StreamDescriptor &&other) {
28 *this = std::move(other);
29}
30
31StreamDescriptor::~StreamDescriptor() {
32 if (!m_close)
33 return;
34
35 if (m_is_socket)
36#if defined(_WIN32)
37 ::closesocket(m_socket);
38#else
39 ::close(fd: m_socket);
40#endif
41 else
42 ::close(fd: m_fd);
43}
44
45StreamDescriptor &StreamDescriptor::operator=(StreamDescriptor &&other) {
46 m_close = other.m_close;
47 other.m_close = false;
48 m_is_socket = other.m_is_socket;
49 if (m_is_socket)
50 m_socket = other.m_socket;
51 else
52 m_fd = other.m_fd;
53 return *this;
54}
55
56StreamDescriptor StreamDescriptor::from_socket(SOCKET s, bool close) {
57 StreamDescriptor sd;
58 sd.m_is_socket = true;
59 sd.m_socket = s;
60 sd.m_close = close;
61 return sd;
62}
63
64StreamDescriptor StreamDescriptor::from_file(int fd, bool close) {
65 StreamDescriptor sd;
66 sd.m_is_socket = false;
67 sd.m_fd = fd;
68 sd.m_close = close;
69 return sd;
70}
71
72bool OutputStream::write_full(llvm::StringRef str) {
73 while (!str.empty()) {
74 int bytes_written = 0;
75 if (descriptor.m_is_socket)
76 bytes_written = ::send(fd: descriptor.m_socket, buf: str.data(), n: str.size(), flags: 0);
77 else
78 bytes_written = ::write(fd: descriptor.m_fd, buf: str.data(), n: str.size());
79
80 if (bytes_written < 0) {
81 if (errno == EINTR || errno == EAGAIN)
82 continue;
83 return false;
84 }
85 str = str.drop_front(N: bytes_written);
86 }
87
88 return true;
89}
90
91bool InputStream::read_full(std::ofstream *log, size_t length,
92 std::string &text) {
93 std::string data;
94 data.resize(n: length);
95
96 char *ptr = &data[0];
97 while (length != 0) {
98 int bytes_read = 0;
99 if (descriptor.m_is_socket)
100 bytes_read = ::recv(fd: descriptor.m_socket, buf: ptr, n: length, flags: 0);
101 else
102 bytes_read = ::read(fd: descriptor.m_fd, buf: ptr, nbytes: length);
103
104 if (bytes_read == 0) {
105 if (log)
106 *log << "End of file (EOF) reading from input file.\n";
107 return false;
108 }
109 if (bytes_read < 0) {
110 int reason = 0;
111#if defined(_WIN32)
112 if (descriptor.m_is_socket)
113 reason = WSAGetLastError();
114 else
115 reason = errno;
116#else
117 reason = errno;
118 if (reason == EINTR || reason == EAGAIN)
119 continue;
120#endif
121
122 if (log)
123 *log << "Error " << reason << " reading from input file.\n";
124 return false;
125 }
126
127 assert(bytes_read >= 0 && (size_t)bytes_read <= length);
128 ptr += bytes_read;
129 length -= bytes_read;
130 }
131 text += data;
132 return true;
133}
134
135bool InputStream::read_line(std::ofstream *log, std::string &line) {
136 line.clear();
137 while (true) {
138 if (!read_full(log, length: 1, text&: line))
139 return false;
140
141 if (llvm::StringRef(line).ends_with(Suffix: "\r\n"))
142 break;
143 }
144 line.erase(pos: line.size() - 2);
145 return true;
146}
147
148bool InputStream::read_expected(std::ofstream *log, llvm::StringRef expected) {
149 std::string result;
150 if (!read_full(log, length: expected.size(), text&: result))
151 return false;
152 if (expected != result) {
153 if (log)
154 *log << "Warning: Expected '" << expected.str() << "', got '" << result
155 << "\n";
156 }
157 return true;
158}
159

source code of lldb/tools/lldb-dap/IOStream.cpp