15ffd83dbSDimitry Andric //===-- StringList.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/Utility/StringList.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
120b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
130b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
140b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric #include <algorithm>
17fe6060f1SDimitry Andric #include <cstdint>
18fe6060f1SDimitry Andric #include <cstring>
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric using namespace lldb_private;
210b57cec5SDimitry Andric
StringList()220b57cec5SDimitry Andric StringList::StringList() : m_strings() {}
230b57cec5SDimitry Andric
StringList(const char * str)240b57cec5SDimitry Andric StringList::StringList(const char *str) : m_strings() {
250b57cec5SDimitry Andric if (str)
260b57cec5SDimitry Andric m_strings.push_back(str);
270b57cec5SDimitry Andric }
280b57cec5SDimitry Andric
StringList(const char ** strv,int strc)290b57cec5SDimitry Andric StringList::StringList(const char **strv, int strc) : m_strings() {
300b57cec5SDimitry Andric for (int i = 0; i < strc; ++i) {
310b57cec5SDimitry Andric if (strv[i])
320b57cec5SDimitry Andric m_strings.push_back(strv[i]);
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric
36fe6060f1SDimitry Andric StringList::~StringList() = default;
370b57cec5SDimitry Andric
AppendString(const char * str)380b57cec5SDimitry Andric void StringList::AppendString(const char *str) {
390b57cec5SDimitry Andric if (str)
400b57cec5SDimitry Andric m_strings.push_back(str);
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric
AppendString(const std::string & s)430b57cec5SDimitry Andric void StringList::AppendString(const std::string &s) { m_strings.push_back(s); }
440b57cec5SDimitry Andric
AppendString(std::string && s)4504eeddc0SDimitry Andric void StringList::AppendString(std::string &&s) {
4604eeddc0SDimitry Andric m_strings.push_back(std::move(s));
4704eeddc0SDimitry Andric }
480b57cec5SDimitry Andric
AppendString(const char * str,size_t str_len)490b57cec5SDimitry Andric void StringList::AppendString(const char *str, size_t str_len) {
500b57cec5SDimitry Andric if (str)
510b57cec5SDimitry Andric m_strings.push_back(std::string(str, str_len));
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric
AppendString(llvm::StringRef str)540b57cec5SDimitry Andric void StringList::AppendString(llvm::StringRef str) {
550b57cec5SDimitry Andric m_strings.push_back(str.str());
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric
AppendString(const llvm::Twine & str)5804eeddc0SDimitry Andric void StringList::AppendString(const llvm::Twine &str) {
5904eeddc0SDimitry Andric m_strings.push_back(str.str());
6004eeddc0SDimitry Andric }
6104eeddc0SDimitry Andric
AppendList(const char ** strv,int strc)620b57cec5SDimitry Andric void StringList::AppendList(const char **strv, int strc) {
630b57cec5SDimitry Andric for (int i = 0; i < strc; ++i) {
640b57cec5SDimitry Andric if (strv[i])
650b57cec5SDimitry Andric m_strings.push_back(strv[i]);
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
AppendList(StringList strings)690b57cec5SDimitry Andric void StringList::AppendList(StringList strings) {
709dba64beSDimitry Andric m_strings.reserve(m_strings.size() + strings.GetSize());
719dba64beSDimitry Andric m_strings.insert(m_strings.end(), strings.begin(), strings.end());
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric
GetSize() const740b57cec5SDimitry Andric size_t StringList::GetSize() const { return m_strings.size(); }
750b57cec5SDimitry Andric
GetMaxStringLength() const760b57cec5SDimitry Andric size_t StringList::GetMaxStringLength() const {
770b57cec5SDimitry Andric size_t max_length = 0;
780b57cec5SDimitry Andric for (const auto &s : m_strings) {
790b57cec5SDimitry Andric const size_t len = s.size();
800b57cec5SDimitry Andric if (max_length < len)
810b57cec5SDimitry Andric max_length = len;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric return max_length;
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric
GetStringAtIndex(size_t idx) const860b57cec5SDimitry Andric const char *StringList::GetStringAtIndex(size_t idx) const {
870b57cec5SDimitry Andric if (idx < m_strings.size())
880b57cec5SDimitry Andric return m_strings[idx].c_str();
890b57cec5SDimitry Andric return nullptr;
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric
Join(const char * separator,Stream & strm)920b57cec5SDimitry Andric void StringList::Join(const char *separator, Stream &strm) {
930b57cec5SDimitry Andric size_t size = GetSize();
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric if (size == 0)
960b57cec5SDimitry Andric return;
970b57cec5SDimitry Andric
980b57cec5SDimitry Andric for (uint32_t i = 0; i < size; ++i) {
990b57cec5SDimitry Andric if (i > 0)
1000b57cec5SDimitry Andric strm.PutCString(separator);
1010b57cec5SDimitry Andric strm.PutCString(GetStringAtIndex(i));
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric
Clear()1050b57cec5SDimitry Andric void StringList::Clear() { m_strings.clear(); }
1060b57cec5SDimitry Andric
LongestCommonPrefix()1079dba64beSDimitry Andric std::string StringList::LongestCommonPrefix() {
1080b57cec5SDimitry Andric if (m_strings.empty())
1099dba64beSDimitry Andric return {};
1100b57cec5SDimitry Andric
111*bdd1243dSDimitry Andric auto args = llvm::ArrayRef(m_strings);
1120b57cec5SDimitry Andric llvm::StringRef prefix = args.front();
1130b57cec5SDimitry Andric for (auto arg : args.drop_front()) {
1140b57cec5SDimitry Andric size_t count = 0;
1150b57cec5SDimitry Andric for (count = 0; count < std::min(prefix.size(), arg.size()); ++count) {
1160b57cec5SDimitry Andric if (prefix[count] != arg[count])
1170b57cec5SDimitry Andric break;
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric prefix = prefix.take_front(count);
1200b57cec5SDimitry Andric }
1219dba64beSDimitry Andric return prefix.str();
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric
InsertStringAtIndex(size_t idx,const char * str)1240b57cec5SDimitry Andric void StringList::InsertStringAtIndex(size_t idx, const char *str) {
1250b57cec5SDimitry Andric if (str) {
1260b57cec5SDimitry Andric if (idx < m_strings.size())
1270b57cec5SDimitry Andric m_strings.insert(m_strings.begin() + idx, str);
1280b57cec5SDimitry Andric else
1290b57cec5SDimitry Andric m_strings.push_back(str);
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric
InsertStringAtIndex(size_t idx,const std::string & str)1330b57cec5SDimitry Andric void StringList::InsertStringAtIndex(size_t idx, const std::string &str) {
1340b57cec5SDimitry Andric if (idx < m_strings.size())
1350b57cec5SDimitry Andric m_strings.insert(m_strings.begin() + idx, str);
1360b57cec5SDimitry Andric else
1370b57cec5SDimitry Andric m_strings.push_back(str);
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric
InsertStringAtIndex(size_t idx,std::string && str)1400b57cec5SDimitry Andric void StringList::InsertStringAtIndex(size_t idx, std::string &&str) {
1410b57cec5SDimitry Andric if (idx < m_strings.size())
14204eeddc0SDimitry Andric m_strings.insert(m_strings.begin() + idx, std::move(str));
1430b57cec5SDimitry Andric else
14404eeddc0SDimitry Andric m_strings.push_back(std::move(str));
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric
DeleteStringAtIndex(size_t idx)1470b57cec5SDimitry Andric void StringList::DeleteStringAtIndex(size_t idx) {
1480b57cec5SDimitry Andric if (idx < m_strings.size())
1490b57cec5SDimitry Andric m_strings.erase(m_strings.begin() + idx);
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric
SplitIntoLines(const std::string & lines)1520b57cec5SDimitry Andric size_t StringList::SplitIntoLines(const std::string &lines) {
1530b57cec5SDimitry Andric return SplitIntoLines(lines.c_str(), lines.size());
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric
SplitIntoLines(const char * lines,size_t len)1560b57cec5SDimitry Andric size_t StringList::SplitIntoLines(const char *lines, size_t len) {
1570b57cec5SDimitry Andric const size_t orig_size = m_strings.size();
1580b57cec5SDimitry Andric
1590b57cec5SDimitry Andric if (len == 0)
1600b57cec5SDimitry Andric return 0;
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric const char *k_newline_chars = "\r\n";
1630b57cec5SDimitry Andric const char *p = lines;
1640b57cec5SDimitry Andric const char *end = lines + len;
1650b57cec5SDimitry Andric while (p < end) {
1660b57cec5SDimitry Andric size_t count = strcspn(p, k_newline_chars);
1670b57cec5SDimitry Andric if (count == 0) {
1680b57cec5SDimitry Andric if (p[count] == '\r' || p[count] == '\n')
1690b57cec5SDimitry Andric m_strings.push_back(std::string());
1700b57cec5SDimitry Andric else
1710b57cec5SDimitry Andric break;
1720b57cec5SDimitry Andric } else {
1730b57cec5SDimitry Andric if (p + count > end)
1740b57cec5SDimitry Andric count = end - p;
1750b57cec5SDimitry Andric m_strings.push_back(std::string(p, count));
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric if (p[count] == '\r' && p[count + 1] == '\n')
1780b57cec5SDimitry Andric count++; // Skip an extra newline char for the DOS newline
1790b57cec5SDimitry Andric count++; // Skip the newline character
1800b57cec5SDimitry Andric p += count;
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric return m_strings.size() - orig_size;
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric
RemoveBlankLines()1850b57cec5SDimitry Andric void StringList::RemoveBlankLines() {
1860b57cec5SDimitry Andric if (GetSize() == 0)
1870b57cec5SDimitry Andric return;
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric size_t idx = 0;
1900b57cec5SDimitry Andric while (idx < m_strings.size()) {
1910b57cec5SDimitry Andric if (m_strings[idx].empty())
1920b57cec5SDimitry Andric DeleteStringAtIndex(idx);
1930b57cec5SDimitry Andric else
1940b57cec5SDimitry Andric idx++;
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric
CopyList(const char * item_preamble,const char * items_sep) const1980b57cec5SDimitry Andric std::string StringList::CopyList(const char *item_preamble,
1990b57cec5SDimitry Andric const char *items_sep) const {
2000b57cec5SDimitry Andric StreamString strm;
2010b57cec5SDimitry Andric for (size_t i = 0; i < GetSize(); i++) {
2020b57cec5SDimitry Andric if (i && items_sep && items_sep[0])
2030b57cec5SDimitry Andric strm << items_sep;
2040b57cec5SDimitry Andric if (item_preamble)
2050b57cec5SDimitry Andric strm << item_preamble;
2060b57cec5SDimitry Andric strm << GetStringAtIndex(i);
2070b57cec5SDimitry Andric }
2085ffd83dbSDimitry Andric return std::string(strm.GetString());
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric
operator <<(const char * str)2110b57cec5SDimitry Andric StringList &StringList::operator<<(const char *str) {
2120b57cec5SDimitry Andric AppendString(str);
2130b57cec5SDimitry Andric return *this;
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric
operator <<(const std::string & str)2160b57cec5SDimitry Andric StringList &StringList::operator<<(const std::string &str) {
2170b57cec5SDimitry Andric AppendString(str);
2180b57cec5SDimitry Andric return *this;
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric
operator <<(const StringList & strings)221e8d8bef9SDimitry Andric StringList &StringList::operator<<(const StringList &strings) {
2220b57cec5SDimitry Andric AppendList(strings);
2230b57cec5SDimitry Andric return *this;
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric
operator =(const std::vector<std::string> & rhs)2260b57cec5SDimitry Andric StringList &StringList::operator=(const std::vector<std::string> &rhs) {
2270b57cec5SDimitry Andric m_strings.assign(rhs.begin(), rhs.end());
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric return *this;
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric
LogDump(Log * log,const char * name)2320b57cec5SDimitry Andric void StringList::LogDump(Log *log, const char *name) {
2330b57cec5SDimitry Andric if (!log)
2340b57cec5SDimitry Andric return;
2350b57cec5SDimitry Andric
2360b57cec5SDimitry Andric StreamString strm;
2370b57cec5SDimitry Andric if (name)
2380b57cec5SDimitry Andric strm.Printf("Begin %s:\n", name);
2390b57cec5SDimitry Andric for (const auto &s : m_strings) {
2400b57cec5SDimitry Andric strm.Indent();
2410b57cec5SDimitry Andric strm.Printf("%s\n", s.c_str());
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric if (name)
2440b57cec5SDimitry Andric strm.Printf("End %s.\n", name);
2450b57cec5SDimitry Andric
2460b57cec5SDimitry Andric LLDB_LOGV(log, "{0}", strm.GetData());
2470b57cec5SDimitry Andric }
248