1 //===-- SBStream.cpp ----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/API/SBStream.h"
11 
12 #include "lldb/Core/Error.h"
13 #include "lldb/Core/Stream.h"
14 #include "lldb/Core/StreamFile.h"
15 #include "lldb/Core/StreamString.h"
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 SBStream::SBStream() : m_opaque_ap(new StreamString()), m_is_file(false) {}
21 
22 SBStream::SBStream(SBStream &&rhs)
23     : m_opaque_ap(std::move(rhs.m_opaque_ap)), m_is_file(rhs.m_is_file) {}
24 
25 SBStream::~SBStream() {}
26 
27 bool SBStream::IsValid() const { return (m_opaque_ap.get() != NULL); }
28 
29 // If this stream is not redirected to a file, it will maintain a local
30 // cache for the stream data which can be accessed using this accessor.
31 const char *SBStream::GetData() {
32   if (m_is_file || m_opaque_ap.get() == NULL)
33     return NULL;
34 
35   return static_cast<StreamString *>(m_opaque_ap.get())->GetData();
36 }
37 
38 // If this stream is not redirected to a file, it will maintain a local
39 // cache for the stream output whose length can be accessed using this
40 // accessor.
41 size_t SBStream::GetSize() {
42   if (m_is_file || m_opaque_ap.get() == NULL)
43     return 0;
44 
45   return static_cast<StreamString *>(m_opaque_ap.get())->GetSize();
46 }
47 
48 void SBStream::Printf(const char *format, ...) {
49   if (!format)
50     return;
51   va_list args;
52   va_start(args, format);
53   ref().PrintfVarArg(format, args);
54   va_end(args);
55 }
56 
57 void SBStream::RedirectToFile(const char *path, bool append) {
58   if (path == nullptr)
59     return;
60 
61   std::string local_data;
62   if (m_opaque_ap.get()) {
63     // See if we have any locally backed data. If so, copy it so we can then
64     // redirect it to the file so we don't lose the data
65     if (!m_is_file)
66       local_data.swap(
67           static_cast<StreamString *>(m_opaque_ap.get())->GetString());
68   }
69   StreamFile *stream_file = new StreamFile;
70   uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
71   if (append)
72     open_options |= File::eOpenOptionAppend;
73   else
74     open_options |= File::eOpenOptionTruncate;
75   stream_file->GetFile().Open(path, open_options,
76                               lldb::eFilePermissionsFileDefault);
77 
78   m_opaque_ap.reset(stream_file);
79 
80   if (m_opaque_ap.get()) {
81     m_is_file = true;
82 
83     // If we had any data locally in our StreamString, then pass that along to
84     // the to new file we are redirecting to.
85     if (!local_data.empty())
86       m_opaque_ap->Write(&local_data[0], local_data.size());
87   } else
88     m_is_file = false;
89 }
90 
91 void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
92   if (fh == nullptr)
93     return;
94 
95   std::string local_data;
96   if (m_opaque_ap.get()) {
97     // See if we have any locally backed data. If so, copy it so we can then
98     // redirect it to the file so we don't lose the data
99     if (!m_is_file)
100       local_data.swap(
101           static_cast<StreamString *>(m_opaque_ap.get())->GetString());
102   }
103   m_opaque_ap.reset(new StreamFile(fh, transfer_fh_ownership));
104 
105   if (m_opaque_ap.get()) {
106     m_is_file = true;
107 
108     // If we had any data locally in our StreamString, then pass that along to
109     // the to new file we are redirecting to.
110     if (!local_data.empty())
111       m_opaque_ap->Write(&local_data[0], local_data.size());
112   } else
113     m_is_file = false;
114 }
115 
116 void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) {
117   std::string local_data;
118   if (m_opaque_ap.get()) {
119     // See if we have any locally backed data. If so, copy it so we can then
120     // redirect it to the file so we don't lose the data
121     if (!m_is_file)
122       local_data.swap(
123           static_cast<StreamString *>(m_opaque_ap.get())->GetString());
124   }
125 
126   m_opaque_ap.reset(new StreamFile(::fdopen(fd, "w"), transfer_fh_ownership));
127   if (m_opaque_ap.get()) {
128     m_is_file = true;
129 
130     // If we had any data locally in our StreamString, then pass that along to
131     // the to new file we are redirecting to.
132     if (!local_data.empty())
133       m_opaque_ap->Write(&local_data[0], local_data.size());
134   } else
135     m_is_file = false;
136 }
137 
138 lldb_private::Stream *SBStream::operator->() { return m_opaque_ap.get(); }
139 
140 lldb_private::Stream *SBStream::get() { return m_opaque_ap.get(); }
141 
142 lldb_private::Stream &SBStream::ref() {
143   if (m_opaque_ap.get() == NULL)
144     m_opaque_ap.reset(new StreamString());
145   return *m_opaque_ap.get();
146 }
147 
148 void SBStream::Clear() {
149   if (m_opaque_ap.get()) {
150     // See if we have any locally backed data. If so, copy it so we can then
151     // redirect it to the file so we don't lose the data
152     if (m_is_file)
153       m_opaque_ap.reset();
154     else
155       static_cast<StreamString *>(m_opaque_ap.get())->GetString().clear();
156   }
157 }
158