1e2ae97f2SGreg Clayton //===-- SBStream.cpp ----------------------------------------*- C++ -*-===//
2e2ae97f2SGreg Clayton //
3e2ae97f2SGreg Clayton //                     The LLVM Compiler Infrastructure
4e2ae97f2SGreg Clayton //
5e2ae97f2SGreg Clayton // This file is distributed under the University of Illinois Open Source
6e2ae97f2SGreg Clayton // License. See LICENSE.TXT for details.
7e2ae97f2SGreg Clayton //
8e2ae97f2SGreg Clayton //===----------------------------------------------------------------------===//
9e2ae97f2SGreg Clayton 
10e2ae97f2SGreg Clayton #include "lldb/API/SBStream.h"
11e2ae97f2SGreg Clayton 
12e2ae97f2SGreg Clayton #include "lldb/Core/StreamFile.h"
13*50bc1ed2SJonas 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 
21b9c1b51eSKate Stone SBStream::SBStream() : m_opaque_ap(new StreamString()), m_is_file(false) {}
22e2ae97f2SGreg Clayton 
23b9c1b51eSKate Stone SBStream::SBStream(SBStream &&rhs)
24b9c1b51eSKate Stone     : m_opaque_ap(std::move(rhs.m_opaque_ap)), m_is_file(rhs.m_is_file) {}
250817da88SGreg Clayton 
26b9c1b51eSKate Stone SBStream::~SBStream() {}
270817da88SGreg Clayton 
28b9c1b51eSKate Stone bool SBStream::IsValid() const { return (m_opaque_ap.get() != NULL); }
29e2ae97f2SGreg Clayton 
3005097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
3105097246SAdrian Prantl // for the stream data which can be accessed using this accessor.
32b9c1b51eSKate Stone const char *SBStream::GetData() {
33e2ae97f2SGreg Clayton   if (m_is_file || m_opaque_ap.get() == NULL)
34e2ae97f2SGreg Clayton     return NULL;
35e2ae97f2SGreg Clayton 
36e2ae97f2SGreg Clayton   return static_cast<StreamString *>(m_opaque_ap.get())->GetData();
37e2ae97f2SGreg Clayton }
38e2ae97f2SGreg Clayton 
3905097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache
4005097246SAdrian Prantl // for the stream output whose length can be accessed using this accessor.
41b9c1b51eSKate Stone size_t SBStream::GetSize() {
42e2ae97f2SGreg Clayton   if (m_is_file || m_opaque_ap.get() == NULL)
4360fd91ffSBill Wendling     return 0;
44e2ae97f2SGreg Clayton 
45e2ae97f2SGreg Clayton   return static_cast<StreamString *>(m_opaque_ap.get())->GetSize();
46e2ae97f2SGreg Clayton }
47e2ae97f2SGreg Clayton 
48b9c1b51eSKate Stone void SBStream::Printf(const char *format, ...) {
494f8189bcSJohnny Chen   if (!format)
504f8189bcSJohnny Chen     return;
51e2ae97f2SGreg Clayton   va_list args;
52e2ae97f2SGreg Clayton   va_start(args, format);
53e2ae97f2SGreg Clayton   ref().PrintfVarArg(format, args);
54e2ae97f2SGreg Clayton   va_end(args);
55e2ae97f2SGreg Clayton }
56e2ae97f2SGreg Clayton 
57b9c1b51eSKate Stone void SBStream::RedirectToFile(const char *path, bool append) {
58e2dcbd00SZachary Turner   if (path == nullptr)
59e2dcbd00SZachary Turner     return;
60e2dcbd00SZachary Turner 
61e2ae97f2SGreg Clayton   std::string local_data;
62b9c1b51eSKate Stone   if (m_opaque_ap.get()) {
63e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
64e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
65e2ae97f2SGreg Clayton     if (!m_is_file)
66c156427dSZachary Turner       local_data = static_cast<StreamString *>(m_opaque_ap.get())->GetString();
67e2ae97f2SGreg Clayton   }
6851b1e2d2SGreg Clayton   StreamFile *stream_file = new StreamFile;
6951b1e2d2SGreg Clayton   uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
7051b1e2d2SGreg Clayton   if (append)
7151b1e2d2SGreg Clayton     open_options |= File::eOpenOptionAppend;
7206357c93SGreg Clayton   else
7306357c93SGreg Clayton     open_options |= File::eOpenOptionTruncate;
7451b1e2d2SGreg Clayton 
75*50bc1ed2SJonas Devlieghere   FileSystem::Instance().Open(stream_file->GetFile(), FileSpec(path),
76*50bc1ed2SJonas Devlieghere                               open_options);
7751b1e2d2SGreg Clayton   m_opaque_ap.reset(stream_file);
78e2ae97f2SGreg Clayton 
79b9c1b51eSKate Stone   if (m_opaque_ap.get()) {
80e2ae97f2SGreg Clayton     m_is_file = true;
81e2ae97f2SGreg Clayton 
82e2ae97f2SGreg Clayton     // If we had any data locally in our StreamString, then pass that along to
83e2ae97f2SGreg Clayton     // the to new file we are redirecting to.
84e2ae97f2SGreg Clayton     if (!local_data.empty())
85e2ae97f2SGreg Clayton       m_opaque_ap->Write(&local_data[0], local_data.size());
86b9c1b51eSKate Stone   } else
87e2ae97f2SGreg Clayton     m_is_file = false;
88e2ae97f2SGreg Clayton }
89e2ae97f2SGreg Clayton 
90b9c1b51eSKate Stone void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
91e2dcbd00SZachary Turner   if (fh == nullptr)
92e2dcbd00SZachary Turner     return;
93e2dcbd00SZachary Turner 
94e2ae97f2SGreg Clayton   std::string local_data;
95b9c1b51eSKate Stone   if (m_opaque_ap.get()) {
96e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
97e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
98e2ae97f2SGreg Clayton     if (!m_is_file)
99c156427dSZachary Turner       local_data = static_cast<StreamString *>(m_opaque_ap.get())->GetString();
100e2ae97f2SGreg Clayton   }
101e2ae97f2SGreg Clayton   m_opaque_ap.reset(new StreamFile(fh, transfer_fh_ownership));
102e2ae97f2SGreg Clayton 
103b9c1b51eSKate Stone   if (m_opaque_ap.get()) {
104e2ae97f2SGreg Clayton     m_is_file = true;
105e2ae97f2SGreg Clayton 
106e2ae97f2SGreg Clayton     // If we had any data locally in our StreamString, then pass that along to
107e2ae97f2SGreg Clayton     // the to new file we are redirecting to.
108e2ae97f2SGreg Clayton     if (!local_data.empty())
109e2ae97f2SGreg Clayton       m_opaque_ap->Write(&local_data[0], local_data.size());
110b9c1b51eSKate Stone   } else
111e2ae97f2SGreg Clayton     m_is_file = false;
112e2ae97f2SGreg Clayton }
113e2ae97f2SGreg Clayton 
114b9c1b51eSKate Stone void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) {
115e2ae97f2SGreg Clayton   std::string local_data;
116b9c1b51eSKate Stone   if (m_opaque_ap.get()) {
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)
120c156427dSZachary Turner       local_data = static_cast<StreamString *>(m_opaque_ap.get())->GetString();
121e2ae97f2SGreg Clayton   }
122e2ae97f2SGreg Clayton 
123e2ae97f2SGreg Clayton   m_opaque_ap.reset(new StreamFile(::fdopen(fd, "w"), transfer_fh_ownership));
124b9c1b51eSKate Stone   if (m_opaque_ap.get()) {
125e2ae97f2SGreg Clayton     m_is_file = true;
126e2ae97f2SGreg Clayton 
127e2ae97f2SGreg Clayton     // If we had any data locally in our StreamString, then pass that along to
128e2ae97f2SGreg Clayton     // the to new file we are redirecting to.
129e2ae97f2SGreg Clayton     if (!local_data.empty())
130e2ae97f2SGreg Clayton       m_opaque_ap->Write(&local_data[0], local_data.size());
131b9c1b51eSKate Stone   } else
132e2ae97f2SGreg Clayton     m_is_file = false;
133e2ae97f2SGreg Clayton }
134e2ae97f2SGreg Clayton 
135b9c1b51eSKate Stone lldb_private::Stream *SBStream::operator->() { return m_opaque_ap.get(); }
136e2ae97f2SGreg Clayton 
137b9c1b51eSKate Stone lldb_private::Stream *SBStream::get() { return m_opaque_ap.get(); }
138e2ae97f2SGreg Clayton 
139b9c1b51eSKate Stone lldb_private::Stream &SBStream::ref() {
140e2ae97f2SGreg Clayton   if (m_opaque_ap.get() == NULL)
141e2ae97f2SGreg Clayton     m_opaque_ap.reset(new StreamString());
142e2ae97f2SGreg Clayton   return *m_opaque_ap.get();
143e2ae97f2SGreg Clayton }
144e2ae97f2SGreg Clayton 
145b9c1b51eSKate Stone void SBStream::Clear() {
146b9c1b51eSKate Stone   if (m_opaque_ap.get()) {
147e2ae97f2SGreg Clayton     // See if we have any locally backed data. If so, copy it so we can then
148e2ae97f2SGreg Clayton     // redirect it to the file so we don't lose the data
149e2ae97f2SGreg Clayton     if (m_is_file)
150e2ae97f2SGreg Clayton       m_opaque_ap.reset();
151e2ae97f2SGreg Clayton     else
152c156427dSZachary Turner       static_cast<StreamString *>(m_opaque_ap.get())->Clear();
153e2ae97f2SGreg Clayton   }
154e2ae97f2SGreg Clayton }
155