1e2ae97f2SGreg Clayton //===-- SBStream.cpp ----------------------------------------*- C++ -*-===//
2e2ae97f2SGreg Clayton //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler 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 
11e2ae97f2SGreg Clayton #include "lldb/Core/StreamFile.h"
1250bc1ed2SJonas Devlieghere #include "lldb/Host/FileSystem.h"
1397206d57SZachary Turner #include "lldb/Utility/Status.h"
14bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
15bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
16e2ae97f2SGreg Clayton 
17e2ae97f2SGreg Clayton using namespace lldb;
18e2ae97f2SGreg Clayton using namespace lldb_private;
19e2ae97f2SGreg Clayton 
20b9c1b51eSKate Stone SBStream::SBStream() : m_opaque_ap(new StreamString()), m_is_file(false) {}
21e2ae97f2SGreg Clayton 
22b9c1b51eSKate Stone SBStream::SBStream(SBStream &&rhs)
23b9c1b51eSKate Stone     : m_opaque_ap(std::move(rhs.m_opaque_ap)), m_is_file(rhs.m_is_file) {}
240817da88SGreg Clayton 
25b9c1b51eSKate Stone SBStream::~SBStream() {}
260817da88SGreg Clayton 
273447077aSJonas Devlieghere bool SBStream::IsValid() const { return (m_opaque_ap != NULL); }
28e2ae97f2SGreg Clayton 
2905097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
3005097246SAdrian Prantl // for the stream data which can be accessed using this accessor.
31b9c1b51eSKate Stone const char *SBStream::GetData() {
323447077aSJonas Devlieghere   if (m_is_file || m_opaque_ap == NULL)
33e2ae97f2SGreg Clayton     return NULL;
34e2ae97f2SGreg Clayton 
35e2ae97f2SGreg Clayton   return static_cast<StreamString *>(m_opaque_ap.get())->GetData();
36e2ae97f2SGreg Clayton }
37e2ae97f2SGreg Clayton 
3805097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
3905097246SAdrian Prantl // for the stream output whose length can be accessed using this accessor.
40b9c1b51eSKate Stone size_t SBStream::GetSize() {
413447077aSJonas Devlieghere   if (m_is_file || m_opaque_ap == NULL)
4260fd91ffSBill Wendling     return 0;
43e2ae97f2SGreg Clayton 
44e2ae97f2SGreg Clayton   return static_cast<StreamString *>(m_opaque_ap.get())->GetSize();
45e2ae97f2SGreg Clayton }
46e2ae97f2SGreg Clayton 
47b9c1b51eSKate Stone void SBStream::Printf(const char *format, ...) {
484f8189bcSJohnny Chen   if (!format)
494f8189bcSJohnny Chen     return;
50e2ae97f2SGreg Clayton   va_list args;
51e2ae97f2SGreg Clayton   va_start(args, format);
52e2ae97f2SGreg Clayton   ref().PrintfVarArg(format, args);
53e2ae97f2SGreg Clayton   va_end(args);
54e2ae97f2SGreg Clayton }
55e2ae97f2SGreg Clayton 
56b9c1b51eSKate Stone void SBStream::RedirectToFile(const char *path, bool append) {
57e2dcbd00SZachary Turner   if (path == nullptr)
58e2dcbd00SZachary Turner     return;
59e2dcbd00SZachary Turner 
60e2ae97f2SGreg Clayton   std::string local_data;
613447077aSJonas Devlieghere   if (m_opaque_ap) {
62e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
63e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
64e2ae97f2SGreg Clayton     if (!m_is_file)
65c156427dSZachary Turner       local_data = static_cast<StreamString *>(m_opaque_ap.get())->GetString();
66e2ae97f2SGreg Clayton   }
6751b1e2d2SGreg Clayton   StreamFile *stream_file = new StreamFile;
6851b1e2d2SGreg Clayton   uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
6951b1e2d2SGreg Clayton   if (append)
7051b1e2d2SGreg Clayton     open_options |= File::eOpenOptionAppend;
7106357c93SGreg Clayton   else
7206357c93SGreg Clayton     open_options |= File::eOpenOptionTruncate;
7351b1e2d2SGreg Clayton 
7450bc1ed2SJonas Devlieghere   FileSystem::Instance().Open(stream_file->GetFile(), FileSpec(path),
7550bc1ed2SJonas Devlieghere                               open_options);
7651b1e2d2SGreg Clayton   m_opaque_ap.reset(stream_file);
77e2ae97f2SGreg Clayton 
783447077aSJonas Devlieghere   if (m_opaque_ap) {
79e2ae97f2SGreg Clayton     m_is_file = true;
80e2ae97f2SGreg Clayton 
81e2ae97f2SGreg Clayton     // If we had any data locally in our StreamString, then pass that along to
82e2ae97f2SGreg Clayton     // the to new file we are redirecting to.
83e2ae97f2SGreg Clayton     if (!local_data.empty())
84e2ae97f2SGreg Clayton       m_opaque_ap->Write(&local_data[0], local_data.size());
85b9c1b51eSKate Stone   } else
86e2ae97f2SGreg Clayton     m_is_file = false;
87e2ae97f2SGreg Clayton }
88e2ae97f2SGreg Clayton 
89b9c1b51eSKate Stone void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
90e2dcbd00SZachary Turner   if (fh == nullptr)
91e2dcbd00SZachary Turner     return;
92e2dcbd00SZachary Turner 
93e2ae97f2SGreg Clayton   std::string local_data;
943447077aSJonas Devlieghere   if (m_opaque_ap) {
95e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
96e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
97e2ae97f2SGreg Clayton     if (!m_is_file)
98c156427dSZachary Turner       local_data = static_cast<StreamString *>(m_opaque_ap.get())->GetString();
99e2ae97f2SGreg Clayton   }
100e2ae97f2SGreg Clayton   m_opaque_ap.reset(new StreamFile(fh, transfer_fh_ownership));
101e2ae97f2SGreg Clayton 
1023447077aSJonas Devlieghere   if (m_opaque_ap) {
103e2ae97f2SGreg Clayton     m_is_file = true;
104e2ae97f2SGreg Clayton 
105e2ae97f2SGreg Clayton     // If we had any data locally in our StreamString, then pass that along to
106e2ae97f2SGreg Clayton     // the to new file we are redirecting to.
107e2ae97f2SGreg Clayton     if (!local_data.empty())
108e2ae97f2SGreg Clayton       m_opaque_ap->Write(&local_data[0], local_data.size());
109b9c1b51eSKate Stone   } else
110e2ae97f2SGreg Clayton     m_is_file = false;
111e2ae97f2SGreg Clayton }
112e2ae97f2SGreg Clayton 
113b9c1b51eSKate Stone void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) {
114e2ae97f2SGreg Clayton   std::string local_data;
1153447077aSJonas Devlieghere   if (m_opaque_ap) {
116e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
117e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
118e2ae97f2SGreg Clayton     if (!m_is_file)
119c156427dSZachary Turner       local_data = static_cast<StreamString *>(m_opaque_ap.get())->GetString();
120e2ae97f2SGreg Clayton   }
121e2ae97f2SGreg Clayton 
122e2ae97f2SGreg Clayton   m_opaque_ap.reset(new StreamFile(::fdopen(fd, "w"), transfer_fh_ownership));
1233447077aSJonas Devlieghere   if (m_opaque_ap) {
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())
129e2ae97f2SGreg Clayton       m_opaque_ap->Write(&local_data[0], local_data.size());
130b9c1b51eSKate Stone   } else
131e2ae97f2SGreg Clayton     m_is_file = false;
132e2ae97f2SGreg Clayton }
133e2ae97f2SGreg Clayton 
134b9c1b51eSKate Stone lldb_private::Stream *SBStream::operator->() { return m_opaque_ap.get(); }
135e2ae97f2SGreg Clayton 
136b9c1b51eSKate Stone lldb_private::Stream *SBStream::get() { return m_opaque_ap.get(); }
137e2ae97f2SGreg Clayton 
138b9c1b51eSKate Stone lldb_private::Stream &SBStream::ref() {
1393447077aSJonas Devlieghere   if (m_opaque_ap == NULL)
140e2ae97f2SGreg Clayton     m_opaque_ap.reset(new StreamString());
1413447077aSJonas Devlieghere   return *m_opaque_ap;
142e2ae97f2SGreg Clayton }
143e2ae97f2SGreg Clayton 
144b9c1b51eSKate Stone void SBStream::Clear() {
1453447077aSJonas Devlieghere   if (m_opaque_ap) {
146e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
147e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
148e2ae97f2SGreg Clayton     if (m_is_file)
149e2ae97f2SGreg Clayton       m_opaque_ap.reset();
150e2ae97f2SGreg Clayton     else
151c156427dSZachary Turner       static_cast<StreamString *>(m_opaque_ap.get())->Clear();
152e2ae97f2SGreg Clayton   }
153e2ae97f2SGreg Clayton }
154