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 
11baf5664fSJonas Devlieghere #include "SBReproducerPrivate.h"
1230cf6095SLawrence D'Anna #include "lldb/API/SBFile.h"
13e2ae97f2SGreg Clayton #include "lldb/Core/StreamFile.h"
1450bc1ed2SJonas Devlieghere #include "lldb/Host/FileSystem.h"
1597206d57SZachary Turner #include "lldb/Utility/Status.h"
16bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
17bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
18e2ae97f2SGreg Clayton 
19e2ae97f2SGreg Clayton using namespace lldb;
20e2ae97f2SGreg Clayton using namespace lldb_private;
21e2ae97f2SGreg Clayton 
22baf5664fSJonas Devlieghere SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) {
23baf5664fSJonas Devlieghere   LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream);
24baf5664fSJonas Devlieghere }
25e2ae97f2SGreg Clayton 
26b9c1b51eSKate Stone SBStream::SBStream(SBStream &&rhs)
27d5b44036SJonas Devlieghere     : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {}
280817da88SGreg Clayton 
29b9c1b51eSKate Stone SBStream::~SBStream() {}
300817da88SGreg Clayton 
31baf5664fSJonas Devlieghere bool SBStream::IsValid() const {
32baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid);
337f5237bcSPavel Labath   return this->operator bool();
347f5237bcSPavel Labath }
357f5237bcSPavel Labath SBStream::operator bool() const {
367f5237bcSPavel Labath   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, operator bool);
37baf5664fSJonas Devlieghere 
38248a1305SKonrad Kleine   return (m_opaque_up != nullptr);
39baf5664fSJonas Devlieghere }
40e2ae97f2SGreg Clayton 
4105097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
4205097246SAdrian Prantl // for the stream data which can be accessed using this accessor.
43b9c1b51eSKate Stone const char *SBStream::GetData() {
44baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData);
45baf5664fSJonas Devlieghere 
46248a1305SKonrad Kleine   if (m_is_file || m_opaque_up == nullptr)
47248a1305SKonrad Kleine     return nullptr;
48e2ae97f2SGreg Clayton 
49d5b44036SJonas Devlieghere   return static_cast<StreamString *>(m_opaque_up.get())->GetData();
50e2ae97f2SGreg Clayton }
51e2ae97f2SGreg Clayton 
5205097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
5305097246SAdrian Prantl // for the stream output whose length can be accessed using this accessor.
54b9c1b51eSKate Stone size_t SBStream::GetSize() {
55baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize);
56baf5664fSJonas Devlieghere 
57248a1305SKonrad Kleine   if (m_is_file || m_opaque_up == nullptr)
5860fd91ffSBill Wendling     return 0;
59e2ae97f2SGreg Clayton 
60d5b44036SJonas Devlieghere   return static_cast<StreamString *>(m_opaque_up.get())->GetSize();
61e2ae97f2SGreg Clayton }
62e2ae97f2SGreg Clayton 
63b9c1b51eSKate Stone void SBStream::Printf(const char *format, ...) {
644f8189bcSJohnny Chen   if (!format)
654f8189bcSJohnny Chen     return;
66e2ae97f2SGreg Clayton   va_list args;
67e2ae97f2SGreg Clayton   va_start(args, format);
68e2ae97f2SGreg Clayton   ref().PrintfVarArg(format, args);
69e2ae97f2SGreg Clayton   va_end(args);
70e2ae97f2SGreg Clayton }
71e2ae97f2SGreg Clayton 
72b9c1b51eSKate Stone void SBStream::RedirectToFile(const char *path, bool append) {
73baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path,
74baf5664fSJonas Devlieghere                      append);
75baf5664fSJonas Devlieghere 
76e2dcbd00SZachary Turner   if (path == nullptr)
77e2dcbd00SZachary Turner     return;
78e2dcbd00SZachary Turner 
79e2ae97f2SGreg Clayton   std::string local_data;
80d5b44036SJonas Devlieghere   if (m_opaque_up) {
81e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
82e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
83e2ae97f2SGreg Clayton     if (!m_is_file)
84*adcd0268SBenjamin Kramer       local_data = std::string(
85*adcd0268SBenjamin Kramer           static_cast<StreamString *>(m_opaque_up.get())->GetString());
86e2ae97f2SGreg Clayton   }
8762c9fe42SLawrence D'Anna   auto open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
8851b1e2d2SGreg Clayton   if (append)
8951b1e2d2SGreg Clayton     open_options |= File::eOpenOptionAppend;
9006357c93SGreg Clayton   else
9106357c93SGreg Clayton     open_options |= File::eOpenOptionTruncate;
9251b1e2d2SGreg Clayton 
932fce1137SLawrence D'Anna   llvm::Expected<FileUP> file =
942fce1137SLawrence D'Anna       FileSystem::Instance().Open(FileSpec(path), open_options);
952fce1137SLawrence D'Anna   if (!file) {
962fce1137SLawrence D'Anna     LLDB_LOG_ERROR(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), file.takeError(),
972fce1137SLawrence D'Anna                    "Cannot open {1}: {0}", path);
982fce1137SLawrence D'Anna     return;
992fce1137SLawrence D'Anna   }
100e2ae97f2SGreg Clayton 
1012fce1137SLawrence D'Anna   m_opaque_up = std::make_unique<StreamFile>(std::move(file.get()));
102e2ae97f2SGreg Clayton   m_is_file = true;
103e2ae97f2SGreg Clayton 
104e2ae97f2SGreg Clayton   // If we had any data locally in our StreamString, then pass that along to
105e2ae97f2SGreg Clayton   // the to new file we are redirecting to.
106e2ae97f2SGreg Clayton   if (!local_data.empty())
107d5b44036SJonas Devlieghere     m_opaque_up->Write(&local_data[0], local_data.size());
108e2ae97f2SGreg Clayton }
109e2ae97f2SGreg Clayton 
110b9c1b51eSKate Stone void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
111baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh,
112baf5664fSJonas Devlieghere                      transfer_fh_ownership);
11330cf6095SLawrence D'Anna   FileSP file = std::make_unique<NativeFile>(fh, transfer_fh_ownership);
11430cf6095SLawrence D'Anna   return RedirectToFile(file);
11530cf6095SLawrence D'Anna }
116baf5664fSJonas Devlieghere 
11730cf6095SLawrence D'Anna void SBStream::RedirectToFile(SBFile file) {
11830cf6095SLawrence D'Anna   LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (SBFile), file)
11930cf6095SLawrence D'Anna   RedirectToFile(file.GetFile());
12030cf6095SLawrence D'Anna }
12130cf6095SLawrence D'Anna 
12230cf6095SLawrence D'Anna void SBStream::RedirectToFile(FileSP file_sp) {
12330cf6095SLawrence D'Anna   LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (FileSP), file_sp);
12430cf6095SLawrence D'Anna 
12530cf6095SLawrence D'Anna   if (!file_sp || !file_sp->IsValid())
126e2dcbd00SZachary Turner     return;
127e2dcbd00SZachary Turner 
128e2ae97f2SGreg Clayton   std::string local_data;
129d5b44036SJonas Devlieghere   if (m_opaque_up) {
130e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
131e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
132e2ae97f2SGreg Clayton     if (!m_is_file)
133*adcd0268SBenjamin Kramer       local_data = std::string(
134*adcd0268SBenjamin Kramer           static_cast<StreamString *>(m_opaque_up.get())->GetString());
135e2ae97f2SGreg Clayton   }
136e2ae97f2SGreg Clayton 
13730cf6095SLawrence D'Anna   m_opaque_up = std::make_unique<StreamFile>(file_sp);
138e2ae97f2SGreg Clayton   m_is_file = true;
139e2ae97f2SGreg Clayton 
140e2ae97f2SGreg Clayton   // If we had any data locally in our StreamString, then pass that along to
141e2ae97f2SGreg Clayton   // the to new file we are redirecting to.
142e2ae97f2SGreg Clayton   if (!local_data.empty())
143d5b44036SJonas Devlieghere     m_opaque_up->Write(&local_data[0], local_data.size());
144e2ae97f2SGreg Clayton }
145e2ae97f2SGreg Clayton 
146b9c1b51eSKate Stone void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) {
147baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd,
148baf5664fSJonas Devlieghere                      transfer_fh_ownership);
149baf5664fSJonas Devlieghere 
150e2ae97f2SGreg Clayton   std::string local_data;
151d5b44036SJonas Devlieghere   if (m_opaque_up) {
152e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
153e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
154e2ae97f2SGreg Clayton     if (!m_is_file)
155*adcd0268SBenjamin Kramer       local_data = std::string(
156*adcd0268SBenjamin Kramer           static_cast<StreamString *>(m_opaque_up.get())->GetString());
157e2ae97f2SGreg Clayton   }
158e2ae97f2SGreg Clayton 
1592fce1137SLawrence D'Anna   m_opaque_up = std::make_unique<StreamFile>(fd, transfer_fh_ownership);
160e2ae97f2SGreg Clayton   m_is_file = true;
161e2ae97f2SGreg Clayton 
162e2ae97f2SGreg Clayton   // If we had any data locally in our StreamString, then pass that along to
163e2ae97f2SGreg Clayton   // the to new file we are redirecting to.
164e2ae97f2SGreg Clayton   if (!local_data.empty())
165d5b44036SJonas Devlieghere     m_opaque_up->Write(&local_data[0], local_data.size());
166e2ae97f2SGreg Clayton }
167e2ae97f2SGreg Clayton 
168d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); }
169e2ae97f2SGreg Clayton 
170d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); }
171e2ae97f2SGreg Clayton 
172b9c1b51eSKate Stone lldb_private::Stream &SBStream::ref() {
173248a1305SKonrad Kleine   if (m_opaque_up == nullptr)
174d5b44036SJonas Devlieghere     m_opaque_up.reset(new StreamString());
175d5b44036SJonas Devlieghere   return *m_opaque_up;
176e2ae97f2SGreg Clayton }
177e2ae97f2SGreg Clayton 
178b9c1b51eSKate Stone void SBStream::Clear() {
179baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear);
180baf5664fSJonas Devlieghere 
181d5b44036SJonas Devlieghere   if (m_opaque_up) {
182e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
183e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
184e2ae97f2SGreg Clayton     if (m_is_file)
185d5b44036SJonas Devlieghere       m_opaque_up.reset();
186e2ae97f2SGreg Clayton     else
187d5b44036SJonas Devlieghere       static_cast<StreamString *>(m_opaque_up.get())->Clear();
188e2ae97f2SGreg Clayton   }
189e2ae97f2SGreg Clayton }
190ae211eceSMichal Gorny 
191ae211eceSMichal Gorny namespace lldb_private {
192ae211eceSMichal Gorny namespace repro {
193ae211eceSMichal Gorny 
194ae211eceSMichal Gorny template <>
195ae211eceSMichal Gorny void RegisterMethods<SBStream>(Registry &R) {
196ae211eceSMichal Gorny   LLDB_REGISTER_CONSTRUCTOR(SBStream, ());
197ae211eceSMichal Gorny   LLDB_REGISTER_METHOD_CONST(bool, SBStream, IsValid, ());
198ae211eceSMichal Gorny   LLDB_REGISTER_METHOD_CONST(bool, SBStream, operator bool, ());
199ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(const char *, SBStream, GetData, ());
200ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(size_t, SBStream, GetSize, ());
201ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (const char *, bool));
20230cf6095SLawrence D'Anna   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (FileSP));
20330cf6095SLawrence D'Anna   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (SBFile));
204ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool));
205ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool));
206ae211eceSMichal Gorny   LLDB_REGISTER_METHOD(void, SBStream, Clear, ());
207ae211eceSMichal Gorny }
208ae211eceSMichal Gorny 
209ae211eceSMichal Gorny }
210ae211eceSMichal Gorny }
211