1 //===-- SBCommandReturnObject.cpp -----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/API/SBCommandReturnObject.h"
10 #include "Utils.h"
11 #include "lldb/API/SBError.h"
12 #include "lldb/API/SBFile.h"
13 #include "lldb/API/SBStream.h"
14 #include "lldb/Interpreter/CommandReturnObject.h"
15 #include "lldb/Utility/ConstString.h"
16 #include "lldb/Utility/Instrumentation.h"
17 #include "lldb/Utility/Status.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 
22 class lldb_private::SBCommandReturnObjectImpl {
23 public:
24   SBCommandReturnObjectImpl() : m_ptr(new CommandReturnObject(false)) {}
25   SBCommandReturnObjectImpl(CommandReturnObject &ref)
26       : m_ptr(&ref), m_owned(false) {}
27   SBCommandReturnObjectImpl(const SBCommandReturnObjectImpl &rhs)
28       : m_ptr(new CommandReturnObject(*rhs.m_ptr)), m_owned(rhs.m_owned) {}
29   SBCommandReturnObjectImpl &operator=(const SBCommandReturnObjectImpl &rhs) {
30     SBCommandReturnObjectImpl copy(rhs);
31     std::swap(*this, copy);
32     return *this;
33   }
34   // rvalue ctor+assignment are not used by SBCommandReturnObject.
35   ~SBCommandReturnObjectImpl() {
36     if (m_owned)
37       delete m_ptr;
38   }
39 
40   CommandReturnObject &operator*() const { return *m_ptr; }
41 
42 private:
43   CommandReturnObject *m_ptr;
44   bool m_owned = true;
45 };
46 
47 SBCommandReturnObject::SBCommandReturnObject()
48     : m_opaque_up(new SBCommandReturnObjectImpl()) {
49   LLDB_INSTRUMENT_VA(this);
50 }
51 
52 SBCommandReturnObject::SBCommandReturnObject(CommandReturnObject &ref)
53     : m_opaque_up(new SBCommandReturnObjectImpl(ref)) {
54   LLDB_INSTRUMENT_VA(this, ref);
55 }
56 
57 SBCommandReturnObject::SBCommandReturnObject(const SBCommandReturnObject &rhs) {
58   LLDB_INSTRUMENT_VA(this, rhs);
59 
60   m_opaque_up = clone(rhs.m_opaque_up);
61 }
62 
63 SBCommandReturnObject &SBCommandReturnObject::
64 operator=(const SBCommandReturnObject &rhs) {
65   LLDB_INSTRUMENT_VA(this, rhs);
66 
67   if (this != &rhs)
68     m_opaque_up = clone(rhs.m_opaque_up);
69   return *this;
70 }
71 
72 SBCommandReturnObject::~SBCommandReturnObject() = default;
73 
74 bool SBCommandReturnObject::IsValid() const {
75   LLDB_INSTRUMENT_VA(this);
76   return this->operator bool();
77 }
78 SBCommandReturnObject::operator bool() const {
79   LLDB_INSTRUMENT_VA(this);
80 
81   // This method is not useful but it needs to stay to keep SB API stable.
82   return true;
83 }
84 
85 const char *SBCommandReturnObject::GetOutput() {
86   LLDB_INSTRUMENT_VA(this);
87 
88   ConstString output(ref().GetOutputData());
89   return output.AsCString(/*value_if_empty*/ "");
90 }
91 
92 const char *SBCommandReturnObject::GetError() {
93   LLDB_INSTRUMENT_VA(this);
94 
95   ConstString output(ref().GetErrorData());
96   return output.AsCString(/*value_if_empty*/ "");
97 }
98 
99 size_t SBCommandReturnObject::GetOutputSize() {
100   LLDB_INSTRUMENT_VA(this);
101 
102   return ref().GetOutputData().size();
103 }
104 
105 size_t SBCommandReturnObject::GetErrorSize() {
106   LLDB_INSTRUMENT_VA(this);
107 
108   return ref().GetErrorData().size();
109 }
110 
111 size_t SBCommandReturnObject::PutOutput(FILE *fh) {
112   LLDB_INSTRUMENT_VA(this, fh);
113   if (fh) {
114     size_t num_bytes = GetOutputSize();
115     if (num_bytes)
116       return ::fprintf(fh, "%s", GetOutput());
117   }
118   return 0;
119 }
120 
121 size_t SBCommandReturnObject::PutOutput(FileSP file_sp) {
122   LLDB_INSTRUMENT_VA(this, file_sp);
123   if (!file_sp)
124     return 0;
125   return file_sp->Printf("%s", GetOutput());
126 }
127 
128 size_t SBCommandReturnObject::PutOutput(SBFile file) {
129   LLDB_INSTRUMENT_VA(this, file);
130   if (!file.m_opaque_sp)
131     return 0;
132   return file.m_opaque_sp->Printf("%s", GetOutput());
133 }
134 
135 size_t SBCommandReturnObject::PutError(FILE *fh) {
136   LLDB_INSTRUMENT_VA(this, fh);
137   if (fh) {
138     size_t num_bytes = GetErrorSize();
139     if (num_bytes)
140       return ::fprintf(fh, "%s", GetError());
141   }
142   return 0;
143 }
144 
145 size_t SBCommandReturnObject::PutError(FileSP file_sp) {
146   LLDB_INSTRUMENT_VA(this, file_sp);
147   if (!file_sp)
148     return 0;
149   return file_sp->Printf("%s", GetError());
150 }
151 
152 size_t SBCommandReturnObject::PutError(SBFile file) {
153   LLDB_INSTRUMENT_VA(this, file);
154   if (!file.m_opaque_sp)
155     return 0;
156   return file.m_opaque_sp->Printf("%s", GetError());
157 }
158 
159 void SBCommandReturnObject::Clear() {
160   LLDB_INSTRUMENT_VA(this);
161 
162   ref().Clear();
163 }
164 
165 lldb::ReturnStatus SBCommandReturnObject::GetStatus() {
166   LLDB_INSTRUMENT_VA(this);
167 
168   return ref().GetStatus();
169 }
170 
171 void SBCommandReturnObject::SetStatus(lldb::ReturnStatus status) {
172   LLDB_INSTRUMENT_VA(this, status);
173 
174   ref().SetStatus(status);
175 }
176 
177 bool SBCommandReturnObject::Succeeded() {
178   LLDB_INSTRUMENT_VA(this);
179 
180   return ref().Succeeded();
181 }
182 
183 bool SBCommandReturnObject::HasResult() {
184   LLDB_INSTRUMENT_VA(this);
185 
186   return ref().HasResult();
187 }
188 
189 void SBCommandReturnObject::AppendMessage(const char *message) {
190   LLDB_INSTRUMENT_VA(this, message);
191 
192   ref().AppendMessage(message);
193 }
194 
195 void SBCommandReturnObject::AppendWarning(const char *message) {
196   LLDB_INSTRUMENT_VA(this, message);
197 
198   ref().AppendWarning(message);
199 }
200 
201 CommandReturnObject *SBCommandReturnObject::operator->() const {
202   return &**m_opaque_up;
203 }
204 
205 CommandReturnObject *SBCommandReturnObject::get() const {
206   return &**m_opaque_up;
207 }
208 
209 CommandReturnObject &SBCommandReturnObject::operator*() const {
210   return **m_opaque_up;
211 }
212 
213 CommandReturnObject &SBCommandReturnObject::ref() const {
214   return **m_opaque_up;
215 }
216 
217 bool SBCommandReturnObject::GetDescription(SBStream &description) {
218   LLDB_INSTRUMENT_VA(this, description);
219 
220   Stream &strm = description.ref();
221 
222   description.Printf("Error:  ");
223   lldb::ReturnStatus status = ref().GetStatus();
224   if (status == lldb::eReturnStatusStarted)
225     strm.PutCString("Started");
226   else if (status == lldb::eReturnStatusInvalid)
227     strm.PutCString("Invalid");
228   else if (ref().Succeeded())
229     strm.PutCString("Success");
230   else
231     strm.PutCString("Fail");
232 
233   if (GetOutputSize() > 0)
234     strm.Printf("\nOutput Message:\n%s", GetOutput());
235 
236   if (GetErrorSize() > 0)
237     strm.Printf("\nError Message:\n%s", GetError());
238 
239   return true;
240 }
241 
242 void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh) {
243   LLDB_INSTRUMENT_VA(this, fh);
244 
245   SetImmediateOutputFile(fh, false);
246 }
247 
248 void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh) {
249   LLDB_INSTRUMENT_VA(this, fh);
250 
251   SetImmediateErrorFile(fh, false);
252 }
253 
254 void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh,
255                                                    bool transfer_ownership) {
256   LLDB_INSTRUMENT_VA(this, fh, transfer_ownership);
257   FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership);
258   ref().SetImmediateOutputFile(file);
259 }
260 
261 void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh,
262                                                   bool transfer_ownership) {
263   LLDB_INSTRUMENT_VA(this, fh, transfer_ownership);
264   FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership);
265   ref().SetImmediateErrorFile(file);
266 }
267 
268 void SBCommandReturnObject::SetImmediateOutputFile(SBFile file) {
269   LLDB_INSTRUMENT_VA(this, file);
270   ref().SetImmediateOutputFile(file.m_opaque_sp);
271 }
272 
273 void SBCommandReturnObject::SetImmediateErrorFile(SBFile file) {
274   LLDB_INSTRUMENT_VA(this, file);
275   ref().SetImmediateErrorFile(file.m_opaque_sp);
276 }
277 
278 void SBCommandReturnObject::SetImmediateOutputFile(FileSP file_sp) {
279   LLDB_INSTRUMENT_VA(this, file_sp);
280   SetImmediateOutputFile(SBFile(file_sp));
281 }
282 
283 void SBCommandReturnObject::SetImmediateErrorFile(FileSP file_sp) {
284   LLDB_INSTRUMENT_VA(this, file_sp);
285   SetImmediateErrorFile(SBFile(file_sp));
286 }
287 
288 void SBCommandReturnObject::PutCString(const char *string, int len) {
289   LLDB_INSTRUMENT_VA(this, string, len);
290 
291   if (len == 0 || string == nullptr || *string == 0) {
292     return;
293   } else if (len > 0) {
294     std::string buffer(string, len);
295     ref().AppendMessage(buffer.c_str());
296   } else
297     ref().AppendMessage(string);
298 }
299 
300 const char *SBCommandReturnObject::GetOutput(bool only_if_no_immediate) {
301   LLDB_INSTRUMENT_VA(this, only_if_no_immediate);
302 
303   if (!only_if_no_immediate ||
304       ref().GetImmediateOutputStream().get() == nullptr)
305     return GetOutput();
306   return nullptr;
307 }
308 
309 const char *SBCommandReturnObject::GetError(bool only_if_no_immediate) {
310   LLDB_INSTRUMENT_VA(this, only_if_no_immediate);
311 
312   if (!only_if_no_immediate || ref().GetImmediateErrorStream().get() == nullptr)
313     return GetError();
314   return nullptr;
315 }
316 
317 size_t SBCommandReturnObject::Printf(const char *format, ...) {
318   va_list args;
319   va_start(args, format);
320   size_t result = ref().GetOutputStream().PrintfVarArg(format, args);
321   va_end(args);
322   return result;
323 }
324 
325 void SBCommandReturnObject::SetError(lldb::SBError &error,
326                                      const char *fallback_error_cstr) {
327   LLDB_INSTRUMENT_VA(this, error, fallback_error_cstr);
328 
329   if (error.IsValid())
330     ref().SetError(error.ref(), fallback_error_cstr);
331   else if (fallback_error_cstr)
332     ref().SetError(Status(), fallback_error_cstr);
333 }
334 
335 void SBCommandReturnObject::SetError(const char *error_cstr) {
336   LLDB_INSTRUMENT_VA(this, error_cstr);
337 
338   if (error_cstr)
339     ref().AppendError(error_cstr);
340 }
341