1e2ae97f2SGreg Clayton //===-- SBStream.cpp ----------------------------------------*- C++ -*-===//
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 
11baf5664fSJonas Devlieghere #include "SBReproducerPrivate.h"
12e2ae97f2SGreg Clayton #include "lldb/Core/StreamFile.h"
1350bc1ed2SJonas Devlieghere #include "lldb/Host/FileSystem.h"
1497206d57SZachary Turner #include "lldb/Utility/Status.h"
15bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
16bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
17e2ae97f2SGreg Clayton 
18e2ae97f2SGreg Clayton using namespace lldb;
19e2ae97f2SGreg Clayton using namespace lldb_private;
20e2ae97f2SGreg Clayton 
21baf5664fSJonas Devlieghere SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) {
22baf5664fSJonas Devlieghere   LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream);
23baf5664fSJonas Devlieghere }
24e2ae97f2SGreg Clayton 
25b9c1b51eSKate Stone SBStream::SBStream(SBStream &&rhs)
26d5b44036SJonas Devlieghere     : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {}
270817da88SGreg Clayton 
28b9c1b51eSKate Stone SBStream::~SBStream() {}
290817da88SGreg Clayton 
30baf5664fSJonas Devlieghere bool SBStream::IsValid() const {
31baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid);
327f5237bcSPavel Labath   return this->operator bool();
337f5237bcSPavel Labath }
347f5237bcSPavel Labath SBStream::operator bool() const {
357f5237bcSPavel Labath   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, operator bool);
36baf5664fSJonas Devlieghere 
37248a1305SKonrad Kleine   return (m_opaque_up != nullptr);
38baf5664fSJonas Devlieghere }
39e2ae97f2SGreg Clayton 
4005097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
4105097246SAdrian Prantl // for the stream data which can be accessed using this accessor.
42b9c1b51eSKate Stone const char *SBStream::GetData() {
43baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData);
44baf5664fSJonas Devlieghere 
45248a1305SKonrad Kleine   if (m_is_file || m_opaque_up == nullptr)
46248a1305SKonrad Kleine     return nullptr;
47e2ae97f2SGreg Clayton 
48d5b44036SJonas Devlieghere   return static_cast<StreamString *>(m_opaque_up.get())->GetData();
49e2ae97f2SGreg Clayton }
50e2ae97f2SGreg Clayton 
5105097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
5205097246SAdrian Prantl // for the stream output whose length can be accessed using this accessor.
53b9c1b51eSKate Stone size_t SBStream::GetSize() {
54baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize);
55baf5664fSJonas Devlieghere 
56248a1305SKonrad Kleine   if (m_is_file || m_opaque_up == nullptr)
5760fd91ffSBill Wendling     return 0;
58e2ae97f2SGreg Clayton 
59d5b44036SJonas Devlieghere   return static_cast<StreamString *>(m_opaque_up.get())->GetSize();
60e2ae97f2SGreg Clayton }
61e2ae97f2SGreg Clayton 
62b9c1b51eSKate Stone void SBStream::Printf(const char *format, ...) {
634f8189bcSJohnny Chen   if (!format)
644f8189bcSJohnny Chen     return;
65e2ae97f2SGreg Clayton   va_list args;
66e2ae97f2SGreg Clayton   va_start(args, format);
67e2ae97f2SGreg Clayton   ref().PrintfVarArg(format, args);
68e2ae97f2SGreg Clayton   va_end(args);
69e2ae97f2SGreg Clayton }
70e2ae97f2SGreg Clayton 
71b9c1b51eSKate Stone void SBStream::RedirectToFile(const char *path, bool append) {
72baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path,
73baf5664fSJonas Devlieghere                      append);
74baf5664fSJonas Devlieghere 
75e2dcbd00SZachary Turner   if (path == nullptr)
76e2dcbd00SZachary Turner     return;
77e2dcbd00SZachary Turner 
78e2ae97f2SGreg Clayton   std::string local_data;
79d5b44036SJonas Devlieghere   if (m_opaque_up) {
80e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
81e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
82e2ae97f2SGreg Clayton     if (!m_is_file)
83d5b44036SJonas Devlieghere       local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString();
84e2ae97f2SGreg Clayton   }
8551b1e2d2SGreg Clayton   uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
8651b1e2d2SGreg Clayton   if (append)
8751b1e2d2SGreg Clayton     open_options |= File::eOpenOptionAppend;
8806357c93SGreg Clayton   else
8906357c93SGreg Clayton     open_options |= File::eOpenOptionTruncate;
9051b1e2d2SGreg Clayton 
91*2fce1137SLawrence D'Anna   llvm::Expected<FileUP> file =
92*2fce1137SLawrence D'Anna       FileSystem::Instance().Open(FileSpec(path), open_options);
93*2fce1137SLawrence D'Anna   if (!file) {
94*2fce1137SLawrence D'Anna     LLDB_LOG_ERROR(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), file.takeError(),
95*2fce1137SLawrence D'Anna                    "Cannot open {1}: {0}", path);
96*2fce1137SLawrence D'Anna     return;
97*2fce1137SLawrence D'Anna   }
98e2ae97f2SGreg Clayton 
99*2fce1137SLawrence D'Anna   m_opaque_up = std::make_unique<StreamFile>(std::move(file.get()));
100e2ae97f2SGreg Clayton   m_is_file = true;
101e2ae97f2SGreg Clayton 
102e2ae97f2SGreg Clayton   // If we had any data locally in our StreamString, then pass that along to
103e2ae97f2SGreg Clayton   // the to new file we are redirecting to.
104e2ae97f2SGreg Clayton   if (!local_data.empty())
105d5b44036SJonas Devlieghere     m_opaque_up->Write(&local_data[0], local_data.size());
106e2ae97f2SGreg Clayton }
107e2ae97f2SGreg Clayton 
108b9c1b51eSKate Stone void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
109baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh,
110baf5664fSJonas Devlieghere                      transfer_fh_ownership);
111baf5664fSJonas Devlieghere 
112e2dcbd00SZachary Turner   if (fh == nullptr)
113e2dcbd00SZachary Turner     return;
114e2dcbd00SZachary Turner 
115e2ae97f2SGreg Clayton   std::string local_data;
116d5b44036SJonas Devlieghere   if (m_opaque_up) {
117e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
118e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
119e2ae97f2SGreg Clayton     if (!m_is_file)
120d5b44036SJonas Devlieghere       local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString();
121e2ae97f2SGreg Clayton   }
122e2ae97f2SGreg Clayton 
123*2fce1137SLawrence D'Anna   m_opaque_up = std::make_unique<StreamFile>(fh, transfer_fh_ownership);
124e2ae97f2SGreg Clayton   m_is_file = true;
125e2ae97f2SGreg Clayton 
126e2ae97f2SGreg Clayton   // If we had any data locally in our StreamString, then pass that along to
127e2ae97f2SGreg Clayton   // the to new file we are redirecting to.
128e2ae97f2SGreg Clayton   if (!local_data.empty())
129d5b44036SJonas Devlieghere     m_opaque_up->Write(&local_data[0], local_data.size());
130e2ae97f2SGreg Clayton }
131e2ae97f2SGreg Clayton 
132b9c1b51eSKate Stone void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) {
133baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd,
134baf5664fSJonas Devlieghere                      transfer_fh_ownership);
135baf5664fSJonas Devlieghere 
136e2ae97f2SGreg Clayton   std::string local_data;
137d5b44036SJonas Devlieghere   if (m_opaque_up) {
138e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
139e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
140e2ae97f2SGreg Clayton     if (!m_is_file)
141d5b44036SJonas Devlieghere       local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString();
142e2ae97f2SGreg Clayton   }
143e2ae97f2SGreg Clayton 
144*2fce1137SLawrence D'Anna   m_opaque_up = std::make_unique<StreamFile>(fd, transfer_fh_ownership);
145e2ae97f2SGreg Clayton   m_is_file = true;
146e2ae97f2SGreg Clayton 
147e2ae97f2SGreg Clayton   // If we had any data locally in our StreamString, then pass that along to
148e2ae97f2SGreg Clayton   // the to new file we are redirecting to.
149e2ae97f2SGreg Clayton   if (!local_data.empty())
150d5b44036SJonas Devlieghere     m_opaque_up->Write(&local_data[0], local_data.size());
151e2ae97f2SGreg Clayton }
152e2ae97f2SGreg Clayton 
153d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); }
154e2ae97f2SGreg Clayton 
155d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); }
156e2ae97f2SGreg Clayton 
157b9c1b51eSKate Stone lldb_private::Stream &SBStream::ref() {
158248a1305SKonrad Kleine   if (m_opaque_up == nullptr)
159d5b44036SJonas Devlieghere     m_opaque_up.reset(new StreamString());
160d5b44036SJonas Devlieghere   return *m_opaque_up;
161e2ae97f2SGreg Clayton }
162e2ae97f2SGreg Clayton 
163b9c1b51eSKate Stone void SBStream::Clear() {
164baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear);
165baf5664fSJonas Devlieghere 
166d5b44036SJonas Devlieghere   if (m_opaque_up) {
167e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
168e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
169e2ae97f2SGreg Clayton     if (m_is_file)
170d5b44036SJonas Devlieghere       m_opaque_up.reset();
171e2ae97f2SGreg Clayton     else
172d5b44036SJonas Devlieghere       static_cast<StreamString *>(m_opaque_up.get())->Clear();
173e2ae97f2SGreg Clayton   }
174e2ae97f2SGreg Clayton }
175ae211eceSMichal Gorny 
176ae211eceSMichal Gorny namespace lldb_private {
177ae211eceSMichal Gorny namespace repro {
178ae211eceSMichal Gorny 
179ae211eceSMichal Gorny template <>
180ae211eceSMichal Gorny void RegisterMethods<SBStream>(Registry &R) {
181ae211eceSMichal Gorny   LLDB_REGISTER_CONSTRUCTOR(SBStream, ());
182ae211eceSMichal Gorny   LLDB_REGISTER_METHOD_CONST(bool, SBStream, IsValid, ());
183ae211eceSMichal Gorny   LLDB_REGISTER_METHOD_CONST(bool, SBStream, operator bool, ());
184ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(const char *, SBStream, GetData, ());
185ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(size_t, SBStream, GetSize, ());
186ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (const char *, bool));
187ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool));
188ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool));
189ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(void, SBStream, Clear, ());
190ae211eceSMichal Gorny }
191ae211eceSMichal Gorny 
192ae211eceSMichal Gorny }
193ae211eceSMichal Gorny }
194