1//===-- SBCommandReturnObject.cpp -------------------------------*- C++ -*-===//
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 "SBReproducerPrivate.h"
11#include "Utils.h"
12#include "lldb/API/SBError.h"
13#include "lldb/API/SBFile.h"
14#include "lldb/API/SBStream.h"
15#include "lldb/Interpreter/CommandReturnObject.h"
16#include "lldb/Utility/ConstString.h"
17#include "lldb/Utility/Status.h"
18
19using namespace lldb;
20using namespace lldb_private;
21
22class lldb_private::SBCommandReturnObjectImpl {
23public:
24  SBCommandReturnObjectImpl()
25      : m_ptr(new CommandReturnObject()), m_owned(true) {}
26  SBCommandReturnObjectImpl(CommandReturnObject &ref)
27      : m_ptr(&ref), m_owned(false) {}
28  SBCommandReturnObjectImpl(const SBCommandReturnObjectImpl &rhs)
29      : m_ptr(new CommandReturnObject(*rhs.m_ptr)), m_owned(rhs.m_owned) {}
30  SBCommandReturnObjectImpl &operator=(const SBCommandReturnObjectImpl &rhs) {
31    SBCommandReturnObjectImpl copy(rhs);
32    std::swap(*this, copy);
33    return *this;
34  }
35  // rvalue ctor+assignment are not used by SBCommandReturnObject.
36  ~SBCommandReturnObjectImpl() {
37    if (m_owned)
38      delete m_ptr;
39  }
40
41  CommandReturnObject &operator*() const { return *m_ptr; }
42
43private:
44  CommandReturnObject *m_ptr;
45  bool m_owned;
46};
47
48SBCommandReturnObject::SBCommandReturnObject()
49    : m_opaque_up(new SBCommandReturnObjectImpl()) {
50  LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBCommandReturnObject);
51}
52
53SBCommandReturnObject::SBCommandReturnObject(CommandReturnObject &ref)
54    : m_opaque_up(new SBCommandReturnObjectImpl(ref)) {
55  LLDB_RECORD_CONSTRUCTOR(SBCommandReturnObject,
56                          (lldb_private::CommandReturnObject &), ref);
57}
58
59SBCommandReturnObject::SBCommandReturnObject(const SBCommandReturnObject &rhs)
60    : m_opaque_up() {
61  LLDB_RECORD_CONSTRUCTOR(SBCommandReturnObject,
62                          (const lldb::SBCommandReturnObject &), rhs);
63
64  m_opaque_up = clone(rhs.m_opaque_up);
65}
66
67SBCommandReturnObject &SBCommandReturnObject::
68operator=(const SBCommandReturnObject &rhs) {
69  LLDB_RECORD_METHOD(
70      lldb::SBCommandReturnObject &,
71      SBCommandReturnObject, operator=,(const lldb::SBCommandReturnObject &),
72      rhs);
73
74  if (this != &rhs)
75    m_opaque_up = clone(rhs.m_opaque_up);
76  return LLDB_RECORD_RESULT(*this);
77}
78
79SBCommandReturnObject::~SBCommandReturnObject() = default;
80
81bool SBCommandReturnObject::IsValid() const {
82  LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBCommandReturnObject, IsValid);
83  return this->operator bool();
84}
85SBCommandReturnObject::operator bool() const {
86  LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBCommandReturnObject, operator bool);
87
88  // This method is not useful but it needs to stay to keep SB API stable.
89  return true;
90}
91
92const char *SBCommandReturnObject::GetOutput() {
93  LLDB_RECORD_METHOD_NO_ARGS(const char *, SBCommandReturnObject, GetOutput);
94
95  ConstString output(ref().GetOutputData());
96  return output.AsCString(/*value_if_empty*/ "");
97}
98
99const char *SBCommandReturnObject::GetError() {
100  LLDB_RECORD_METHOD_NO_ARGS(const char *, SBCommandReturnObject, GetError);
101
102  ConstString output(ref().GetErrorData());
103  return output.AsCString(/*value_if_empty*/ "");
104}
105
106size_t SBCommandReturnObject::GetOutputSize() {
107  LLDB_RECORD_METHOD_NO_ARGS(size_t, SBCommandReturnObject, GetOutputSize);
108
109  return ref().GetOutputData().size();
110}
111
112size_t SBCommandReturnObject::GetErrorSize() {
113  LLDB_RECORD_METHOD_NO_ARGS(size_t, SBCommandReturnObject, GetErrorSize);
114
115  return ref().GetErrorData().size();
116}
117
118size_t SBCommandReturnObject::PutOutput(FILE *fh) {
119  LLDB_RECORD_DUMMY(size_t, SBCommandReturnObject, PutOutput, (FILE *), fh);
120  if (fh) {
121    size_t num_bytes = GetOutputSize();
122    if (num_bytes)
123      return ::fprintf(fh, "%s", GetOutput());
124  }
125  return 0;
126}
127
128size_t SBCommandReturnObject::PutOutput(FileSP file_sp) {
129  LLDB_RECORD_METHOD(size_t, SBCommandReturnObject, PutOutput, (FileSP),
130                     file_sp);
131  if (!file_sp)
132    return 0;
133  return file_sp->Printf("%s", GetOutput());
134}
135
136size_t SBCommandReturnObject::PutOutput(SBFile file) {
137  LLDB_RECORD_METHOD(size_t, SBCommandReturnObject, PutOutput, (SBFile), file);
138  if (!file.m_opaque_sp)
139    return 0;
140  return file.m_opaque_sp->Printf("%s", GetOutput());
141}
142
143size_t SBCommandReturnObject::PutError(FILE *fh) {
144  LLDB_RECORD_DUMMY(size_t, SBCommandReturnObject, PutError, (FILE *), fh);
145  if (fh) {
146    size_t num_bytes = GetErrorSize();
147    if (num_bytes)
148      return ::fprintf(fh, "%s", GetError());
149  }
150  return 0;
151}
152
153size_t SBCommandReturnObject::PutError(FileSP file_sp) {
154  LLDB_RECORD_METHOD(size_t, SBCommandReturnObject, PutError, (FileSP),
155                     file_sp);
156  if (!file_sp)
157    return 0;
158  return file_sp->Printf("%s", GetError());
159}
160
161size_t SBCommandReturnObject::PutError(SBFile file) {
162  LLDB_RECORD_METHOD(size_t, SBCommandReturnObject, PutError, (SBFile), file);
163  if (!file.m_opaque_sp)
164    return 0;
165  return file.m_opaque_sp->Printf("%s", GetError());
166}
167
168void SBCommandReturnObject::Clear() {
169  LLDB_RECORD_METHOD_NO_ARGS(void, SBCommandReturnObject, Clear);
170
171  ref().Clear();
172}
173
174lldb::ReturnStatus SBCommandReturnObject::GetStatus() {
175  LLDB_RECORD_METHOD_NO_ARGS(lldb::ReturnStatus, SBCommandReturnObject,
176                             GetStatus);
177
178  return ref().GetStatus();
179}
180
181void SBCommandReturnObject::SetStatus(lldb::ReturnStatus status) {
182  LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetStatus,
183                     (lldb::ReturnStatus), status);
184
185  ref().SetStatus(status);
186}
187
188bool SBCommandReturnObject::Succeeded() {
189  LLDB_RECORD_METHOD_NO_ARGS(bool, SBCommandReturnObject, Succeeded);
190
191  return ref().Succeeded();
192}
193
194bool SBCommandReturnObject::HasResult() {
195  LLDB_RECORD_METHOD_NO_ARGS(bool, SBCommandReturnObject, HasResult);
196
197  return ref().HasResult();
198}
199
200void SBCommandReturnObject::AppendMessage(const char *message) {
201  LLDB_RECORD_METHOD(void, SBCommandReturnObject, AppendMessage, (const char *),
202                     message);
203
204  ref().AppendMessage(message);
205}
206
207void SBCommandReturnObject::AppendWarning(const char *message) {
208  LLDB_RECORD_METHOD(void, SBCommandReturnObject, AppendWarning, (const char *),
209                     message);
210
211  ref().AppendWarning(message);
212}
213
214CommandReturnObject *SBCommandReturnObject::operator->() const {
215  return &**m_opaque_up;
216}
217
218CommandReturnObject *SBCommandReturnObject::get() const {
219  return &**m_opaque_up;
220}
221
222CommandReturnObject &SBCommandReturnObject::operator*() const {
223  return **m_opaque_up;
224}
225
226CommandReturnObject &SBCommandReturnObject::ref() const {
227  return **m_opaque_up;
228}
229
230bool SBCommandReturnObject::GetDescription(SBStream &description) {
231  LLDB_RECORD_METHOD(bool, SBCommandReturnObject, GetDescription,
232                     (lldb::SBStream &), description);
233
234  Stream &strm = description.ref();
235
236  description.Printf("Error:  ");
237  lldb::ReturnStatus status = ref().GetStatus();
238  if (status == lldb::eReturnStatusStarted)
239    strm.PutCString("Started");
240  else if (status == lldb::eReturnStatusInvalid)
241    strm.PutCString("Invalid");
242  else if (ref().Succeeded())
243    strm.PutCString("Success");
244  else
245    strm.PutCString("Fail");
246
247  if (GetOutputSize() > 0)
248    strm.Printf("\nOutput Message:\n%s", GetOutput());
249
250  if (GetErrorSize() > 0)
251    strm.Printf("\nError Message:\n%s", GetError());
252
253  return true;
254}
255
256void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh) {
257  LLDB_RECORD_DUMMY(void, SBCommandReturnObject, SetImmediateOutputFile,
258                    (FILE *), fh);
259
260  SetImmediateOutputFile(fh, false);
261}
262
263void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh) {
264  LLDB_RECORD_DUMMY(void, SBCommandReturnObject, SetImmediateErrorFile,
265                    (FILE *), fh);
266
267  SetImmediateErrorFile(fh, false);
268}
269
270void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh,
271                                                   bool transfer_ownership) {
272  LLDB_RECORD_DUMMY(void, SBCommandReturnObject, SetImmediateOutputFile,
273                    (FILE *, bool), fh, transfer_ownership);
274  FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership);
275  ref().SetImmediateOutputFile(file);
276}
277
278void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh,
279                                                  bool transfer_ownership) {
280  LLDB_RECORD_DUMMY(void, SBCommandReturnObject, SetImmediateErrorFile,
281                    (FILE *, bool), fh, transfer_ownership);
282  FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership);
283  ref().SetImmediateErrorFile(file);
284}
285
286void SBCommandReturnObject::SetImmediateOutputFile(SBFile file) {
287  LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
288                     (SBFile), file);
289  ref().SetImmediateOutputFile(file.m_opaque_sp);
290}
291
292void SBCommandReturnObject::SetImmediateErrorFile(SBFile file) {
293  LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
294                     (SBFile), file);
295  ref().SetImmediateErrorFile(file.m_opaque_sp);
296}
297
298void SBCommandReturnObject::SetImmediateOutputFile(FileSP file_sp) {
299  LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
300                     (FileSP), file_sp);
301  SetImmediateOutputFile(SBFile(file_sp));
302}
303
304void SBCommandReturnObject::SetImmediateErrorFile(FileSP file_sp) {
305  LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
306                     (FileSP), file_sp);
307  SetImmediateErrorFile(SBFile(file_sp));
308}
309
310void SBCommandReturnObject::PutCString(const char *string, int len) {
311  LLDB_RECORD_METHOD(void, SBCommandReturnObject, PutCString,
312                     (const char *, int), string, len);
313
314  if (len == 0 || string == nullptr || *string == 0) {
315    return;
316  } else if (len > 0) {
317    std::string buffer(string, len);
318    ref().AppendMessage(buffer.c_str());
319  } else
320    ref().AppendMessage(string);
321}
322
323const char *SBCommandReturnObject::GetOutput(bool only_if_no_immediate) {
324  LLDB_RECORD_METHOD(const char *, SBCommandReturnObject, GetOutput, (bool),
325                     only_if_no_immediate);
326
327  if (!only_if_no_immediate ||
328      ref().GetImmediateOutputStream().get() == nullptr)
329    return GetOutput();
330  return nullptr;
331}
332
333const char *SBCommandReturnObject::GetError(bool only_if_no_immediate) {
334  LLDB_RECORD_METHOD(const char *, SBCommandReturnObject, GetError, (bool),
335                     only_if_no_immediate);
336
337  if (!only_if_no_immediate || ref().GetImmediateErrorStream().get() == nullptr)
338    return GetError();
339  return nullptr;
340}
341
342size_t SBCommandReturnObject::Printf(const char *format, ...) {
343  va_list args;
344  va_start(args, format);
345  size_t result = ref().GetOutputStream().PrintfVarArg(format, args);
346  va_end(args);
347  return result;
348}
349
350void SBCommandReturnObject::SetError(lldb::SBError &error,
351                                     const char *fallback_error_cstr) {
352  LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetError,
353                     (lldb::SBError &, const char *), error,
354                     fallback_error_cstr);
355
356  if (error.IsValid())
357    ref().SetError(error.ref(), fallback_error_cstr);
358  else if (fallback_error_cstr)
359    ref().SetError(Status(), fallback_error_cstr);
360}
361
362void SBCommandReturnObject::SetError(const char *error_cstr) {
363  LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetError, (const char *),
364                     error_cstr);
365
366  if (error_cstr)
367    ref().SetError(error_cstr);
368}
369
370namespace lldb_private {
371namespace repro {
372
373template <>
374void RegisterMethods<SBCommandReturnObject>(Registry &R) {
375  LLDB_REGISTER_CONSTRUCTOR(SBCommandReturnObject, ());
376  LLDB_REGISTER_CONSTRUCTOR(SBCommandReturnObject,
377                            (lldb_private::CommandReturnObject &));
378  LLDB_REGISTER_CONSTRUCTOR(SBCommandReturnObject,
379                            (const lldb::SBCommandReturnObject &));
380  LLDB_REGISTER_METHOD(
381      lldb::SBCommandReturnObject &,
382      SBCommandReturnObject, operator=,(const lldb::SBCommandReturnObject &));
383  LLDB_REGISTER_METHOD_CONST(bool, SBCommandReturnObject, IsValid, ());
384  LLDB_REGISTER_METHOD_CONST(bool, SBCommandReturnObject, operator bool, ());
385  LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetOutput, ());
386  LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetError, ());
387  LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, GetOutputSize, ());
388  LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, GetErrorSize, ());
389  LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutOutput, (FILE *));
390  LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutError, (FILE *));
391  LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutOutput, (SBFile));
392  LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutError, (SBFile));
393  LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutOutput, (FileSP));
394  LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutError, (FileSP));
395  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, Clear, ());
396  LLDB_REGISTER_METHOD(lldb::ReturnStatus, SBCommandReturnObject, GetStatus,
397                       ());
398  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetStatus,
399                       (lldb::ReturnStatus));
400  LLDB_REGISTER_METHOD(bool, SBCommandReturnObject, Succeeded, ());
401  LLDB_REGISTER_METHOD(bool, SBCommandReturnObject, HasResult, ());
402  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, AppendMessage,
403                       (const char *));
404  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, AppendWarning,
405                       (const char *));
406  LLDB_REGISTER_METHOD(bool, SBCommandReturnObject, GetDescription,
407                       (lldb::SBStream &));
408  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
409                       (FILE *));
410  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
411                       (FILE *));
412  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
413                       (SBFile));
414  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
415                       (SBFile));
416  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
417                       (FileSP));
418  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
419                       (FileSP));
420  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
421                       (FILE *, bool));
422  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
423                       (FILE *, bool));
424  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, PutCString,
425                       (const char *, int));
426  LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetOutput,
427                       (bool));
428  LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetError, (bool));
429  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetError,
430                       (lldb::SBError &, const char *));
431  LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetError, (const char *));
432}
433
434}
435}
436