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 
1251b1e2d2SGreg Clayton #include "lldb/Core/Error.h"
13e2ae97f2SGreg Clayton #include "lldb/Core/Stream.h"
14e2ae97f2SGreg Clayton #include "lldb/Core/StreamFile.h"
15e2ae97f2SGreg Clayton #include "lldb/Core/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 
27b9c1b51eSKate Stone bool SBStream::IsValid() const { return (m_opaque_ap.get() != NULL); }
28e2ae97f2SGreg Clayton 
29e2ae97f2SGreg Clayton // If this stream is not redirected to a file, it will maintain a local
30e2ae97f2SGreg Clayton // cache for the stream data which can be accessed using this accessor.
31b9c1b51eSKate Stone const char *SBStream::GetData() {
32e2ae97f2SGreg Clayton   if (m_is_file || m_opaque_ap.get() == NULL)
33e2ae97f2SGreg Clayton     return NULL;
34e2ae97f2SGreg Clayton 
35e2ae97f2SGreg Clayton   return static_cast<StreamString *>(m_opaque_ap.get())->GetData();
36e2ae97f2SGreg Clayton }
37e2ae97f2SGreg Clayton 
38e2ae97f2SGreg Clayton // If this stream is not redirected to a file, it will maintain a local
39e2ae97f2SGreg Clayton // cache for the stream output whose length can be accessed using this
40e2ae97f2SGreg Clayton // 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)
66*c156427dSZachary 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;
74b9c1b51eSKate Stone   stream_file->GetFile().Open(path, open_options,
75b9c1b51eSKate Stone                               lldb::eFilePermissionsFileDefault);
7651b1e2d2SGreg Clayton 
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)
99*c156427dSZachary 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)
120*c156427dSZachary 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
152*c156427dSZachary Turner       static_cast<StreamString *>(m_opaque_ap.get())->Clear();
153e2ae97f2SGreg Clayton   }
154e2ae97f2SGreg Clayton }
155