1061da546Spatrick //===-- IOStream.cpp --------------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "IOStream.h"
10061da546Spatrick 
11061da546Spatrick #if defined(_WIN32)
12061da546Spatrick #include <io.h>
13061da546Spatrick #else
14061da546Spatrick #include <netinet/in.h>
15061da546Spatrick #include <sys/socket.h>
16061da546Spatrick #include <unistd.h>
17061da546Spatrick #endif
18061da546Spatrick 
19061da546Spatrick #include <fstream>
20061da546Spatrick #include <string>
21061da546Spatrick #include <vector>
22061da546Spatrick 
23061da546Spatrick using namespace lldb_vscode;
24061da546Spatrick 
25*f6aab3d8Srobert StreamDescriptor::StreamDescriptor() = default;
26061da546Spatrick 
StreamDescriptor(StreamDescriptor && other)27061da546Spatrick StreamDescriptor::StreamDescriptor(StreamDescriptor &&other) {
28061da546Spatrick   *this = std::move(other);
29061da546Spatrick }
30061da546Spatrick 
~StreamDescriptor()31061da546Spatrick StreamDescriptor::~StreamDescriptor() {
32061da546Spatrick   if (!m_close)
33061da546Spatrick     return;
34061da546Spatrick 
35061da546Spatrick   if (m_is_socket)
36061da546Spatrick #if defined(_WIN32)
37061da546Spatrick     ::closesocket(m_socket);
38061da546Spatrick #else
39061da546Spatrick     ::close(m_socket);
40061da546Spatrick #endif
41061da546Spatrick   else
42061da546Spatrick     ::close(m_fd);
43061da546Spatrick }
44061da546Spatrick 
operator =(StreamDescriptor && other)45061da546Spatrick StreamDescriptor &StreamDescriptor::operator=(StreamDescriptor &&other) {
46061da546Spatrick   m_close = other.m_close;
47061da546Spatrick   other.m_close = false;
48061da546Spatrick   m_is_socket = other.m_is_socket;
49061da546Spatrick   if (m_is_socket)
50061da546Spatrick     m_socket = other.m_socket;
51061da546Spatrick   else
52061da546Spatrick     m_fd = other.m_fd;
53061da546Spatrick   return *this;
54061da546Spatrick }
55061da546Spatrick 
from_socket(SOCKET s,bool close)56061da546Spatrick StreamDescriptor StreamDescriptor::from_socket(SOCKET s, bool close) {
57061da546Spatrick   StreamDescriptor sd;
58061da546Spatrick   sd.m_is_socket = true;
59061da546Spatrick   sd.m_socket = s;
60061da546Spatrick   sd.m_close = close;
61061da546Spatrick   return sd;
62061da546Spatrick }
63061da546Spatrick 
from_file(int fd,bool close)64061da546Spatrick StreamDescriptor StreamDescriptor::from_file(int fd, bool close) {
65061da546Spatrick   StreamDescriptor sd;
66061da546Spatrick   sd.m_is_socket = false;
67061da546Spatrick   sd.m_fd = fd;
68061da546Spatrick   sd.m_close = close;
69061da546Spatrick   return sd;
70061da546Spatrick }
71061da546Spatrick 
write_full(llvm::StringRef str)72061da546Spatrick bool OutputStream::write_full(llvm::StringRef str) {
73061da546Spatrick   while (!str.empty()) {
74061da546Spatrick     int bytes_written = 0;
75061da546Spatrick     if (descriptor.m_is_socket)
76061da546Spatrick       bytes_written = ::send(descriptor.m_socket, str.data(), str.size(), 0);
77061da546Spatrick     else
78061da546Spatrick       bytes_written = ::write(descriptor.m_fd, str.data(), str.size());
79061da546Spatrick 
80061da546Spatrick     if (bytes_written < 0) {
81061da546Spatrick       if (errno == EINTR || errno == EAGAIN)
82061da546Spatrick         continue;
83061da546Spatrick       return false;
84061da546Spatrick     }
85061da546Spatrick     str = str.drop_front(bytes_written);
86061da546Spatrick   }
87061da546Spatrick 
88061da546Spatrick   return true;
89061da546Spatrick }
90061da546Spatrick 
read_full(std::ofstream * log,size_t length,std::string & text)91061da546Spatrick bool InputStream::read_full(std::ofstream *log, size_t length,
92061da546Spatrick                             std::string &text) {
93061da546Spatrick   std::string data;
94061da546Spatrick   data.resize(length);
95061da546Spatrick 
96061da546Spatrick   char *ptr = &data[0];
97061da546Spatrick   while (length != 0) {
98061da546Spatrick     int bytes_read = 0;
99061da546Spatrick     if (descriptor.m_is_socket)
100061da546Spatrick       bytes_read = ::recv(descriptor.m_socket, ptr, length, 0);
101061da546Spatrick     else
102061da546Spatrick       bytes_read = ::read(descriptor.m_fd, ptr, length);
103061da546Spatrick 
104061da546Spatrick     if (bytes_read == 0) {
105061da546Spatrick       if (log)
106061da546Spatrick         *log << "End of file (EOF) reading from input file.\n";
107061da546Spatrick       return false;
108061da546Spatrick     }
109061da546Spatrick     if (bytes_read < 0) {
110061da546Spatrick       int reason = 0;
111061da546Spatrick #if defined(_WIN32)
112061da546Spatrick       if (descriptor.m_is_socket)
113061da546Spatrick         reason = WSAGetLastError();
114061da546Spatrick       else
115061da546Spatrick         reason = errno;
116061da546Spatrick #else
117061da546Spatrick       reason = errno;
118061da546Spatrick       if (reason == EINTR || reason == EAGAIN)
119061da546Spatrick         continue;
120061da546Spatrick #endif
121061da546Spatrick 
122061da546Spatrick       if (log)
123061da546Spatrick         *log << "Error " << reason << " reading from input file.\n";
124061da546Spatrick       return false;
125061da546Spatrick     }
126061da546Spatrick 
127061da546Spatrick     assert(bytes_read >= 0 && (size_t)bytes_read <= length);
128061da546Spatrick     ptr += bytes_read;
129061da546Spatrick     length -= bytes_read;
130061da546Spatrick   }
131061da546Spatrick   text += data;
132061da546Spatrick   return true;
133061da546Spatrick }
134061da546Spatrick 
read_line(std::ofstream * log,std::string & line)135061da546Spatrick bool InputStream::read_line(std::ofstream *log, std::string &line) {
136061da546Spatrick   line.clear();
137061da546Spatrick   while (true) {
138061da546Spatrick     if (!read_full(log, 1, line))
139061da546Spatrick       return false;
140061da546Spatrick 
141061da546Spatrick     if (llvm::StringRef(line).endswith("\r\n"))
142061da546Spatrick       break;
143061da546Spatrick   }
144061da546Spatrick   line.erase(line.size() - 2);
145061da546Spatrick   return true;
146061da546Spatrick }
147061da546Spatrick 
read_expected(std::ofstream * log,llvm::StringRef expected)148061da546Spatrick bool InputStream::read_expected(std::ofstream *log, llvm::StringRef expected) {
149061da546Spatrick   std::string result;
150061da546Spatrick   if (!read_full(log, expected.size(), result))
151061da546Spatrick     return false;
152061da546Spatrick   if (expected != result) {
153061da546Spatrick     if (log)
154061da546Spatrick       *log << "Warning: Expected '" << expected.str() << "', got '" << result
155061da546Spatrick            << "\n";
156061da546Spatrick   }
157061da546Spatrick   return true;
158061da546Spatrick }
159