180814287SRaphael Isemann //===-- SBStream.cpp ------------------------------------------------------===//
2e2ae97f2SGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e2ae97f2SGreg Clayton //
7e2ae97f2SGreg Clayton //===----------------------------------------------------------------------===//
8e2ae97f2SGreg Clayton
9e2ae97f2SGreg Clayton #include "lldb/API/SBStream.h"
10e2ae97f2SGreg Clayton
1130cf6095SLawrence D'Anna #include "lldb/API/SBFile.h"
12e2ae97f2SGreg Clayton #include "lldb/Core/StreamFile.h"
1350bc1ed2SJonas Devlieghere #include "lldb/Host/FileSystem.h"
141755f5b1SJonas Devlieghere #include "lldb/Utility/Instrumentation.h"
15*c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
1697206d57SZachary Turner #include "lldb/Utility/Status.h"
17bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
18bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
19e2ae97f2SGreg Clayton
20e2ae97f2SGreg Clayton using namespace lldb;
21e2ae97f2SGreg Clayton using namespace lldb_private;
22e2ae97f2SGreg Clayton
SBStream()239494c510SJonas Devlieghere SBStream::SBStream() : m_opaque_up(new StreamString()) {
241755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this);
25baf5664fSJonas Devlieghere }
26e2ae97f2SGreg Clayton
SBStream(SBStream && rhs)27b9c1b51eSKate Stone SBStream::SBStream(SBStream &&rhs)
28d5b44036SJonas Devlieghere : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {}
290817da88SGreg Clayton
30866b7a65SJonas Devlieghere SBStream::~SBStream() = default;
310817da88SGreg Clayton
IsValid() const32baf5664fSJonas Devlieghere bool SBStream::IsValid() const {
331755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this);
347f5237bcSPavel Labath return this->operator bool();
357f5237bcSPavel Labath }
operator bool() const367f5237bcSPavel Labath SBStream::operator bool() const {
371755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this);
38baf5664fSJonas Devlieghere
39248a1305SKonrad Kleine return (m_opaque_up != nullptr);
40baf5664fSJonas Devlieghere }
41e2ae97f2SGreg Clayton
4205097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
4305097246SAdrian Prantl // for the stream data which can be accessed using this accessor.
GetData()44b9c1b51eSKate Stone const char *SBStream::GetData() {
451755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this);
46baf5664fSJonas Devlieghere
47248a1305SKonrad Kleine if (m_is_file || m_opaque_up == nullptr)
48248a1305SKonrad Kleine return nullptr;
49e2ae97f2SGreg Clayton
50d5b44036SJonas Devlieghere return static_cast<StreamString *>(m_opaque_up.get())->GetData();
51e2ae97f2SGreg Clayton }
52e2ae97f2SGreg Clayton
5305097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
5405097246SAdrian Prantl // for the stream output whose length can be accessed using this accessor.
GetSize()55b9c1b51eSKate Stone size_t SBStream::GetSize() {
561755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this);
57baf5664fSJonas Devlieghere
58248a1305SKonrad Kleine if (m_is_file || m_opaque_up == nullptr)
5960fd91ffSBill Wendling return 0;
60e2ae97f2SGreg Clayton
61d5b44036SJonas Devlieghere return static_cast<StreamString *>(m_opaque_up.get())->GetSize();
62e2ae97f2SGreg Clayton }
63e2ae97f2SGreg Clayton
Print(const char * str)64bfb27837SJonas Devlieghere void SBStream::Print(const char *str) {
651755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this, str);
66bfb27837SJonas Devlieghere
67bfb27837SJonas Devlieghere Printf("%s", str);
68bfb27837SJonas Devlieghere }
69bfb27837SJonas Devlieghere
Printf(const char * format,...)70b9c1b51eSKate Stone void SBStream::Printf(const char *format, ...) {
714f8189bcSJohnny Chen if (!format)
724f8189bcSJohnny Chen return;
73e2ae97f2SGreg Clayton va_list args;
74e2ae97f2SGreg Clayton va_start(args, format);
75e2ae97f2SGreg Clayton ref().PrintfVarArg(format, args);
76e2ae97f2SGreg Clayton va_end(args);
77e2ae97f2SGreg Clayton }
78e2ae97f2SGreg Clayton
RedirectToFile(const char * path,bool append)79b9c1b51eSKate Stone void SBStream::RedirectToFile(const char *path, bool append) {
801755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this, path, append);
81baf5664fSJonas Devlieghere
82e2dcbd00SZachary Turner if (path == nullptr)
83e2dcbd00SZachary Turner return;
84e2dcbd00SZachary Turner
85e2ae97f2SGreg Clayton std::string local_data;
86d5b44036SJonas Devlieghere if (m_opaque_up) {
87e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then
88e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data
89e2ae97f2SGreg Clayton if (!m_is_file)
90adcd0268SBenjamin Kramer local_data = std::string(
91adcd0268SBenjamin Kramer static_cast<StreamString *>(m_opaque_up.get())->GetString());
92e2ae97f2SGreg Clayton }
9314735cabSMichał Górny auto open_options = File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;
9451b1e2d2SGreg Clayton if (append)
9551b1e2d2SGreg Clayton open_options |= File::eOpenOptionAppend;
9606357c93SGreg Clayton else
9706357c93SGreg Clayton open_options |= File::eOpenOptionTruncate;
9851b1e2d2SGreg Clayton
992fce1137SLawrence D'Anna llvm::Expected<FileUP> file =
1002fce1137SLawrence D'Anna FileSystem::Instance().Open(FileSpec(path), open_options);
1012fce1137SLawrence D'Anna if (!file) {
102a007a6d8SPavel Labath LLDB_LOG_ERROR(GetLog(LLDBLog::API), file.takeError(),
1032fce1137SLawrence D'Anna "Cannot open {1}: {0}", path);
1042fce1137SLawrence D'Anna return;
1052fce1137SLawrence D'Anna }
106e2ae97f2SGreg Clayton
1072fce1137SLawrence D'Anna m_opaque_up = std::make_unique<StreamFile>(std::move(file.get()));
108e2ae97f2SGreg Clayton m_is_file = true;
109e2ae97f2SGreg Clayton
110e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to
111e2ae97f2SGreg Clayton // the to new file we are redirecting to.
112e2ae97f2SGreg Clayton if (!local_data.empty())
113d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size());
114e2ae97f2SGreg Clayton }
115e2ae97f2SGreg Clayton
RedirectToFileHandle(FILE * fh,bool transfer_fh_ownership)116b9c1b51eSKate Stone void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
1171755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this, fh, transfer_fh_ownership);
11830cf6095SLawrence D'Anna FileSP file = std::make_unique<NativeFile>(fh, transfer_fh_ownership);
11930cf6095SLawrence D'Anna return RedirectToFile(file);
12030cf6095SLawrence D'Anna }
121baf5664fSJonas Devlieghere
RedirectToFile(SBFile file)12230cf6095SLawrence D'Anna void SBStream::RedirectToFile(SBFile file) {
1231755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this, file)
12430cf6095SLawrence D'Anna RedirectToFile(file.GetFile());
12530cf6095SLawrence D'Anna }
12630cf6095SLawrence D'Anna
RedirectToFile(FileSP file_sp)12730cf6095SLawrence D'Anna void SBStream::RedirectToFile(FileSP file_sp) {
1281755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this, file_sp);
12930cf6095SLawrence D'Anna
13030cf6095SLawrence D'Anna if (!file_sp || !file_sp->IsValid())
131e2dcbd00SZachary Turner return;
132e2dcbd00SZachary Turner
133e2ae97f2SGreg Clayton std::string local_data;
134d5b44036SJonas Devlieghere if (m_opaque_up) {
135e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then
136e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data
137e2ae97f2SGreg Clayton if (!m_is_file)
138adcd0268SBenjamin Kramer local_data = std::string(
139adcd0268SBenjamin Kramer static_cast<StreamString *>(m_opaque_up.get())->GetString());
140e2ae97f2SGreg Clayton }
141e2ae97f2SGreg Clayton
14230cf6095SLawrence D'Anna m_opaque_up = std::make_unique<StreamFile>(file_sp);
143e2ae97f2SGreg Clayton m_is_file = true;
144e2ae97f2SGreg Clayton
145e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to
146e2ae97f2SGreg Clayton // the to new file we are redirecting to.
147e2ae97f2SGreg Clayton if (!local_data.empty())
148d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size());
149e2ae97f2SGreg Clayton }
150e2ae97f2SGreg Clayton
RedirectToFileDescriptor(int fd,bool transfer_fh_ownership)151b9c1b51eSKate Stone void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) {
1521755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this, fd, transfer_fh_ownership);
153baf5664fSJonas Devlieghere
154e2ae97f2SGreg Clayton std::string local_data;
155d5b44036SJonas Devlieghere if (m_opaque_up) {
156e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then
157e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data
158e2ae97f2SGreg Clayton if (!m_is_file)
159adcd0268SBenjamin Kramer local_data = std::string(
160adcd0268SBenjamin Kramer static_cast<StreamString *>(m_opaque_up.get())->GetString());
161e2ae97f2SGreg Clayton }
162e2ae97f2SGreg Clayton
1632fce1137SLawrence D'Anna m_opaque_up = std::make_unique<StreamFile>(fd, transfer_fh_ownership);
164e2ae97f2SGreg Clayton m_is_file = true;
165e2ae97f2SGreg Clayton
166e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to
167e2ae97f2SGreg Clayton // the to new file we are redirecting to.
168e2ae97f2SGreg Clayton if (!local_data.empty())
169d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size());
170e2ae97f2SGreg Clayton }
171e2ae97f2SGreg Clayton
operator ->()172d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); }
173e2ae97f2SGreg Clayton
get()174d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); }
175e2ae97f2SGreg Clayton
ref()176b9c1b51eSKate Stone lldb_private::Stream &SBStream::ref() {
177248a1305SKonrad Kleine if (m_opaque_up == nullptr)
1781c0bbe43SJonas Devlieghere m_opaque_up = std::make_unique<StreamString>();
179d5b44036SJonas Devlieghere return *m_opaque_up;
180e2ae97f2SGreg Clayton }
181e2ae97f2SGreg Clayton
Clear()182b9c1b51eSKate Stone void SBStream::Clear() {
1831755f5b1SJonas Devlieghere LLDB_INSTRUMENT_VA(this);
184baf5664fSJonas Devlieghere
185d5b44036SJonas Devlieghere if (m_opaque_up) {
186e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then
187e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data
188e2ae97f2SGreg Clayton if (m_is_file)
189d5b44036SJonas Devlieghere m_opaque_up.reset();
190e2ae97f2SGreg Clayton else
191d5b44036SJonas Devlieghere static_cast<StreamString *>(m_opaque_up.get())->Clear();
192e2ae97f2SGreg Clayton }
193e2ae97f2SGreg Clayton }
194