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 
20e2ae97f2SGreg Clayton SBStream::SBStream () :
21f6eaba85SJohnny Chen     m_opaque_ap (new StreamString()),
22e2ae97f2SGreg Clayton     m_is_file (false)
23e2ae97f2SGreg Clayton {
24e2ae97f2SGreg Clayton }
25e2ae97f2SGreg Clayton 
26*0817da88SGreg Clayton SBStream::SBStream (SBStream &&rhs) :
27*0817da88SGreg Clayton     m_opaque_ap (std::move(rhs.m_opaque_ap)),
28*0817da88SGreg Clayton     m_is_file (rhs.m_is_file)
29*0817da88SGreg Clayton {
30*0817da88SGreg Clayton }
31*0817da88SGreg Clayton 
32*0817da88SGreg Clayton 
33e2ae97f2SGreg Clayton SBStream::~SBStream ()
34e2ae97f2SGreg Clayton {
35e2ae97f2SGreg Clayton }
36e2ae97f2SGreg Clayton 
37e2ae97f2SGreg Clayton bool
38e2ae97f2SGreg Clayton SBStream::IsValid() const
39e2ae97f2SGreg Clayton {
40e2ae97f2SGreg Clayton     return (m_opaque_ap.get() != NULL);
41e2ae97f2SGreg Clayton }
42e2ae97f2SGreg Clayton 
43e2ae97f2SGreg Clayton // If this stream is not redirected to a file, it will maintain a local
44e2ae97f2SGreg Clayton // cache for the stream data which can be accessed using this accessor.
45e2ae97f2SGreg Clayton const char *
46e2ae97f2SGreg Clayton SBStream::GetData ()
47e2ae97f2SGreg Clayton {
48e2ae97f2SGreg Clayton     if (m_is_file || m_opaque_ap.get() == NULL)
49e2ae97f2SGreg Clayton         return NULL;
50e2ae97f2SGreg Clayton 
51e2ae97f2SGreg Clayton     return static_cast<StreamString *>(m_opaque_ap.get())->GetData();
52e2ae97f2SGreg Clayton }
53e2ae97f2SGreg Clayton 
54e2ae97f2SGreg Clayton // If this stream is not redirected to a file, it will maintain a local
55e2ae97f2SGreg Clayton // cache for the stream output whose length can be accessed using this
56e2ae97f2SGreg Clayton // accessor.
57e2ae97f2SGreg Clayton size_t
58e2ae97f2SGreg Clayton SBStream::GetSize()
59e2ae97f2SGreg Clayton {
60e2ae97f2SGreg Clayton     if (m_is_file || m_opaque_ap.get() == NULL)
6160fd91ffSBill Wendling         return 0;
62e2ae97f2SGreg Clayton 
63e2ae97f2SGreg Clayton     return static_cast<StreamString *>(m_opaque_ap.get())->GetSize();
64e2ae97f2SGreg Clayton }
65e2ae97f2SGreg Clayton 
66e2ae97f2SGreg Clayton void
67e2ae97f2SGreg Clayton SBStream::Printf (const char *format, ...)
68e2ae97f2SGreg Clayton {
694f8189bcSJohnny Chen     if (!format)
704f8189bcSJohnny Chen         return;
71e2ae97f2SGreg Clayton     va_list args;
72e2ae97f2SGreg Clayton     va_start (args, format);
73e2ae97f2SGreg Clayton     ref().PrintfVarArg (format, args);
74e2ae97f2SGreg Clayton     va_end (args);
75e2ae97f2SGreg Clayton }
76e2ae97f2SGreg Clayton 
77e2ae97f2SGreg Clayton void
78e2ae97f2SGreg Clayton SBStream::RedirectToFile (const char *path, bool append)
79e2ae97f2SGreg Clayton {
80e2dcbd00SZachary Turner     if (path == nullptr)
81e2dcbd00SZachary Turner         return;
82e2dcbd00SZachary Turner 
83e2ae97f2SGreg Clayton     std::string local_data;
84e2ae97f2SGreg Clayton     if (m_opaque_ap.get())
85e2ae97f2SGreg Clayton     {
86e2ae97f2SGreg Clayton         // See if we have any locally backed data. If so, copy it so we can then
87e2ae97f2SGreg Clayton         // redirect it to the file so we don't lose the data
88e2ae97f2SGreg Clayton         if (!m_is_file)
89e2ae97f2SGreg Clayton             local_data.swap(static_cast<StreamString *>(m_opaque_ap.get())->GetString());
90e2ae97f2SGreg Clayton     }
9151b1e2d2SGreg Clayton     StreamFile *stream_file = new StreamFile;
9251b1e2d2SGreg Clayton     uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
9351b1e2d2SGreg Clayton     if (append)
9451b1e2d2SGreg Clayton         open_options |= File::eOpenOptionAppend;
9506357c93SGreg Clayton     else
9606357c93SGreg Clayton         open_options |= File::eOpenOptionTruncate;
97fbb76349SGreg Clayton     stream_file->GetFile().Open (path, open_options, lldb::eFilePermissionsFileDefault);
9851b1e2d2SGreg Clayton 
9951b1e2d2SGreg Clayton     m_opaque_ap.reset (stream_file);
100e2ae97f2SGreg Clayton 
101e2ae97f2SGreg Clayton     if (m_opaque_ap.get())
102e2ae97f2SGreg Clayton     {
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());
109e2ae97f2SGreg Clayton     }
110e2ae97f2SGreg Clayton     else
111e2ae97f2SGreg Clayton         m_is_file = false;
112e2ae97f2SGreg Clayton }
113e2ae97f2SGreg Clayton 
114e2ae97f2SGreg Clayton void
115e2ae97f2SGreg Clayton SBStream::RedirectToFileHandle (FILE *fh, bool transfer_fh_ownership)
116e2ae97f2SGreg Clayton {
117e2dcbd00SZachary Turner     if (fh == nullptr)
118e2dcbd00SZachary Turner         return;
119e2dcbd00SZachary Turner 
120e2ae97f2SGreg Clayton     std::string local_data;
121e2ae97f2SGreg Clayton     if (m_opaque_ap.get())
122e2ae97f2SGreg Clayton     {
123e2ae97f2SGreg Clayton         // See if we have any locally backed data. If so, copy it so we can then
124e2ae97f2SGreg Clayton         // redirect it to the file so we don't lose the data
125e2ae97f2SGreg Clayton         if (!m_is_file)
126e2ae97f2SGreg Clayton             local_data.swap(static_cast<StreamString *>(m_opaque_ap.get())->GetString());
127e2ae97f2SGreg Clayton     }
128e2ae97f2SGreg Clayton     m_opaque_ap.reset (new StreamFile (fh, transfer_fh_ownership));
129e2ae97f2SGreg Clayton 
130e2ae97f2SGreg Clayton     if (m_opaque_ap.get())
131e2ae97f2SGreg Clayton     {
132e2ae97f2SGreg Clayton         m_is_file = true;
133e2ae97f2SGreg Clayton 
134e2ae97f2SGreg Clayton         // If we had any data locally in our StreamString, then pass that along to
135e2ae97f2SGreg Clayton         // the to new file we are redirecting to.
136e2ae97f2SGreg Clayton         if (!local_data.empty())
137e2ae97f2SGreg Clayton             m_opaque_ap->Write (&local_data[0], local_data.size());
138e2ae97f2SGreg Clayton     }
139e2ae97f2SGreg Clayton     else
140e2ae97f2SGreg Clayton         m_is_file = false;
141e2ae97f2SGreg Clayton }
142e2ae97f2SGreg Clayton 
143e2ae97f2SGreg Clayton void
144e2ae97f2SGreg Clayton SBStream::RedirectToFileDescriptor (int fd, bool transfer_fh_ownership)
145e2ae97f2SGreg Clayton {
146e2ae97f2SGreg Clayton     std::string local_data;
147e2ae97f2SGreg Clayton     if (m_opaque_ap.get())
148e2ae97f2SGreg Clayton     {
149e2ae97f2SGreg Clayton         // See if we have any locally backed data. If so, copy it so we can then
150e2ae97f2SGreg Clayton         // redirect it to the file so we don't lose the data
151e2ae97f2SGreg Clayton         if (!m_is_file)
152e2ae97f2SGreg Clayton             local_data.swap(static_cast<StreamString *>(m_opaque_ap.get())->GetString());
153e2ae97f2SGreg Clayton     }
154e2ae97f2SGreg Clayton 
155e2ae97f2SGreg Clayton     m_opaque_ap.reset (new StreamFile (::fdopen (fd, "w"), transfer_fh_ownership));
156e2ae97f2SGreg Clayton     if (m_opaque_ap.get())
157e2ae97f2SGreg Clayton     {
158e2ae97f2SGreg Clayton         m_is_file = true;
159e2ae97f2SGreg Clayton 
160e2ae97f2SGreg Clayton         // If we had any data locally in our StreamString, then pass that along to
161e2ae97f2SGreg Clayton         // the to new file we are redirecting to.
162e2ae97f2SGreg Clayton         if (!local_data.empty())
163e2ae97f2SGreg Clayton             m_opaque_ap->Write (&local_data[0], local_data.size());
164e2ae97f2SGreg Clayton     }
165e2ae97f2SGreg Clayton     else
166e2ae97f2SGreg Clayton         m_is_file = false;
167e2ae97f2SGreg Clayton 
168e2ae97f2SGreg Clayton }
169e2ae97f2SGreg Clayton 
170e2ae97f2SGreg Clayton lldb_private::Stream *
171e2ae97f2SGreg Clayton SBStream::operator->()
172e2ae97f2SGreg Clayton {
173e2ae97f2SGreg Clayton     return m_opaque_ap.get();
174e2ae97f2SGreg Clayton }
175e2ae97f2SGreg Clayton 
176e2ae97f2SGreg Clayton lldb_private::Stream *
177e2ae97f2SGreg Clayton SBStream::get()
178e2ae97f2SGreg Clayton {
179e2ae97f2SGreg Clayton     return m_opaque_ap.get();
180e2ae97f2SGreg Clayton }
181e2ae97f2SGreg Clayton 
182e2ae97f2SGreg Clayton lldb_private::Stream &
183e2ae97f2SGreg Clayton SBStream::ref()
184e2ae97f2SGreg Clayton {
185e2ae97f2SGreg Clayton     if (m_opaque_ap.get() == NULL)
186e2ae97f2SGreg Clayton         m_opaque_ap.reset (new StreamString());
187e2ae97f2SGreg Clayton     return *m_opaque_ap.get();
188e2ae97f2SGreg Clayton }
189e2ae97f2SGreg Clayton 
190e2ae97f2SGreg Clayton void
191e2ae97f2SGreg Clayton SBStream::Clear ()
192e2ae97f2SGreg Clayton {
193e2ae97f2SGreg Clayton     if (m_opaque_ap.get())
194e2ae97f2SGreg Clayton     {
195e2ae97f2SGreg Clayton         // See if we have any locally backed data. If so, copy it so we can then
196e2ae97f2SGreg Clayton         // redirect it to the file so we don't lose the data
197e2ae97f2SGreg Clayton         if (m_is_file)
198e2ae97f2SGreg Clayton             m_opaque_ap.reset();
199e2ae97f2SGreg Clayton         else
200e2ae97f2SGreg Clayton             static_cast<StreamString *>(m_opaque_ap.get())->GetString().clear();
201e2ae97f2SGreg Clayton     }
202e2ae97f2SGreg Clayton }
203