xref: /llvm-project/lldb/tools/lldb-vscode/IOStream.cpp (revision 09c258ef6a2fcca2161488b214d53ef39891fa22)
101263c6cSJonas Devlieghere //===-- IOStream.cpp --------------------------------------------*- C++ -*-===//
201263c6cSJonas Devlieghere //
301263c6cSJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
401263c6cSJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information.
501263c6cSJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
601263c6cSJonas Devlieghere //
701263c6cSJonas Devlieghere //===----------------------------------------------------------------------===//
801263c6cSJonas Devlieghere 
901263c6cSJonas Devlieghere #include "IOStream.h"
1001263c6cSJonas Devlieghere 
1101263c6cSJonas Devlieghere #if defined(_WIN32)
1201263c6cSJonas Devlieghere #include <io.h>
1301263c6cSJonas Devlieghere #else
1401263c6cSJonas Devlieghere #include <netinet/in.h>
1501263c6cSJonas Devlieghere #include <sys/socket.h>
1601263c6cSJonas Devlieghere #include <unistd.h>
1701263c6cSJonas Devlieghere #endif
1801263c6cSJonas Devlieghere 
1901263c6cSJonas Devlieghere #include <fstream>
2001263c6cSJonas Devlieghere #include <string>
2101263c6cSJonas Devlieghere 
2201263c6cSJonas Devlieghere using namespace lldb_dap;
2301263c6cSJonas Devlieghere 
2401263c6cSJonas Devlieghere StreamDescriptor::StreamDescriptor() = default;
2501263c6cSJonas Devlieghere 
2601263c6cSJonas Devlieghere StreamDescriptor::StreamDescriptor(StreamDescriptor &&other) {
2701263c6cSJonas Devlieghere   *this = std::move(other);
2801263c6cSJonas Devlieghere }
2901263c6cSJonas Devlieghere 
3001263c6cSJonas Devlieghere StreamDescriptor::~StreamDescriptor() {
3101263c6cSJonas Devlieghere   if (!m_close)
3201263c6cSJonas Devlieghere     return;
3301263c6cSJonas Devlieghere 
3401263c6cSJonas Devlieghere   if (m_is_socket)
3501263c6cSJonas Devlieghere #if defined(_WIN32)
3601263c6cSJonas Devlieghere     ::closesocket(m_socket);
3701263c6cSJonas Devlieghere #else
3801263c6cSJonas Devlieghere     ::close(m_socket);
3901263c6cSJonas Devlieghere #endif
4001263c6cSJonas Devlieghere   else
4101263c6cSJonas Devlieghere     ::close(m_fd);
4201263c6cSJonas Devlieghere }
4301263c6cSJonas Devlieghere 
4401263c6cSJonas Devlieghere StreamDescriptor &StreamDescriptor::operator=(StreamDescriptor &&other) {
4501263c6cSJonas Devlieghere   m_close = other.m_close;
4601263c6cSJonas Devlieghere   other.m_close = false;
4701263c6cSJonas Devlieghere   m_is_socket = other.m_is_socket;
4801263c6cSJonas Devlieghere   if (m_is_socket)
4901263c6cSJonas Devlieghere     m_socket = other.m_socket;
5001263c6cSJonas Devlieghere   else
5101263c6cSJonas Devlieghere     m_fd = other.m_fd;
5201263c6cSJonas Devlieghere   return *this;
5301263c6cSJonas Devlieghere }
5401263c6cSJonas Devlieghere 
5501263c6cSJonas Devlieghere StreamDescriptor StreamDescriptor::from_socket(SOCKET s, bool close) {
5601263c6cSJonas Devlieghere   StreamDescriptor sd;
5701263c6cSJonas Devlieghere   sd.m_is_socket = true;
5801263c6cSJonas Devlieghere   sd.m_socket = s;
5901263c6cSJonas Devlieghere   sd.m_close = close;
6001263c6cSJonas Devlieghere   return sd;
6101263c6cSJonas Devlieghere }
6201263c6cSJonas Devlieghere 
6301263c6cSJonas Devlieghere StreamDescriptor StreamDescriptor::from_file(int fd, bool close) {
6401263c6cSJonas Devlieghere   StreamDescriptor sd;
6501263c6cSJonas Devlieghere   sd.m_is_socket = false;
6601263c6cSJonas Devlieghere   sd.m_fd = fd;
6701263c6cSJonas Devlieghere   sd.m_close = close;
6801263c6cSJonas Devlieghere   return sd;
6901263c6cSJonas Devlieghere }
7001263c6cSJonas Devlieghere 
7101263c6cSJonas Devlieghere bool OutputStream::write_full(llvm::StringRef str) {
7201263c6cSJonas Devlieghere   while (!str.empty()) {
7301263c6cSJonas Devlieghere     int bytes_written = 0;
7401263c6cSJonas Devlieghere     if (descriptor.m_is_socket)
7501263c6cSJonas Devlieghere       bytes_written = ::send(descriptor.m_socket, str.data(), str.size(), 0);
7601263c6cSJonas Devlieghere     else
7701263c6cSJonas Devlieghere       bytes_written = ::write(descriptor.m_fd, str.data(), str.size());
7801263c6cSJonas Devlieghere 
7901263c6cSJonas Devlieghere     if (bytes_written < 0) {
8001263c6cSJonas Devlieghere       if (errno == EINTR || errno == EAGAIN)
8101263c6cSJonas Devlieghere         continue;
8201263c6cSJonas Devlieghere       return false;
8301263c6cSJonas Devlieghere     }
8401263c6cSJonas Devlieghere     str = str.drop_front(bytes_written);
8501263c6cSJonas Devlieghere   }
8601263c6cSJonas Devlieghere 
8701263c6cSJonas Devlieghere   return true;
8801263c6cSJonas Devlieghere }
8901263c6cSJonas Devlieghere 
9001263c6cSJonas Devlieghere bool InputStream::read_full(std::ofstream *log, size_t length,
9101263c6cSJonas Devlieghere                             std::string &text) {
9201263c6cSJonas Devlieghere   std::string data;
9301263c6cSJonas Devlieghere   data.resize(length);
9401263c6cSJonas Devlieghere 
9501263c6cSJonas Devlieghere   char *ptr = &data[0];
9601263c6cSJonas Devlieghere   while (length != 0) {
9701263c6cSJonas Devlieghere     int bytes_read = 0;
9801263c6cSJonas Devlieghere     if (descriptor.m_is_socket)
9901263c6cSJonas Devlieghere       bytes_read = ::recv(descriptor.m_socket, ptr, length, 0);
10001263c6cSJonas Devlieghere     else
10101263c6cSJonas Devlieghere       bytes_read = ::read(descriptor.m_fd, ptr, length);
10201263c6cSJonas Devlieghere 
10301263c6cSJonas Devlieghere     if (bytes_read == 0) {
10401263c6cSJonas Devlieghere       if (log)
10501263c6cSJonas Devlieghere         *log << "End of file (EOF) reading from input file.\n";
10601263c6cSJonas Devlieghere       return false;
10701263c6cSJonas Devlieghere     }
10801263c6cSJonas Devlieghere     if (bytes_read < 0) {
10901263c6cSJonas Devlieghere       int reason = 0;
11001263c6cSJonas Devlieghere #if defined(_WIN32)
11101263c6cSJonas Devlieghere       if (descriptor.m_is_socket)
11201263c6cSJonas Devlieghere         reason = WSAGetLastError();
11301263c6cSJonas Devlieghere       else
11401263c6cSJonas Devlieghere         reason = errno;
11501263c6cSJonas Devlieghere #else
11601263c6cSJonas Devlieghere       reason = errno;
11701263c6cSJonas Devlieghere       if (reason == EINTR || reason == EAGAIN)
11801263c6cSJonas Devlieghere         continue;
11901263c6cSJonas Devlieghere #endif
12001263c6cSJonas Devlieghere 
12101263c6cSJonas Devlieghere       if (log)
12201263c6cSJonas Devlieghere         *log << "Error " << reason << " reading from input file.\n";
12301263c6cSJonas Devlieghere       return false;
12401263c6cSJonas Devlieghere     }
12501263c6cSJonas Devlieghere 
12601263c6cSJonas Devlieghere     assert(bytes_read >= 0 && (size_t)bytes_read <= length);
12701263c6cSJonas Devlieghere     ptr += bytes_read;
12801263c6cSJonas Devlieghere     length -= bytes_read;
12901263c6cSJonas Devlieghere   }
13001263c6cSJonas Devlieghere   text += data;
13101263c6cSJonas Devlieghere   return true;
13201263c6cSJonas Devlieghere }
13301263c6cSJonas Devlieghere 
13401263c6cSJonas Devlieghere bool InputStream::read_line(std::ofstream *log, std::string &line) {
13501263c6cSJonas Devlieghere   line.clear();
13601263c6cSJonas Devlieghere   while (true) {
13701263c6cSJonas Devlieghere     if (!read_full(log, 1, line))
13801263c6cSJonas Devlieghere       return false;
13901263c6cSJonas Devlieghere 
140*744f3891SKazu Hirata     if (llvm::StringRef(line).ends_with("\r\n"))
14101263c6cSJonas Devlieghere       break;
14201263c6cSJonas Devlieghere   }
14301263c6cSJonas Devlieghere   line.erase(line.size() - 2);
14401263c6cSJonas Devlieghere   return true;
14501263c6cSJonas Devlieghere }
14601263c6cSJonas Devlieghere 
14701263c6cSJonas Devlieghere bool InputStream::read_expected(std::ofstream *log, llvm::StringRef expected) {
14801263c6cSJonas Devlieghere   std::string result;
14901263c6cSJonas Devlieghere   if (!read_full(log, expected.size(), result))
15001263c6cSJonas Devlieghere     return false;
15101263c6cSJonas Devlieghere   if (expected != result) {
15201263c6cSJonas Devlieghere     if (log)
15301263c6cSJonas Devlieghere       *log << "Warning: Expected '" << expected.str() << "', got '" << result
15401263c6cSJonas Devlieghere            << "\n";
15501263c6cSJonas Devlieghere   }
15601263c6cSJonas Devlieghere   return true;
15701263c6cSJonas Devlieghere }
158