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