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 
11*baf5664fSJonas 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 
21*baf5664fSJonas Devlieghere SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) {
22*baf5664fSJonas Devlieghere   LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream);
23*baf5664fSJonas 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 
30*baf5664fSJonas Devlieghere bool SBStream::IsValid() const {
31*baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid);
32*baf5664fSJonas Devlieghere 
33*baf5664fSJonas Devlieghere   return (m_opaque_up != NULL);
34*baf5664fSJonas Devlieghere }
35e2ae97f2SGreg Clayton 
3605097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
3705097246SAdrian Prantl // for the stream data which can be accessed using this accessor.
38b9c1b51eSKate Stone const char *SBStream::GetData() {
39*baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData);
40*baf5664fSJonas Devlieghere 
41d5b44036SJonas Devlieghere   if (m_is_file || m_opaque_up == NULL)
42e2ae97f2SGreg Clayton     return NULL;
43e2ae97f2SGreg Clayton 
44d5b44036SJonas Devlieghere   return static_cast<StreamString *>(m_opaque_up.get())->GetData();
45e2ae97f2SGreg Clayton }
46e2ae97f2SGreg Clayton 
4705097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
4805097246SAdrian Prantl // for the stream output whose length can be accessed using this accessor.
49b9c1b51eSKate Stone size_t SBStream::GetSize() {
50*baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize);
51*baf5664fSJonas Devlieghere 
52d5b44036SJonas Devlieghere   if (m_is_file || m_opaque_up == NULL)
5360fd91ffSBill Wendling     return 0;
54e2ae97f2SGreg Clayton 
55d5b44036SJonas Devlieghere   return static_cast<StreamString *>(m_opaque_up.get())->GetSize();
56e2ae97f2SGreg Clayton }
57e2ae97f2SGreg Clayton 
58b9c1b51eSKate Stone void SBStream::Printf(const char *format, ...) {
594f8189bcSJohnny Chen   if (!format)
604f8189bcSJohnny Chen     return;
61e2ae97f2SGreg Clayton   va_list args;
62e2ae97f2SGreg Clayton   va_start(args, format);
63e2ae97f2SGreg Clayton   ref().PrintfVarArg(format, args);
64e2ae97f2SGreg Clayton   va_end(args);
65e2ae97f2SGreg Clayton }
66e2ae97f2SGreg Clayton 
67b9c1b51eSKate Stone void SBStream::RedirectToFile(const char *path, bool append) {
68*baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path,
69*baf5664fSJonas Devlieghere                      append);
70*baf5664fSJonas Devlieghere 
71e2dcbd00SZachary Turner   if (path == nullptr)
72e2dcbd00SZachary Turner     return;
73e2dcbd00SZachary Turner 
74e2ae97f2SGreg Clayton   std::string local_data;
75d5b44036SJonas Devlieghere   if (m_opaque_up) {
76e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
77e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
78e2ae97f2SGreg Clayton     if (!m_is_file)
79d5b44036SJonas Devlieghere       local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString();
80e2ae97f2SGreg Clayton   }
8151b1e2d2SGreg Clayton   StreamFile *stream_file = new StreamFile;
8251b1e2d2SGreg Clayton   uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
8351b1e2d2SGreg Clayton   if (append)
8451b1e2d2SGreg Clayton     open_options |= File::eOpenOptionAppend;
8506357c93SGreg Clayton   else
8606357c93SGreg Clayton     open_options |= File::eOpenOptionTruncate;
8751b1e2d2SGreg Clayton 
8850bc1ed2SJonas Devlieghere   FileSystem::Instance().Open(stream_file->GetFile(), FileSpec(path),
8950bc1ed2SJonas Devlieghere                               open_options);
90d5b44036SJonas Devlieghere   m_opaque_up.reset(stream_file);
91e2ae97f2SGreg Clayton 
92d5b44036SJonas Devlieghere   if (m_opaque_up) {
93e2ae97f2SGreg Clayton     m_is_file = true;
94e2ae97f2SGreg Clayton 
95e2ae97f2SGreg Clayton     // If we had any data locally in our StreamString, then pass that along to
96e2ae97f2SGreg Clayton     // the to new file we are redirecting to.
97e2ae97f2SGreg Clayton     if (!local_data.empty())
98d5b44036SJonas Devlieghere       m_opaque_up->Write(&local_data[0], local_data.size());
99b9c1b51eSKate Stone   } else
100e2ae97f2SGreg Clayton     m_is_file = false;
101e2ae97f2SGreg Clayton }
102e2ae97f2SGreg Clayton 
103b9c1b51eSKate Stone void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
104*baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh,
105*baf5664fSJonas Devlieghere                      transfer_fh_ownership);
106*baf5664fSJonas Devlieghere 
107e2dcbd00SZachary Turner   if (fh == nullptr)
108e2dcbd00SZachary Turner     return;
109e2dcbd00SZachary Turner 
110e2ae97f2SGreg Clayton   std::string local_data;
111d5b44036SJonas Devlieghere   if (m_opaque_up) {
112e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
113e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
114e2ae97f2SGreg Clayton     if (!m_is_file)
115d5b44036SJonas Devlieghere       local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString();
116e2ae97f2SGreg Clayton   }
117d5b44036SJonas Devlieghere   m_opaque_up.reset(new StreamFile(fh, transfer_fh_ownership));
118e2ae97f2SGreg Clayton 
119d5b44036SJonas Devlieghere   if (m_opaque_up) {
120e2ae97f2SGreg Clayton     m_is_file = true;
121e2ae97f2SGreg Clayton 
122e2ae97f2SGreg Clayton     // If we had any data locally in our StreamString, then pass that along to
123e2ae97f2SGreg Clayton     // the to new file we are redirecting to.
124e2ae97f2SGreg Clayton     if (!local_data.empty())
125d5b44036SJonas Devlieghere       m_opaque_up->Write(&local_data[0], local_data.size());
126b9c1b51eSKate Stone   } else
127e2ae97f2SGreg Clayton     m_is_file = false;
128e2ae97f2SGreg Clayton }
129e2ae97f2SGreg Clayton 
130b9c1b51eSKate Stone void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) {
131*baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd,
132*baf5664fSJonas Devlieghere                      transfer_fh_ownership);
133*baf5664fSJonas Devlieghere 
134e2ae97f2SGreg Clayton   std::string local_data;
135d5b44036SJonas Devlieghere   if (m_opaque_up) {
136e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
137e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
138e2ae97f2SGreg Clayton     if (!m_is_file)
139d5b44036SJonas Devlieghere       local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString();
140e2ae97f2SGreg Clayton   }
141e2ae97f2SGreg Clayton 
142d5b44036SJonas Devlieghere   m_opaque_up.reset(new StreamFile(::fdopen(fd, "w"), transfer_fh_ownership));
143d5b44036SJonas Devlieghere   if (m_opaque_up) {
144e2ae97f2SGreg Clayton     m_is_file = true;
145e2ae97f2SGreg Clayton 
146e2ae97f2SGreg Clayton     // If we had any data locally in our StreamString, then pass that along to
147e2ae97f2SGreg Clayton     // the to new file we are redirecting to.
148e2ae97f2SGreg Clayton     if (!local_data.empty())
149d5b44036SJonas Devlieghere       m_opaque_up->Write(&local_data[0], local_data.size());
150b9c1b51eSKate Stone   } else
151e2ae97f2SGreg Clayton     m_is_file = false;
152e2ae97f2SGreg Clayton }
153e2ae97f2SGreg Clayton 
154d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); }
155e2ae97f2SGreg Clayton 
156d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); }
157e2ae97f2SGreg Clayton 
158b9c1b51eSKate Stone lldb_private::Stream &SBStream::ref() {
159d5b44036SJonas Devlieghere   if (m_opaque_up == NULL)
160d5b44036SJonas Devlieghere     m_opaque_up.reset(new StreamString());
161d5b44036SJonas Devlieghere   return *m_opaque_up;
162e2ae97f2SGreg Clayton }
163e2ae97f2SGreg Clayton 
164b9c1b51eSKate Stone void SBStream::Clear() {
165*baf5664fSJonas Devlieghere   LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear);
166*baf5664fSJonas Devlieghere 
167d5b44036SJonas Devlieghere   if (m_opaque_up) {
168e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
169e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
170e2ae97f2SGreg Clayton     if (m_is_file)
171d5b44036SJonas Devlieghere       m_opaque_up.reset();
172e2ae97f2SGreg Clayton     else
173d5b44036SJonas Devlieghere       static_cast<StreamString *>(m_opaque_up.get())->Clear();
174e2ae97f2SGreg Clayton   }
175e2ae97f2SGreg Clayton }
176