15ffd83dbSDimitry Andric //===-- SBStream.cpp ------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/API/SBStream.h"
100b57cec5SDimitry Andric 
119dba64beSDimitry Andric #include "lldb/API/SBFile.h"
120b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
13*c9157d92SDimitry Andric #include "lldb/Host/StreamFile.h"
1404eeddc0SDimitry Andric #include "lldb/Utility/Instrumentation.h"
1581ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
160b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
170b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
180b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric using namespace lldb;
210b57cec5SDimitry Andric using namespace lldb_private;
220b57cec5SDimitry Andric 
SBStream()23fe6060f1SDimitry Andric SBStream::SBStream() : m_opaque_up(new StreamString()) {
2404eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this);
250b57cec5SDimitry Andric }
260b57cec5SDimitry Andric 
SBStream(SBStream && rhs)270b57cec5SDimitry Andric SBStream::SBStream(SBStream &&rhs)
280b57cec5SDimitry Andric     : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {}
290b57cec5SDimitry Andric 
305ffd83dbSDimitry Andric SBStream::~SBStream() = default;
310b57cec5SDimitry Andric 
IsValid() const320b57cec5SDimitry Andric bool SBStream::IsValid() const {
3304eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this);
340b57cec5SDimitry Andric   return this->operator bool();
350b57cec5SDimitry Andric }
operator bool() const360b57cec5SDimitry Andric SBStream::operator bool() const {
3704eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this);
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   return (m_opaque_up != nullptr);
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric // If this stream is not redirected to a file, it will maintain a local cache
430b57cec5SDimitry Andric // for the stream data which can be accessed using this accessor.
GetData()440b57cec5SDimitry Andric const char *SBStream::GetData() {
4504eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this);
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   if (m_is_file || m_opaque_up == nullptr)
480b57cec5SDimitry Andric     return nullptr;
490b57cec5SDimitry Andric 
50fe013be4SDimitry Andric   return ConstString(static_cast<StreamString *>(m_opaque_up.get())->GetData())
51fe013be4SDimitry Andric       .GetCString();
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric // If this stream is not redirected to a file, it will maintain a local cache
550b57cec5SDimitry Andric // for the stream output whose length can be accessed using this accessor.
GetSize()560b57cec5SDimitry Andric size_t SBStream::GetSize() {
5704eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this);
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   if (m_is_file || m_opaque_up == nullptr)
600b57cec5SDimitry Andric     return 0;
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   return static_cast<StreamString *>(m_opaque_up.get())->GetSize();
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
Print(const char * str)655ffd83dbSDimitry Andric void SBStream::Print(const char *str) {
6604eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this, str);
675ffd83dbSDimitry Andric 
685ffd83dbSDimitry Andric   Printf("%s", str);
695ffd83dbSDimitry Andric }
705ffd83dbSDimitry Andric 
Printf(const char * format,...)710b57cec5SDimitry Andric void SBStream::Printf(const char *format, ...) {
720b57cec5SDimitry Andric   if (!format)
730b57cec5SDimitry Andric     return;
740b57cec5SDimitry Andric   va_list args;
750b57cec5SDimitry Andric   va_start(args, format);
760b57cec5SDimitry Andric   ref().PrintfVarArg(format, args);
770b57cec5SDimitry Andric   va_end(args);
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
RedirectToFile(const char * path,bool append)800b57cec5SDimitry Andric void SBStream::RedirectToFile(const char *path, bool append) {
8104eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this, path, append);
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   if (path == nullptr)
840b57cec5SDimitry Andric     return;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   std::string local_data;
870b57cec5SDimitry Andric   if (m_opaque_up) {
880b57cec5SDimitry Andric     // See if we have any locally backed data. If so, copy it so we can then
890b57cec5SDimitry Andric     // redirect it to the file so we don't lose the data
900b57cec5SDimitry Andric     if (!m_is_file)
915ffd83dbSDimitry Andric       local_data = std::string(
925ffd83dbSDimitry Andric           static_cast<StreamString *>(m_opaque_up.get())->GetString());
930b57cec5SDimitry Andric   }
94349cc55cSDimitry Andric   auto open_options = File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;
950b57cec5SDimitry Andric   if (append)
960b57cec5SDimitry Andric     open_options |= File::eOpenOptionAppend;
970b57cec5SDimitry Andric   else
980b57cec5SDimitry Andric     open_options |= File::eOpenOptionTruncate;
990b57cec5SDimitry Andric 
1009dba64beSDimitry Andric   llvm::Expected<FileUP> file =
1019dba64beSDimitry Andric       FileSystem::Instance().Open(FileSpec(path), open_options);
1029dba64beSDimitry Andric   if (!file) {
10381ad6265SDimitry Andric     LLDB_LOG_ERROR(GetLog(LLDBLog::API), file.takeError(),
1049dba64beSDimitry Andric                    "Cannot open {1}: {0}", path);
1059dba64beSDimitry Andric     return;
1069dba64beSDimitry Andric   }
1070b57cec5SDimitry Andric 
1089dba64beSDimitry Andric   m_opaque_up = std::make_unique<StreamFile>(std::move(file.get()));
1090b57cec5SDimitry Andric   m_is_file = true;
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   // If we had any data locally in our StreamString, then pass that along to
1120b57cec5SDimitry Andric   // the to new file we are redirecting to.
1130b57cec5SDimitry Andric   if (!local_data.empty())
1140b57cec5SDimitry Andric     m_opaque_up->Write(&local_data[0], local_data.size());
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
RedirectToFileHandle(FILE * fh,bool transfer_fh_ownership)1170b57cec5SDimitry Andric void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
11804eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this, fh, transfer_fh_ownership);
1199dba64beSDimitry Andric   FileSP file = std::make_unique<NativeFile>(fh, transfer_fh_ownership);
1209dba64beSDimitry Andric   return RedirectToFile(file);
1219dba64beSDimitry Andric }
1220b57cec5SDimitry Andric 
RedirectToFile(SBFile file)1239dba64beSDimitry Andric void SBStream::RedirectToFile(SBFile file) {
12404eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this, file)
1259dba64beSDimitry Andric   RedirectToFile(file.GetFile());
1269dba64beSDimitry Andric }
1279dba64beSDimitry Andric 
RedirectToFile(FileSP file_sp)1289dba64beSDimitry Andric void SBStream::RedirectToFile(FileSP file_sp) {
12904eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this, file_sp);
1309dba64beSDimitry Andric 
1319dba64beSDimitry Andric   if (!file_sp || !file_sp->IsValid())
1320b57cec5SDimitry Andric     return;
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   std::string local_data;
1350b57cec5SDimitry Andric   if (m_opaque_up) {
1360b57cec5SDimitry Andric     // See if we have any locally backed data. If so, copy it so we can then
1370b57cec5SDimitry Andric     // redirect it to the file so we don't lose the data
1380b57cec5SDimitry Andric     if (!m_is_file)
1395ffd83dbSDimitry Andric       local_data = std::string(
1405ffd83dbSDimitry Andric           static_cast<StreamString *>(m_opaque_up.get())->GetString());
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric 
1439dba64beSDimitry Andric   m_opaque_up = std::make_unique<StreamFile>(file_sp);
1440b57cec5SDimitry Andric   m_is_file = true;
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric   // If we had any data locally in our StreamString, then pass that along to
1470b57cec5SDimitry Andric   // the to new file we are redirecting to.
1480b57cec5SDimitry Andric   if (!local_data.empty())
1490b57cec5SDimitry Andric     m_opaque_up->Write(&local_data[0], local_data.size());
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
RedirectToFileDescriptor(int fd,bool transfer_fh_ownership)1520b57cec5SDimitry Andric void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) {
15304eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this, fd, transfer_fh_ownership);
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   std::string local_data;
1560b57cec5SDimitry Andric   if (m_opaque_up) {
1570b57cec5SDimitry Andric     // See if we have any locally backed data. If so, copy it so we can then
1580b57cec5SDimitry Andric     // redirect it to the file so we don't lose the data
1590b57cec5SDimitry Andric     if (!m_is_file)
1605ffd83dbSDimitry Andric       local_data = std::string(
1615ffd83dbSDimitry Andric           static_cast<StreamString *>(m_opaque_up.get())->GetString());
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric 
1649dba64beSDimitry Andric   m_opaque_up = std::make_unique<StreamFile>(fd, transfer_fh_ownership);
1650b57cec5SDimitry Andric   m_is_file = true;
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   // If we had any data locally in our StreamString, then pass that along to
1680b57cec5SDimitry Andric   // the to new file we are redirecting to.
1690b57cec5SDimitry Andric   if (!local_data.empty())
1700b57cec5SDimitry Andric     m_opaque_up->Write(&local_data[0], local_data.size());
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric 
operator ->()1730b57cec5SDimitry Andric lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); }
1740b57cec5SDimitry Andric 
get()1750b57cec5SDimitry Andric lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); }
1760b57cec5SDimitry Andric 
ref()1770b57cec5SDimitry Andric lldb_private::Stream &SBStream::ref() {
1780b57cec5SDimitry Andric   if (m_opaque_up == nullptr)
1795ffd83dbSDimitry Andric     m_opaque_up = std::make_unique<StreamString>();
1800b57cec5SDimitry Andric   return *m_opaque_up;
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric 
Clear()1830b57cec5SDimitry Andric void SBStream::Clear() {
18404eeddc0SDimitry Andric   LLDB_INSTRUMENT_VA(this);
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   if (m_opaque_up) {
1870b57cec5SDimitry Andric     // See if we have any locally backed data. If so, copy it so we can then
1880b57cec5SDimitry Andric     // redirect it to the file so we don't lose the data
1890b57cec5SDimitry Andric     if (m_is_file)
1900b57cec5SDimitry Andric       m_opaque_up.reset();
1910b57cec5SDimitry Andric     else
1920b57cec5SDimitry Andric       static_cast<StreamString *>(m_opaque_up.get())->Clear();
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric }
195