1e2ae97f2SGreg Clayton //===-- SBStream.cpp ----------------------------------------*- C++ -*-===// 2e2ae97f2SGreg Clayton // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e2ae97f2SGreg Clayton // 7e2ae97f2SGreg Clayton //===----------------------------------------------------------------------===// 8e2ae97f2SGreg Clayton 9e2ae97f2SGreg Clayton #include "lldb/API/SBStream.h" 10e2ae97f2SGreg Clayton 11*baf5664fSJonas Devlieghere #include "SBReproducerPrivate.h" 12e2ae97f2SGreg Clayton #include "lldb/Core/StreamFile.h" 1350bc1ed2SJonas Devlieghere #include "lldb/Host/FileSystem.h" 1497206d57SZachary Turner #include "lldb/Utility/Status.h" 15bf9a7730SZachary Turner #include "lldb/Utility/Stream.h" 16bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h" 17e2ae97f2SGreg Clayton 18e2ae97f2SGreg Clayton using namespace lldb; 19e2ae97f2SGreg Clayton using namespace lldb_private; 20e2ae97f2SGreg Clayton 21*baf5664fSJonas Devlieghere SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) { 22*baf5664fSJonas Devlieghere LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream); 23*baf5664fSJonas Devlieghere } 24e2ae97f2SGreg Clayton 25b9c1b51eSKate Stone SBStream::SBStream(SBStream &&rhs) 26d5b44036SJonas Devlieghere : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {} 270817da88SGreg Clayton 28b9c1b51eSKate Stone SBStream::~SBStream() {} 290817da88SGreg Clayton 30*baf5664fSJonas Devlieghere bool SBStream::IsValid() const { 31*baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid); 32*baf5664fSJonas Devlieghere 33*baf5664fSJonas Devlieghere return (m_opaque_up != NULL); 34*baf5664fSJonas Devlieghere } 35e2ae97f2SGreg Clayton 3605097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache 3705097246SAdrian Prantl // for the stream data which can be accessed using this accessor. 38b9c1b51eSKate Stone const char *SBStream::GetData() { 39*baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData); 40*baf5664fSJonas Devlieghere 41d5b44036SJonas Devlieghere if (m_is_file || m_opaque_up == NULL) 42e2ae97f2SGreg Clayton return NULL; 43e2ae97f2SGreg Clayton 44d5b44036SJonas Devlieghere return static_cast<StreamString *>(m_opaque_up.get())->GetData(); 45e2ae97f2SGreg Clayton } 46e2ae97f2SGreg Clayton 4705097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache 4805097246SAdrian Prantl // for the stream output whose length can be accessed using this accessor. 49b9c1b51eSKate Stone size_t SBStream::GetSize() { 50*baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize); 51*baf5664fSJonas Devlieghere 52d5b44036SJonas Devlieghere if (m_is_file || m_opaque_up == NULL) 5360fd91ffSBill Wendling return 0; 54e2ae97f2SGreg Clayton 55d5b44036SJonas Devlieghere return static_cast<StreamString *>(m_opaque_up.get())->GetSize(); 56e2ae97f2SGreg Clayton } 57e2ae97f2SGreg Clayton 58b9c1b51eSKate Stone void SBStream::Printf(const char *format, ...) { 594f8189bcSJohnny Chen if (!format) 604f8189bcSJohnny Chen return; 61e2ae97f2SGreg Clayton va_list args; 62e2ae97f2SGreg Clayton va_start(args, format); 63e2ae97f2SGreg Clayton ref().PrintfVarArg(format, args); 64e2ae97f2SGreg Clayton va_end(args); 65e2ae97f2SGreg Clayton } 66e2ae97f2SGreg Clayton 67b9c1b51eSKate Stone void SBStream::RedirectToFile(const char *path, bool append) { 68*baf5664fSJonas Devlieghere LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path, 69*baf5664fSJonas Devlieghere append); 70*baf5664fSJonas Devlieghere 71e2dcbd00SZachary Turner if (path == nullptr) 72e2dcbd00SZachary Turner return; 73e2dcbd00SZachary Turner 74e2ae97f2SGreg Clayton std::string local_data; 75d5b44036SJonas Devlieghere if (m_opaque_up) { 76e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 77e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 78e2ae97f2SGreg Clayton if (!m_is_file) 79d5b44036SJonas Devlieghere local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 80e2ae97f2SGreg Clayton } 8151b1e2d2SGreg Clayton StreamFile *stream_file = new StreamFile; 8251b1e2d2SGreg Clayton uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; 8351b1e2d2SGreg Clayton if (append) 8451b1e2d2SGreg Clayton open_options |= File::eOpenOptionAppend; 8506357c93SGreg Clayton else 8606357c93SGreg Clayton open_options |= File::eOpenOptionTruncate; 8751b1e2d2SGreg Clayton 8850bc1ed2SJonas Devlieghere FileSystem::Instance().Open(stream_file->GetFile(), FileSpec(path), 8950bc1ed2SJonas Devlieghere open_options); 90d5b44036SJonas Devlieghere m_opaque_up.reset(stream_file); 91e2ae97f2SGreg Clayton 92d5b44036SJonas Devlieghere if (m_opaque_up) { 93e2ae97f2SGreg Clayton m_is_file = true; 94e2ae97f2SGreg Clayton 95e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to 96e2ae97f2SGreg Clayton // the to new file we are redirecting to. 97e2ae97f2SGreg Clayton if (!local_data.empty()) 98d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size()); 99b9c1b51eSKate Stone } else 100e2ae97f2SGreg Clayton m_is_file = false; 101e2ae97f2SGreg Clayton } 102e2ae97f2SGreg Clayton 103b9c1b51eSKate Stone void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) { 104*baf5664fSJonas Devlieghere LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh, 105*baf5664fSJonas Devlieghere transfer_fh_ownership); 106*baf5664fSJonas Devlieghere 107e2dcbd00SZachary Turner if (fh == nullptr) 108e2dcbd00SZachary Turner return; 109e2dcbd00SZachary Turner 110e2ae97f2SGreg Clayton std::string local_data; 111d5b44036SJonas Devlieghere if (m_opaque_up) { 112e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 113e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 114e2ae97f2SGreg Clayton if (!m_is_file) 115d5b44036SJonas Devlieghere local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 116e2ae97f2SGreg Clayton } 117d5b44036SJonas Devlieghere m_opaque_up.reset(new StreamFile(fh, transfer_fh_ownership)); 118e2ae97f2SGreg Clayton 119d5b44036SJonas Devlieghere if (m_opaque_up) { 120e2ae97f2SGreg Clayton m_is_file = true; 121e2ae97f2SGreg Clayton 122e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to 123e2ae97f2SGreg Clayton // the to new file we are redirecting to. 124e2ae97f2SGreg Clayton if (!local_data.empty()) 125d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size()); 126b9c1b51eSKate Stone } else 127e2ae97f2SGreg Clayton m_is_file = false; 128e2ae97f2SGreg Clayton } 129e2ae97f2SGreg Clayton 130b9c1b51eSKate Stone void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) { 131*baf5664fSJonas Devlieghere LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd, 132*baf5664fSJonas Devlieghere transfer_fh_ownership); 133*baf5664fSJonas Devlieghere 134e2ae97f2SGreg Clayton std::string local_data; 135d5b44036SJonas Devlieghere if (m_opaque_up) { 136e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 137e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 138e2ae97f2SGreg Clayton if (!m_is_file) 139d5b44036SJonas Devlieghere local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 140e2ae97f2SGreg Clayton } 141e2ae97f2SGreg Clayton 142d5b44036SJonas Devlieghere m_opaque_up.reset(new StreamFile(::fdopen(fd, "w"), transfer_fh_ownership)); 143d5b44036SJonas Devlieghere if (m_opaque_up) { 144e2ae97f2SGreg Clayton m_is_file = true; 145e2ae97f2SGreg Clayton 146e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to 147e2ae97f2SGreg Clayton // the to new file we are redirecting to. 148e2ae97f2SGreg Clayton if (!local_data.empty()) 149d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size()); 150b9c1b51eSKate Stone } else 151e2ae97f2SGreg Clayton m_is_file = false; 152e2ae97f2SGreg Clayton } 153e2ae97f2SGreg Clayton 154d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); } 155e2ae97f2SGreg Clayton 156d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); } 157e2ae97f2SGreg Clayton 158b9c1b51eSKate Stone lldb_private::Stream &SBStream::ref() { 159d5b44036SJonas Devlieghere if (m_opaque_up == NULL) 160d5b44036SJonas Devlieghere m_opaque_up.reset(new StreamString()); 161d5b44036SJonas Devlieghere return *m_opaque_up; 162e2ae97f2SGreg Clayton } 163e2ae97f2SGreg Clayton 164b9c1b51eSKate Stone void SBStream::Clear() { 165*baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear); 166*baf5664fSJonas Devlieghere 167d5b44036SJonas Devlieghere if (m_opaque_up) { 168e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 169e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 170e2ae97f2SGreg Clayton if (m_is_file) 171d5b44036SJonas Devlieghere m_opaque_up.reset(); 172e2ae97f2SGreg Clayton else 173d5b44036SJonas Devlieghere static_cast<StreamString *>(m_opaque_up.get())->Clear(); 174e2ae97f2SGreg Clayton } 175e2ae97f2SGreg Clayton } 176